From d6d1bdfefafff50b7b6d15d218c0a188570be541 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 10 Jun 2017 21:26:24 +0200 Subject: some big renames into subdirs of aspects updated README removed size_t in sys/types.h and sys/types.h itself, size_t is in stddef.h --- src/Makefile | 91 ++++++------ src/README | 34 ++++- src/console.c | 55 ------- src/console.h | 19 --- src/driver.c | 65 --------- src/driver.h | 31 ---- src/drivers/driver.c | 65 +++++++++ src/drivers/driver.h | 31 ++++ src/drivers/hdi/ps2/keyboard.c | 316 +++++++++++++++++++++++++++++++++++++++++ src/drivers/hdi/ps2/keyboard.h | 69 +++++++++ src/drivers/hdi/ps2/mouse.c | 250 ++++++++++++++++++++++++++++++++ src/drivers/hdi/ps2/mouse.h | 65 +++++++++ src/hardware/interrupts.asm | 90 ++++++++++++ src/hardware/interrupts.c | 215 ++++++++++++++++++++++++++++ src/hardware/interrupts.h | 103 ++++++++++++++ src/hardware/pci.c | 187 ++++++++++++++++++++++++ src/hardware/pci.h | 49 +++++++ src/hardware/port.asm | 49 +++++++ src/hardware/port.c | 17 +++ src/hardware/port.h | 23 +++ src/interrupts.asm | 90 ------------ src/interrupts.c | 215 ---------------------------- src/interrupts.h | 103 -------------- src/kernel.asm | 8 -- src/kernel.c | 202 -------------------------- src/kernel.h | 10 -- src/kernel/console.c | 55 +++++++ src/kernel/console.h | 19 +++ src/kernel/kernel.asm | 8 ++ src/kernel/kernel.c | 202 ++++++++++++++++++++++++++ src/kernel/kernel.h | 10 ++ src/kernel/serial.c | 121 ++++++++++++++++ src/kernel/serial.h | 20 +++ src/kernel/vgatext.c | 262 ++++++++++++++++++++++++++++++++++ src/kernel/vgatext.h | 68 +++++++++ src/keyboard.c | 316 ----------------------------------------- src/keyboard.h | 69 --------- src/libc/limits.h | 7 + src/libc/setjmp.asm | 44 ++++++ src/libc/setjmp.h | 24 ++++ src/libc/stddef.h | 10 ++ src/libc/stdio.c | 106 ++++++++++++++ src/libc/stdio.h | 20 +++ src/libc/stdlib.c | 48 +++++++ src/libc/stdlib.h | 6 + src/libc/string.c | 75 ++++++++++ src/libc/string.h | 12 ++ src/limits.h | 7 - src/mouse.c | 250 -------------------------------- src/mouse.h | 65 --------- src/pci.c | 187 ------------------------ src/pci.h | 49 ------- src/port.asm | 49 ------- src/port.c | 17 --- src/port.h | 23 --- src/serial.c | 121 ---------------- src/serial.h | 20 --- src/setjmp.asm | 44 ------ src/setjmp.h | 24 ---- src/stddef.h | 8 -- src/stdio.c | 106 -------------- src/stdio.h | 20 --- src/stdlib.c | 48 ------- src/stdlib.h | 6 - src/string.c | 75 ---------- src/string.h | 12 -- src/sys/types.h | 8 -- src/vgatext.c | 262 ---------------------------------- src/vgatext.h | 68 --------- 69 files changed, 2724 insertions(+), 2699 deletions(-) delete mode 100644 src/console.c delete mode 100644 src/console.h delete mode 100644 src/driver.c delete mode 100644 src/driver.h create mode 100644 src/drivers/driver.c create mode 100644 src/drivers/driver.h create mode 100644 src/drivers/hdi/ps2/keyboard.c create mode 100644 src/drivers/hdi/ps2/keyboard.h create mode 100644 src/drivers/hdi/ps2/mouse.c create mode 100644 src/drivers/hdi/ps2/mouse.h create mode 100644 src/hardware/interrupts.asm create mode 100644 src/hardware/interrupts.c create mode 100644 src/hardware/interrupts.h create mode 100644 src/hardware/pci.c create mode 100644 src/hardware/pci.h create mode 100644 src/hardware/port.asm create mode 100644 src/hardware/port.c create mode 100644 src/hardware/port.h delete mode 100644 src/interrupts.asm delete mode 100644 src/interrupts.c delete mode 100644 src/interrupts.h delete mode 100644 src/kernel.asm delete mode 100644 src/kernel.c delete mode 100644 src/kernel.h create mode 100644 src/kernel/console.c create mode 100644 src/kernel/console.h create mode 100644 src/kernel/kernel.asm create mode 100644 src/kernel/kernel.c create mode 100644 src/kernel/kernel.h create mode 100644 src/kernel/serial.c create mode 100644 src/kernel/serial.h create mode 100644 src/kernel/vgatext.c create mode 100644 src/kernel/vgatext.h delete mode 100644 src/keyboard.c delete mode 100644 src/keyboard.h create mode 100644 src/libc/limits.h create mode 100644 src/libc/setjmp.asm create mode 100644 src/libc/setjmp.h create mode 100644 src/libc/stddef.h create mode 100644 src/libc/stdio.c create mode 100644 src/libc/stdio.h create mode 100644 src/libc/stdlib.c create mode 100644 src/libc/stdlib.h create mode 100644 src/libc/string.c create mode 100644 src/libc/string.h delete mode 100644 src/limits.h delete mode 100644 src/mouse.c delete mode 100644 src/mouse.h delete mode 100644 src/pci.c delete mode 100644 src/pci.h delete mode 100644 src/port.asm delete mode 100644 src/port.c delete mode 100644 src/port.h delete mode 100644 src/serial.c delete mode 100644 src/serial.h delete mode 100644 src/setjmp.asm delete mode 100644 src/setjmp.h delete mode 100644 src/stddef.h delete mode 100644 src/stdio.c delete mode 100644 src/stdio.h delete mode 100644 src/stdlib.c delete mode 100644 src/stdlib.h delete mode 100644 src/string.c delete mode 100644 src/string.h delete mode 100644 src/sys/types.h delete mode 100644 src/vgatext.c delete mode 100644 src/vgatext.h diff --git a/src/Makefile b/src/Makefile index c89f9c3..f352a6c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,6 @@ CC := gcc -CFLAGS := -std=c99 -m32 -ffreestanding -O0 -g -Wall -Werror +INCLUDES = -I. -Ilibc -Ihardware -Idrivers -Idrivers/hdi -Idrivers/hdi/ps2 -Ikernel +CFLAGS := -std=c99 -m32 -ffreestanding -O0 -g -Wall -Werror $(INCLUDES) LD := ld NASMFLAGS := -f elf32 NASM := nasm @@ -33,70 +34,76 @@ kernel.bin: kernel.elf kernel.sym: kernel.elf $(OBJCOPY) --only-keep-debug kernel.elf kernel.sym -kernel.elf: kernel.o kernel_asm.o console.o vgatext.o serial.o port.o port_asm.o interrupts.o interrupts_asm.o driver.o pci.o keyboard.o mouse.o string.o stdlib.o stdio.o setjmp.o +kernel.elf: kernel/kernel.o kernel/kernel_asm.o kernel/console.o kernel/vgatext.o kernel/serial.o hardware/port.o hardware/port_asm.o hardware/interrupts.o hardware/interrupts_asm.o hardware/pci.o drivers/driver.o drivers/hdi/ps2/keyboard.o drivers/hdi/ps2/mouse.o libc/string.o libc/stdlib.o libc/stdio.o libc/setjmp.o $(LD) -o kernel.elf -N -n -Ttext 0x8400 --oformat elf32-i386 \ - kernel.o kernel_asm.o console.o vgatext.o serial.o \ - port.o port_asm.o interrupts.o interrupts_asm.o \ - driver.o pci.o \ - keyboard.o mouse.o \ - string.o stdlib.o stdio.o setjmp.o + kernel/kernel.o kernel/kernel_asm.o \ + kernel/console.o kernel/vgatext.o kernel/serial.o \ + hardware/port.o hardware/port_asm.o \ + hardware/interrupts.o hardware/interrupts_asm.o \ + hardware/pci.o \ + drivers/driver.o \ + drivers/hdi/ps2/keyboard.o drivers/hdi/ps2/mouse.o \ + libc/string.o libc/stdlib.o libc/stdio.o libc/setjmp.o magic.bin: boot/magic.asm $(NASM) boot/magic.asm -DMAGIC='"$(MAGIC)"' -f bin -o magic.bin -kernel.o: kernel.c - $(CC) $(CFLAGS) -c -o kernel.o kernel.c +kernel/kernel.o: kernel/kernel.c + $(CC) $(CFLAGS) -c -o kernel/kernel.o kernel/kernel.c -kernel_asm.o: kernel.asm - $(NASM) kernel.asm $(NASMFLAGS) -o kernel_asm.o +kernel/kernel_asm.o: kernel/kernel.asm + $(NASM) kernel/kernel.asm $(NASMFLAGS) -o kernel/kernel_asm.o -port.o: port.c port.h - $(CC) $(CFLAGS) -c -o port.o port.c +hardware/port.o: hardware/port.c hardware/port.h + $(CC) $(CFLAGS) -c -o hardware/port.o hardware/port.c -port_asm.o: port.asm - $(NASM) port.asm $(NASMFLAGS) -o port_asm.o +hardware/port_asm.o: hardware/port.asm + $(NASM) hardware/port.asm $(NASMFLAGS) -o hardware/port_asm.o -console.o: console.c console.h vgatext.h serial.h - $(CC) $(CFLAGS) -c -o console.o console.c +kernel/console.o: kernel/console.c kernel/console.h kernel/vgatext.h kernel/serial.h + $(CC) $(CFLAGS) -c -o kernel/console.o kernel/console.c -vgatext.o: vgatext.c vgatext.h - $(CC) $(CFLAGS) -c -o vgatext.o vgatext.c +kernel/vgatext.o: kernel/vgatext.c kernel/vgatext.h + $(CC) $(CFLAGS) -c -o kernel/vgatext.o kernel/vgatext.c -serial.o: serial.c serial.h - $(CC) $(CFLAGS) -c -o serial.o serial.c +kernel/serial.o: kernel/serial.c kernel/serial.h + $(CC) $(CFLAGS) -c -o kernel/serial.o kernel/serial.c -interrupts.o: interrupts.c interrupts.h - $(CC) $(CFLAGS) -c -o interrupts.o interrupts.c +hardware/interrupts.o: hardware/interrupts.c hardware/interrupts.h + $(CC) $(CFLAGS) -c -o hardware/interrupts.o hardware/interrupts.c -interrupts_asm.o: interrupts.asm - $(NASM) interrupts.asm $(NASMFLAGS) -o interrupts_asm.o +hardware/interrupts_asm.o: hardware/interrupts.asm + $(NASM) hardware/interrupts.asm $(NASMFLAGS) -o hardware/interrupts_asm.o -driver.o: driver.c driver.h - $(CC) $(CFLAGS) -c -o driver.o driver.c +hardware/pci.o: hardware/pci.c hardware/pci.h + $(CC) $(CFLAGS) -c -o hardware/pci.o hardware/pci.c -pci.o: pci.c pci.h - $(CC) $(CFLAGS) -c -o pci.o pci.c +drivers/driver.o: drivers/driver.c drivers/driver.h + $(CC) $(CFLAGS) -c -o drivers/driver.o drivers/driver.c -keyboard.o: keyboard.c keyboard.h - $(CC) $(CFLAGS) -c -o keyboard.o keyboard.c +drivers/hdi/ps2/keyboard.o: drivers/hdi/ps2/keyboard.c drivers/hdi/ps2/keyboard.h + $(CC) $(CFLAGS) -c -o drivers/hdi/ps2/keyboard.o drivers/hdi/ps2/keyboard.c -mouse.o: mouse.c mouse.h - $(CC) $(CFLAGS) -c -o mouse.o mouse.c +drivers/hdi/ps2/mouse.o: drivers/hdi/ps2/mouse.c drivers/hdi/ps2/mouse.h + $(CC) $(CFLAGS) -c -o drivers/hdi/ps2/mouse.o drivers/hdi/ps2/mouse.c -string.o: string.c string.h - $(CC) $(CFLAGS) -c -o string.o string.c +libc/string.o: libc/string.c libc/string.h + $(CC) $(CFLAGS) -c -o libc/string.o libc/string.c -stdlib.o: stdlib.c stdlib.h - $(CC) $(CFLAGS) -c -o stdlib.o stdlib.c +libc/stdlib.o: libc/stdlib.c libc/stdlib.h + $(CC) $(CFLAGS) -c -o libc/stdlib.o libc/stdlib.c -stdio.o: stdio.c stdio.h - $(CC) $(CFLAGS) -c -o stdio.o stdio.c +libc/stdio.o: libc/stdio.c libc/stdio.h + $(CC) $(CFLAGS) -c -o libc/stdio.o libc/stdio.c -setjmp.o: setjmp.asm - $(NASM) setjmp.asm $(NASMFLAGS) -o setjmp.o +libc/setjmp.o: libc/setjmp.asm + $(NASM) libc/setjmp.asm $(NASMFLAGS) -o libc/setjmp.o clean: - -rm -f boot.bin kernel.bin kernel.sym kernel.elf image.bin magic.bin *.o boot.map image.tmp + -rm -f boot.bin kernel.bin kernel.sym kernel.elf image.bin magic.bin boot.map image.tmp \ + serial.log \ + libc/*.o hardware/*.o kernel/*.o \ + drivers/*.o drivers/*/*.o drivers/*/*/*.o run-qemu-hd: image.bin qemu-system-i386 -net nic,model=ne2k_pci -d guest_errors -m 32 -drive "file=image.bin,if=ide,format=raw" \ diff --git a/src/README b/src/README index 0d1719c..c1f1577 100644 --- a/src/README +++ b/src/README @@ -1,3 +1,8 @@ +boot +---- + +Simple bootloader, loading in two phases and loading the kernel itself + * boot.bin - boot sector (stage 1 and 2, total 2k), offset 0x7c00 * boot.asm - the main boot sector code using: * kernel.bin - linked kernel with fix start offset 0x8400 @@ -9,20 +14,39 @@ * magic.bin (512 bytes magic marker sector) * magic.asm -kernel utility routines +kernel +------ + +Kernel main and utility routines like early consoles. + * kernel.c - kernel helper functions -* port.c, port.asm - I/O ports -* interrupts.c, interrups.asm - interrupt handlers -* pci.c - PCI introspection and driver initialization * console.c - the kernel console, can use VGA or serial port for now * vga.c - VGA basic output routines for early kernel output * serial.c - serial output to COM1 (only sequential ASCII chars, no terminal) -kernel drivers +hardware +-------- + +Hardware abstraction layer. + +* port.c, port.asm - I/O ports +* interrupts.c, interrups.asm - interrupt handlers +* pci.c - PCI introspection and driver initialization + +drivers +------- + +Driver framework and specific drivers. + * driver.c - generic driver manager * keyboard.c - PS/2 keyboard * mouse.c - PS/2 mouse +libc +---- + +Stub C library implementation. + C library definitions * stddef.h - definition of NULL, size_t * limits.h - domain range constants like INT_MAX diff --git a/src/console.c b/src/console.c deleted file mode 100644 index 6113823..0000000 --- a/src/console.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "console.h" - -#include "string.h" -#include "stddef.h" - -void console_init( console_t *console ) -{ - memset( console, 0, sizeof( console_t ) ); - - console->vga_text = NULL; - console->serial = NULL; -} - -void console_add_vga_text_output( console_t *console, vga_text_t *vga_text ) -{ - console->vga_text = vga_text; -} - -void console_add_serial_output( console_t *console, serial_t *serial ) -{ - console->serial = serial; -} - -void console_put_char( console_t *console, const char c ) -{ - if( console->vga_text != NULL ) { - vga_text_put_char( console->vga_text, c ); - } - - if( console->serial != NULL ) { - serial_put_char( console->serial, c ); - } -} - -void console_put_string( console_t *console, const char *s ) -{ - if( console->vga_text != NULL ) { - vga_text_put_string( console->vga_text, s ); - } - - if( console->serial != NULL ) { - serial_put_string( console->serial, s ); - } -} - -void console_put_newline( console_t *console ) -{ - if( console->vga_text != NULL ) { - vga_text_put_newline( console->vga_text ); - } - - if( console->serial != NULL ) { - serial_put_newline( console->serial ); - } -} diff --git a/src/console.h b/src/console.h deleted file mode 100644 index a1c55ac..0000000 --- a/src/console.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CONSOLE_H -#define CONSOLE_H - -#include "vgatext.h" -#include "serial.h" - -typedef struct { - vga_text_t *vga_text; - serial_t *serial; -} console_t; - -void console_init( console_t *console ); -void console_add_vga_text_output( console_t *console, vga_text_t *vga_text ); -void console_add_serial_output( console_t *console, serial_t *serial ); -void console_put_char( console_t *console, const char c ); -void console_put_string( console_t *console, const char *s ); -void console_put_newline( console_t *console ); - -#endif // CONSOLE_H diff --git a/src/driver.c b/src/driver.c deleted file mode 100644 index 5a1a479..0000000 --- a/src/driver.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "driver.h" - -#include "kernel.h" -#include "string.h" - -void driver_manager_init( driver_manager_t *manager ) -{ - memset( manager, 0, sizeof( driver_manager_t ) ); - - manager->nof_drivers = 0; -} - -void driver_manager_add_driver( driver_manager_t *manager, driver_t *driver ) -{ - if( manager->nof_drivers >= MAX_NOF_DRIVERS - 1 ) { - kernel_panic( "Allocating more than %d drivers.. increase kernel constant", MAX_NOF_DRIVERS ); - } - - manager->driver[manager->nof_drivers] = driver; - manager->nof_drivers++; -} - -void driver_manager_activate_all( driver_manager_t *manager ) -{ - for( int i = 0; i < manager->nof_drivers; i++ ) { - driver_t *driver = (driver_t *)manager->driver[i]; - driver_vtable_t *driver_vtable = driver->vtable; - driver_vtable->activate( driver ); - } -} - -void driver_manager_deactivate_all( driver_manager_t *manager ) -{ - if( manager->nof_drivers == 0 ) { - return; - } - - for( int i = manager->nof_drivers - 1; i >= 0; i-- ) { - driver_t *driver = (driver_t *)manager->driver[i]; - driver_vtable_t *driver_vtable = driver->vtable; - driver_vtable->deactivate( driver ); - } -} - -void driver_manager_deinit( driver_manager_t *manager ) -{ - if( manager->nof_drivers == 0 ) { - return; - } - - for( int i = manager->nof_drivers - 1; i >= 0; i-- ) { - driver_t *driver = (driver_t *)manager->driver[i]; - driver_vtable_t *driver_vtable = driver->vtable; - driver_vtable->deinit( driver ); - } -} - -void driver_manager_print_info_all( driver_manager_t *manager ) -{ - for( int i = 0; i < manager->nof_drivers; i++ ) { - driver_t *driver = (driver_t *)manager->driver[i]; - driver_vtable_t *driver_vtable = driver->vtable; - driver_vtable->print_info( driver ); - } -} diff --git a/src/driver.h b/src/driver.h deleted file mode 100644 index c110308..0000000 --- a/src/driver.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef DRIVER_H -#define DRIVER_H - -#include "interrupts.h" - -typedef struct { - void (*activate)( void *obj ); - void (*deactivate)( void *obj ); - void (*deinit)( void *obj ); - void (*print_info)( void *obj ); -} driver_vtable_t; - -typedef struct { - driver_vtable_t *vtable; -} driver_t; - -#define MAX_NOF_DRIVERS 256 - -typedef struct { - int nof_drivers; - driver_t *driver[MAX_NOF_DRIVERS]; -} driver_manager_t; - -void driver_manager_init( driver_manager_t *manager ); -void driver_manager_add_driver( driver_manager_t *manager, driver_t *driver ); -void driver_manager_activate_all( driver_manager_t *manager ); -void driver_manager_deactivate_all( driver_manager_t *manager ); -void driver_manager_deinit( driver_manager_t *manager ); -void driver_manager_print_info_all( driver_manager_t *manager ); - -#endif // DRIVER_H diff --git a/src/drivers/driver.c b/src/drivers/driver.c new file mode 100644 index 0000000..5a1a479 --- /dev/null +++ b/src/drivers/driver.c @@ -0,0 +1,65 @@ +#include "driver.h" + +#include "kernel.h" +#include "string.h" + +void driver_manager_init( driver_manager_t *manager ) +{ + memset( manager, 0, sizeof( driver_manager_t ) ); + + manager->nof_drivers = 0; +} + +void driver_manager_add_driver( driver_manager_t *manager, driver_t *driver ) +{ + if( manager->nof_drivers >= MAX_NOF_DRIVERS - 1 ) { + kernel_panic( "Allocating more than %d drivers.. increase kernel constant", MAX_NOF_DRIVERS ); + } + + manager->driver[manager->nof_drivers] = driver; + manager->nof_drivers++; +} + +void driver_manager_activate_all( driver_manager_t *manager ) +{ + for( int i = 0; i < manager->nof_drivers; i++ ) { + driver_t *driver = (driver_t *)manager->driver[i]; + driver_vtable_t *driver_vtable = driver->vtable; + driver_vtable->activate( driver ); + } +} + +void driver_manager_deactivate_all( driver_manager_t *manager ) +{ + if( manager->nof_drivers == 0 ) { + return; + } + + for( int i = manager->nof_drivers - 1; i >= 0; i-- ) { + driver_t *driver = (driver_t *)manager->driver[i]; + driver_vtable_t *driver_vtable = driver->vtable; + driver_vtable->deactivate( driver ); + } +} + +void driver_manager_deinit( driver_manager_t *manager ) +{ + if( manager->nof_drivers == 0 ) { + return; + } + + for( int i = manager->nof_drivers - 1; i >= 0; i-- ) { + driver_t *driver = (driver_t *)manager->driver[i]; + driver_vtable_t *driver_vtable = driver->vtable; + driver_vtable->deinit( driver ); + } +} + +void driver_manager_print_info_all( driver_manager_t *manager ) +{ + for( int i = 0; i < manager->nof_drivers; i++ ) { + driver_t *driver = (driver_t *)manager->driver[i]; + driver_vtable_t *driver_vtable = driver->vtable; + driver_vtable->print_info( driver ); + } +} diff --git a/src/drivers/driver.h b/src/drivers/driver.h new file mode 100644 index 0000000..c110308 --- /dev/null +++ b/src/drivers/driver.h @@ -0,0 +1,31 @@ +#ifndef DRIVER_H +#define DRIVER_H + +#include "interrupts.h" + +typedef struct { + void (*activate)( void *obj ); + void (*deactivate)( void *obj ); + void (*deinit)( void *obj ); + void (*print_info)( void *obj ); +} driver_vtable_t; + +typedef struct { + driver_vtable_t *vtable; +} driver_t; + +#define MAX_NOF_DRIVERS 256 + +typedef struct { + int nof_drivers; + driver_t *driver[MAX_NOF_DRIVERS]; +} driver_manager_t; + +void driver_manager_init( driver_manager_t *manager ); +void driver_manager_add_driver( driver_manager_t *manager, driver_t *driver ); +void driver_manager_activate_all( driver_manager_t *manager ); +void driver_manager_deactivate_all( driver_manager_t *manager ); +void driver_manager_deinit( driver_manager_t *manager ); +void driver_manager_print_info_all( driver_manager_t *manager ); + +#endif // DRIVER_H diff --git a/src/drivers/hdi/ps2/keyboard.c b/src/drivers/hdi/ps2/keyboard.c new file mode 100644 index 0000000..d7d8d88 --- /dev/null +++ b/src/drivers/hdi/ps2/keyboard.c @@ -0,0 +1,316 @@ +#include "keyboard.h" +#include "stdio.h" + +// status register on command port (read) +#define STATUS_REG_OUTPUT_BUF_FULL 0x01 +#define STATUS_REG_INPUT_BUF_FULL 0x02 + +// generic PS/2 commands +#define COMMAND_GET_STATE 0x20 +#define COMMAND_SET_STATE 0x60 +#define COMMAND_DISABLE_PORT1 0xAD +#define COMMAND_ENABLE_PORT1 0xAE + +// status control register flags +#define STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT1 0x01 +#define STATUS_CONTROL_CONFIG_CLOCK_PORT1 0x10 + +// keyboard specific commands, PSAUX1 +#define KBD_COMMAND_SET_LEDS 0xED +#define KBD_SET_SCANCODE 0xF0 +#define KBD_ACTIVATE 0xF4 + +// keyboard LED status codes +#define KBD_LED_SCROLL_LOCK_ON 0x01 +#define KBD_LED_NUM_LOCK_ON 0x02 +#define KBD_LED_CAPS_LOCK_ON 0x04 +#define KBD_LED_ALL_OFF 0x00 +#define KBD_LED_ALL_ON KBD_LED_SCROLL_LOCK_ON | KBD_LED_NUM_LOCK_ON | KBD_LED_CAPS_LOCK_ON + +// keyboard scan codes +#define KBD_SCANCODE_1 0x01 +#define KBD_SCANCODE_2 0x02 +#define KBD_SCANCODE_3 0x03 + +#undef DEBUG + +static uint8_t read_data( keyboard_t *keyboard ) +{ + while( ( port8_read( &keyboard->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) == 0 ) { } + return port8_read( &keyboard->data_port ); +} + +static void send_command( keyboard_t *keyboard, uint8_t command ) +{ + while( port8_read( &keyboard->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { } + port8_write( &keyboard->command_port, command ); +} + +static void write_data( keyboard_t *keyboard, uint8_t data ) +{ + while( port8_read( &keyboard->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { } + port8_write( &keyboard->data_port, data ); +} + +/* +static void read_ack( keyboard_t *keyboard ) +{ + uint8_t data = read_data( keyboard ); + if( data == 0xFA ) { + return; + } else { + kernel_warn( "ERR PS/2 keyboard: acknoledgment failed 0x%X\n", data ); + } +} +*/ + +static keyboard_vtable_t keyboard_vtable = { + { + keyboard_activate, + keyboard_deactivate, + keyboard_deinit, + keyboard_print_info + } +}; + +void keyboard_init( keyboard_t *keyboard, keyboard_event_handler_t handler, void *context ) +{ + memset( keyboard, 0, sizeof( keyboard_t ) ); + + port8_init( &keyboard->command_port, 0x64 ); + port8_init( &keyboard->data_port, 0x60 ); + + keyboard->shift = false; + keyboard->handler = handler; + keyboard->context = context; + + keyboard->base.vtable = &keyboard_vtable.base; +} + +void keyboard_activate( void *obj ) +{ + puts( "Activating driver for PS/2 keyboard.." ); + + keyboard_t *keyboard = obj; + + // first switch off port 1 + send_command( keyboard, COMMAND_DISABLE_PORT1 ); + + // consume character pressed before executing the kernel + while( port8_read( &keyboard->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) { + port8_read( &keyboard->data_port ); + } + + // enable interrupts for port 1 + send_command( keyboard, COMMAND_GET_STATE ); + uint8_t status = read_data( keyboard ); + status |= STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT1; + status &= ~STATUS_CONTROL_CONFIG_CLOCK_PORT1; + send_command( keyboard, COMMAND_SET_STATE ); + write_data( keyboard, status ); + + // disable all LEDs on keyboard + //~ send_command( keyboard, KBD_COMMAND_SET_LEDS ); + //~ write_data( keyboard, KBD_LED_ALL_ON ); + + // set scan code + //~ send_command( keyboard, KBD_SET_SCANCODE ); + //~ write_data( keyboard, KBD_SCANCODE_2 ); + + // activate keyboard + //send_command( keyboard, KBD_ACTIVATE ); + //read_ack( keyboard ); + + // enable port 1 + send_command( keyboard, COMMAND_ENABLE_PORT1 ); +} + +void keyboard_deactivate( void *obj ) +{ + puts( "Deactivating driver for PS/2 keyboard.." ); + + keyboard_t *keyboard = obj; + + send_command( keyboard, COMMAND_DISABLE_PORT1 ); +} + +void keyboard_deinit( void *obj ) +{ + // nothing to do +} + +typedef enum { + KEYCODE_UNKNOWN, + KEYCODE_ASCII_CHAR +} keycode_type_t; + +typedef struct { + keycode_type_t type; + char c; +} keycode_t; + +typedef enum { + SCANCODE_SET_NORMAL = 0, + SCANCODE_SET_SHIFT = 1, + SCANCODE_SET_E0 = 2, + SCANCODE_SET_E1 = 3 +} scancode_set_t; + +// TODO: here come the translations to other keyboard layouts, +// assumming a QWERTY US keyboard here.. +static char scancode_map[4][128] = { + { + 0, 0, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', '\b', 0, + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', '\n', 0, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', 0, 0, + 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0 , 0 , 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 , 0 , 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 , 0 , 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 , 0 , 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, '!', '@', '#', '$', '%', '^', + '&', '*', '(', ')', '_', '+', 0, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', + 'O', 'P', '{', '}', '\n', 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '"', '~', 0, '|', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, 0, + 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0 , 0 , 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 , 0 , 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 , 0 , 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 , 0 , 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + } +}; + +static keycode_t scancode_to_keycode( scancode_set_t set, uint8_t scan_code ) +{ + keycode_t key_code; + key_code.type = KEYCODE_UNKNOWN; + + key_code.c = scancode_map[set][scan_code]; + if( key_code.c > 0 ) { + key_code.type = KEYCODE_ASCII_CHAR; + } + return key_code; +} + +#define SCAN_CODE_BREAK_CODE 0x80 +#define SCAN_CODE_LEFT_SHIFT 0x2A +#define SCAN_CODE_RIGHT_SHIFT 0x36 + +uint32_t keyboard_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ) +{ + keyboard_t *keyboard = (keyboard_t *)handler->driver; + + // we can only wake up on IRQ1 because we don't send commands + // after initialization + uint8_t scan_code = port8_read( &keyboard->data_port ); + + // we get break code when the high bit is set, so the + // the key is released + bool break_code = false; + if( scan_code & SCAN_CODE_BREAK_CODE ) { + break_code = true; + } + + scan_code &= ~SCAN_CODE_BREAK_CODE; + + if( scan_code == SCAN_CODE_LEFT_SHIFT || + scan_code == SCAN_CODE_RIGHT_SHIFT ) { + if( break_code ) { + keyboard->shift = false; + } else { + keyboard->shift = true; + } + } + + scancode_set_t code_set = SCANCODE_SET_NORMAL; + if( keyboard->shift ) { + code_set = SCANCODE_SET_SHIFT; + } + + keycode_t key_code = scancode_to_keycode( code_set, scan_code ); + +#ifdef DEBUG + printf( "KBD SCAN:0x%X S:%d B:%d S:%d T:0x%X '%c' 0x%X\n", + scan_code, code_set, break_code, keyboard->shift, + key_code.type, key_code.c, key_code.c ); +#endif + + keyboard_event_t event; + if( break_code ) { + event.type = KEYBOARD_EVENT_TYPE_KEY_RELEASED; + } else { + event.type = KEYBOARD_EVENT_TYPE_KEY_PRESSED; + } + event.modifiers = 0; + if( keyboard->shift ) { + event.modifiers |= KEYBOARD_MODIFIER_SHIFT; + } + // TODO: for control, alt, meta, etc. + event.key = KEYBOARD_KEY_UNKNOWN; + if( key_code.type == KEYCODE_ASCII_CHAR ) { + event.key = KEYBOARD_KEY_ASCII; + event.ascii_key = key_code.c; + } + + keyboard->handler( &event, keyboard->context ); + + return esp; +} + +void keyboard_print_info( void *obj ) +{ + puts( "PS/2 keyboard driver" ); +} diff --git a/src/drivers/hdi/ps2/keyboard.h b/src/drivers/hdi/ps2/keyboard.h new file mode 100644 index 0000000..5f90ee8 --- /dev/null +++ b/src/drivers/hdi/ps2/keyboard.h @@ -0,0 +1,69 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#include + +#include "string.h" + +#include "interrupts.h" +#include "port.h" + +#include "driver.h" + +typedef enum { + KEYBOARD_EVENT_TYPE_KEY_PRESSED, + KEYBOARD_EVENT_TYPE_KEY_RELEASED +} keyboard_event_type_t; + +typedef enum { + KEYBOARD_MODIFIER_SHIFT = 0x01, + KEYBOARD_MODIFIER_CTRL = 0x02, + KEYBOARD_MODIFIER_ALT = 0x04 +} keyboard_modifier_mask_t; + +typedef enum { + KEYBOARD_KEY_UNKNOWN, + KEYBOARD_KEY_ASCII, + KEYBOARD_KEY_ESC, + KEYBOARD_KEY_TAB, + KEYBOARD_KEY_INS, + KEYBAORD_KEY_DEL, + KEYBAORD_KEY_BACKSPACE, + KEYBAORD_CURSOR_LEFT, + KEYBOARD_CURSOR_RIGHT, + KEYBOARD_CURSOR_UP, + KEYBOARD_CURSOR_DOWN +} keyboard_key_t; + +typedef struct { + keyboard_event_type_t type; + keyboard_modifier_mask_t modifiers; + keyboard_key_t key; + char ascii_key; +} keyboard_event_t; + +typedef void (*keyboard_event_handler_t)( keyboard_event_t *event, void *context ); + +typedef struct { + driver_t base; + interrupt_t *interrupts; + port8_t command_port; + port8_t data_port; + bool shift; + keyboard_event_handler_t handler; + void *context; +} keyboard_t; + +typedef struct { + driver_vtable_t base; +} keyboard_vtable_t; + +void keyboard_init( keyboard_t *keyboard, keyboard_event_handler_t handler, void *context ); +void keyboard_activate( void *obj ); +void keyboard_deactivate( void *obj ); +void keyboard_deinit( void *obj ); +void keyboard_print_info( void *obj ); + +uint32_t keyboard_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ); + +#endif // KEYBOARD_H diff --git a/src/drivers/hdi/ps2/mouse.c b/src/drivers/hdi/ps2/mouse.c new file mode 100644 index 0000000..46984eb --- /dev/null +++ b/src/drivers/hdi/ps2/mouse.c @@ -0,0 +1,250 @@ +#include "mouse.h" + +#include "stdio.h" + +// status register on command port (read) +#define STATUS_REG_OUTPUT_BUF_FULL 0x01 +#define STATUS_REG_INPUT_BUF_FULL 0x02 +#define STATUS_REG_OUTPUT_BUF2_FULL 0x20 + +// status control register flags +#define STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT2 0x02 +#define STATUS_CONTROL_CONFIG_CLOCK_PORT2 0x20 + +// generic PS/2 commands +#define COMMAND_GET_STATE 0x20 +#define COMMAND_SET_STATE 0x60 +#define COMMAND_DISABLE_PORT2 0xA7 +#define COMMAND_ENABLE_PORT2 0xA8 +#define COMMAND_SEND_TO_PORT2 0xD4 + +// mouse commands +#define MOUSE_COMMAND_GET_DEVICE_ID 0xF2 +#define MOUSE_COMMAND_SET_SAMPLE_RATE 0xF3 +#define MOUSE_COMMAND_ENABLE_DATAREPORTING 0xF4 +#define MOUSE_COMMAND_SET_DEFAULTS 0xF6 +#define DEFAULT_NOF_PACKETS 3 + +// mouse data packet one +#define MOUSE_BYTE1_LEFT_BUTTON 0x01 +#define MOUSE_BYTE1_RIGHT_BUTTON 0x02 +#define MOUSE_BYTE1_MIDDLE_BUTTON 0x04 +#define MOUSE_BYTE1_ID_BIT 0x08 +#define MOUSE_BYTE1_X_SIGN 0x10 +#define MOUSE_BYTE1_Y_SIGN 0x20 +#define MOUSE_BYTE1_X_OVERFLOW 0x40 +#define MOUSE_BYTE1_Y_OVERFLOW 0x80 + +#undef DEBUG + +static uint8_t read_data( mouse_t *mouse ) +{ + while( ( port8_read( &mouse->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) == 0 ) { } + return port8_read( &mouse->data_port ); +} + +static void send_command( mouse_t *mouse, uint8_t command ) +{ + while( port8_read( &mouse->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { } + port8_write( &mouse->command_port, command ); +} + +static void write_data( mouse_t *mouse, uint8_t data ) +{ + while( port8_read( &mouse->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { } + port8_write( &mouse->data_port, data ); +} + +static void read_ack( mouse_t *mouse ) +{ + uint8_t data = read_data( mouse ); + if( data == 0xFA ) { + return; + } else { + printf( "ERR PS/2 mouse: acknoledgment failed 0x%X\n", data ); + } +} + +static void set_sample_rate( mouse_t *mouse, uint8_t samples ) +{ + send_command( mouse, COMMAND_SEND_TO_PORT2 ); + write_data( mouse, MOUSE_COMMAND_SET_SAMPLE_RATE ); + read_ack( mouse ); + + send_command( mouse, COMMAND_SEND_TO_PORT2 ); + write_data( mouse, samples ); + read_ack( mouse ); +} + +static mouse_vtable_t mouse_vtable = { + { + mouse_activate, + mouse_deactivate, + mouse_deinit, + mouse_print_info + } +}; + +void mouse_init( mouse_t *mouse, mouse_event_handler_t handler, void *context ) +{ + memset( mouse, 0, sizeof( mouse_t ) ); + + // TODO: we should probe for wheel mouse and more than 3 packets + mouse->nof_packets = DEFAULT_NOF_PACKETS; + + vga_text_t *vga_text = (vga_text_t *)context; + + mouse->res_x = vga_text->res_x; + mouse->res_y = vga_text->res_y; + mouse->cursor_x = mouse->res_x / 2; + mouse->cursor_y = mouse->res_y / 2; + mouse->handler = handler; + mouse->context = context; + + port8_init( &mouse->command_port, 0x64 ); + port8_init( &mouse->data_port, 0x60 ); + + mouse->base.vtable = &mouse_vtable.base; +} + +void mouse_activate( void *obj ) +{ + puts( "Activating driver for PS/2 mouse.." ); + + mouse_t *mouse = obj; + + // enable port 2 + send_command( mouse, COMMAND_ENABLE_PORT2 ); + + // enable interrupts for port 2 + send_command( mouse, COMMAND_GET_STATE ); + uint8_t status = read_data( mouse ); + status |= STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT2; + status &= ~STATUS_CONTROL_CONFIG_CLOCK_PORT2; + send_command( mouse, COMMAND_SET_STATE ); + write_data( mouse, status ); + + // detecting mouse wheel (and 4th data packet) + set_sample_rate( mouse, 200 ); + set_sample_rate( mouse, 100 ); + set_sample_rate( mouse, 80 ); + send_command( mouse, COMMAND_SEND_TO_PORT2 ); + write_data( mouse, MOUSE_COMMAND_GET_DEVICE_ID ); + read_ack( mouse ); + uint8_t id = read_data( mouse ); + printf( "PS/2 mouse model id is 0x%X\n", id ); + if( id == 0x03 ) { + mouse->nof_packets = 4; + } + + // set mouse defaults +// send_command( mouse, COMMAND_SEND_TO_PORT2 ); +// write_data( mouse, MOUSE_COMMAND_SET_DEFAULTS ); + + // enable mouse on second port + send_command( mouse, COMMAND_SEND_TO_PORT2 ); + write_data( mouse, MOUSE_COMMAND_ENABLE_DATAREPORTING ); + read_ack( mouse ); +} + +void mouse_deactivate( void *obj ) +{ + puts( "Dectivating driver for PS/2 mouse.." ); + + mouse_t *mouse = obj; + + send_command( mouse, COMMAND_DISABLE_PORT2 ); +} + +void mouse_deinit( void *obj ) +{ + // nothing to do +} + +uint32_t mouse_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ) +{ + mouse_t *mouse = (mouse_t *)handler->driver; + + uint8_t status = port8_read( &mouse->command_port ); + if( !( status & STATUS_REG_OUTPUT_BUF2_FULL ) ) { + return esp; + } + + mouse->buf[mouse->offset] = port8_read( &mouse->data_port ); + +#ifdef DEBUG + printf( "MOUSE: %d 0x%X\n", mouse->offset, mouse->buf[mouse->offset] ); +#endif + + switch( mouse->offset ) { + case 0: + if( mouse->buf[0] & MOUSE_BYTE1_ID_BIT ) { + for( int i = 0; i < 3; i++ ) { + if( ( mouse->buf[0] & ( 0x01 << i ) ) != ( mouse->buttons & ( 0x01 << i ) ) ) { + mouse_event_t event; + event.button = i + 1; + if( mouse->buttons & ( 0x01 << i ) ) { + event.type = MOUSE_EVENT_TYPE_BUTTON_UP; + } else { + event.type = MOUSE_EVENT_TYPE_BUTTON_DOWN; + } + event.cursor_x = mouse->cursor_x; + event.cursor_y = mouse->cursor_y; + mouse->handler( &event, mouse->context ); + } + } + mouse->buttons = mouse->buf[0]; + } + break; + + case 1: + // delay evaluation of move events till second byte + break; + + case 2: + if( mouse->buf[1] !=0 || mouse->buf[2] != 0 ) { + + mouse_event_t event; + event.type = MOUSE_EVENT_TYPE_MOVE; + event.old_cursor_x = mouse->cursor_x; + event.old_cursor_y = mouse->cursor_y; + + mouse->cursor_x += (int8_t)mouse->buf[1]; + mouse->cursor_y -= (int8_t)mouse->buf[2]; + if( mouse->cursor_x < 0 ) { + mouse->cursor_x = 0; + } + if( mouse->cursor_x > mouse->res_x - 1 ) { + mouse->cursor_x = mouse->res_x - 1; + } + if( mouse->cursor_y < 0 ) { + mouse->cursor_y = 0; + } + if( mouse->cursor_y > mouse->res_y - 1 ) { + mouse->cursor_y = mouse->res_y - 1; + } + + event.cursor_x = mouse->cursor_x; + event.cursor_y = mouse->cursor_y; + + mouse->handler( &event, mouse->context ); + } + + break; + + case 3: + // TODO: read fourth data packet, but don't handle + // it yet + break; + } + + // advance offset + mouse->offset = ( mouse->offset + 1 ) % mouse->nof_packets; + + return esp; +} + +void mouse_print_info( void *obj ) +{ + puts( "PS/2 mouse driver" ); +} diff --git a/src/drivers/hdi/ps2/mouse.h b/src/drivers/hdi/ps2/mouse.h new file mode 100644 index 0000000..cbd02ef --- /dev/null +++ b/src/drivers/hdi/ps2/mouse.h @@ -0,0 +1,65 @@ +#ifndef MOUSE_H +#define MOUSE_H + +#include "string.h" + +#include "interrupts.h" +#include "port.h" + +#include "driver.h" + +#define MAX_NOF_MOUSE_PACKETS 5 + +typedef enum { + MOUSE_EVENT_TYPE_BUTTON_UP, + MOUSE_EVENT_TYPE_BUTTON_DOWN, + MOUSE_EVENT_TYPE_MOVE +} mouse_event_type_t; + +typedef enum { + MOUSE_BUTTON_LEFT = 1, + MOUSE_BUTTON_RIGHT = 2, + MOUSE_BUTTON_MIDDLE = 3 +} mouse_button_t; + +typedef struct { + mouse_event_type_t type; + mouse_button_t button; + int32_t old_cursor_x; + int32_t old_cursor_y; + int32_t cursor_x; + int32_t cursor_y; +} mouse_event_t; + +typedef void (*mouse_event_handler_t)( mouse_event_t *event, void *context ); + +typedef struct { + driver_t base; + interrupt_t *interrupts; + port8_t command_port; + port8_t data_port; + int nof_packets; // 3 or more mouse packets + uint8_t buf[MAX_NOF_MOUSE_PACKETS]; + uint8_t buttons; + uint8_t offset; + uint32_t res_x; + uint32_t res_y; + int32_t cursor_x; + int32_t cursor_y; + mouse_event_handler_t handler; + void *context; +} mouse_t; + +typedef struct { + driver_vtable_t base; +} mouse_vtable_t; + +void mouse_init( mouse_t *mouse, mouse_event_handler_t handler, void *context ); +void mouse_activate( void *obj ); +void mouse_deactivate( void *obj ); +void mouse_deinit( void *obj ); +void mouse_print_info( void *obj ); + +uint32_t mouse_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ); + +#endif // MOUSE_H diff --git a/src/hardware/interrupts.asm b/src/hardware/interrupts.asm new file mode 100644 index 0000000..155b2af --- /dev/null +++ b/src/hardware/interrupts.asm @@ -0,0 +1,90 @@ +[bits 32] + +global interrupts_enable +global interrupts_disable +global interrupts_load_idt +extern interrupts_handle_static_interrupt + +; void interrupts_enable( void ) +interrupts_enable: + push ebp + mov ebp, esp + sti + leave + ret + +; void interrupts_disable( void ) +interrupts_disable: + push ebp + mov ebp, esp + cli + leave + ret + +; void interrupts_load_idt( interrupt_descriptor_table_pointer_t *idt_pointer ) +interrupts_load_idt: + push ebp + mov ebp, esp + mov ecx, [ebp+8] + lidt [ecx] + leave + ret + +; the handler to ignore interrupts +global interrupts_ignore_request +interrupts_ignore_request: + iret + +; void interrupts_handle_request_0x00( ); +%macro exception_stub 1 +global interrupts_handle_exception_%1 +interrupts_handle_exception_%1: + mov [interrupt_no], byte %1 + jmp int_entry +%endmacro + +exception_stub 0x00 + +; IRQs and exceptions would normally collidate, that's why the +; hardware interrupts must be transposed by an offset +IRQ_BASE equ 0x20 + +%macro irq_stub 1 +global interrupts_handle_irq_%1 +interrupts_handle_irq_%1: + mov [interrupt_no], byte IRQ_BASE + %1 + jmp int_entry +%endmacro + +irq_stub 0x00 +irq_stub 0x01 +irq_stub 0x0C + +int_entry: + ; safe state of interrupted code + pusha + push ds + push es + push fs + push gs + + ; call the static C handler with the correct interrupt number + ; uint32_t interrupts_handle_interrupt( uint8_t interrupt_no, uint32_t esp ); + push esp + mov eax, [interrupt_no] + push eax + call interrupts_handle_static_interrupt + ;add esp, 8 + mov esp, eax + + ; restore state + pop gs + pop fs + pop es + pop ds + popa + + iret + +interrupt_no: + db 0 diff --git a/src/hardware/interrupts.c b/src/hardware/interrupts.c new file mode 100644 index 0000000..614dbf0 --- /dev/null +++ b/src/hardware/interrupts.c @@ -0,0 +1,215 @@ +#include "interrupts.h" + +#include "string.h" +#include "stdio.h" + +#include "kernel.h" + +#include "keyboard.h" + +// TODO: for now the code segment is the first entry in the boot GDT +#define GDT_CODE_SEGMENT_SELECTOR 8 + +// the Present bit in a IDT entry +#define IDT_PRESENT_BIT 0x80 + +// DPL rings +#define KERNEL_RING 0 + +// types of IDT entries +#define IDT_TYPE_INTERRUPT_GATE 0xE + +// PIC constants + +#define ICW1_ICW4 0x01 // support a 4th initialization word (ICW4) +#define ICW1_INIT 0x10 // bit indicating initialization of chip + +// offset for hardware interrupts (for PIC ICW2) +#define ICW2_IRQ_BASE_MASTER IRQ_BASE +#define ICW2_IRQ_BASE_SLAVE ICW2_IRQ_BASE_MASTER + 8 + +// IRQ selection (master and slave, ICW3) +#define ICW3_MASTER_IR0 0x01 +#define ICW3_MASTER_IR1 0x02 +#define ICW3_MASTER_IR2 0x04 +#define ICW3_MASTER_IR3 0x08 +#define ICW3_MASTER_IR4 0x10 +#define ICW3_MASTER_IR5 0x20 +#define ICW3_MASTER_IR6 0x40 +#define ICW3_MASTER_IR7 0x80 +#define ICW3_SLAVE_IR0 0x00 +#define ICW3_SLAVE_IR1 0x01 +#define ICW3_SLAVE_IR2 0x02 +#define ICW3_SLAVE_IR3 0x03 +#define ICW3_SLAVE_IR4 0x04 +#define ICW3_SLAVE_IR5 0x05 +#define ICW3_SLAVE_IR6 0x06 +#define ICW3_SLAVE_IR7 0x07 + +// special mode PIC ICW4 +#define ICW4_8086 0x01 +#define ICW4_AUTO_ACK_EOI 0x02 +#define ICW4_BUF_MASTER 0x04 +#define ICW4_BUFFER 0x08 +#define ICW4_FULLY_NESTED 0x10 + +// OCW2 +#define OCW2_EOI 0x20 // non-specific End Of Interrupt + +void interrupt_handler_init_void( interrupt_handler_t *handler ) +{ + memset( handler, 0, sizeof( interrupt_handler_t ) ); +} + +void interrupt_handler_init( interrupt_handler_t *handler, uint8_t interrupt_no, struct interrupt_t *interrupt, interrupt_handler_func_t handle, void *driver ) +{ + memset( handler, 0, sizeof( interrupt_handler_t ) ); + + handler->interrupt_no = interrupt_no; + handler->interrupt = interrupt; + handler->handle = handle; + handler->driver = driver; +} + +// must be global: when called via assembly code we loose the context +// of the interrupt handler structure +static interrupt_t *active_interrupt; + +void interrupts_init( interrupt_t *interrupt ) +{ + memset( interrupt, 0, sizeof( interrupt_t ) ); + + interrupt_handler_t empty_interrupt_handler; + interrupt_handler_init_void( &empty_interrupt_handler ); + + for( int i = 0; i < NOF_INTERRUPTS; i++ ) { + interrupts_register_interrupt_gate( interrupt, i, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_ignore_request, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + interrupts_register_interrupt_handler( empty_interrupt_handler ); + } + + // divide-by-zero exception 0x00 + interrupt_handler_t divide_by_zero_interrupt_handler; + interrupt_handler_init( ÷_by_zero_interrupt_handler, 0x00, interrupt, interrupts_exception_division_by_zero, NULL ); + + interrupts_register_interrupt_gate( interrupt, 0x00, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_exception_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + interrupts_register_interrupt_handler( divide_by_zero_interrupt_handler ); + + // IRQ 0 - PIT - programmable interrupt timer + interrupt_handler_t pit_interrupt_handler; + interrupt_handler_init( &pit_interrupt_handler, IRQ_BASE + 0x00, interrupt, interrupts_interrupt_PIT, NULL ); + + interrupts_register_interrupt_gate( interrupt, IRQ_BASE + 0x00, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_irq_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + interrupts_register_interrupt_handler( pit_interrupt_handler ); + + // IRQ 1 - PS/2 keyboard + interrupts_register_interrupt_gate( interrupt, IRQ_BASE + 0x01, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_irq_0x01, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + + // IRQ 12 - PS/2 mouse + interrupts_register_interrupt_gate( interrupt, IRQ_BASE + 0x0C, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_irq_0x0C, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + + port8_init( &interrupt->PIC_master_control, 0x20 ); + port8_init( &interrupt->PIC_master_data, 0x21 ); + port8_init( &interrupt->PIC_slave_control, 0xA0 ); + port8_init( &interrupt->PIC_slave_data, 0xA1 ); + + // initialize hardware management PICs (ICW1) + port8_write( &interrupt->PIC_master_control, ICW1_ICW4 | ICW1_INIT ); + port8_write( &interrupt->PIC_slave_control, ICW1_ICW4 | ICW1_INIT ); + + // set IRQ base of both PICS (ICW2), remap them so they + // don't collide with CPU exceptions (this is true after 0x20) + port8_write( &interrupt->PIC_master_data, ICW2_IRQ_BASE_MASTER ); + port8_write( &interrupt->PIC_slave_data, ICW2_IRQ_BASE_SLAVE ); + + // use IRQ2 for master slave communication (ICW3) + port8_write( &interrupt->PIC_master_data, ICW3_MASTER_IR2 ); + port8_write( &interrupt->PIC_slave_data, ICW3_SLAVE_IR2 ); + + // unbuffered, manual acknoledgment and 8086 mode (ICW4) + // TODO: use buffered mode later? + port8_write( &interrupt->PIC_master_data, ICW4_8086 ); + port8_write( &interrupt->PIC_slave_data, ICW4_8086 ); + + // done, enable all IRQs by setting the interrupt mask register + // 0 for all bits. We are not interested in the old state of + // the mask as we are initializing in protected mode + // TODO: later we will mask uninmported interrupts maybe? + port8_write( &interrupt->PIC_master_data, 0 ); + port8_write( &interrupt->PIC_slave_data, 0 ); + + // tell CPU where the IDT is + interrupt->idt_pointer.size = NOF_INTERRUPTS * sizeof( interrupt_gate_descriptor_t ) - 1; + interrupt->idt_pointer.base = (uint32_t)interrupt->descriptor_table; + + interrupts_load_idt( &interrupt->idt_pointer ); + + active_interrupt = interrupt; +} + +void interrupts_register_interrupt_gate( interrupt_t *interrupts, + uint8_t interrupt_no, uint16_t gdt_code_segment_selector, + void (*helper_handler)( ), uint8_t privilege_level, uint8_t descriptor_type ) +{ + interrupt_gate_descriptor_t *descr = &interrupts->descriptor_table[interrupt_no]; + + descr->handler_address_low_bits = ( (uint32_t )helper_handler ) & 0xFFFF; + descr->handler_address_high_bits = ( ( (uint32_t )helper_handler ) >> 16 ) & 0xFFFF; + descr->gdt_code_segment_selector = gdt_code_segment_selector; + descr->access = IDT_PRESENT_BIT | (( privilege_level & 0x3 ) << 5 ) | descriptor_type; + descr->reserved = 0; +} + +void interrupts_register_interrupt_handler( interrupt_handler_t handler ) +{ + handler.interrupt->interrupt_handler[handler.interrupt_no] = handler; +} + +uint32_t interrupts_exception_division_by_zero( interrupt_handler_t *handler, uint32_t esp ) +{ + // TODO: caused by kernel code or user land code? or a task we can kill? + // For now, the kernel has no task management, so we panic + kernel_panic( "Division by zero with ESP 0x%X\n", esp ); + + return esp; +} + +uint32_t interrupts_interrupt_PIT( interrupt_handler_t *handler, uint32_t esp ) +{ + // for now do noting with the timer tick + return esp; +} + +uint32_t interrupts_handle_static_interrupt( uint8_t interrupt_no, uint32_t esp ) +{ + if( active_interrupt == NULL ) { + kernel_panic( "No active interrupt handler!" ); + } + + return interrupts_handle_interrupt( active_interrupt, interrupt_no, esp ); +} + +uint32_t interrupts_handle_interrupt( interrupt_t *interrupt, uint8_t interrupt_no, uint32_t esp ) +{ + interrupt_handler_t *handler = &interrupt->interrupt_handler[interrupt_no]; + + if( handler->handle == NULL ) { + kernel_panic( "Unhandled interrupt 0x%X with ESP 0x%X\n", interrupt_no, esp ); + } + + uint32_t new_esp = handler->handle( handler, esp ); + + // send ACK to PIC for hardware interrups + if( interrupt_no >= IRQ_BASE && interrupt_no <= IRQ_BASE + 16 ) { + port8_write( &interrupt->PIC_master_control, OCW2_EOI ); + if( interrupt_no >= IRQ_BASE + 8 ) { + port8_write( &interrupt->PIC_slave_control, OCW2_EOI ); + } + } + + return new_esp; +} diff --git a/src/hardware/interrupts.h b/src/hardware/interrupts.h new file mode 100644 index 0000000..8ab485e --- /dev/null +++ b/src/hardware/interrupts.h @@ -0,0 +1,103 @@ +#ifndef INTERRUPTS_H +#define INTERRUPTS_H + +#include + +#include "port.h" + +// total number of supported interrupts +#define NOF_INTERRUPTS 256 + +// offset for hardware interrupts +#define IRQ_BASE 0x20 + +// TCC 0.9.26 bug?, __attribute__( ( packed ) ) on structs not working, +// also not working on members.. resorting to pragmas +#if defined( __TINYC__ ) +#pragma pack(1) +#endif + +// packed IDT structure, note TCC needs every member to have a packed +// attribute, GCC/Clang are happy with the packed attribute at the +// structure level +typedef struct interrupt_gate_descriptor_t { + uint16_t handler_address_low_bits; + uint16_t gdt_code_segment_selector; + uint8_t reserved; + uint8_t access; + uint16_t handler_address_high_bits; +} __attribute__( ( packed ) ) interrupt_gate_descriptor_t; + +#if defined( __TINYC__ ) +#pragma pack() +#endif + +#if defined( __TINYC__ ) +#pragma pack(1) +#endif + +typedef struct { + uint16_t size; + uint32_t base; +} __attribute__( ( packed ) ) interrupt_descriptor_table_pointer_t; + +#if defined( __TINYC__ ) +#pragma pack() +#endif + +struct interrupt_t; +struct interrupt_handler_t; + +typedef uint32_t (*interrupt_handler_func_t)( struct interrupt_handler_t *handler, uint32_t esp ); + +typedef struct interrupt_handler_t { + uint8_t interrupt_no; + struct interrupt_t *interrupt; + interrupt_handler_func_t handle; + void *driver; +} interrupt_handler_t; + +void interrupt_handler_init_void( interrupt_handler_t *handler ); +void interrupt_handler_init( interrupt_handler_t *handler, uint8_t interrupt_no, struct interrupt_t *interrupt, interrupt_handler_func_t handle, void *driver ); + +typedef struct interrupt_t { + interrupt_descriptor_table_pointer_t idt_pointer; + interrupt_gate_descriptor_t descriptor_table[NOF_INTERRUPTS]; + interrupt_handler_t interrupt_handler[NOF_INTERRUPTS]; + // PIC master control register: command and status register + port8_t PIC_master_control; + // PIC master data register: interrupt mask and data register + port8_t PIC_master_data; + // since PC/AT we always have a slave PIC, we don't support the PC/XT architecture + // with just one PIC + port8_t PIC_slave_control; + port8_t PIC_slave_data; +} interrupt_t; + +void interrupts_enable( void ); +void interrupts_disable( void ); +void interrupts_init( interrupt_t *interrupt ); +void interrupts_register_interrupt_gate( interrupt_t *interrupt, + uint8_t interrupt_no, uint16_t gdt_code_segment_selector, + void (*helper_handler)( ), uint8_t privilege_level, uint8_t descriptor_type ); +void interrupts_register_interrupt_handler( interrupt_handler_t handler ); + +void interrupts_load_idt( interrupt_descriptor_table_pointer_t *idt_pointer ); + +uint32_t interrupts_handle_interrupt( interrupt_t *interrupt, uint8_t interrupt_no, uint32_t esp ); + +uint32_t interrupts_handle_static_interrupt( uint8_t interrupt_no, uint32_t esp ); + +uint32_t interrupts_exception_division_by_zero( interrupt_handler_t *handler, uint32_t esp ); + +uint32_t interrupts_interrupt_PIT( interrupt_handler_t *handler, uint32_t esp ); + +void interrupts_ignore_request( ); +void interrupts_handle_exception_0x00( ); +void interrupts_handle_irq_0x00( ); +void interrupts_handle_irq_0x01( ); +void interrupts_handle_irq_0x0C( ); + +// later: tasks and stacks, queues + +#endif // INTERRUPTS_H diff --git a/src/hardware/pci.c b/src/hardware/pci.c new file mode 100644 index 0000000..6b124b2 --- /dev/null +++ b/src/hardware/pci.c @@ -0,0 +1,187 @@ +#include "pci.h" + +#include "string.h" +#include "stdio.h" + +#define NOF_BUSES 8 +#define NOF_DEVICES_PER_BUS 32 +#define NOF_FUNCTIONS_PER_DEVICE 8 +#define NOF_BARS 6 + +#define PCI_VENDOR_ID 0x00 +#define PCI_DEVICE_ID 0x02 +#define PCI_REVISION 0x08 +#define PCI_INTERFACE 0x09 +#define PCI_SUBCLASS 0x0A +#define PCI_CLASS 0x0B +#define PCI_HEADER_TYPE 0x0E +#define PCI_BAR_BASE 0x10 + +void pci_controller_init( pci_controller_t *controller ) +{ + memset( controller, 0, sizeof( pci_controller_t ) ); + + port32_init( &controller->command_port, 0xCF8 ); + port32_init( &controller->data_port, 0xCFC ); +} + +static uint32_t compute_id( uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ) +{ + uint32_t id; + + id = ( 0x01 << 31 ) + | ( ( bus & 0xFF ) << 16 ) + | ( ( device & 0x1F ) << 11 ) + | ( ( function & 0x07 ) << 8 ) + | ( offset & 0xFC ); + + return id; +} + +uint16_t pci_controller_read( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ) +{ + uint32_t id = compute_id( bus, device, function, offset ); + + port32_write( &controller->command_port, id ); + + uint32_t data = port32_read( &controller->data_port ); + + // we get 256 byte data blocks aligned to 32-bit addresses + // for each offset + data = data >> ( ( 8 * ( offset % 4 ) ) & 0xFFFF ); + + return data; +} + +void pci_controller_write( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset, uint32_t data ) +{ + uint32_t id = compute_id( bus, device, function, offset ); + + port32_write( &controller->command_port, id ); + port32_write( &controller->data_port, data ); +} + +void pci_controller_scan_and_register( pci_controller_t *controller, driver_manager_t *driver_manager, interrupt_t *interrupt ) +{ + for( int bus = 0; bus < NOF_BUSES; bus++ ) { + for( int device = 0; device < NOF_DEVICES_PER_BUS; device++ ) { + // TODO: detect single/multi function device from header + for( int function = 0; function < NOF_FUNCTIONS_PER_DEVICE; function++ ) { + pci_device_descriptor_t device_descriptor; + pci_device_descriptor_init( &device_descriptor, controller, bus, device, function ); + + // no device + if( device_descriptor.device_id == 0x0 || + device_descriptor.device_id == 0xFFFF ) { + continue; + } + + printf( "%X:%X.%d: %X:%X (interface: %X, class %X:%X, rev: %d)\n", + bus, device, function, + device_descriptor.vendor_id, + device_descriptor.device_id, + device_descriptor.interface_id, + device_descriptor.class_id, + device_descriptor.subclass_id, + device_descriptor.revision_id ); + + uint8_t header_type = pci_controller_read( controller, bus, device, function, PCI_HEADER_TYPE ) & 0x7F; + int max_nof_bars = NOF_BARS; + if( header_type & 0x01 ) { + max_nof_bars = 2; + } + + for( int bar_number = 0; bar_number < max_nof_bars; bar_number++ ) { + pci_base_address_register_t bar; + pci_base_address_register_init( &bar, controller, bus, device, function, bar_number ); + if( bar.type == BASE_ADDRESS_REGISTER_TYPE_IO && bar.addr ) { + device_descriptor.port_base = (uint32_t)bar.addr; + } + + driver_t *driver = pci_device_get_driver( &device_descriptor, interrupt ); + if( driver ) { + driver_manager_add_driver( driver_manager, driver ); + } + } + } + } + } +} + +void pci_device_descriptor_init( pci_device_descriptor_t *descriptor, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function ) +{ + memset( descriptor, 0, sizeof( pci_device_descriptor_t ) ); + + descriptor->vendor_id = pci_controller_read( controller, bus, device, function, PCI_VENDOR_ID ); + descriptor->device_id = pci_controller_read( controller, bus, device, function, PCI_DEVICE_ID ); + descriptor->class_id = pci_controller_read( controller, bus, device, function, PCI_CLASS ); + descriptor->subclass_id = pci_controller_read( controller, bus, device, function, PCI_SUBCLASS ); + descriptor->interface_id = pci_controller_read( controller, bus, device, function, PCI_INTERFACE ); + descriptor->revision_id = pci_controller_read( controller, bus, device, function, PCI_REVISION ); +} + +void pci_base_address_register_init( pci_base_address_register_t *base_address_register, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint16_t bar ) +{ + memset( base_address_register, 0, sizeof( pci_base_address_register_t ) ); + + uint32_t val = pci_controller_read( controller, bus, device, function, PCI_BAR_BASE + sizeof( uint32_t ) * bar ); + + // bit 0 indicates whether we are I/O or memory mapped + base_address_register->type = ( val & 0x01 ) ? BASE_ADDRESS_REGISTER_TYPE_IO : BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED; + + switch( base_address_register->type ) { + case BASE_ADDRESS_REGISTER_TYPE_IO: + base_address_register->addr = (uint8_t *)( val & 0xFFFC ); + base_address_register->prefetchable = false; + break; + + case BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED: + switch( val << 1 & 0x03 ) { + case 0x00: + // 32-bit mode + break; + + case 0x01: + // 20-bit mode + break; + + case 0x02: + // 64-bit mode + break; + } + break; + } +} + +driver_t *pci_device_get_driver( pci_device_descriptor_t *descriptor, interrupt_t *interrupt ) +{ + // find a specific device + switch( descriptor->vendor_id ) { + case 0x10ec: // Realtek Semiconductor + switch( descriptor->device_id ) { + case 0x8029: // RTL-8029 + break; + } + break; + + case 0x8086: // Intel + break; + + default: + break; + } + + // find a generic driver + switch( descriptor->class_id ) { + case 0x03: // graphics + switch( descriptor->subclass_id ) { + case 0x00: // VGA + break; + } + break; + + default: // no driver found + break; + } + return NULL; +} diff --git a/src/hardware/pci.h b/src/hardware/pci.h new file mode 100644 index 0000000..ddbc990 --- /dev/null +++ b/src/hardware/pci.h @@ -0,0 +1,49 @@ +#ifndef PCI_H +#define PCI_H + +#include + +#include "port.h" +#include "interrupts.h" +#include "driver.h" + +typedef struct { + uint16_t vendor_id; + uint16_t device_id; + uint8_t class_id; + uint8_t subclass_id; + uint8_t interface_id; + uint8_t revision_id; + uint32_t port_base; +} pci_device_descriptor_t; + +typedef struct { + port32_t command_port; + port32_t data_port; +} pci_controller_t; + +typedef enum { + BASE_ADDRESS_REGISTER_TYPE_IO, + BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED +} pci_base_address_register_type_t; + +typedef struct { + pci_base_address_register_type_t type; + bool prefetchable; + uint8_t *addr; + uint32_t *size; +} pci_base_address_register_t; + +void pci_controller_init( pci_controller_t *controller ); + +uint16_t pci_controller_read( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ); +void pci_controller_write( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset, uint32_t data ); +void pci_controller_scan_and_register( pci_controller_t *controller, driver_manager_t *driver_manager, interrupt_t *interrupt ); + +void pci_device_descriptor_init( pci_device_descriptor_t *descriptor, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function ); + +void pci_base_address_register_init( pci_base_address_register_t *base_address_register, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint16_t bar ); + +driver_t *pci_device_get_driver( pci_device_descriptor_t *descriptor, interrupt_t *interrupt ); + +#endif // PCI_H diff --git a/src/hardware/port.asm b/src/hardware/port.asm new file mode 100644 index 0000000..555a4e8 --- /dev/null +++ b/src/hardware/port.asm @@ -0,0 +1,49 @@ +[bits 32] + +global port8_write +global port8_read + +; void port8_write( port8_t *port, uint8_t data ); +port8_write: + push ebp + mov ebp, esp + mov ecx, [ebp+8] + mov edx, DWORD [ecx] + movzx ax, BYTE [ebp+12] + out dx, al + leave + ret + +; uint8_t port8_read( port8_t *port ) +port8_read: + push ebp + mov ebp, esp + mov ecx, DWORD [ebp+8] + mov edx, [ecx] + in al, dx + leave + ret + +global port32_write +global port32_read + +; void port32_write( port32_t *port, uint32_t data ); +port32_write: + push ebp + mov ebp, esp + mov ecx, [ebp+8] + mov edx, DWORD [ecx] + mov eax, DWORD [ebp+12] + out dx, eax + leave + ret + +; uint32_t port32_read( port32_t *port ) +port32_read: + push ebp + mov ebp, esp + mov ecx, DWORD [ebp+8] + mov edx, [ecx] + in eax, dx + leave + ret diff --git a/src/hardware/port.c b/src/hardware/port.c new file mode 100644 index 0000000..46e7f37 --- /dev/null +++ b/src/hardware/port.c @@ -0,0 +1,17 @@ +#include "port.h" + +#include "string.h" + +void port8_init( port8_t *port, uint16_t number ) +{ + memset( port, 0, sizeof( port8_t ) ); + + port->number = number; +} + +void port32_init( port32_t *port, uint16_t number ) +{ + memset( port, 0, sizeof( port32_t ) ); + + port->number = number; +} diff --git a/src/hardware/port.h b/src/hardware/port.h new file mode 100644 index 0000000..ec96d09 --- /dev/null +++ b/src/hardware/port.h @@ -0,0 +1,23 @@ +#ifndef PORT_H +#define PORT_H + +#include + +typedef struct { + uint16_t number; // port number, e.g. 0x3d4 VGA index register +} port8_t; + +void port8_init( port8_t *port, uint16_t number ); +void port8_write( port8_t *port, uint8_t data ); +uint8_t port8_read( port8_t *port ); + +typedef struct { + uint16_t number; // port number, e.g. 0x3d4 VGA index register +} port32_t; + +void port32_init( port32_t *port, uint16_t number ); +void port32_write( port32_t *port, uint32_t data ); +uint32_t port32_read( port32_t *port ); + +#endif // PORT_H + diff --git a/src/interrupts.asm b/src/interrupts.asm deleted file mode 100644 index 155b2af..0000000 --- a/src/interrupts.asm +++ /dev/null @@ -1,90 +0,0 @@ -[bits 32] - -global interrupts_enable -global interrupts_disable -global interrupts_load_idt -extern interrupts_handle_static_interrupt - -; void interrupts_enable( void ) -interrupts_enable: - push ebp - mov ebp, esp - sti - leave - ret - -; void interrupts_disable( void ) -interrupts_disable: - push ebp - mov ebp, esp - cli - leave - ret - -; void interrupts_load_idt( interrupt_descriptor_table_pointer_t *idt_pointer ) -interrupts_load_idt: - push ebp - mov ebp, esp - mov ecx, [ebp+8] - lidt [ecx] - leave - ret - -; the handler to ignore interrupts -global interrupts_ignore_request -interrupts_ignore_request: - iret - -; void interrupts_handle_request_0x00( ); -%macro exception_stub 1 -global interrupts_handle_exception_%1 -interrupts_handle_exception_%1: - mov [interrupt_no], byte %1 - jmp int_entry -%endmacro - -exception_stub 0x00 - -; IRQs and exceptions would normally collidate, that's why the -; hardware interrupts must be transposed by an offset -IRQ_BASE equ 0x20 - -%macro irq_stub 1 -global interrupts_handle_irq_%1 -interrupts_handle_irq_%1: - mov [interrupt_no], byte IRQ_BASE + %1 - jmp int_entry -%endmacro - -irq_stub 0x00 -irq_stub 0x01 -irq_stub 0x0C - -int_entry: - ; safe state of interrupted code - pusha - push ds - push es - push fs - push gs - - ; call the static C handler with the correct interrupt number - ; uint32_t interrupts_handle_interrupt( uint8_t interrupt_no, uint32_t esp ); - push esp - mov eax, [interrupt_no] - push eax - call interrupts_handle_static_interrupt - ;add esp, 8 - mov esp, eax - - ; restore state - pop gs - pop fs - pop es - pop ds - popa - - iret - -interrupt_no: - db 0 diff --git a/src/interrupts.c b/src/interrupts.c deleted file mode 100644 index 614dbf0..0000000 --- a/src/interrupts.c +++ /dev/null @@ -1,215 +0,0 @@ -#include "interrupts.h" - -#include "string.h" -#include "stdio.h" - -#include "kernel.h" - -#include "keyboard.h" - -// TODO: for now the code segment is the first entry in the boot GDT -#define GDT_CODE_SEGMENT_SELECTOR 8 - -// the Present bit in a IDT entry -#define IDT_PRESENT_BIT 0x80 - -// DPL rings -#define KERNEL_RING 0 - -// types of IDT entries -#define IDT_TYPE_INTERRUPT_GATE 0xE - -// PIC constants - -#define ICW1_ICW4 0x01 // support a 4th initialization word (ICW4) -#define ICW1_INIT 0x10 // bit indicating initialization of chip - -// offset for hardware interrupts (for PIC ICW2) -#define ICW2_IRQ_BASE_MASTER IRQ_BASE -#define ICW2_IRQ_BASE_SLAVE ICW2_IRQ_BASE_MASTER + 8 - -// IRQ selection (master and slave, ICW3) -#define ICW3_MASTER_IR0 0x01 -#define ICW3_MASTER_IR1 0x02 -#define ICW3_MASTER_IR2 0x04 -#define ICW3_MASTER_IR3 0x08 -#define ICW3_MASTER_IR4 0x10 -#define ICW3_MASTER_IR5 0x20 -#define ICW3_MASTER_IR6 0x40 -#define ICW3_MASTER_IR7 0x80 -#define ICW3_SLAVE_IR0 0x00 -#define ICW3_SLAVE_IR1 0x01 -#define ICW3_SLAVE_IR2 0x02 -#define ICW3_SLAVE_IR3 0x03 -#define ICW3_SLAVE_IR4 0x04 -#define ICW3_SLAVE_IR5 0x05 -#define ICW3_SLAVE_IR6 0x06 -#define ICW3_SLAVE_IR7 0x07 - -// special mode PIC ICW4 -#define ICW4_8086 0x01 -#define ICW4_AUTO_ACK_EOI 0x02 -#define ICW4_BUF_MASTER 0x04 -#define ICW4_BUFFER 0x08 -#define ICW4_FULLY_NESTED 0x10 - -// OCW2 -#define OCW2_EOI 0x20 // non-specific End Of Interrupt - -void interrupt_handler_init_void( interrupt_handler_t *handler ) -{ - memset( handler, 0, sizeof( interrupt_handler_t ) ); -} - -void interrupt_handler_init( interrupt_handler_t *handler, uint8_t interrupt_no, struct interrupt_t *interrupt, interrupt_handler_func_t handle, void *driver ) -{ - memset( handler, 0, sizeof( interrupt_handler_t ) ); - - handler->interrupt_no = interrupt_no; - handler->interrupt = interrupt; - handler->handle = handle; - handler->driver = driver; -} - -// must be global: when called via assembly code we loose the context -// of the interrupt handler structure -static interrupt_t *active_interrupt; - -void interrupts_init( interrupt_t *interrupt ) -{ - memset( interrupt, 0, sizeof( interrupt_t ) ); - - interrupt_handler_t empty_interrupt_handler; - interrupt_handler_init_void( &empty_interrupt_handler ); - - for( int i = 0; i < NOF_INTERRUPTS; i++ ) { - interrupts_register_interrupt_gate( interrupt, i, GDT_CODE_SEGMENT_SELECTOR, - &interrupts_ignore_request, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); - interrupts_register_interrupt_handler( empty_interrupt_handler ); - } - - // divide-by-zero exception 0x00 - interrupt_handler_t divide_by_zero_interrupt_handler; - interrupt_handler_init( ÷_by_zero_interrupt_handler, 0x00, interrupt, interrupts_exception_division_by_zero, NULL ); - - interrupts_register_interrupt_gate( interrupt, 0x00, GDT_CODE_SEGMENT_SELECTOR, - &interrupts_handle_exception_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); - interrupts_register_interrupt_handler( divide_by_zero_interrupt_handler ); - - // IRQ 0 - PIT - programmable interrupt timer - interrupt_handler_t pit_interrupt_handler; - interrupt_handler_init( &pit_interrupt_handler, IRQ_BASE + 0x00, interrupt, interrupts_interrupt_PIT, NULL ); - - interrupts_register_interrupt_gate( interrupt, IRQ_BASE + 0x00, GDT_CODE_SEGMENT_SELECTOR, - &interrupts_handle_irq_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); - interrupts_register_interrupt_handler( pit_interrupt_handler ); - - // IRQ 1 - PS/2 keyboard - interrupts_register_interrupt_gate( interrupt, IRQ_BASE + 0x01, GDT_CODE_SEGMENT_SELECTOR, - &interrupts_handle_irq_0x01, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); - - // IRQ 12 - PS/2 mouse - interrupts_register_interrupt_gate( interrupt, IRQ_BASE + 0x0C, GDT_CODE_SEGMENT_SELECTOR, - &interrupts_handle_irq_0x0C, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); - - port8_init( &interrupt->PIC_master_control, 0x20 ); - port8_init( &interrupt->PIC_master_data, 0x21 ); - port8_init( &interrupt->PIC_slave_control, 0xA0 ); - port8_init( &interrupt->PIC_slave_data, 0xA1 ); - - // initialize hardware management PICs (ICW1) - port8_write( &interrupt->PIC_master_control, ICW1_ICW4 | ICW1_INIT ); - port8_write( &interrupt->PIC_slave_control, ICW1_ICW4 | ICW1_INIT ); - - // set IRQ base of both PICS (ICW2), remap them so they - // don't collide with CPU exceptions (this is true after 0x20) - port8_write( &interrupt->PIC_master_data, ICW2_IRQ_BASE_MASTER ); - port8_write( &interrupt->PIC_slave_data, ICW2_IRQ_BASE_SLAVE ); - - // use IRQ2 for master slave communication (ICW3) - port8_write( &interrupt->PIC_master_data, ICW3_MASTER_IR2 ); - port8_write( &interrupt->PIC_slave_data, ICW3_SLAVE_IR2 ); - - // unbuffered, manual acknoledgment and 8086 mode (ICW4) - // TODO: use buffered mode later? - port8_write( &interrupt->PIC_master_data, ICW4_8086 ); - port8_write( &interrupt->PIC_slave_data, ICW4_8086 ); - - // done, enable all IRQs by setting the interrupt mask register - // 0 for all bits. We are not interested in the old state of - // the mask as we are initializing in protected mode - // TODO: later we will mask uninmported interrupts maybe? - port8_write( &interrupt->PIC_master_data, 0 ); - port8_write( &interrupt->PIC_slave_data, 0 ); - - // tell CPU where the IDT is - interrupt->idt_pointer.size = NOF_INTERRUPTS * sizeof( interrupt_gate_descriptor_t ) - 1; - interrupt->idt_pointer.base = (uint32_t)interrupt->descriptor_table; - - interrupts_load_idt( &interrupt->idt_pointer ); - - active_interrupt = interrupt; -} - -void interrupts_register_interrupt_gate( interrupt_t *interrupts, - uint8_t interrupt_no, uint16_t gdt_code_segment_selector, - void (*helper_handler)( ), uint8_t privilege_level, uint8_t descriptor_type ) -{ - interrupt_gate_descriptor_t *descr = &interrupts->descriptor_table[interrupt_no]; - - descr->handler_address_low_bits = ( (uint32_t )helper_handler ) & 0xFFFF; - descr->handler_address_high_bits = ( ( (uint32_t )helper_handler ) >> 16 ) & 0xFFFF; - descr->gdt_code_segment_selector = gdt_code_segment_selector; - descr->access = IDT_PRESENT_BIT | (( privilege_level & 0x3 ) << 5 ) | descriptor_type; - descr->reserved = 0; -} - -void interrupts_register_interrupt_handler( interrupt_handler_t handler ) -{ - handler.interrupt->interrupt_handler[handler.interrupt_no] = handler; -} - -uint32_t interrupts_exception_division_by_zero( interrupt_handler_t *handler, uint32_t esp ) -{ - // TODO: caused by kernel code or user land code? or a task we can kill? - // For now, the kernel has no task management, so we panic - kernel_panic( "Division by zero with ESP 0x%X\n", esp ); - - return esp; -} - -uint32_t interrupts_interrupt_PIT( interrupt_handler_t *handler, uint32_t esp ) -{ - // for now do noting with the timer tick - return esp; -} - -uint32_t interrupts_handle_static_interrupt( uint8_t interrupt_no, uint32_t esp ) -{ - if( active_interrupt == NULL ) { - kernel_panic( "No active interrupt handler!" ); - } - - return interrupts_handle_interrupt( active_interrupt, interrupt_no, esp ); -} - -uint32_t interrupts_handle_interrupt( interrupt_t *interrupt, uint8_t interrupt_no, uint32_t esp ) -{ - interrupt_handler_t *handler = &interrupt->interrupt_handler[interrupt_no]; - - if( handler->handle == NULL ) { - kernel_panic( "Unhandled interrupt 0x%X with ESP 0x%X\n", interrupt_no, esp ); - } - - uint32_t new_esp = handler->handle( handler, esp ); - - // send ACK to PIC for hardware interrups - if( interrupt_no >= IRQ_BASE && interrupt_no <= IRQ_BASE + 16 ) { - port8_write( &interrupt->PIC_master_control, OCW2_EOI ); - if( interrupt_no >= IRQ_BASE + 8 ) { - port8_write( &interrupt->PIC_slave_control, OCW2_EOI ); - } - } - - return new_esp; -} diff --git a/src/interrupts.h b/src/interrupts.h deleted file mode 100644 index 8ab485e..0000000 --- a/src/interrupts.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef INTERRUPTS_H -#define INTERRUPTS_H - -#include - -#include "port.h" - -// total number of supported interrupts -#define NOF_INTERRUPTS 256 - -// offset for hardware interrupts -#define IRQ_BASE 0x20 - -// TCC 0.9.26 bug?, __attribute__( ( packed ) ) on structs not working, -// also not working on members.. resorting to pragmas -#if defined( __TINYC__ ) -#pragma pack(1) -#endif - -// packed IDT structure, note TCC needs every member to have a packed -// attribute, GCC/Clang are happy with the packed attribute at the -// structure level -typedef struct interrupt_gate_descriptor_t { - uint16_t handler_address_low_bits; - uint16_t gdt_code_segment_selector; - uint8_t reserved; - uint8_t access; - uint16_t handler_address_high_bits; -} __attribute__( ( packed ) ) interrupt_gate_descriptor_t; - -#if defined( __TINYC__ ) -#pragma pack() -#endif - -#if defined( __TINYC__ ) -#pragma pack(1) -#endif - -typedef struct { - uint16_t size; - uint32_t base; -} __attribute__( ( packed ) ) interrupt_descriptor_table_pointer_t; - -#if defined( __TINYC__ ) -#pragma pack() -#endif - -struct interrupt_t; -struct interrupt_handler_t; - -typedef uint32_t (*interrupt_handler_func_t)( struct interrupt_handler_t *handler, uint32_t esp ); - -typedef struct interrupt_handler_t { - uint8_t interrupt_no; - struct interrupt_t *interrupt; - interrupt_handler_func_t handle; - void *driver; -} interrupt_handler_t; - -void interrupt_handler_init_void( interrupt_handler_t *handler ); -void interrupt_handler_init( interrupt_handler_t *handler, uint8_t interrupt_no, struct interrupt_t *interrupt, interrupt_handler_func_t handle, void *driver ); - -typedef struct interrupt_t { - interrupt_descriptor_table_pointer_t idt_pointer; - interrupt_gate_descriptor_t descriptor_table[NOF_INTERRUPTS]; - interrupt_handler_t interrupt_handler[NOF_INTERRUPTS]; - // PIC master control register: command and status register - port8_t PIC_master_control; - // PIC master data register: interrupt mask and data register - port8_t PIC_master_data; - // since PC/AT we always have a slave PIC, we don't support the PC/XT architecture - // with just one PIC - port8_t PIC_slave_control; - port8_t PIC_slave_data; -} interrupt_t; - -void interrupts_enable( void ); -void interrupts_disable( void ); -void interrupts_init( interrupt_t *interrupt ); -void interrupts_register_interrupt_gate( interrupt_t *interrupt, - uint8_t interrupt_no, uint16_t gdt_code_segment_selector, - void (*helper_handler)( ), uint8_t privilege_level, uint8_t descriptor_type ); -void interrupts_register_interrupt_handler( interrupt_handler_t handler ); - -void interrupts_load_idt( interrupt_descriptor_table_pointer_t *idt_pointer ); - -uint32_t interrupts_handle_interrupt( interrupt_t *interrupt, uint8_t interrupt_no, uint32_t esp ); - -uint32_t interrupts_handle_static_interrupt( uint8_t interrupt_no, uint32_t esp ); - -uint32_t interrupts_exception_division_by_zero( interrupt_handler_t *handler, uint32_t esp ); - -uint32_t interrupts_interrupt_PIT( interrupt_handler_t *handler, uint32_t esp ); - -void interrupts_ignore_request( ); -void interrupts_handle_exception_0x00( ); -void interrupts_handle_irq_0x00( ); -void interrupts_handle_irq_0x01( ); -void interrupts_handle_irq_0x0C( ); - -// later: tasks and stacks, queues - -#endif // INTERRUPTS_H diff --git a/src/kernel.asm b/src/kernel.asm deleted file mode 100644 index f024897..0000000 --- a/src/kernel.asm +++ /dev/null @@ -1,8 +0,0 @@ -[bits 32] - -global kernel_halt - -; void kernel_halt( void ) -kernel_halt: - hlt - ret diff --git a/src/kernel.c b/src/kernel.c deleted file mode 100644 index 3c520d6..0000000 --- a/src/kernel.c +++ /dev/null @@ -1,202 +0,0 @@ -#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" - -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; - } -} diff --git a/src/kernel.h b/src/kernel.h deleted file mode 100644 index dc23fd6..0000000 --- a/src/kernel.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef KERNEL_H -#define KERNEL_H - -#include "stdio.h" - -void kernel_main( void ); -void kernel_panic( const char *format, ... ); -void kernel_halt( void ); - -#endif // KERNEL_H diff --git a/src/kernel/console.c b/src/kernel/console.c new file mode 100644 index 0000000..6113823 --- /dev/null +++ b/src/kernel/console.c @@ -0,0 +1,55 @@ +#include "console.h" + +#include "string.h" +#include "stddef.h" + +void console_init( console_t *console ) +{ + memset( console, 0, sizeof( console_t ) ); + + console->vga_text = NULL; + console->serial = NULL; +} + +void console_add_vga_text_output( console_t *console, vga_text_t *vga_text ) +{ + console->vga_text = vga_text; +} + +void console_add_serial_output( console_t *console, serial_t *serial ) +{ + console->serial = serial; +} + +void console_put_char( console_t *console, const char c ) +{ + if( console->vga_text != NULL ) { + vga_text_put_char( console->vga_text, c ); + } + + if( console->serial != NULL ) { + serial_put_char( console->serial, c ); + } +} + +void console_put_string( console_t *console, const char *s ) +{ + if( console->vga_text != NULL ) { + vga_text_put_string( console->vga_text, s ); + } + + if( console->serial != NULL ) { + serial_put_string( console->serial, s ); + } +} + +void console_put_newline( console_t *console ) +{ + if( console->vga_text != NULL ) { + vga_text_put_newline( console->vga_text ); + } + + if( console->serial != NULL ) { + serial_put_newline( console->serial ); + } +} diff --git a/src/kernel/console.h b/src/kernel/console.h new file mode 100644 index 0000000..a1c55ac --- /dev/null +++ b/src/kernel/console.h @@ -0,0 +1,19 @@ +#ifndef CONSOLE_H +#define CONSOLE_H + +#include "vgatext.h" +#include "serial.h" + +typedef struct { + vga_text_t *vga_text; + serial_t *serial; +} console_t; + +void console_init( console_t *console ); +void console_add_vga_text_output( console_t *console, vga_text_t *vga_text ); +void console_add_serial_output( console_t *console, serial_t *serial ); +void console_put_char( console_t *console, const char c ); +void console_put_string( console_t *console, const char *s ); +void console_put_newline( console_t *console ); + +#endif // CONSOLE_H diff --git a/src/kernel/kernel.asm b/src/kernel/kernel.asm new file mode 100644 index 0000000..f024897 --- /dev/null +++ b/src/kernel/kernel.asm @@ -0,0 +1,8 @@ +[bits 32] + +global kernel_halt + +; void kernel_halt( void ) +kernel_halt: + hlt + ret 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 +#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" + +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; + } +} diff --git a/src/kernel/kernel.h b/src/kernel/kernel.h new file mode 100644 index 0000000..dc23fd6 --- /dev/null +++ b/src/kernel/kernel.h @@ -0,0 +1,10 @@ +#ifndef KERNEL_H +#define KERNEL_H + +#include "stdio.h" + +void kernel_main( void ); +void kernel_panic( const char *format, ... ); +void kernel_halt( void ); + +#endif // KERNEL_H diff --git a/src/kernel/serial.c b/src/kernel/serial.c new file mode 100644 index 0000000..c5a6d95 --- /dev/null +++ b/src/kernel/serial.c @@ -0,0 +1,121 @@ +#include "serial.h" +#include "string.h" +#include "stdlib.h" + +// COM1 - I/O ports +#define COM1_PORT_BASE 0x3F8 + +// RDR - Receive buffer register (on port read, if DLAB=0) +// THR - Transmitter holding register (on port write, if DLAB=0) +// DL - Divisor Latch (on port write, LSB, if DLAB=1) +#define COM1_TRANSMIT_PORT COM1_PORT_BASE + +// IER - Interrupt Enable Register (if DLAB=0) +// DL - Divisor Latch (on port write, MSB, if DLAB=1) +#define COM1_INTERRUPT_ENABLE_PORT COM1_PORT_BASE + 1 + +// IIR - Interrupt Identification Register (on read) +// FCR - FIFO Control Register (write only) +#define COM1_FIFO_CONTROL_PORT COM1_PORT_BASE + 2 + +// LCR - Line Control Register +#define COM1_LCR_PORT COM1_PORT_BASE + 3 + +// MCR - Modem Control Register +#define COM1_MCR_PORT COM1_PORT_BASE + 4 + +// LSR - Line Status Register +#define COM1_LSR_PORT COM1_PORT_BASE + 5 + +// IER - Interrupt Enable Register +#define IER_ENABLE_IRQ_DATA_READY 0x01 +#define IER_ENABLE_IRQ_WRITE_READY 0x02 +#define IER_ENABLE_IRQ_STATUS 0x04 +#define IER_ENABLE_IRQ_MODEM_STATUS 0x08 + +// LSR - Line Status Register +#define LSR_THRE 0x20 // Transmitter Holding Register Empty + +// LCR - Line Control Register +#define LCR_DATA_BITS_5 0x00 +#define LCR_DATA_BITS_6 0x01 +#define LCR_DATA_BITS_7 0x02 +#define LCR_DATA_BITS_8 0x03 +#define LCR_ONE_STOPBIT 0x00 +#define LCR_TWO_STOPBITS 0x04 +#define LCR_PARITY_ENABLE 0x08 +#define LCR_PARITY_EVEN 0x10 +#define LCR_PARITY_STICKY 0x20 +#define LCR_SET_BREAK 0x40 +#define LCR_DLAB_ENABLE 0x80 // DLAB=1/0, baud rate DL register selector + +// MCR - Modem Control Register +#define MCR_DTR_LOW 0x01 +#define MCR_DTR_RTS_LOW 0x02 +#define MCR_DTS_OUT2_LOW 0x04 +#define MCR_LOCAL_LOOPBACK 0x08 + +// baud rate helpers (division of 115200 by divisor results in baud rate) +#define BAUD_RATE_DIVISOR_115200 1 +#define BAUD_RATE_DIVISOR_57600 2 +#define BAUD_RATE_DIVISOR_38400 3 +#define BAUD_RATE_DIVISOR_19200 6 +#define BAUD_RATE_DIVISOR_14400 8 +#define BAUD_RATE_DIVISOR_9600 12 +#define BAUD_RATE_DIVISOR_4800 24 +#define BAUD_RATE_DIVISOR_2400 48 +#define BAUD_RATE_DIVISOR_1200 96 +#define BAUD_RATE_DIVISOR_300 384 + +void serial_init( serial_t *serial ) +{ + memset( serial, 0, sizeof( serial_t ) ); + + port8_init( &serial->port_transmit, COM1_TRANSMIT_PORT ); + port8_init( &serial->port_interrupt_enable, COM1_INTERRUPT_ENABLE_PORT ); + port8_init( &serial->port_fifo_control, COM1_FIFO_CONTROL_PORT ); + port8_init( &serial->port_line_control, COM1_LCR_PORT ); + port8_init( &serial->port_modem_control, COM1_MCR_PORT ); + port8_init( &serial->port_line_status, COM1_LSR_PORT ); + + // disable all interrupts + port8_write( &serial->port_interrupt_enable, 0x00 ); + + // set baud rate, enable DLAB so we can access the DL registers + port8_write( &serial->port_line_control, + LCR_DATA_BITS_8 | LCR_DLAB_ENABLE ); + port8_write( &serial->port_transmit, BAUD_RATE_DIVISOR_9600 ); + port8_write( &serial->port_interrupt_enable, 0 ); + port8_write( &serial->port_line_control, + LCR_DATA_BITS_8 ); + + // disable FIFO (16550+ only, TODO: probe?) + port8_write( &serial->port_fifo_control, 0x00 ); + + // No loopback + // TODO: more? + port8_write( &serial->port_modem_control, 0x00 ); +} + +void serial_put_char( serial_t *serial, const char c ) +{ + uint8_t status; + do { + status = port8_read( &serial->port_line_status ); + } while( ( status & LSR_THRE ) == 0 ); + + port8_write( &serial->port_transmit, c ); +} + +void serial_put_string( serial_t *serial, const char *s ) +{ + for( size_t i = 0; i < strlen( s ); i++ ) { + serial_put_char( serial, s[i] ); + } +} + +void serial_put_newline( serial_t *serial ) +{ + serial_put_char( serial, '\r' ); + serial_put_char( serial, '\n' ); +} diff --git a/src/kernel/serial.h b/src/kernel/serial.h new file mode 100644 index 0000000..b30fe55 --- /dev/null +++ b/src/kernel/serial.h @@ -0,0 +1,20 @@ +#ifndef SERIAL_H +#define SERIAL_H + +#include "port.h" + +typedef struct { + port8_t port_transmit; + port8_t port_interrupt_enable; + port8_t port_fifo_control; + port8_t port_line_control; + port8_t port_modem_control; + port8_t port_line_status; +} serial_t; + +void serial_init( serial_t *serial ); +void serial_put_char( serial_t *serial, const char c ); +void serial_put_string( serial_t *serial, const char *s ); +void serial_put_newline( serial_t *serial ); + +#endif // SERIAL_H diff --git a/src/kernel/vgatext.c b/src/kernel/vgatext.c new file mode 100644 index 0000000..cbee587 --- /dev/null +++ b/src/kernel/vgatext.c @@ -0,0 +1,262 @@ +#include "vgatext.h" + +#include + +#include "string.h" +#include "stdlib.h" +#include "kernel.h" + +static bool params_ok( vga_text_t *vga_text, const int x, const int y ); +static int calculate_offset( vga_text_t *vga_text, const int x, const int y ); +static uint8_t calculate_color_cell( vga_text_t *vga_text ); +static void scroll_screen( vga_text_t *vga_text ); + +void vga_text_init( vga_text_t *vga_text ) +{ + memset( vga_text, 0, sizeof( vga_text_t ) ); + + vga_text->res_x = VGA_TEXT_DEFAULT_RES_X; + vga_text->res_y = VGA_TEXT_DEFAULT_RES_Y; + vga_text->color = VGA_TEXT_COLOR_DARK_GREY; + vga_text->background_color = VGA_TEXT_COLOR_BLACK; + vga_text->show_mouse_cursor = false; + vga_text->mouse_cursor_x = -1; + vga_text->mouse_cursor_y = -1; + + // make sure we use the 0x3dx VGA_TEXT ports, is done + // in assembly in stage 2 too + port8_init( &vga_text->crtc_misc_port, 0x3d2 ); + port8_write( &vga_text->crtc_misc_port, 1 ); + + // set up VGA_TEXT ports + port8_init( &vga_text->crtc_index_port, 0x3d4 ); + port8_init( &vga_text->crtc_data_port, 0x3d5 ); + + vga_text_set_cursor_from_hardware( vga_text ); +}; + +void vga_text_clear_screen( vga_text_t *vga_text ) +{ + volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; + + for( int i = 0; i < 2 * ( vga_text->res_x * vga_text->res_y ); i += 2 ) { + *(VIDEO_MEMORY+i) = ' '; + *(VIDEO_MEMORY+i+1) = calculate_color_cell( vga_text ); + } + + vga_text_set_cursor( vga_text, 0, 0 ); +} + +void vga_text_set_cursor( vga_text_t *vga_text, const int x, const int y ) +{ + if( !params_ok( vga_text, x, y ) ) { + kernel_panic( "Cursor parameters out of bounds: (%d, %d), resolution is only (%d, %d)", + x, y, vga_text->res_x, vga_text->res_y ); + } + + vga_text->cursor_x = x; + vga_text->cursor_y = y; + + // TODO: have a silent mode where we don't update the cursor + vga_text_set_cursor_on_hardware( vga_text ); +} + +void vga_text_set_cursor_from_hardware( vga_text_t *vga_text ) +{ + uint16_t hw_cursor_pos; + + port8_write( &vga_text->crtc_index_port, 14 ); + uint8_t data = port8_read( &(vga_text->crtc_data_port ) ); + hw_cursor_pos = data << 8; + + port8_write( &vga_text->crtc_index_port, 15 ); + data = port8_read( &(vga_text->crtc_data_port ) ); + + hw_cursor_pos |= data; + + vga_text->cursor_x = hw_cursor_pos % vga_text->res_x; + vga_text->cursor_y = hw_cursor_pos / vga_text->res_x; + + // reset to sane values if we get funny values from the VGA_TEXT card + if( vga_text->cursor_x < 0 || vga_text->cursor_x > vga_text->res_x || + vga_text->cursor_y < 0 || vga_text->cursor_y > vga_text->res_y ) { + vga_text->cursor_x = 0; + vga_text->cursor_y = 0; + } +} + +void vga_text_set_cursor_on_hardware( vga_text_t *vga_text ) +{ + uint16_t hw_cursor_pos = vga_text->cursor_x + vga_text->cursor_y * vga_text->res_x; + + port8_write( &vga_text->crtc_index_port, 15 ); + port8_write( &vga_text->crtc_data_port, hw_cursor_pos & 0xff ); + port8_write( &vga_text->crtc_index_port, 14 ); + port8_write( &vga_text->crtc_data_port, hw_cursor_pos >> 8 ); +} + +int vga_text_get_cursor_x( vga_text_t *vga_text ) +{ + return vga_text->cursor_x; +} + +int vga_text_get_cursor_y( vga_text_t *vga_text ) +{ + return vga_text->cursor_y; +} + +void vga_text_set_color( vga_text_t *vga_text, const vga_text_color_t color ) +{ + vga_text->color = color; +} + +void vga_text_set_background_color( vga_text_t *vga_text, const vga_text_color_t color ) +{ + vga_text->background_color = color; +} + +static int calculate_offset( vga_text_t *vga_text, const int x, const int y ) +{ + int offset = ( vga_text->res_x * y + x ) * 2; + + return offset; +} + +static void scroll_screen( vga_text_t *vga_text ) +{ + volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; + + memmove( (void *)VIDEO_MEMORY, (const void *)VIDEO_MEMORY + 2 * vga_text->res_x, 2 * ( vga_text->res_y - 1 ) * vga_text->res_x ); + + for( int i = 2 * ( vga_text->res_x * ( vga_text->res_y - 1 ) ); i < 2 * ( vga_text->res_x * vga_text->res_y ); i += 2 ) { + *(VIDEO_MEMORY+i) = ' '; + *(VIDEO_MEMORY+i+1) = calculate_color_cell( vga_text ); + } + + vga_text->cursor_y = vga_text->res_y - 1; +} + +static uint8_t calculate_color_cell( vga_text_t *vga_text ) +{ + uint8_t cell; + + cell = ( vga_text->background_color << 4 ) | vga_text->color; + + return cell; +} + +static bool params_ok( vga_text_t *vga_text, const int x, const int y ) +{ + if( x > vga_text->res_x || y > vga_text->res_y ) return false; + + return true; +} + +void vga_text_put_char_at( vga_text_t *vga_text, const int x, const int y, const char c ) +{ + vga_text_set_cursor( vga_text, x, y ); + vga_text_put_char( vga_text, c ); +} + + +void vga_text_put_string_at( vga_text_t *vga_text, const int x, const int y, const char *s ) +{ + vga_text_set_cursor( vga_text, x, y ); + vga_text_put_string( vga_text, s ); +} + +void vga_text_put_char( vga_text_t *vga_text, const char c ) +{ + int offset = calculate_offset( vga_text, vga_text->cursor_x, vga_text->cursor_y ); + + volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; + *(VIDEO_MEMORY+offset) = (uint8_t)c; + *(VIDEO_MEMORY+offset+1) = calculate_color_cell( vga_text ); + + vga_text->cursor_x++; + if( vga_text->cursor_x >= vga_text->res_x ) { + vga_text->cursor_x = 0; + vga_text->cursor_y++; + if( vga_text->cursor_y >= vga_text->res_y ) { + scroll_screen( vga_text ); + } + } + + vga_text_set_cursor_on_hardware( vga_text ); +} + +void vga_text_put_string( vga_text_t *vga_text, const char *s ) +{ + for( size_t i = 0; i < strlen( s ); i++ ) { + vga_text_put_char( vga_text, s[i] ); + } +} + +void vga_text_put_newline( vga_text_t *vga_text ) +{ + vga_text->cursor_x = 0; + vga_text->cursor_y++; + if( vga_text->cursor_y >= vga_text->res_y ) { + scroll_screen( vga_text ); + } + + vga_text_set_cursor_on_hardware( vga_text ); +} + +void vga_text_set_background_color_at( vga_text_t *vga_text, const int x, const int y, vga_text_color_t color ) +{ + int offset = calculate_offset( vga_text, x, y ); + + volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; + *(VIDEO_MEMORY+offset+1) = ( *(VIDEO_MEMORY+offset+1) & 0x0f ) | ( color << 4 ); +} + +vga_text_color_t vga_text_get_background_color_at( vga_text_t *vga_text, const int x, const int y ) +{ + int offset = calculate_offset( vga_text, x, y ); + + volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; + uint8_t cell = *(VIDEO_MEMORY+offset+1); + + return cell & 0xf0; +} + +void vga_text_inverse_colors_at( vga_text_t *vga_text, const int x, const int y ) +{ + int offset = calculate_offset( vga_text, x, y ); + + volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; + *(VIDEO_MEMORY+offset+1) = ( ( *(VIDEO_MEMORY+offset+1) & 0x0f ) << 4 ) + | ( ( *(VIDEO_MEMORY+offset+1) & 0xf0 ) >> 4 ); +} + +void vga_text_show_mouse_cursor( vga_text_t *vga_text ) +{ + if( !vga_text->show_mouse_cursor ) { + vga_text->show_mouse_cursor = true; + vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); + } +} + +void vga_text_move_mouse_cursor( vga_text_t *vga_text, const int x, const int y ) +{ + if( vga_text->show_mouse_cursor ) { + vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); + } + + vga_text->mouse_cursor_x = x; + vga_text->mouse_cursor_y = y; + + if( vga_text->show_mouse_cursor ) { + vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); + } +} + +void vga_text_hide_mouse_cursor( vga_text_t *vga_text ) +{ + if( vga_text->show_mouse_cursor ) { + vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); + vga_text->show_mouse_cursor = false; + } +} + diff --git a/src/kernel/vgatext.h b/src/kernel/vgatext.h new file mode 100644 index 0000000..499e3d8 --- /dev/null +++ b/src/kernel/vgatext.h @@ -0,0 +1,68 @@ +#ifndef VGA_TEXT_H +#define VGA_TEXT_H + +#include + +#include "port.h" + +enum { + VGA_TEXT_DEFAULT_RES_X = 80, + VGA_TEXT_DEFAULT_RES_Y = 25 +}; + +typedef enum { + VGA_TEXT_COLOR_BLACK = 0, + VGA_TEXT_COLOR_BLUE = 1, + VGA_TEXT_COLOR_GREEN = 2, + VGA_TEXT_COLOR_CYAN = 3, + VGA_TEXT_COLOR_RED = 4, + VGA_TEXT_COLOR_MAGENTA = 5, + VGA_TEXT_COLOR_BROWN = 6, + VGA_TEXT_COLOR_LIGHT_GREY = 7, + VGA_TEXT_COLOR_DARK_GREY = 8, + VGA_TEXT_COLOR_LIGHT_BLUE = 9, + VGA_TEXT_COLOR_LIGHT_GREEN = 10, + VGA_TEXT_COLOR_LIGHT_CYAN = 11, + VGA_TEXT_COLOR_LIGHT_RED = 12, + VGA_TEXT_COLOR_LIGHT_MAGENTA = 13, + VGA_TEXT_COLOR_LIGHT_BROWN = 14, + VGA_TEXT_COLOR_WHITE = 15 +} vga_text_color_t; + +typedef struct { + int res_x; // resolution, default 80 + int res_y; // resolution, default 25 + int cursor_x; // current cursor position X + int cursor_y; // current cursor position Y + vga_text_color_t color; + vga_text_color_t background_color; + port8_t crtc_misc_port; + port8_t crtc_index_port; + port8_t crtc_data_port; + bool show_mouse_cursor; + int mouse_cursor_x; + int mouse_cursor_y; +} vga_text_t; + +void vga_text_init( vga_text_t *vga_text ); +void vga_text_clear_screen( vga_text_t *vga_text ); +void vga_text_set_cursor( vga_text_t *vga_text, const int x, const int y ); +void vga_text_set_cursor_from_hardware( vga_text_t *vga_text ); +void vga_text_set_cursor_on_hardware( vga_text_t *vga_text ); +int vga_text_get_cursor_x( vga_text_t *vga_text ); +int vga_text_get_cursor_y( vga_text_t *vga_text ); +void vga_text_set_color( vga_text_t *vga_text, const vga_text_color_t color ); +void vga_text_set_background_color( vga_text_t *vga_text, const vga_text_color_t color ); +void vga_text_put_char_at( vga_text_t *vga_text, const int x, const int y, const char c ); +void vga_text_put_string_at( vga_text_t *vga_text, const int x, const int y, const char *s ); +void vga_text_put_char( vga_text_t *vga_text, const char c ); +void vga_text_put_string( vga_text_t *vga_text, const char *s ); +void vga_text_put_newline( vga_text_t *vga_text ); +void vga_text_set_background_color_at( vga_text_t *vga_text, const int x, const int y, vga_text_color_t color ); +vga_text_color_t vga_text_get_background_color_at( vga_text_t *vga_text, const int x, const int y ); +void vga_text_inverse_colors_at( vga_text_t *vga_text, const int x, const int y ); +void vga_text_show_mouse_cursor( vga_text_t *vga_text ); +void vga_text_move_mouse_cursor( vga_text_t *vga_text, const int x, const int y ); +void vga_text_hide_mouse_cursor( vga_text_t *vga_text ); + +#endif /* VGA_TEXT_H */ diff --git a/src/keyboard.c b/src/keyboard.c deleted file mode 100644 index d7d8d88..0000000 --- a/src/keyboard.c +++ /dev/null @@ -1,316 +0,0 @@ -#include "keyboard.h" -#include "stdio.h" - -// status register on command port (read) -#define STATUS_REG_OUTPUT_BUF_FULL 0x01 -#define STATUS_REG_INPUT_BUF_FULL 0x02 - -// generic PS/2 commands -#define COMMAND_GET_STATE 0x20 -#define COMMAND_SET_STATE 0x60 -#define COMMAND_DISABLE_PORT1 0xAD -#define COMMAND_ENABLE_PORT1 0xAE - -// status control register flags -#define STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT1 0x01 -#define STATUS_CONTROL_CONFIG_CLOCK_PORT1 0x10 - -// keyboard specific commands, PSAUX1 -#define KBD_COMMAND_SET_LEDS 0xED -#define KBD_SET_SCANCODE 0xF0 -#define KBD_ACTIVATE 0xF4 - -// keyboard LED status codes -#define KBD_LED_SCROLL_LOCK_ON 0x01 -#define KBD_LED_NUM_LOCK_ON 0x02 -#define KBD_LED_CAPS_LOCK_ON 0x04 -#define KBD_LED_ALL_OFF 0x00 -#define KBD_LED_ALL_ON KBD_LED_SCROLL_LOCK_ON | KBD_LED_NUM_LOCK_ON | KBD_LED_CAPS_LOCK_ON - -// keyboard scan codes -#define KBD_SCANCODE_1 0x01 -#define KBD_SCANCODE_2 0x02 -#define KBD_SCANCODE_3 0x03 - -#undef DEBUG - -static uint8_t read_data( keyboard_t *keyboard ) -{ - while( ( port8_read( &keyboard->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) == 0 ) { } - return port8_read( &keyboard->data_port ); -} - -static void send_command( keyboard_t *keyboard, uint8_t command ) -{ - while( port8_read( &keyboard->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { } - port8_write( &keyboard->command_port, command ); -} - -static void write_data( keyboard_t *keyboard, uint8_t data ) -{ - while( port8_read( &keyboard->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { } - port8_write( &keyboard->data_port, data ); -} - -/* -static void read_ack( keyboard_t *keyboard ) -{ - uint8_t data = read_data( keyboard ); - if( data == 0xFA ) { - return; - } else { - kernel_warn( "ERR PS/2 keyboard: acknoledgment failed 0x%X\n", data ); - } -} -*/ - -static keyboard_vtable_t keyboard_vtable = { - { - keyboard_activate, - keyboard_deactivate, - keyboard_deinit, - keyboard_print_info - } -}; - -void keyboard_init( keyboard_t *keyboard, keyboard_event_handler_t handler, void *context ) -{ - memset( keyboard, 0, sizeof( keyboard_t ) ); - - port8_init( &keyboard->command_port, 0x64 ); - port8_init( &keyboard->data_port, 0x60 ); - - keyboard->shift = false; - keyboard->handler = handler; - keyboard->context = context; - - keyboard->base.vtable = &keyboard_vtable.base; -} - -void keyboard_activate( void *obj ) -{ - puts( "Activating driver for PS/2 keyboard.." ); - - keyboard_t *keyboard = obj; - - // first switch off port 1 - send_command( keyboard, COMMAND_DISABLE_PORT1 ); - - // consume character pressed before executing the kernel - while( port8_read( &keyboard->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) { - port8_read( &keyboard->data_port ); - } - - // enable interrupts for port 1 - send_command( keyboard, COMMAND_GET_STATE ); - uint8_t status = read_data( keyboard ); - status |= STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT1; - status &= ~STATUS_CONTROL_CONFIG_CLOCK_PORT1; - send_command( keyboard, COMMAND_SET_STATE ); - write_data( keyboard, status ); - - // disable all LEDs on keyboard - //~ send_command( keyboard, KBD_COMMAND_SET_LEDS ); - //~ write_data( keyboard, KBD_LED_ALL_ON ); - - // set scan code - //~ send_command( keyboard, KBD_SET_SCANCODE ); - //~ write_data( keyboard, KBD_SCANCODE_2 ); - - // activate keyboard - //send_command( keyboard, KBD_ACTIVATE ); - //read_ack( keyboard ); - - // enable port 1 - send_command( keyboard, COMMAND_ENABLE_PORT1 ); -} - -void keyboard_deactivate( void *obj ) -{ - puts( "Deactivating driver for PS/2 keyboard.." ); - - keyboard_t *keyboard = obj; - - send_command( keyboard, COMMAND_DISABLE_PORT1 ); -} - -void keyboard_deinit( void *obj ) -{ - // nothing to do -} - -typedef enum { - KEYCODE_UNKNOWN, - KEYCODE_ASCII_CHAR -} keycode_type_t; - -typedef struct { - keycode_type_t type; - char c; -} keycode_t; - -typedef enum { - SCANCODE_SET_NORMAL = 0, - SCANCODE_SET_SHIFT = 1, - SCANCODE_SET_E0 = 2, - SCANCODE_SET_E1 = 3 -} scancode_set_t; - -// TODO: here come the translations to other keyboard layouts, -// assumming a QWERTY US keyboard here.. -static char scancode_map[4][128] = { - { - 0, 0, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '-', '=', '\b', 0, - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', '\n', 0, 'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', 0, 0, - 0, ' ', 0, 0, 0, 0, 0, 0, - 0, 0, 0 , 0 , 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 , 0 , 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 , 0 , 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 , 0 , 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 - }, - { - 0, 0, '!', '@', '#', '$', '%', '^', - '&', '*', '(', ')', '_', '+', 0, 0, - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', - 'O', 'P', '{', '}', '\n', 0, 'A', 'S', - 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', - '"', '~', 0, '|', 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', '<', '>', '?', 0, 0, - 0, ' ', 0, 0, 0, 0, 0, 0, - 0, 0, 0 , 0 , 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 , 0 , 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 , 0 , 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 , 0 , 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 - }, - { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 - }, - { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 - } -}; - -static keycode_t scancode_to_keycode( scancode_set_t set, uint8_t scan_code ) -{ - keycode_t key_code; - key_code.type = KEYCODE_UNKNOWN; - - key_code.c = scancode_map[set][scan_code]; - if( key_code.c > 0 ) { - key_code.type = KEYCODE_ASCII_CHAR; - } - return key_code; -} - -#define SCAN_CODE_BREAK_CODE 0x80 -#define SCAN_CODE_LEFT_SHIFT 0x2A -#define SCAN_CODE_RIGHT_SHIFT 0x36 - -uint32_t keyboard_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ) -{ - keyboard_t *keyboard = (keyboard_t *)handler->driver; - - // we can only wake up on IRQ1 because we don't send commands - // after initialization - uint8_t scan_code = port8_read( &keyboard->data_port ); - - // we get break code when the high bit is set, so the - // the key is released - bool break_code = false; - if( scan_code & SCAN_CODE_BREAK_CODE ) { - break_code = true; - } - - scan_code &= ~SCAN_CODE_BREAK_CODE; - - if( scan_code == SCAN_CODE_LEFT_SHIFT || - scan_code == SCAN_CODE_RIGHT_SHIFT ) { - if( break_code ) { - keyboard->shift = false; - } else { - keyboard->shift = true; - } - } - - scancode_set_t code_set = SCANCODE_SET_NORMAL; - if( keyboard->shift ) { - code_set = SCANCODE_SET_SHIFT; - } - - keycode_t key_code = scancode_to_keycode( code_set, scan_code ); - -#ifdef DEBUG - printf( "KBD SCAN:0x%X S:%d B:%d S:%d T:0x%X '%c' 0x%X\n", - scan_code, code_set, break_code, keyboard->shift, - key_code.type, key_code.c, key_code.c ); -#endif - - keyboard_event_t event; - if( break_code ) { - event.type = KEYBOARD_EVENT_TYPE_KEY_RELEASED; - } else { - event.type = KEYBOARD_EVENT_TYPE_KEY_PRESSED; - } - event.modifiers = 0; - if( keyboard->shift ) { - event.modifiers |= KEYBOARD_MODIFIER_SHIFT; - } - // TODO: for control, alt, meta, etc. - event.key = KEYBOARD_KEY_UNKNOWN; - if( key_code.type == KEYCODE_ASCII_CHAR ) { - event.key = KEYBOARD_KEY_ASCII; - event.ascii_key = key_code.c; - } - - keyboard->handler( &event, keyboard->context ); - - return esp; -} - -void keyboard_print_info( void *obj ) -{ - puts( "PS/2 keyboard driver" ); -} diff --git a/src/keyboard.h b/src/keyboard.h deleted file mode 100644 index 5f90ee8..0000000 --- a/src/keyboard.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef KEYBOARD_H -#define KEYBOARD_H - -#include - -#include "string.h" - -#include "interrupts.h" -#include "port.h" - -#include "driver.h" - -typedef enum { - KEYBOARD_EVENT_TYPE_KEY_PRESSED, - KEYBOARD_EVENT_TYPE_KEY_RELEASED -} keyboard_event_type_t; - -typedef enum { - KEYBOARD_MODIFIER_SHIFT = 0x01, - KEYBOARD_MODIFIER_CTRL = 0x02, - KEYBOARD_MODIFIER_ALT = 0x04 -} keyboard_modifier_mask_t; - -typedef enum { - KEYBOARD_KEY_UNKNOWN, - KEYBOARD_KEY_ASCII, - KEYBOARD_KEY_ESC, - KEYBOARD_KEY_TAB, - KEYBOARD_KEY_INS, - KEYBAORD_KEY_DEL, - KEYBAORD_KEY_BACKSPACE, - KEYBAORD_CURSOR_LEFT, - KEYBOARD_CURSOR_RIGHT, - KEYBOARD_CURSOR_UP, - KEYBOARD_CURSOR_DOWN -} keyboard_key_t; - -typedef struct { - keyboard_event_type_t type; - keyboard_modifier_mask_t modifiers; - keyboard_key_t key; - char ascii_key; -} keyboard_event_t; - -typedef void (*keyboard_event_handler_t)( keyboard_event_t *event, void *context ); - -typedef struct { - driver_t base; - interrupt_t *interrupts; - port8_t command_port; - port8_t data_port; - bool shift; - keyboard_event_handler_t handler; - void *context; -} keyboard_t; - -typedef struct { - driver_vtable_t base; -} keyboard_vtable_t; - -void keyboard_init( keyboard_t *keyboard, keyboard_event_handler_t handler, void *context ); -void keyboard_activate( void *obj ); -void keyboard_deactivate( void *obj ); -void keyboard_deinit( void *obj ); -void keyboard_print_info( void *obj ); - -uint32_t keyboard_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ); - -#endif // KEYBOARD_H diff --git a/src/libc/limits.h b/src/libc/limits.h new file mode 100644 index 0000000..1fc4e37 --- /dev/null +++ b/src/libc/limits.h @@ -0,0 +1,7 @@ +#ifndef LIMITS_H +#define LIMITS_H + +#define INT_MAX 2147483647 +#define INT_MIN -2147483648 + +#endif // LIMITS_H diff --git a/src/libc/setjmp.asm b/src/libc/setjmp.asm new file mode 100644 index 0000000..a20a0af --- /dev/null +++ b/src/libc/setjmp.asm @@ -0,0 +1,44 @@ +[bits 32] + +global setjmp +global longjmp + +;typedef struct { +; uint32_t ebx; +; uint32_t esp; +; uint32_t ebp; +; uint32_t esi; +; uint32_t edi; +; uint32_t eip; +;} jmp_buf[1]; + +; int setjmp(jmp_buf env) +setjmp: + mov eax, [esp+4] ; the adress of the jump buffer + mov [eax], ebx ; safe registers + mov [eax+4], esp + mov [eax+8], ebp + mov [eax+12], esi + mov [eax+16], edi + mov edx, [esp] ; get return address from the stack (pushed here by call) + mov [eax+20], edx + mov eax, 0 ; indicate that we come from setjmp, not from a longjmp + ret + +; void longjmp(jmp_buf env, int value); +longjmp: + mov eax, [esp+4] ; the address of the jump buffer + mov ecx, [esp+8] ; the return value for setjmp + mov ebx, [eax] ; restore registers + mov esp, [eax+4] + mov ebp, [eax+8] + mov esi, [eax+12] + mov edi, [eax+16] + mov edx, [eax+20] ; get jump address and store it on the stack for 'ret' + mov [esp], edx + mov eax, ecx ; get return value + cmp eax, 0 + jnz .return ; non zero, ok, return it + mov eax, 1 ; setjmp called with 0, not good, return 1 +.return: + ret diff --git a/src/libc/setjmp.h b/src/libc/setjmp.h new file mode 100644 index 0000000..5f987f1 --- /dev/null +++ b/src/libc/setjmp.h @@ -0,0 +1,24 @@ +#ifndef SETJMP_H +#define SETJMP_H + +#include + +// C99 states this should be an array so we can address it without +// the & operator, see prototypes of setjmp and longjmp +// eax, ecx and edx are scratch registers, save the others +// also store the jump address (eip) +typedef struct { + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t eip; +} jmp_buf[1]; + +int setjmp( jmp_buf env ); + +void longjmp( jmp_buf env, int val ); + +#endif // SETJMP_H + diff --git a/src/libc/stddef.h b/src/libc/stddef.h new file mode 100644 index 0000000..4333661 --- /dev/null +++ b/src/libc/stddef.h @@ -0,0 +1,10 @@ +#ifndef STDDEF_H +#define STDDEF_H + +#include + +#define NULL ( (void *)0 ) + +typedef uint32_t size_t; + +#endif /* STDDEF_H */ diff --git a/src/libc/stdio.c b/src/libc/stdio.c new file mode 100644 index 0000000..1d53f7a --- /dev/null +++ b/src/libc/stdio.c @@ -0,0 +1,106 @@ +#include "stdio.h" +#include "stddef.h" +#include "stdlib.h" +#include "string.h" + +console_t *global_console = NULL; + +int puts( const char *s ) +{ + if( global_console == NULL ) { + return EOF; + } + + console_put_string( global_console, s ); + console_put_newline( global_console ); + + return 1; +} + +int printf( const char *format, ... ) +{ + va_list args; + + va_start( args, format ); + int res = vprintf( format, args ); + va_end( args ); + + return res; +} + +int vprintf( const char *format, va_list args ) +{ + const char *s = format; + int n = 0; + + if( global_console == NULL ) { + return -1; + } + + while( *s != '\0' ) { + switch( *s ) { + case '\n': + console_put_newline( global_console ); + n++; + break; + + case '%': + s++; + if( *s == '\0' ) { + console_put_string( global_console, "" ); + console_put_newline( global_console ); + return -1; + } + + switch( *s ) { + case '%': + console_put_char( global_console, '%' ); + break; + + case 'X': { + char buf[19]; + itoa( va_arg( args, int ), (char *)buf, 16 ); + console_put_string( global_console, buf ); + n += strlen( buf ); + } + break; + + case 'd': { + char buf[19]; + itoa( va_arg( args, int ), (char *)buf, 10 ); + console_put_string( global_console, buf ); + n += strlen( buf ); + } + break; + + case 'c': + console_put_char( global_console, va_arg( args, int ) ); + break; + + case 's': + console_put_string( global_console, va_arg( args, const char * ) ); + break; + + default: + console_put_string( global_console, "" ); + console_put_newline( global_console ); + } + + break; + + default: + console_put_char( global_console, *s ); + n++; + } + s++; + } + + return n; +} + +void stdio_set_console( console_t *console ) +{ + global_console = console; +} diff --git a/src/libc/stdio.h b/src/libc/stdio.h new file mode 100644 index 0000000..bc7fac0 --- /dev/null +++ b/src/libc/stdio.h @@ -0,0 +1,20 @@ +#ifndef STDIO_H +#define STDIO_H + +#include + +#include "stddef.h" + +#include "console.h" + +#define EOF (-1) + +extern console_t *global_console; + +int puts( const char *s ); +int printf( const char *format, ... ); +int vprintf( const char *format, va_list args ); + +void stdio_set_console( console_t *console ); + +#endif //STDIO_H diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c new file mode 100644 index 0000000..46bdce8 --- /dev/null +++ b/src/libc/stdlib.c @@ -0,0 +1,48 @@ +#include +#include "string.h" +#include "stdlib.h" +#include "stddef.h" + +static void strreverse( char *s ) +{ + char *end = s + strlen( s ) - 1; + + while( s < end ) { + // XOR swap; + *s ^= *end; + *end ^= *s; + *s ^= *end; + s++; + end--; + } +} + +char *itoa( int v, char *s, int base ) +{ + static char digit[] = "0123456789ABCDEF"; + bool sign = false; + char *p = s; + + if( base < 2 || base > 16 ) { + return NULL; + } + + if( v < 0 ) { + v = -v; + sign = true; + } + + do { + *p++ = digit[v % base]; + } while( ( v /= base ) > 0 ); + + if( sign ) { + *p++ = '-'; + } + *p = '\0'; + + strreverse( s ); + + return s; +} + diff --git a/src/libc/stdlib.h b/src/libc/stdlib.h new file mode 100644 index 0000000..331012e --- /dev/null +++ b/src/libc/stdlib.h @@ -0,0 +1,6 @@ +#ifndef STDLIB_H +#define STDLIB_H + +char *itoa( int v, char *s, int base ); + +#endif // STDLIB_H diff --git a/src/libc/string.c b/src/libc/string.c new file mode 100644 index 0000000..8d4f876 --- /dev/null +++ b/src/libc/string.c @@ -0,0 +1,75 @@ +#include "string.h" + +void *memset( void *s, int c, size_t n ) +{ + for( size_t i = 0; i < n; i++ ) { + ((char *)s)[i] = c; + } + + return s; +} + +void *memmove( void *d, const void *s, size_t n ) +{ + const char *ss = (const char *)s; + char *dd = (char *)d; + + if( dd == ss ) return d; + + if( dd <= ss ) { + while( n > 0 ) { + *dd++ = *ss++; + n--; + } + } else { + dd += n; + ss += n; + while( n > 0 ) { + *--dd = *--ss; + n--; + } + } + + return d; +} + +size_t strlen( const char *s ) +{ + size_t len; + const char *p = s; + + for( len = 0; *p; len++, p++ ); + + return len; +} + +int strcmp( const char *s1, const char *s2 ) +{ + while( *s1 && *s2 && *s1 == *s2 ) { + s1++; + s2++; + } + + return *s1 - *s2; +} + +size_t strlcpy( char *d, const char *s, size_t n ) +{ + size_t len = 0; + + while( len < n && s[len] != '\0' ) { + d[len] = s[len]; + len++; + } + d[len] = '\0'; + + while( s[len] != '\0' ) { + len++; + } + + if( len >= n ) { + d[n-1] = '\0'; + } + + return len; +} diff --git a/src/libc/string.h b/src/libc/string.h new file mode 100644 index 0000000..476c8c0 --- /dev/null +++ b/src/libc/string.h @@ -0,0 +1,12 @@ +#ifndef STRING_H +#define STRING_H + +#include "stddef.h" + +void *memset( void *s, int c, size_t n ); +void *memmove( void *d, const void *s, size_t n ); +size_t strlen( const char *s ); +int strcmp( const char *s1, const char *s2 ); +size_t strlcpy( char *d, const char *s, size_t n ); + +#endif // STRING_H diff --git a/src/limits.h b/src/limits.h deleted file mode 100644 index 1fc4e37..0000000 --- a/src/limits.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef LIMITS_H -#define LIMITS_H - -#define INT_MAX 2147483647 -#define INT_MIN -2147483648 - -#endif // LIMITS_H diff --git a/src/mouse.c b/src/mouse.c deleted file mode 100644 index 46984eb..0000000 --- a/src/mouse.c +++ /dev/null @@ -1,250 +0,0 @@ -#include "mouse.h" - -#include "stdio.h" - -// status register on command port (read) -#define STATUS_REG_OUTPUT_BUF_FULL 0x01 -#define STATUS_REG_INPUT_BUF_FULL 0x02 -#define STATUS_REG_OUTPUT_BUF2_FULL 0x20 - -// status control register flags -#define STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT2 0x02 -#define STATUS_CONTROL_CONFIG_CLOCK_PORT2 0x20 - -// generic PS/2 commands -#define COMMAND_GET_STATE 0x20 -#define COMMAND_SET_STATE 0x60 -#define COMMAND_DISABLE_PORT2 0xA7 -#define COMMAND_ENABLE_PORT2 0xA8 -#define COMMAND_SEND_TO_PORT2 0xD4 - -// mouse commands -#define MOUSE_COMMAND_GET_DEVICE_ID 0xF2 -#define MOUSE_COMMAND_SET_SAMPLE_RATE 0xF3 -#define MOUSE_COMMAND_ENABLE_DATAREPORTING 0xF4 -#define MOUSE_COMMAND_SET_DEFAULTS 0xF6 -#define DEFAULT_NOF_PACKETS 3 - -// mouse data packet one -#define MOUSE_BYTE1_LEFT_BUTTON 0x01 -#define MOUSE_BYTE1_RIGHT_BUTTON 0x02 -#define MOUSE_BYTE1_MIDDLE_BUTTON 0x04 -#define MOUSE_BYTE1_ID_BIT 0x08 -#define MOUSE_BYTE1_X_SIGN 0x10 -#define MOUSE_BYTE1_Y_SIGN 0x20 -#define MOUSE_BYTE1_X_OVERFLOW 0x40 -#define MOUSE_BYTE1_Y_OVERFLOW 0x80 - -#undef DEBUG - -static uint8_t read_data( mouse_t *mouse ) -{ - while( ( port8_read( &mouse->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) == 0 ) { } - return port8_read( &mouse->data_port ); -} - -static void send_command( mouse_t *mouse, uint8_t command ) -{ - while( port8_read( &mouse->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { } - port8_write( &mouse->command_port, command ); -} - -static void write_data( mouse_t *mouse, uint8_t data ) -{ - while( port8_read( &mouse->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { } - port8_write( &mouse->data_port, data ); -} - -static void read_ack( mouse_t *mouse ) -{ - uint8_t data = read_data( mouse ); - if( data == 0xFA ) { - return; - } else { - printf( "ERR PS/2 mouse: acknoledgment failed 0x%X\n", data ); - } -} - -static void set_sample_rate( mouse_t *mouse, uint8_t samples ) -{ - send_command( mouse, COMMAND_SEND_TO_PORT2 ); - write_data( mouse, MOUSE_COMMAND_SET_SAMPLE_RATE ); - read_ack( mouse ); - - send_command( mouse, COMMAND_SEND_TO_PORT2 ); - write_data( mouse, samples ); - read_ack( mouse ); -} - -static mouse_vtable_t mouse_vtable = { - { - mouse_activate, - mouse_deactivate, - mouse_deinit, - mouse_print_info - } -}; - -void mouse_init( mouse_t *mouse, mouse_event_handler_t handler, void *context ) -{ - memset( mouse, 0, sizeof( mouse_t ) ); - - // TODO: we should probe for wheel mouse and more than 3 packets - mouse->nof_packets = DEFAULT_NOF_PACKETS; - - vga_text_t *vga_text = (vga_text_t *)context; - - mouse->res_x = vga_text->res_x; - mouse->res_y = vga_text->res_y; - mouse->cursor_x = mouse->res_x / 2; - mouse->cursor_y = mouse->res_y / 2; - mouse->handler = handler; - mouse->context = context; - - port8_init( &mouse->command_port, 0x64 ); - port8_init( &mouse->data_port, 0x60 ); - - mouse->base.vtable = &mouse_vtable.base; -} - -void mouse_activate( void *obj ) -{ - puts( "Activating driver for PS/2 mouse.." ); - - mouse_t *mouse = obj; - - // enable port 2 - send_command( mouse, COMMAND_ENABLE_PORT2 ); - - // enable interrupts for port 2 - send_command( mouse, COMMAND_GET_STATE ); - uint8_t status = read_data( mouse ); - status |= STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT2; - status &= ~STATUS_CONTROL_CONFIG_CLOCK_PORT2; - send_command( mouse, COMMAND_SET_STATE ); - write_data( mouse, status ); - - // detecting mouse wheel (and 4th data packet) - set_sample_rate( mouse, 200 ); - set_sample_rate( mouse, 100 ); - set_sample_rate( mouse, 80 ); - send_command( mouse, COMMAND_SEND_TO_PORT2 ); - write_data( mouse, MOUSE_COMMAND_GET_DEVICE_ID ); - read_ack( mouse ); - uint8_t id = read_data( mouse ); - printf( "PS/2 mouse model id is 0x%X\n", id ); - if( id == 0x03 ) { - mouse->nof_packets = 4; - } - - // set mouse defaults -// send_command( mouse, COMMAND_SEND_TO_PORT2 ); -// write_data( mouse, MOUSE_COMMAND_SET_DEFAULTS ); - - // enable mouse on second port - send_command( mouse, COMMAND_SEND_TO_PORT2 ); - write_data( mouse, MOUSE_COMMAND_ENABLE_DATAREPORTING ); - read_ack( mouse ); -} - -void mouse_deactivate( void *obj ) -{ - puts( "Dectivating driver for PS/2 mouse.." ); - - mouse_t *mouse = obj; - - send_command( mouse, COMMAND_DISABLE_PORT2 ); -} - -void mouse_deinit( void *obj ) -{ - // nothing to do -} - -uint32_t mouse_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ) -{ - mouse_t *mouse = (mouse_t *)handler->driver; - - uint8_t status = port8_read( &mouse->command_port ); - if( !( status & STATUS_REG_OUTPUT_BUF2_FULL ) ) { - return esp; - } - - mouse->buf[mouse->offset] = port8_read( &mouse->data_port ); - -#ifdef DEBUG - printf( "MOUSE: %d 0x%X\n", mouse->offset, mouse->buf[mouse->offset] ); -#endif - - switch( mouse->offset ) { - case 0: - if( mouse->buf[0] & MOUSE_BYTE1_ID_BIT ) { - for( int i = 0; i < 3; i++ ) { - if( ( mouse->buf[0] & ( 0x01 << i ) ) != ( mouse->buttons & ( 0x01 << i ) ) ) { - mouse_event_t event; - event.button = i + 1; - if( mouse->buttons & ( 0x01 << i ) ) { - event.type = MOUSE_EVENT_TYPE_BUTTON_UP; - } else { - event.type = MOUSE_EVENT_TYPE_BUTTON_DOWN; - } - event.cursor_x = mouse->cursor_x; - event.cursor_y = mouse->cursor_y; - mouse->handler( &event, mouse->context ); - } - } - mouse->buttons = mouse->buf[0]; - } - break; - - case 1: - // delay evaluation of move events till second byte - break; - - case 2: - if( mouse->buf[1] !=0 || mouse->buf[2] != 0 ) { - - mouse_event_t event; - event.type = MOUSE_EVENT_TYPE_MOVE; - event.old_cursor_x = mouse->cursor_x; - event.old_cursor_y = mouse->cursor_y; - - mouse->cursor_x += (int8_t)mouse->buf[1]; - mouse->cursor_y -= (int8_t)mouse->buf[2]; - if( mouse->cursor_x < 0 ) { - mouse->cursor_x = 0; - } - if( mouse->cursor_x > mouse->res_x - 1 ) { - mouse->cursor_x = mouse->res_x - 1; - } - if( mouse->cursor_y < 0 ) { - mouse->cursor_y = 0; - } - if( mouse->cursor_y > mouse->res_y - 1 ) { - mouse->cursor_y = mouse->res_y - 1; - } - - event.cursor_x = mouse->cursor_x; - event.cursor_y = mouse->cursor_y; - - mouse->handler( &event, mouse->context ); - } - - break; - - case 3: - // TODO: read fourth data packet, but don't handle - // it yet - break; - } - - // advance offset - mouse->offset = ( mouse->offset + 1 ) % mouse->nof_packets; - - return esp; -} - -void mouse_print_info( void *obj ) -{ - puts( "PS/2 mouse driver" ); -} diff --git a/src/mouse.h b/src/mouse.h deleted file mode 100644 index cbd02ef..0000000 --- a/src/mouse.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef MOUSE_H -#define MOUSE_H - -#include "string.h" - -#include "interrupts.h" -#include "port.h" - -#include "driver.h" - -#define MAX_NOF_MOUSE_PACKETS 5 - -typedef enum { - MOUSE_EVENT_TYPE_BUTTON_UP, - MOUSE_EVENT_TYPE_BUTTON_DOWN, - MOUSE_EVENT_TYPE_MOVE -} mouse_event_type_t; - -typedef enum { - MOUSE_BUTTON_LEFT = 1, - MOUSE_BUTTON_RIGHT = 2, - MOUSE_BUTTON_MIDDLE = 3 -} mouse_button_t; - -typedef struct { - mouse_event_type_t type; - mouse_button_t button; - int32_t old_cursor_x; - int32_t old_cursor_y; - int32_t cursor_x; - int32_t cursor_y; -} mouse_event_t; - -typedef void (*mouse_event_handler_t)( mouse_event_t *event, void *context ); - -typedef struct { - driver_t base; - interrupt_t *interrupts; - port8_t command_port; - port8_t data_port; - int nof_packets; // 3 or more mouse packets - uint8_t buf[MAX_NOF_MOUSE_PACKETS]; - uint8_t buttons; - uint8_t offset; - uint32_t res_x; - uint32_t res_y; - int32_t cursor_x; - int32_t cursor_y; - mouse_event_handler_t handler; - void *context; -} mouse_t; - -typedef struct { - driver_vtable_t base; -} mouse_vtable_t; - -void mouse_init( mouse_t *mouse, mouse_event_handler_t handler, void *context ); -void mouse_activate( void *obj ); -void mouse_deactivate( void *obj ); -void mouse_deinit( void *obj ); -void mouse_print_info( void *obj ); - -uint32_t mouse_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ); - -#endif // MOUSE_H diff --git a/src/pci.c b/src/pci.c deleted file mode 100644 index 6b124b2..0000000 --- a/src/pci.c +++ /dev/null @@ -1,187 +0,0 @@ -#include "pci.h" - -#include "string.h" -#include "stdio.h" - -#define NOF_BUSES 8 -#define NOF_DEVICES_PER_BUS 32 -#define NOF_FUNCTIONS_PER_DEVICE 8 -#define NOF_BARS 6 - -#define PCI_VENDOR_ID 0x00 -#define PCI_DEVICE_ID 0x02 -#define PCI_REVISION 0x08 -#define PCI_INTERFACE 0x09 -#define PCI_SUBCLASS 0x0A -#define PCI_CLASS 0x0B -#define PCI_HEADER_TYPE 0x0E -#define PCI_BAR_BASE 0x10 - -void pci_controller_init( pci_controller_t *controller ) -{ - memset( controller, 0, sizeof( pci_controller_t ) ); - - port32_init( &controller->command_port, 0xCF8 ); - port32_init( &controller->data_port, 0xCFC ); -} - -static uint32_t compute_id( uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ) -{ - uint32_t id; - - id = ( 0x01 << 31 ) - | ( ( bus & 0xFF ) << 16 ) - | ( ( device & 0x1F ) << 11 ) - | ( ( function & 0x07 ) << 8 ) - | ( offset & 0xFC ); - - return id; -} - -uint16_t pci_controller_read( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ) -{ - uint32_t id = compute_id( bus, device, function, offset ); - - port32_write( &controller->command_port, id ); - - uint32_t data = port32_read( &controller->data_port ); - - // we get 256 byte data blocks aligned to 32-bit addresses - // for each offset - data = data >> ( ( 8 * ( offset % 4 ) ) & 0xFFFF ); - - return data; -} - -void pci_controller_write( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset, uint32_t data ) -{ - uint32_t id = compute_id( bus, device, function, offset ); - - port32_write( &controller->command_port, id ); - port32_write( &controller->data_port, data ); -} - -void pci_controller_scan_and_register( pci_controller_t *controller, driver_manager_t *driver_manager, interrupt_t *interrupt ) -{ - for( int bus = 0; bus < NOF_BUSES; bus++ ) { - for( int device = 0; device < NOF_DEVICES_PER_BUS; device++ ) { - // TODO: detect single/multi function device from header - for( int function = 0; function < NOF_FUNCTIONS_PER_DEVICE; function++ ) { - pci_device_descriptor_t device_descriptor; - pci_device_descriptor_init( &device_descriptor, controller, bus, device, function ); - - // no device - if( device_descriptor.device_id == 0x0 || - device_descriptor.device_id == 0xFFFF ) { - continue; - } - - printf( "%X:%X.%d: %X:%X (interface: %X, class %X:%X, rev: %d)\n", - bus, device, function, - device_descriptor.vendor_id, - device_descriptor.device_id, - device_descriptor.interface_id, - device_descriptor.class_id, - device_descriptor.subclass_id, - device_descriptor.revision_id ); - - uint8_t header_type = pci_controller_read( controller, bus, device, function, PCI_HEADER_TYPE ) & 0x7F; - int max_nof_bars = NOF_BARS; - if( header_type & 0x01 ) { - max_nof_bars = 2; - } - - for( int bar_number = 0; bar_number < max_nof_bars; bar_number++ ) { - pci_base_address_register_t bar; - pci_base_address_register_init( &bar, controller, bus, device, function, bar_number ); - if( bar.type == BASE_ADDRESS_REGISTER_TYPE_IO && bar.addr ) { - device_descriptor.port_base = (uint32_t)bar.addr; - } - - driver_t *driver = pci_device_get_driver( &device_descriptor, interrupt ); - if( driver ) { - driver_manager_add_driver( driver_manager, driver ); - } - } - } - } - } -} - -void pci_device_descriptor_init( pci_device_descriptor_t *descriptor, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function ) -{ - memset( descriptor, 0, sizeof( pci_device_descriptor_t ) ); - - descriptor->vendor_id = pci_controller_read( controller, bus, device, function, PCI_VENDOR_ID ); - descriptor->device_id = pci_controller_read( controller, bus, device, function, PCI_DEVICE_ID ); - descriptor->class_id = pci_controller_read( controller, bus, device, function, PCI_CLASS ); - descriptor->subclass_id = pci_controller_read( controller, bus, device, function, PCI_SUBCLASS ); - descriptor->interface_id = pci_controller_read( controller, bus, device, function, PCI_INTERFACE ); - descriptor->revision_id = pci_controller_read( controller, bus, device, function, PCI_REVISION ); -} - -void pci_base_address_register_init( pci_base_address_register_t *base_address_register, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint16_t bar ) -{ - memset( base_address_register, 0, sizeof( pci_base_address_register_t ) ); - - uint32_t val = pci_controller_read( controller, bus, device, function, PCI_BAR_BASE + sizeof( uint32_t ) * bar ); - - // bit 0 indicates whether we are I/O or memory mapped - base_address_register->type = ( val & 0x01 ) ? BASE_ADDRESS_REGISTER_TYPE_IO : BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED; - - switch( base_address_register->type ) { - case BASE_ADDRESS_REGISTER_TYPE_IO: - base_address_register->addr = (uint8_t *)( val & 0xFFFC ); - base_address_register->prefetchable = false; - break; - - case BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED: - switch( val << 1 & 0x03 ) { - case 0x00: - // 32-bit mode - break; - - case 0x01: - // 20-bit mode - break; - - case 0x02: - // 64-bit mode - break; - } - break; - } -} - -driver_t *pci_device_get_driver( pci_device_descriptor_t *descriptor, interrupt_t *interrupt ) -{ - // find a specific device - switch( descriptor->vendor_id ) { - case 0x10ec: // Realtek Semiconductor - switch( descriptor->device_id ) { - case 0x8029: // RTL-8029 - break; - } - break; - - case 0x8086: // Intel - break; - - default: - break; - } - - // find a generic driver - switch( descriptor->class_id ) { - case 0x03: // graphics - switch( descriptor->subclass_id ) { - case 0x00: // VGA - break; - } - break; - - default: // no driver found - break; - } - return NULL; -} diff --git a/src/pci.h b/src/pci.h deleted file mode 100644 index ddbc990..0000000 --- a/src/pci.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef PCI_H -#define PCI_H - -#include - -#include "port.h" -#include "interrupts.h" -#include "driver.h" - -typedef struct { - uint16_t vendor_id; - uint16_t device_id; - uint8_t class_id; - uint8_t subclass_id; - uint8_t interface_id; - uint8_t revision_id; - uint32_t port_base; -} pci_device_descriptor_t; - -typedef struct { - port32_t command_port; - port32_t data_port; -} pci_controller_t; - -typedef enum { - BASE_ADDRESS_REGISTER_TYPE_IO, - BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED -} pci_base_address_register_type_t; - -typedef struct { - pci_base_address_register_type_t type; - bool prefetchable; - uint8_t *addr; - uint32_t *size; -} pci_base_address_register_t; - -void pci_controller_init( pci_controller_t *controller ); - -uint16_t pci_controller_read( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ); -void pci_controller_write( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset, uint32_t data ); -void pci_controller_scan_and_register( pci_controller_t *controller, driver_manager_t *driver_manager, interrupt_t *interrupt ); - -void pci_device_descriptor_init( pci_device_descriptor_t *descriptor, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function ); - -void pci_base_address_register_init( pci_base_address_register_t *base_address_register, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint16_t bar ); - -driver_t *pci_device_get_driver( pci_device_descriptor_t *descriptor, interrupt_t *interrupt ); - -#endif // PCI_H diff --git a/src/port.asm b/src/port.asm deleted file mode 100644 index 555a4e8..0000000 --- a/src/port.asm +++ /dev/null @@ -1,49 +0,0 @@ -[bits 32] - -global port8_write -global port8_read - -; void port8_write( port8_t *port, uint8_t data ); -port8_write: - push ebp - mov ebp, esp - mov ecx, [ebp+8] - mov edx, DWORD [ecx] - movzx ax, BYTE [ebp+12] - out dx, al - leave - ret - -; uint8_t port8_read( port8_t *port ) -port8_read: - push ebp - mov ebp, esp - mov ecx, DWORD [ebp+8] - mov edx, [ecx] - in al, dx - leave - ret - -global port32_write -global port32_read - -; void port32_write( port32_t *port, uint32_t data ); -port32_write: - push ebp - mov ebp, esp - mov ecx, [ebp+8] - mov edx, DWORD [ecx] - mov eax, DWORD [ebp+12] - out dx, eax - leave - ret - -; uint32_t port32_read( port32_t *port ) -port32_read: - push ebp - mov ebp, esp - mov ecx, DWORD [ebp+8] - mov edx, [ecx] - in eax, dx - leave - ret diff --git a/src/port.c b/src/port.c deleted file mode 100644 index 46e7f37..0000000 --- a/src/port.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "port.h" - -#include "string.h" - -void port8_init( port8_t *port, uint16_t number ) -{ - memset( port, 0, sizeof( port8_t ) ); - - port->number = number; -} - -void port32_init( port32_t *port, uint16_t number ) -{ - memset( port, 0, sizeof( port32_t ) ); - - port->number = number; -} diff --git a/src/port.h b/src/port.h deleted file mode 100644 index ec96d09..0000000 --- a/src/port.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PORT_H -#define PORT_H - -#include - -typedef struct { - uint16_t number; // port number, e.g. 0x3d4 VGA index register -} port8_t; - -void port8_init( port8_t *port, uint16_t number ); -void port8_write( port8_t *port, uint8_t data ); -uint8_t port8_read( port8_t *port ); - -typedef struct { - uint16_t number; // port number, e.g. 0x3d4 VGA index register -} port32_t; - -void port32_init( port32_t *port, uint16_t number ); -void port32_write( port32_t *port, uint32_t data ); -uint32_t port32_read( port32_t *port ); - -#endif // PORT_H - diff --git a/src/serial.c b/src/serial.c deleted file mode 100644 index c5a6d95..0000000 --- a/src/serial.c +++ /dev/null @@ -1,121 +0,0 @@ -#include "serial.h" -#include "string.h" -#include "stdlib.h" - -// COM1 - I/O ports -#define COM1_PORT_BASE 0x3F8 - -// RDR - Receive buffer register (on port read, if DLAB=0) -// THR - Transmitter holding register (on port write, if DLAB=0) -// DL - Divisor Latch (on port write, LSB, if DLAB=1) -#define COM1_TRANSMIT_PORT COM1_PORT_BASE - -// IER - Interrupt Enable Register (if DLAB=0) -// DL - Divisor Latch (on port write, MSB, if DLAB=1) -#define COM1_INTERRUPT_ENABLE_PORT COM1_PORT_BASE + 1 - -// IIR - Interrupt Identification Register (on read) -// FCR - FIFO Control Register (write only) -#define COM1_FIFO_CONTROL_PORT COM1_PORT_BASE + 2 - -// LCR - Line Control Register -#define COM1_LCR_PORT COM1_PORT_BASE + 3 - -// MCR - Modem Control Register -#define COM1_MCR_PORT COM1_PORT_BASE + 4 - -// LSR - Line Status Register -#define COM1_LSR_PORT COM1_PORT_BASE + 5 - -// IER - Interrupt Enable Register -#define IER_ENABLE_IRQ_DATA_READY 0x01 -#define IER_ENABLE_IRQ_WRITE_READY 0x02 -#define IER_ENABLE_IRQ_STATUS 0x04 -#define IER_ENABLE_IRQ_MODEM_STATUS 0x08 - -// LSR - Line Status Register -#define LSR_THRE 0x20 // Transmitter Holding Register Empty - -// LCR - Line Control Register -#define LCR_DATA_BITS_5 0x00 -#define LCR_DATA_BITS_6 0x01 -#define LCR_DATA_BITS_7 0x02 -#define LCR_DATA_BITS_8 0x03 -#define LCR_ONE_STOPBIT 0x00 -#define LCR_TWO_STOPBITS 0x04 -#define LCR_PARITY_ENABLE 0x08 -#define LCR_PARITY_EVEN 0x10 -#define LCR_PARITY_STICKY 0x20 -#define LCR_SET_BREAK 0x40 -#define LCR_DLAB_ENABLE 0x80 // DLAB=1/0, baud rate DL register selector - -// MCR - Modem Control Register -#define MCR_DTR_LOW 0x01 -#define MCR_DTR_RTS_LOW 0x02 -#define MCR_DTS_OUT2_LOW 0x04 -#define MCR_LOCAL_LOOPBACK 0x08 - -// baud rate helpers (division of 115200 by divisor results in baud rate) -#define BAUD_RATE_DIVISOR_115200 1 -#define BAUD_RATE_DIVISOR_57600 2 -#define BAUD_RATE_DIVISOR_38400 3 -#define BAUD_RATE_DIVISOR_19200 6 -#define BAUD_RATE_DIVISOR_14400 8 -#define BAUD_RATE_DIVISOR_9600 12 -#define BAUD_RATE_DIVISOR_4800 24 -#define BAUD_RATE_DIVISOR_2400 48 -#define BAUD_RATE_DIVISOR_1200 96 -#define BAUD_RATE_DIVISOR_300 384 - -void serial_init( serial_t *serial ) -{ - memset( serial, 0, sizeof( serial_t ) ); - - port8_init( &serial->port_transmit, COM1_TRANSMIT_PORT ); - port8_init( &serial->port_interrupt_enable, COM1_INTERRUPT_ENABLE_PORT ); - port8_init( &serial->port_fifo_control, COM1_FIFO_CONTROL_PORT ); - port8_init( &serial->port_line_control, COM1_LCR_PORT ); - port8_init( &serial->port_modem_control, COM1_MCR_PORT ); - port8_init( &serial->port_line_status, COM1_LSR_PORT ); - - // disable all interrupts - port8_write( &serial->port_interrupt_enable, 0x00 ); - - // set baud rate, enable DLAB so we can access the DL registers - port8_write( &serial->port_line_control, - LCR_DATA_BITS_8 | LCR_DLAB_ENABLE ); - port8_write( &serial->port_transmit, BAUD_RATE_DIVISOR_9600 ); - port8_write( &serial->port_interrupt_enable, 0 ); - port8_write( &serial->port_line_control, - LCR_DATA_BITS_8 ); - - // disable FIFO (16550+ only, TODO: probe?) - port8_write( &serial->port_fifo_control, 0x00 ); - - // No loopback - // TODO: more? - port8_write( &serial->port_modem_control, 0x00 ); -} - -void serial_put_char( serial_t *serial, const char c ) -{ - uint8_t status; - do { - status = port8_read( &serial->port_line_status ); - } while( ( status & LSR_THRE ) == 0 ); - - port8_write( &serial->port_transmit, c ); -} - -void serial_put_string( serial_t *serial, const char *s ) -{ - for( size_t i = 0; i < strlen( s ); i++ ) { - serial_put_char( serial, s[i] ); - } -} - -void serial_put_newline( serial_t *serial ) -{ - serial_put_char( serial, '\r' ); - serial_put_char( serial, '\n' ); -} diff --git a/src/serial.h b/src/serial.h deleted file mode 100644 index b30fe55..0000000 --- a/src/serial.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SERIAL_H -#define SERIAL_H - -#include "port.h" - -typedef struct { - port8_t port_transmit; - port8_t port_interrupt_enable; - port8_t port_fifo_control; - port8_t port_line_control; - port8_t port_modem_control; - port8_t port_line_status; -} serial_t; - -void serial_init( serial_t *serial ); -void serial_put_char( serial_t *serial, const char c ); -void serial_put_string( serial_t *serial, const char *s ); -void serial_put_newline( serial_t *serial ); - -#endif // SERIAL_H diff --git a/src/setjmp.asm b/src/setjmp.asm deleted file mode 100644 index a20a0af..0000000 --- a/src/setjmp.asm +++ /dev/null @@ -1,44 +0,0 @@ -[bits 32] - -global setjmp -global longjmp - -;typedef struct { -; uint32_t ebx; -; uint32_t esp; -; uint32_t ebp; -; uint32_t esi; -; uint32_t edi; -; uint32_t eip; -;} jmp_buf[1]; - -; int setjmp(jmp_buf env) -setjmp: - mov eax, [esp+4] ; the adress of the jump buffer - mov [eax], ebx ; safe registers - mov [eax+4], esp - mov [eax+8], ebp - mov [eax+12], esi - mov [eax+16], edi - mov edx, [esp] ; get return address from the stack (pushed here by call) - mov [eax+20], edx - mov eax, 0 ; indicate that we come from setjmp, not from a longjmp - ret - -; void longjmp(jmp_buf env, int value); -longjmp: - mov eax, [esp+4] ; the address of the jump buffer - mov ecx, [esp+8] ; the return value for setjmp - mov ebx, [eax] ; restore registers - mov esp, [eax+4] - mov ebp, [eax+8] - mov esi, [eax+12] - mov edi, [eax+16] - mov edx, [eax+20] ; get jump address and store it on the stack for 'ret' - mov [esp], edx - mov eax, ecx ; get return value - cmp eax, 0 - jnz .return ; non zero, ok, return it - mov eax, 1 ; setjmp called with 0, not good, return 1 -.return: - ret diff --git a/src/setjmp.h b/src/setjmp.h deleted file mode 100644 index 5f987f1..0000000 --- a/src/setjmp.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SETJMP_H -#define SETJMP_H - -#include - -// C99 states this should be an array so we can address it without -// the & operator, see prototypes of setjmp and longjmp -// eax, ecx and edx are scratch registers, save the others -// also store the jump address (eip) -typedef struct { - uint32_t ebx; - uint32_t esp; - uint32_t ebp; - uint32_t esi; - uint32_t edi; - uint32_t eip; -} jmp_buf[1]; - -int setjmp( jmp_buf env ); - -void longjmp( jmp_buf env, int val ); - -#endif // SETJMP_H - diff --git a/src/stddef.h b/src/stddef.h deleted file mode 100644 index 57a0297..0000000 --- a/src/stddef.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef STDDEF_H -#define STDDEF_H - -#define NULL ( (void *)0 ) - -#define size_t uint32_t - -#endif /* STDDEF_H */ diff --git a/src/stdio.c b/src/stdio.c deleted file mode 100644 index 1d53f7a..0000000 --- a/src/stdio.c +++ /dev/null @@ -1,106 +0,0 @@ -#include "stdio.h" -#include "stddef.h" -#include "stdlib.h" -#include "string.h" - -console_t *global_console = NULL; - -int puts( const char *s ) -{ - if( global_console == NULL ) { - return EOF; - } - - console_put_string( global_console, s ); - console_put_newline( global_console ); - - return 1; -} - -int printf( const char *format, ... ) -{ - va_list args; - - va_start( args, format ); - int res = vprintf( format, args ); - va_end( args ); - - return res; -} - -int vprintf( const char *format, va_list args ) -{ - const char *s = format; - int n = 0; - - if( global_console == NULL ) { - return -1; - } - - while( *s != '\0' ) { - switch( *s ) { - case '\n': - console_put_newline( global_console ); - n++; - break; - - case '%': - s++; - if( *s == '\0' ) { - console_put_string( global_console, "" ); - console_put_newline( global_console ); - return -1; - } - - switch( *s ) { - case '%': - console_put_char( global_console, '%' ); - break; - - case 'X': { - char buf[19]; - itoa( va_arg( args, int ), (char *)buf, 16 ); - console_put_string( global_console, buf ); - n += strlen( buf ); - } - break; - - case 'd': { - char buf[19]; - itoa( va_arg( args, int ), (char *)buf, 10 ); - console_put_string( global_console, buf ); - n += strlen( buf ); - } - break; - - case 'c': - console_put_char( global_console, va_arg( args, int ) ); - break; - - case 's': - console_put_string( global_console, va_arg( args, const char * ) ); - break; - - default: - console_put_string( global_console, "" ); - console_put_newline( global_console ); - } - - break; - - default: - console_put_char( global_console, *s ); - n++; - } - s++; - } - - return n; -} - -void stdio_set_console( console_t *console ) -{ - global_console = console; -} diff --git a/src/stdio.h b/src/stdio.h deleted file mode 100644 index bc7fac0..0000000 --- a/src/stdio.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef STDIO_H -#define STDIO_H - -#include - -#include "stddef.h" - -#include "console.h" - -#define EOF (-1) - -extern console_t *global_console; - -int puts( const char *s ); -int printf( const char *format, ... ); -int vprintf( const char *format, va_list args ); - -void stdio_set_console( console_t *console ); - -#endif //STDIO_H diff --git a/src/stdlib.c b/src/stdlib.c deleted file mode 100644 index 46bdce8..0000000 --- a/src/stdlib.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include "string.h" -#include "stdlib.h" -#include "stddef.h" - -static void strreverse( char *s ) -{ - char *end = s + strlen( s ) - 1; - - while( s < end ) { - // XOR swap; - *s ^= *end; - *end ^= *s; - *s ^= *end; - s++; - end--; - } -} - -char *itoa( int v, char *s, int base ) -{ - static char digit[] = "0123456789ABCDEF"; - bool sign = false; - char *p = s; - - if( base < 2 || base > 16 ) { - return NULL; - } - - if( v < 0 ) { - v = -v; - sign = true; - } - - do { - *p++ = digit[v % base]; - } while( ( v /= base ) > 0 ); - - if( sign ) { - *p++ = '-'; - } - *p = '\0'; - - strreverse( s ); - - return s; -} - diff --git a/src/stdlib.h b/src/stdlib.h deleted file mode 100644 index 331012e..0000000 --- a/src/stdlib.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef STDLIB_H -#define STDLIB_H - -char *itoa( int v, char *s, int base ); - -#endif // STDLIB_H diff --git a/src/string.c b/src/string.c deleted file mode 100644 index 8d4f876..0000000 --- a/src/string.c +++ /dev/null @@ -1,75 +0,0 @@ -#include "string.h" - -void *memset( void *s, int c, size_t n ) -{ - for( size_t i = 0; i < n; i++ ) { - ((char *)s)[i] = c; - } - - return s; -} - -void *memmove( void *d, const void *s, size_t n ) -{ - const char *ss = (const char *)s; - char *dd = (char *)d; - - if( dd == ss ) return d; - - if( dd <= ss ) { - while( n > 0 ) { - *dd++ = *ss++; - n--; - } - } else { - dd += n; - ss += n; - while( n > 0 ) { - *--dd = *--ss; - n--; - } - } - - return d; -} - -size_t strlen( const char *s ) -{ - size_t len; - const char *p = s; - - for( len = 0; *p; len++, p++ ); - - return len; -} - -int strcmp( const char *s1, const char *s2 ) -{ - while( *s1 && *s2 && *s1 == *s2 ) { - s1++; - s2++; - } - - return *s1 - *s2; -} - -size_t strlcpy( char *d, const char *s, size_t n ) -{ - size_t len = 0; - - while( len < n && s[len] != '\0' ) { - d[len] = s[len]; - len++; - } - d[len] = '\0'; - - while( s[len] != '\0' ) { - len++; - } - - if( len >= n ) { - d[n-1] = '\0'; - } - - return len; -} diff --git a/src/string.h b/src/string.h deleted file mode 100644 index e24df9b..0000000 --- a/src/string.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef STRING_H -#define STRING_H - -#include "sys/types.h" - -void *memset( void *s, int c, size_t n ); -void *memmove( void *d, const void *s, size_t n ); -size_t strlen( const char *s ); -int strcmp( const char *s1, const char *s2 ); -size_t strlcpy( char *d, const char *s, size_t n ); - -#endif // STRING_H diff --git a/src/sys/types.h b/src/sys/types.h deleted file mode 100644 index 1ec9642..0000000 --- a/src/sys/types.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef SYS_TYPES_H -#define SYS_TYPES_H - -#include - -typedef uint32_t size_t; - -#endif /* SYS_TYPES_H */ diff --git a/src/vgatext.c b/src/vgatext.c deleted file mode 100644 index cbee587..0000000 --- a/src/vgatext.c +++ /dev/null @@ -1,262 +0,0 @@ -#include "vgatext.h" - -#include - -#include "string.h" -#include "stdlib.h" -#include "kernel.h" - -static bool params_ok( vga_text_t *vga_text, const int x, const int y ); -static int calculate_offset( vga_text_t *vga_text, const int x, const int y ); -static uint8_t calculate_color_cell( vga_text_t *vga_text ); -static void scroll_screen( vga_text_t *vga_text ); - -void vga_text_init( vga_text_t *vga_text ) -{ - memset( vga_text, 0, sizeof( vga_text_t ) ); - - vga_text->res_x = VGA_TEXT_DEFAULT_RES_X; - vga_text->res_y = VGA_TEXT_DEFAULT_RES_Y; - vga_text->color = VGA_TEXT_COLOR_DARK_GREY; - vga_text->background_color = VGA_TEXT_COLOR_BLACK; - vga_text->show_mouse_cursor = false; - vga_text->mouse_cursor_x = -1; - vga_text->mouse_cursor_y = -1; - - // make sure we use the 0x3dx VGA_TEXT ports, is done - // in assembly in stage 2 too - port8_init( &vga_text->crtc_misc_port, 0x3d2 ); - port8_write( &vga_text->crtc_misc_port, 1 ); - - // set up VGA_TEXT ports - port8_init( &vga_text->crtc_index_port, 0x3d4 ); - port8_init( &vga_text->crtc_data_port, 0x3d5 ); - - vga_text_set_cursor_from_hardware( vga_text ); -}; - -void vga_text_clear_screen( vga_text_t *vga_text ) -{ - volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; - - for( int i = 0; i < 2 * ( vga_text->res_x * vga_text->res_y ); i += 2 ) { - *(VIDEO_MEMORY+i) = ' '; - *(VIDEO_MEMORY+i+1) = calculate_color_cell( vga_text ); - } - - vga_text_set_cursor( vga_text, 0, 0 ); -} - -void vga_text_set_cursor( vga_text_t *vga_text, const int x, const int y ) -{ - if( !params_ok( vga_text, x, y ) ) { - kernel_panic( "Cursor parameters out of bounds: (%d, %d), resolution is only (%d, %d)", - x, y, vga_text->res_x, vga_text->res_y ); - } - - vga_text->cursor_x = x; - vga_text->cursor_y = y; - - // TODO: have a silent mode where we don't update the cursor - vga_text_set_cursor_on_hardware( vga_text ); -} - -void vga_text_set_cursor_from_hardware( vga_text_t *vga_text ) -{ - uint16_t hw_cursor_pos; - - port8_write( &vga_text->crtc_index_port, 14 ); - uint8_t data = port8_read( &(vga_text->crtc_data_port ) ); - hw_cursor_pos = data << 8; - - port8_write( &vga_text->crtc_index_port, 15 ); - data = port8_read( &(vga_text->crtc_data_port ) ); - - hw_cursor_pos |= data; - - vga_text->cursor_x = hw_cursor_pos % vga_text->res_x; - vga_text->cursor_y = hw_cursor_pos / vga_text->res_x; - - // reset to sane values if we get funny values from the VGA_TEXT card - if( vga_text->cursor_x < 0 || vga_text->cursor_x > vga_text->res_x || - vga_text->cursor_y < 0 || vga_text->cursor_y > vga_text->res_y ) { - vga_text->cursor_x = 0; - vga_text->cursor_y = 0; - } -} - -void vga_text_set_cursor_on_hardware( vga_text_t *vga_text ) -{ - uint16_t hw_cursor_pos = vga_text->cursor_x + vga_text->cursor_y * vga_text->res_x; - - port8_write( &vga_text->crtc_index_port, 15 ); - port8_write( &vga_text->crtc_data_port, hw_cursor_pos & 0xff ); - port8_write( &vga_text->crtc_index_port, 14 ); - port8_write( &vga_text->crtc_data_port, hw_cursor_pos >> 8 ); -} - -int vga_text_get_cursor_x( vga_text_t *vga_text ) -{ - return vga_text->cursor_x; -} - -int vga_text_get_cursor_y( vga_text_t *vga_text ) -{ - return vga_text->cursor_y; -} - -void vga_text_set_color( vga_text_t *vga_text, const vga_text_color_t color ) -{ - vga_text->color = color; -} - -void vga_text_set_background_color( vga_text_t *vga_text, const vga_text_color_t color ) -{ - vga_text->background_color = color; -} - -static int calculate_offset( vga_text_t *vga_text, const int x, const int y ) -{ - int offset = ( vga_text->res_x * y + x ) * 2; - - return offset; -} - -static void scroll_screen( vga_text_t *vga_text ) -{ - volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; - - memmove( (void *)VIDEO_MEMORY, (const void *)VIDEO_MEMORY + 2 * vga_text->res_x, 2 * ( vga_text->res_y - 1 ) * vga_text->res_x ); - - for( int i = 2 * ( vga_text->res_x * ( vga_text->res_y - 1 ) ); i < 2 * ( vga_text->res_x * vga_text->res_y ); i += 2 ) { - *(VIDEO_MEMORY+i) = ' '; - *(VIDEO_MEMORY+i+1) = calculate_color_cell( vga_text ); - } - - vga_text->cursor_y = vga_text->res_y - 1; -} - -static uint8_t calculate_color_cell( vga_text_t *vga_text ) -{ - uint8_t cell; - - cell = ( vga_text->background_color << 4 ) | vga_text->color; - - return cell; -} - -static bool params_ok( vga_text_t *vga_text, const int x, const int y ) -{ - if( x > vga_text->res_x || y > vga_text->res_y ) return false; - - return true; -} - -void vga_text_put_char_at( vga_text_t *vga_text, const int x, const int y, const char c ) -{ - vga_text_set_cursor( vga_text, x, y ); - vga_text_put_char( vga_text, c ); -} - - -void vga_text_put_string_at( vga_text_t *vga_text, const int x, const int y, const char *s ) -{ - vga_text_set_cursor( vga_text, x, y ); - vga_text_put_string( vga_text, s ); -} - -void vga_text_put_char( vga_text_t *vga_text, const char c ) -{ - int offset = calculate_offset( vga_text, vga_text->cursor_x, vga_text->cursor_y ); - - volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; - *(VIDEO_MEMORY+offset) = (uint8_t)c; - *(VIDEO_MEMORY+offset+1) = calculate_color_cell( vga_text ); - - vga_text->cursor_x++; - if( vga_text->cursor_x >= vga_text->res_x ) { - vga_text->cursor_x = 0; - vga_text->cursor_y++; - if( vga_text->cursor_y >= vga_text->res_y ) { - scroll_screen( vga_text ); - } - } - - vga_text_set_cursor_on_hardware( vga_text ); -} - -void vga_text_put_string( vga_text_t *vga_text, const char *s ) -{ - for( size_t i = 0; i < strlen( s ); i++ ) { - vga_text_put_char( vga_text, s[i] ); - } -} - -void vga_text_put_newline( vga_text_t *vga_text ) -{ - vga_text->cursor_x = 0; - vga_text->cursor_y++; - if( vga_text->cursor_y >= vga_text->res_y ) { - scroll_screen( vga_text ); - } - - vga_text_set_cursor_on_hardware( vga_text ); -} - -void vga_text_set_background_color_at( vga_text_t *vga_text, const int x, const int y, vga_text_color_t color ) -{ - int offset = calculate_offset( vga_text, x, y ); - - volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; - *(VIDEO_MEMORY+offset+1) = ( *(VIDEO_MEMORY+offset+1) & 0x0f ) | ( color << 4 ); -} - -vga_text_color_t vga_text_get_background_color_at( vga_text_t *vga_text, const int x, const int y ) -{ - int offset = calculate_offset( vga_text, x, y ); - - volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; - uint8_t cell = *(VIDEO_MEMORY+offset+1); - - return cell & 0xf0; -} - -void vga_text_inverse_colors_at( vga_text_t *vga_text, const int x, const int y ) -{ - int offset = calculate_offset( vga_text, x, y ); - - volatile uint8_t *VIDEO_MEMORY = (uint8_t *)0xb8000; - *(VIDEO_MEMORY+offset+1) = ( ( *(VIDEO_MEMORY+offset+1) & 0x0f ) << 4 ) - | ( ( *(VIDEO_MEMORY+offset+1) & 0xf0 ) >> 4 ); -} - -void vga_text_show_mouse_cursor( vga_text_t *vga_text ) -{ - if( !vga_text->show_mouse_cursor ) { - vga_text->show_mouse_cursor = true; - vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); - } -} - -void vga_text_move_mouse_cursor( vga_text_t *vga_text, const int x, const int y ) -{ - if( vga_text->show_mouse_cursor ) { - vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); - } - - vga_text->mouse_cursor_x = x; - vga_text->mouse_cursor_y = y; - - if( vga_text->show_mouse_cursor ) { - vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); - } -} - -void vga_text_hide_mouse_cursor( vga_text_t *vga_text ) -{ - if( vga_text->show_mouse_cursor ) { - vga_text_inverse_colors_at( vga_text, vga_text->mouse_cursor_x, vga_text->mouse_cursor_y ); - vga_text->show_mouse_cursor = false; - } -} - diff --git a/src/vgatext.h b/src/vgatext.h deleted file mode 100644 index 499e3d8..0000000 --- a/src/vgatext.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef VGA_TEXT_H -#define VGA_TEXT_H - -#include - -#include "port.h" - -enum { - VGA_TEXT_DEFAULT_RES_X = 80, - VGA_TEXT_DEFAULT_RES_Y = 25 -}; - -typedef enum { - VGA_TEXT_COLOR_BLACK = 0, - VGA_TEXT_COLOR_BLUE = 1, - VGA_TEXT_COLOR_GREEN = 2, - VGA_TEXT_COLOR_CYAN = 3, - VGA_TEXT_COLOR_RED = 4, - VGA_TEXT_COLOR_MAGENTA = 5, - VGA_TEXT_COLOR_BROWN = 6, - VGA_TEXT_COLOR_LIGHT_GREY = 7, - VGA_TEXT_COLOR_DARK_GREY = 8, - VGA_TEXT_COLOR_LIGHT_BLUE = 9, - VGA_TEXT_COLOR_LIGHT_GREEN = 10, - VGA_TEXT_COLOR_LIGHT_CYAN = 11, - VGA_TEXT_COLOR_LIGHT_RED = 12, - VGA_TEXT_COLOR_LIGHT_MAGENTA = 13, - VGA_TEXT_COLOR_LIGHT_BROWN = 14, - VGA_TEXT_COLOR_WHITE = 15 -} vga_text_color_t; - -typedef struct { - int res_x; // resolution, default 80 - int res_y; // resolution, default 25 - int cursor_x; // current cursor position X - int cursor_y; // current cursor position Y - vga_text_color_t color; - vga_text_color_t background_color; - port8_t crtc_misc_port; - port8_t crtc_index_port; - port8_t crtc_data_port; - bool show_mouse_cursor; - int mouse_cursor_x; - int mouse_cursor_y; -} vga_text_t; - -void vga_text_init( vga_text_t *vga_text ); -void vga_text_clear_screen( vga_text_t *vga_text ); -void vga_text_set_cursor( vga_text_t *vga_text, const int x, const int y ); -void vga_text_set_cursor_from_hardware( vga_text_t *vga_text ); -void vga_text_set_cursor_on_hardware( vga_text_t *vga_text ); -int vga_text_get_cursor_x( vga_text_t *vga_text ); -int vga_text_get_cursor_y( vga_text_t *vga_text ); -void vga_text_set_color( vga_text_t *vga_text, const vga_text_color_t color ); -void vga_text_set_background_color( vga_text_t *vga_text, const vga_text_color_t color ); -void vga_text_put_char_at( vga_text_t *vga_text, const int x, const int y, const char c ); -void vga_text_put_string_at( vga_text_t *vga_text, const int x, const int y, const char *s ); -void vga_text_put_char( vga_text_t *vga_text, const char c ); -void vga_text_put_string( vga_text_t *vga_text, const char *s ); -void vga_text_put_newline( vga_text_t *vga_text ); -void vga_text_set_background_color_at( vga_text_t *vga_text, const int x, const int y, vga_text_color_t color ); -vga_text_color_t vga_text_get_background_color_at( vga_text_t *vga_text, const int x, const int y ); -void vga_text_inverse_colors_at( vga_text_t *vga_text, const int x, const int y ); -void vga_text_show_mouse_cursor( vga_text_t *vga_text ); -void vga_text_move_mouse_cursor( vga_text_t *vga_text, const int x, const int y ); -void vga_text_hide_mouse_cursor( vga_text_t *vga_text ); - -#endif /* VGA_TEXT_H */ -- cgit v1.2.3-54-g00ecf