diff options
Diffstat (limited to 'src/kernel/kernel.c')
-rw-r--r-- | src/kernel/kernel.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c new file mode 100644 index 0000000..3c520d6 --- /dev/null +++ b/src/kernel/kernel.c @@ -0,0 +1,202 @@ +#include <stdbool.h> +#include <stdint.h> +#include <stdarg.h> + +#include "vgatext.h" +#include "serial.h" +#include "console.h" +#include "stdlib.h" +#include "string.h" +#include "stdio.h" +#include "interrupts.h" +#include "driver.h" +#include "keyboard.h" +#include "mouse.h" +#include "pci.h" +#include "setjmp.h" + +#include "kernel.h" + +static jmp_buf panic_jmp_buf; + +static void handle_keyboard_event( keyboard_event_t *event, void *context ); +static void handle_mouse_event( mouse_event_t *event, void *context ); + +static bool terminate = false; + +// TODO: eliminate this, have a global kernel data structure, +// also elimiate all the object allocated on the stack in kernel_main +static driver_manager_t *global_driver_manager; + +// must be first entry in kernel.bin (0x8400) as stage 2 of +// the boot loader expects the entry point to be here! +void kernel_main( void ) +{ + serial_t serial; + serial_init( &serial ); + + vga_text_t vga_text; + vga_text_init( &vga_text ); + vga_text_set_color( &vga_text, VGA_TEXT_COLOR_LIGHT_GREY ); + vga_text_set_background_color( &vga_text, VGA_TEXT_COLOR_BLACK ); + + console_t console; + console_init( &console ); + console_add_vga_text_output( &console, &vga_text ); + console_add_serial_output( &console, &serial ); + + // initialize the early console of the kernel + stdio_set_console( &console ); + puts( "Started early kernel console" ); + printf( "Kernel code and data is at 0x%X, kernel stack at 0x%X\n", 0x8400, 0x90000 ); + + // exit point in case of kernel panic, do this as soon as + // possible, as soon we have an early console we can croak on + if( setjmp( panic_jmp_buf ) > 0 ) { + goto TERMINATE; + } + + puts( "Initializing interrupts" ); + interrupt_t interrupt; + interrupts_init( &interrupt ); + + puts( "Initializing drivers" ); + driver_manager_t driver_manager; + driver_manager_init( &driver_manager ); + global_driver_manager = &driver_manager; + + // hard-wired drivers + + keyboard_t keyboard; + keyboard_init( &keyboard, &handle_keyboard_event, (void *)&vga_text ); + interrupt_handler_t keyboard_interrupt_handler; + interrupt_handler_init( &keyboard_interrupt_handler, IRQ_BASE + 0x01, &interrupt, keyboard_handle_interrupt, &keyboard ); + interrupts_register_interrupt_handler( keyboard_interrupt_handler ); + driver_manager_add_driver( &driver_manager, (driver_t *)&keyboard ); + + mouse_t mouse; + mouse_init( &mouse, &handle_mouse_event, (void *)&vga_text ); + interrupt_handler_t mouse_interrupt_handler; + interrupt_handler_init( &mouse_interrupt_handler, IRQ_BASE + 0x0C, &interrupt, mouse_handle_interrupt, &mouse ); + interrupts_register_interrupt_handler( mouse_interrupt_handler ); + driver_manager_add_driver( &driver_manager, (driver_t *)&mouse ); + + // exit point in case of kernel panic, do this as soon as + // possible + if( setjmp( panic_jmp_buf ) > 0 ) { + goto TERMINATE; + } + + // dynamically detected and registered drivers + puts( "Detecting devices via PCI.." ); + pci_controller_t pci_controller; + pci_controller_init( &pci_controller ); + pci_controller_scan_and_register( &pci_controller, &driver_manager, &interrupt ); + + puts( "Activating drivers" ); + driver_manager_activate_all( &driver_manager ); + + puts( "Enabling interrupt handing now.." ); + interrupts_enable( ); + + puts( "Running.." ); + + // endless loop doing nothing, later we have to get events + // here from queues and for instance print characters received + // from the keyboard to stdout + while( !terminate ) { + // for now we are only interested in interrupts, + // so we let the main thread sleep instead of + // burning CPU.. + kernel_halt( ); + } + +TERMINATE: + puts( "Deactivating drivers" ); + driver_manager_deactivate_all( &driver_manager ); + + driver_manager_deinit( &driver_manager ); + + puts( "Kernel terminated" ); +} + +void kernel_panic( const char *format, ... ) +{ + (void)printf( "\n*** KERNEL PANIC ***\n" ); + + va_list args; + va_start( args, format ); + (void)vprintf( format, args ); + va_end( args ); + + longjmp( panic_jmp_buf, 47 ); +} + +static void handle_keyboard_event( keyboard_event_t *event, void *context ) +{ + static int pos = 0; + static char buf[80]; + vga_text_t *vga_text = (vga_text_t *)context; + + vga_text_hide_mouse_cursor( vga_text ); + + if( event->type == KEYBOARD_EVENT_TYPE_KEY_PRESSED ) { + if( event->key == KEYBOARD_KEY_ASCII ) { + if( event->ascii_key == '\n' ) { + buf[pos] = '\0'; + pos = 0; + puts( "" ); + if( strcmp( buf, "help" ) == 0 ) { + puts( "halt - terminate os" ); + puts( "mem - show memory usage" ); + puts( "driver - show status of drivers" ); + puts( "proc - show process status" ); + } else if( strcmp( buf, "halt" ) == 0 ) { + terminate = true; + } else if( strcmp( buf, "mem" ) == 0 ) { + // TODO: print memory usage + } else if( strcmp( buf, "proc" ) == 0 ) { + // TODO: print scheduler status + } else if( strcmp( buf, "driver" ) == 0 ) { + driver_manager_print_info_all( global_driver_manager ); + } else { + printf( "ERR: Unknown pre-boot command '%s'\n", buf ); + } + } else if( event->ascii_key == '\b' ) { + if( pos > 0 ) { + buf[--pos] = '\0'; + printf( "\n%s", buf ); + } + } else { + printf( "%c", event->ascii_key ); + buf[pos++] = event->ascii_key; + } + } + } +} + +static void handle_mouse_event( mouse_event_t *event, void *context ) +{ + vga_text_t *vga_text = (vga_text_t *)context; + + switch( event->type ) { + case MOUSE_EVENT_TYPE_BUTTON_UP: + vga_text_hide_mouse_cursor( vga_text ); + printf( "MOUSE UP %d AT X:%d, Y:%d\n", event->button, event->cursor_x, + event->cursor_y ); + vga_text_show_mouse_cursor( vga_text ); + break; + + case MOUSE_EVENT_TYPE_BUTTON_DOWN: + vga_text_hide_mouse_cursor( vga_text ); + printf( "MOUSE DOWN %d AT X:%d, Y:%d\n", event->button, event->cursor_x, + event->cursor_y ); + vga_text_show_mouse_cursor( vga_text ); + break; + + case MOUSE_EVENT_TYPE_MOVE: + vga_text_move_mouse_cursor( vga_text, event->cursor_x, event->cursor_y ); + vga_text_show_mouse_cursor( vga_text ); + break; + } +} |