#include #include #include #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" // TODO: move away from main! #include "drivers/video/vga.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 (0x8800) 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" ); // TODO: get those values somehow from the boot loader printf( "Kernel code and data is at 0x%X, kernel stack at 0x%X\n", 0x8800, 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 ); // TODO: move away in pci.c or in a dynamic loader module later vga_t vga; vga_init( &vga, NULL ); driver_manager_add_driver( &driver_manager, (driver_t *)&vga ); puts( "Activating drivers" ); driver_manager_activate_all( &driver_manager ); if( vga_set_mode( &vga, vga_make_mode( 320, 200, 8 ) ) ) { // vga_set_pixel( &vga, 1, 1, vga_make_RGB( 0x00, 0x00, 0xA8 ) ); vga_draw_rectangle( &vga, 0, 0, 320, 200, vga_make_RGB( 0x00, 0x00, 0xA8 ) ); } // TODO: later, disable VGA text console in stdio and add the // graphical one.. 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; } }