From ec52f2d0b7de0621976670801044589dbb2681b3 Mon Sep 17 00:00:00 2001 From: Jon Feldman Date: Mon, 20 Feb 2017 21:04:50 -0500 Subject: [PATCH] More-ish refactoring --- Makefile | 2 +- common/kernel_main.c | 4 +- i686/idt.c | 146 +++++++++++++++------------------------- i686/include/idt.h | 31 +++++++++ i686/timer.c | 17 +++++ i686/utils.c | 3 +- module/biosvga/module.c | 4 +- module/console.c | 23 +++++-- 8 files changed, 126 insertions(+), 104 deletions(-) create mode 100644 i686/include/idt.h diff --git a/Makefile b/Makefile index daedf78..246db95 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # The only one that needs changing is the assembler # rule, as we use nasm instead of GNU as. -CONF=-DCONF_EARLY_KPRINTF=1 +CONF=-DCONF_TIMER_FREQ=1000 TGT=i686 diff --git a/common/kernel_main.c b/common/kernel_main.c index b64842e..f8214ec 100644 --- a/common/kernel_main.c +++ b/common/kernel_main.c @@ -10,13 +10,13 @@ int kernel_main(struct multiboot *mboot_ptr) printf("1%c%% %s %X\n", 'c', "whoop", 0xDEADBEEF); - console_deinit(); - while(1) { uint64_t ticks = clock(); printf("%X%X\r", ((uint32_t*)&ticks)[1], ((uint32_t*)&ticks)[0]); asm("hlt"); } + console_deinit(); + return 0xDEADBEEF; } diff --git a/i686/idt.c b/i686/idt.c index e61f569..0ab044b 100644 --- a/i686/idt.c +++ b/i686/idt.c @@ -1,93 +1,15 @@ #include #include -#include - -// A struct describing an interrupt gate. -struct idt_entry_struct -{ - uint16_t base_lo; // The lower 16 bits of the address to jump to when this interrupt fires. - uint16_t sel; // Kernel segment selector. - uint8_t always0; // This must always be zero. - uint8_t flags; // More flags. See documentation. - uint16_t base_hi; // The upper 16 bits of the address to jump to. -} __attribute__((packed)); -typedef struct idt_entry_struct idt_entry_t; - -// A struct describing a pointer to an array of interrupt handlers. -// This is in a format suitable for giving to 'lidt'. -struct idt_ptr_struct -{ - uint16_t limit; - uint32_t base; // The address of the first element in our idt_entry_t array. -} __attribute__((packed)); -typedef struct idt_ptr_struct idt_ptr_t; - -idt_entry_t idt_entries[256]; -idt_ptr_t idt_ptr; - -void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) -{ - idt_entries[num].base_lo = base & 0xFFFF; - idt_entries[num].base_hi = (base >> 16) & 0xFFFF; +#include - idt_entries[num].sel = sel; - idt_entries[num].always0 = 0; - // We must uncomment the OR below when we get to using user-mode. - // It sets the interrupt gate's privilege level to 3. - idt_entries[num].flags = flags /* | 0x60 */; -} - -struct interrupt_frame -{ - uint32_t ds; // Data segment selector - uint32_t edi, esi, ebp, reserve, ebx, edx, ecx, eax; // Pushed by pusha. - uint32_t int_no, err_code; // Interrupt number and error code (if applicable) - uint32_t eip, cs, eflags, esp, ss; // Pushed by the processor automatically. -}; - -void isr_handler(struct interrupt_frame* esp) { -} - -int ticks_lock = 0; -uint64_t ticks = 0; - -uint64_t clock() { - return ticks; -} - -char table[255] = { - 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', - '-', '=', '\b', '\t', '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, '+', ' ', -}; - -uint32_t timer_lock; - -void irq_handler(struct interrupt_frame* esp) { - char c_kb = 0; - - if (esp->int_no >= 7) { - outb(0xA0, 0x20); - } +#include - outb(0x20, 0x20); +#define ISR_CALL(N) \ + idt_set_gate( N , (uint32_t) isr_##N , 0x08, 0x8E ) - switch(esp->int_no) { - case 0: - ++ticks; - break; - case 1: - c_kb = inb(0x60); - putc(table[c_kb]); - break; - default: - break; - } -} +#define IRQ_CALL(N) \ + idt_set_gate( 32 + N , (uint32_t) irq_##N , 0x08, 0x8E ) extern void isr_0(); extern void isr_1(); @@ -139,19 +61,45 @@ extern void irq_13(); extern void irq_14(); extern void irq_15(); -#define ISR_CALL(N) \ - idt_set_gate( N , (uint32_t) isr_##N , 0x08, 0x8E ) +idt_entry_t idt_entries[256]; +idt_ptr_t idt_ptr; +int_handle interrupts[256]; -#define IRQ_CALL(N) \ - idt_set_gate( 32 + N , (uint32_t) irq_##N , 0x08, 0x8E ) +void register_int_handler(int index, int_handle hdl) { + interrupts[index] = hdl; +} -void init_idt() +void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { - idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1; - idt_ptr.base = (uint32_t)&idt_entries; + idt_entries[num].base_lo = base & 0xFFFF; + idt_entries[num].base_hi = (base >> 16) & 0xFFFF; - memset(&idt_entries, 0, sizeof(idt_entry_t)*256); + idt_entries[num].sel = sel; + idt_entries[num].always0 = 0; + // We must uncomment the OR below when we get to using user-mode. + // It sets the interrupt gate's privilege level to 3. + idt_entries[num].flags = flags | 0x60; +} +void isr_handler(struct interrupt_frame* esp) { + if (interrupts[esp->int_no]) + (interrupts[esp->int_no])(esp); +} + +void irq_handler(struct interrupt_frame* esp) { + char c_kb = 0; + + if (esp->int_no >= 7) { + outb(0xA0, 0x20); + } + + outb(0x20, 0x20); + + if (interrupts[esp->int_no + 32]) + interrupts[esp->int_no + 32](esp); +} + +void init_isr() { ISR_CALL(0); ISR_CALL(1); ISR_CALL(2); @@ -184,7 +132,10 @@ void init_idt() ISR_CALL(29); ISR_CALL(30); ISR_CALL(31); +} +void init_irq() +{ outb(0x20, 0x11); outb(0xA0, 0x11); @@ -216,6 +167,17 @@ void init_idt() IRQ_CALL(13); IRQ_CALL(14); IRQ_CALL(15); +} + +void init_idt() +{ + idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1; + idt_ptr.base = (uint32_t)&idt_entries; + + memset(&idt_entries, 0, sizeof(idt_entry_t)*256); + + init_isr(); + init_irq(); idt_flush((uint32_t)&idt_ptr); diff --git a/i686/include/idt.h b/i686/include/idt.h new file mode 100644 index 0000000..1d1da16 --- /dev/null +++ b/i686/include/idt.h @@ -0,0 +1,31 @@ +// A struct describing an interrupt gate. +struct idt_entry_struct +{ + uint16_t base_lo; // The lower 16 bits of the address to jump to when this interrupt fires. + uint16_t sel; // Kernel segment selector. + uint8_t always0; // This must always be zero. + uint8_t flags; // More flags. See documentation. + uint16_t base_hi; // The upper 16 bits of the address to jump to. +} __attribute__((packed)); +typedef struct idt_entry_struct idt_entry_t; + +// A struct describing a pointer to an array of interrupt handlers. +// This is in a format suitable for giving to 'lidt'. +struct idt_ptr_struct +{ + uint16_t limit; + uint32_t base; // The address of the first element in our idt_entry_t array. +} __attribute__((packed)); +typedef struct idt_ptr_struct idt_ptr_t; + +struct interrupt_frame +{ + uint32_t ds; // Data segment selector + uint32_t edi, esi, ebp, reserve, ebx, edx, ecx, eax; // Pushed by pusha. + uint32_t int_no, err_code; // Interrupt number and error code (if applicable) + uint32_t eip, cs, eflags, esp, ss; // Pushed by the processor automatically. +}; + +typedef void (*int_handle)(struct interrupt_frame*); + +void register_int_handler(int, int_handle); diff --git a/i686/timer.c b/i686/timer.c index 8532e28..2755c04 100644 --- a/i686/timer.c +++ b/i686/timer.c @@ -1,6 +1,8 @@ #include #include +#include + #include int set_pitdiv(int freq) { @@ -15,3 +17,18 @@ int set_pitdiv(int freq) { outb(0x40, l); outb(0x40, h); } + +uint64_t ticks = 0; + +uint64_t clock() { + return ticks; +} + +void clock_inc(struct interrupt_frame* frame) { + ++ticks; +} + +void i686_pic_init() { + register_int_handler(32, clock_inc); + set_pitdiv(CONF_TIMER_FREQ); +} diff --git a/i686/utils.c b/i686/utils.c index b2c833c..38ce5c3 100644 --- a/i686/utils.c +++ b/i686/utils.c @@ -52,5 +52,6 @@ int set_pitdiv(int freq); void i686_init() { init_gdt(); init_idt(); - set_pitdiv(1000); + + i686_pic_init(); } diff --git a/module/biosvga/module.c b/module/biosvga/module.c index 4f29b00..a9f4866 100644 --- a/module/biosvga/module.c +++ b/module/biosvga/module.c @@ -62,10 +62,10 @@ struct output biosvga_module = { void biosvga_init() { x = y = 0; - console_reg(&biosvga_module); + console_reg_write(&biosvga_module); } void biosvga_deinit() { - console_unreg(&biosvga_module); + console_unreg_write(&biosvga_module); // Stub. } diff --git a/module/console.c b/module/console.c index 22bfe6b..9faf2c4 100644 --- a/module/console.c +++ b/module/console.c @@ -7,18 +7,29 @@ actually printing to; in the future, adding a new backend for framebuffer render #include #include -struct output *active; +struct output *out_active; +struct input *in_active; void put_handler(char c) { - active->out(c); + out_active->out(c); } -void console_reg(struct output* out) { - active = out; +void console_reg_write(struct output* out) { + out_active = out; } -void console_unreg(struct output* out) { - active = out; +void console_unreg_write(struct output* out) { + if (out_active == out) + out_active = NULL; +} + +void console_reg_read(struct input* out) { + in_active = out; +} + +void console_unreg_read(struct input* out) { + if (in_active == out) + in_active = NULL; } void console_init() { -- 2.39.5