summaryrefslogtreecommitdiff
path: root/src/kernel/kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/kernel.c')
-rw-r--r--src/kernel/kernel.c202
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;
+ }
+}