From da2a70455db08beee59a388cd91c34f4144afe46 Mon Sep 17 00:00:00 2001 From: Jon Feldman Date: Mon, 20 Feb 2017 19:42:58 -0500 Subject: [PATCH] Good chunk of refactoring --- Makefile | 9 +- common/kernel_main.c | 8 +- common/stdc/dumphex.c | 17 ++ common/stdc/memcmp.c | 18 +-- common/stdc/memcpy.c | 10 +- common/stdc/memmove.c | 22 +-- common/stdc/memset.c | 8 +- common/stdc/printf.c | 14 ++ common/stdc/putc.c | 5 + common/stdc/puts.c | 9 ++ common/stdc/strcatlen.c | 11 ++ common/stdc/strlen.c | 8 +- common/stdc/vsprintf.c | 47 ++++++ i686/gdt.c | 60 ++++++++ i686/idt.c | 223 +++++++++++++++++++++++++++ i686/timer.c | 17 ++ i686/utils.c | 324 +-------------------------------------- include/module_console.h | 28 +--- include/stdc/stdio.h | 22 +++ include/stdc/string.h | 11 +- module/biosvga/module.c | 77 ++++++---- module/console.c | 199 +----------------------- module/serial/module.c | 19 +-- 23 files changed, 538 insertions(+), 628 deletions(-) create mode 100644 common/stdc/dumphex.c create mode 100644 common/stdc/printf.c create mode 100644 common/stdc/putc.c create mode 100644 common/stdc/puts.c create mode 100644 common/stdc/strcatlen.c create mode 100644 common/stdc/vsprintf.c create mode 100644 i686/gdt.c create mode 100644 i686/idt.c create mode 100644 i686/timer.c create mode 100644 include/stdc/stdio.h diff --git a/Makefile b/Makefile index c78b257..daedf78 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,10 @@ CONF=-DCONF_EARLY_KPRINTF=1 TGT=i686 SOURCES= \ - $(TGT)/entry.o \ - $(TGT)/utils.o \ - module/biosvga/module.o module/serial/module.o module/console.o \ + $(TGT)/entry.o $(TGT)/utils.o $(TGT)/gdt.o $(TGT)/idt.o $(TGT)/timer.o \ + module/biosvga/module.o \ + module/console.o \ + common/stdc/putc.o common/stdc/puts.o common/stdc/vsprintf.o common/stdc/printf.o common/stdc/strcatlen.o common/stdc/dumphex.o \ common/stdc/memmove.o common/stdc/strlen.o common/stdc/memcmp.o common/stdc/memset.o common/stdc/memcpy.o \ common/kernel_main.o @@ -26,7 +27,7 @@ NM=$(TGTNAM)-nm RL=$(TGTNAM)-ranlib CFLAGS=-ffreestanding -std=gnu11 -CPPFLAGS=-Iinclude -I$(TGT)/include +CPPFLAGS=-Iinclude -Iinclude/stdc -I$(TGT)/include LDFLAGS=-T$(LDSC) ASFLAGS= LIBS= diff --git a/common/kernel_main.c b/common/kernel_main.c index e46e46b..b64842e 100644 --- a/common/kernel_main.c +++ b/common/kernel_main.c @@ -2,17 +2,19 @@ #include #include +#include + int kernel_main(struct multiboot *mboot_ptr) { console_init(); - kprintf("1%c%% %s %X\n", 'c', "whoop", 0xDEADBEEF); + printf("1%c%% %s %X\n", 'c', "whoop", 0xDEADBEEF); console_deinit(); while(1) { - uint64_t clock = kclock(); - kprintf("%X%X\r", ((uint32_t*)&clock)[1], ((uint32_t*)&clock)[0]); + uint64_t ticks = clock(); + printf("%X%X\r", ((uint32_t*)&ticks)[1], ((uint32_t*)&ticks)[0]); asm("hlt"); } diff --git a/common/stdc/dumphex.c b/common/stdc/dumphex.c new file mode 100644 index 0000000..8866733 --- /dev/null +++ b/common/stdc/dumphex.c @@ -0,0 +1,17 @@ +#include +#include + +int dumphex(char* buf, const char* index, unsigned int num) { + uint8_t *num_8 = (uint8_t *)# + char *obuf = buf; + for (int i = 3; i >= 0; i--) { + uint8_t high = (num_8[i] >> 4) & 0xf; + uint8_t low = num_8[i] & 0xf; + + *buf = (index)[high]; buf++; + *buf = (index)[low]; buf++; + } + + return buf - obuf; +} + diff --git a/common/stdc/memcmp.c b/common/stdc/memcmp.c index 576a242..6a0a71a 100644 --- a/common/stdc/memcmp.c +++ b/common/stdc/memcmp.c @@ -1,13 +1,13 @@ #include int memcmp(const void* aptr, const void* bptr, size_t size) { - const unsigned char* a = (const unsigned char*) aptr; - const unsigned char* b = (const unsigned char*) bptr; - for (size_t i = 0; i < size; i++) { - if (a[i] < b[i]) - return -1; - else if (b[i] < a[i]) - return 1; - } - return 0; + const unsigned char* a = (const unsigned char*) aptr; + const unsigned char* b = (const unsigned char*) bptr; + for (size_t i = 0; i < size; i++) { + if (a[i] < b[i]) + return -1; + else if (b[i] < a[i]) + return 1; + } + return 0; } diff --git a/common/stdc/memcpy.c b/common/stdc/memcpy.c index 1834816..878ff2b 100644 --- a/common/stdc/memcpy.c +++ b/common/stdc/memcpy.c @@ -1,9 +1,9 @@ #include void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) { - unsigned char* dst = (unsigned char*) dstptr; - const unsigned char* src = (const unsigned char*) srcptr; - for (size_t i = 0; i < size; i++) - dst[i] = src[i]; - return dstptr; + unsigned char* dst = (unsigned char*) dstptr; + const unsigned char* src = (const unsigned char*) srcptr; + for (size_t i = 0; i < size; i++) + dst[i] = src[i]; + return dstptr; } diff --git a/common/stdc/memmove.c b/common/stdc/memmove.c index ceac1e1..b5a96f1 100644 --- a/common/stdc/memmove.c +++ b/common/stdc/memmove.c @@ -1,14 +1,16 @@ #include void* memmove(void* dstptr, const void* srcptr, size_t size) { - unsigned char* dst = (unsigned char*) dstptr; - const unsigned char* src = (const unsigned char*) srcptr; - if (dst < src) { - for (size_t i = 0; i < size; i++) - dst[i] = src[i]; - } else { - for (size_t i = size; i != 0; i--) - dst[i-1] = src[i-1]; - } - return dstptr; + unsigned char* dst = (unsigned char*) dstptr; + const unsigned char* src = (const unsigned char*) srcptr; + + if (dst < src) { + for (size_t i = 0; i < size; i++) + dst[i] = src[i]; + } else { + for (size_t i = size; i != 0; i--) + dst[i-1] = src[i-1]; + } + + return dstptr; } diff --git a/common/stdc/memset.c b/common/stdc/memset.c index 449d1e7..cbcfa6a 100644 --- a/common/stdc/memset.c +++ b/common/stdc/memset.c @@ -1,8 +1,8 @@ #include void* memset(void* bufptr, int value, size_t size) { - unsigned char* buf = (unsigned char*) bufptr; - for (size_t i = 0; i < size; i++) - buf[i] = (unsigned char) value; - return bufptr; + unsigned char* buf = (unsigned char*) bufptr; + for (size_t i = 0; i < size; i++) + buf[i] = (unsigned char) value; + return bufptr; } diff --git a/common/stdc/printf.c b/common/stdc/printf.c new file mode 100644 index 0000000..1e8fe63 --- /dev/null +++ b/common/stdc/printf.c @@ -0,0 +1,14 @@ +#include + +void printf(const char* fmt, ...) { + char buf[4096]; + va_list ap; + va_start(ap, fmt); + + vsprintf(buf, fmt, ap); + + va_end(ap); + + puts(buf); +} + diff --git a/common/stdc/putc.c b/common/stdc/putc.c new file mode 100644 index 0000000..c38db8d --- /dev/null +++ b/common/stdc/putc.c @@ -0,0 +1,5 @@ +#include + +void putc(char c) { + put_handler(c); +} diff --git a/common/stdc/puts.c b/common/stdc/puts.c new file mode 100644 index 0000000..b0e7bd8 --- /dev/null +++ b/common/stdc/puts.c @@ -0,0 +1,9 @@ +#include + +void puts(char* str) { + while(*str != 0) { + putc(*str); + ++str; + } +} + diff --git a/common/stdc/strcatlen.c b/common/stdc/strcatlen.c new file mode 100644 index 0000000..f2945d7 --- /dev/null +++ b/common/stdc/strcatlen.c @@ -0,0 +1,11 @@ +#include + +int strcatlen(char* a, char* b) { + char* o = b; + while(*b != 0) { + *a = *b; + a++; + b++; + } + return b - o; +} diff --git a/common/stdc/strlen.c b/common/stdc/strlen.c index 8ac0dbe..5e2cf33 100644 --- a/common/stdc/strlen.c +++ b/common/stdc/strlen.c @@ -1,8 +1,8 @@ #include size_t strlen(const char* str) { - size_t len = 0; - while (str[len]) - len++; - return len; + size_t len = 0; + while (str[len]) + len++; + return len; } diff --git a/common/stdc/vsprintf.c b/common/stdc/vsprintf.c new file mode 100644 index 0000000..64cf60a --- /dev/null +++ b/common/stdc/vsprintf.c @@ -0,0 +1,47 @@ +#include + +void vsprintf(char *buffer, const char* fmt_con, va_list ap) { + char* fmt = (char*)fmt_con; + char* buf = buffer; + while(*fmt != 0) { + if (*fmt == '%') { + // Format string. + ++fmt; + switch (*fmt) { + case 'c': + *buf = (char)va_arg(ap, int); + buf++; + fmt++; + break; + case '%': + *buf = '%'; + buf++; + fmt++; + break; + case 's': + buf += strcatlen(buf, va_arg(ap, char*)); + fmt++; + break; + case 'x': + buf += dumphex(buf, "0123456789abcdef", va_arg(ap, unsigned int)); + ++fmt; + break; + case 'X': + buf += dumphex(buf, "0123456789ABCDEF", va_arg(ap, unsigned int)); + ++fmt; + break; + case 'd': + case 'u': + default: + ++fmt; + break; + } + } else { + *buf = *fmt; + ++buf; + ++fmt; + } + } + + *buf = 0; +} diff --git a/i686/gdt.c b/i686/gdt.c new file mode 100644 index 0000000..691860d --- /dev/null +++ b/i686/gdt.c @@ -0,0 +1,60 @@ +#include +#include + +#include + +// Lets us access our ASM functions from our C code. +extern void gdt_flush(uint32_t); + +// This structure contains the value of one GDT entry. +// We use the attribute 'packed' to tell GCC not to change +// any of the alignment in the structure. +struct gdt_entry_struct +{ + uint16_t limit_low; // The lower 16 bits of the limit. + uint16_t base_low; // The lower 16 bits of the base. + uint8_t base_middle; // The next 8 bits of the base. + uint8_t access; // Access flags, determine what ring this segment can be used in. + uint8_t granularity; + uint8_t base_high; // The last 8 bits of the base. +} __attribute__((packed)); +typedef struct gdt_entry_struct gdt_entry_t; + +struct gdt_ptr_struct +{ + uint16_t limit; // The upper 16 bits of all selector limits. + uint32_t base; // The address of the first gdt_entry_t struct. +} + __attribute__((packed)); +typedef struct gdt_ptr_struct gdt_ptr_t; + +gdt_entry_t gdt_entries[5]; +gdt_ptr_t gdt_ptr; + +// Set the value of one GDT entry. +void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) +{ + gdt_entries[num].base_low = (base & 0xFFFF); + gdt_entries[num].base_middle = (base >> 16) & 0xFF; + gdt_entries[num].base_high = (base >> 24) & 0xFF; + + gdt_entries[num].limit_low = (limit & 0xFFFF); + gdt_entries[num].granularity = (limit >> 16) & 0x0F; + + gdt_entries[num].granularity |= gran & 0xF0; + gdt_entries[num].access = access; +} + +void init_gdt() +{ + gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; + gdt_ptr.base = (uint32_t)&gdt_entries; + + gdt_set_gate(0, 0, 0, 0, 0); // Null segment + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment + gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment + gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment + + gdt_flush((uint32_t)&gdt_ptr); +} diff --git a/i686/idt.c b/i686/idt.c new file mode 100644 index 0000000..e61f569 --- /dev/null +++ b/i686/idt.c @@ -0,0 +1,223 @@ +#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; + + 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); + } + + outb(0x20, 0x20); + + switch(esp->int_no) { + case 0: + ++ticks; + break; + case 1: + c_kb = inb(0x60); + putc(table[c_kb]); + break; + default: + break; + } +} + +extern void isr_0(); +extern void isr_1(); +extern void isr_2(); +extern void isr_3(); +extern void isr_4(); +extern void isr_5(); +extern void isr_6(); +extern void isr_7(); +extern void isr_8(); +extern void isr_9(); +extern void isr_10(); +extern void isr_11(); +extern void isr_12(); +extern void isr_13(); +extern void isr_14(); +extern void isr_15(); +extern void isr_16(); +extern void isr_17(); +extern void isr_18(); +extern void isr_19(); +extern void isr_20(); +extern void isr_21(); +extern void isr_22(); +extern void isr_23(); +extern void isr_24(); +extern void isr_25(); +extern void isr_26(); +extern void isr_27(); +extern void isr_28(); +extern void isr_29(); +extern void isr_30(); +extern void isr_31(); + +extern void irq_0(); +extern void irq_1(); +extern void irq_2(); +extern void irq_3(); +extern void irq_4(); +extern void irq_5(); +extern void irq_6(); +extern void irq_7(); +extern void irq_8(); +extern void irq_9(); +extern void irq_10(); +extern void irq_11(); +extern void irq_12(); +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 ) + +#define IRQ_CALL(N) \ + idt_set_gate( 32 + N , (uint32_t) irq_##N , 0x08, 0x8E ) + +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); + + ISR_CALL(0); + ISR_CALL(1); + ISR_CALL(2); + ISR_CALL(3); + ISR_CALL(4); + ISR_CALL(5); + ISR_CALL(6); + ISR_CALL(7); + ISR_CALL(8); + ISR_CALL(9); + ISR_CALL(10); + ISR_CALL(11); + ISR_CALL(12); + ISR_CALL(13); + ISR_CALL(14); + ISR_CALL(15); + ISR_CALL(16); + ISR_CALL(17); + ISR_CALL(18); + ISR_CALL(19); + ISR_CALL(20); + ISR_CALL(21); + ISR_CALL(22); + ISR_CALL(23); + ISR_CALL(24); + ISR_CALL(25); + ISR_CALL(26); + ISR_CALL(27); + ISR_CALL(28); + ISR_CALL(29); + ISR_CALL(30); + ISR_CALL(31); + + outb(0x20, 0x11); + outb(0xA0, 0x11); + + outb(0x21, 0x20); + outb(0xA1, 0x28); + + outb(0x21, 0x04); + outb(0xA1, 0x02); + + outb(0x21, 0x01); + outb(0xA1, 0x01); + + outb(0x21, 0x0); + outb(0xA1, 0x0); + + IRQ_CALL(0); + IRQ_CALL(1); + IRQ_CALL(2); + IRQ_CALL(3); + IRQ_CALL(4); + IRQ_CALL(5); + IRQ_CALL(6); + IRQ_CALL(7); + IRQ_CALL(8); + IRQ_CALL(9); + IRQ_CALL(10); + IRQ_CALL(11); + IRQ_CALL(12); + IRQ_CALL(13); + IRQ_CALL(14); + IRQ_CALL(15); + + idt_flush((uint32_t)&idt_ptr); + + asm volatile ("sti"); +} diff --git a/i686/timer.c b/i686/timer.c new file mode 100644 index 0000000..8532e28 --- /dev/null +++ b/i686/timer.c @@ -0,0 +1,17 @@ +#include +#include + +#include + +int set_pitdiv(int freq) { + uint32_t div = 1193180 / freq; + outb(0x43, 0x36); + + // Divisor has to be sent byte-wise, so split here into upper/lower bytes. + uint8_t l = (uint8_t)(div & 0xFF); + uint8_t h = (uint8_t)( (div >> 8) & 0xFF ); + + // Send the frequency divisor. + outb(0x40, l); + outb(0x40, h); +} diff --git a/i686/utils.c b/i686/utils.c index ea4be47..b2c833c 100644 --- a/i686/utils.c +++ b/i686/utils.c @@ -45,327 +45,9 @@ uint32_t inl(uint16_t port) return ret; } - -// Lets us access our ASM functions from our C code. -extern void gdt_flush(uint32_t); - -// This structure contains the value of one GDT entry. -// We use the attribute 'packed' to tell GCC not to change -// any of the alignment in the structure. -struct gdt_entry_struct -{ - uint16_t limit_low; // The lower 16 bits of the limit. - uint16_t base_low; // The lower 16 bits of the base. - uint8_t base_middle; // The next 8 bits of the base. - uint8_t access; // Access flags, determine what ring this segment can be used in. - uint8_t granularity; - uint8_t base_high; // The last 8 bits of the base. -} __attribute__((packed)); -typedef struct gdt_entry_struct gdt_entry_t; - -struct gdt_ptr_struct -{ - uint16_t limit; // The upper 16 bits of all selector limits. - uint32_t base; // The address of the first gdt_entry_t struct. -} - __attribute__((packed)); -typedef struct gdt_ptr_struct gdt_ptr_t; - -gdt_entry_t gdt_entries[5]; -gdt_ptr_t gdt_ptr; - -// Set the value of one GDT entry. -static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) -{ - gdt_entries[num].base_low = (base & 0xFFFF); - gdt_entries[num].base_middle = (base >> 16) & 0xFF; - gdt_entries[num].base_high = (base >> 24) & 0xFF; - - gdt_entries[num].limit_low = (limit & 0xFFFF); - gdt_entries[num].granularity = (limit >> 16) & 0x0F; - - gdt_entries[num].granularity |= gran & 0xF0; - gdt_entries[num].access = access; -} - -static void init_gdt() -{ - gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; - gdt_ptr.base = (uint32_t)&gdt_entries; - - gdt_set_gate(0, 0, 0, 0, 0); // Null segment - gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment - gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment - gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment - gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment - - gdt_flush((uint32_t)&gdt_ptr); -} - -// 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; - -static 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; - - 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. -}; - -char *strs_isr[] = { - "divide by zero", - "debug exception", - "non maskable interrupt", - "breakpoint", - "into detected overflow", - "out of bounds exception", - "invalid opcode exception", - "no coprocessor exception", - "double fault", - "coprocessor segment overrun", - "bad tss", - "segment not present", - "stack fault", - "general protection fault", - "page fault", - "unknown interrupt", - "coprocessor fault", - "alignment check exception", - "machine check exception" -}; - -void isr_handler(struct interrupt_frame* esp) { - kprintf("int %x: ", esp->int_no); - if (esp->int_no <= 18) { - kprintf("%s\n", strs_isr[esp->int_no]); - } else { - kprintf("reserved\n"); - } -} - -uint64_t ticks = 0; - -uint64_t kclock() { - return ticks; -} - -char *irq_strs[] = { - "PIT", - "Keyboard", - "Cascade", - "COM2", - "COM1", - "LPT1", - "CMOS rtc", - "Peripheral 1", - "Peripheral 2", - "Peripheral 3", - "PS/2 Mouse", - "FPU/Coprocessor", - "ATA0", - "ATA1", -}; - -void irq_handler(struct interrupt_frame* esp) { - char c_kb; - - if (esp->int_no >= 7) { - outb(0xA0, 0x20); - } - - outb(0x20, 0x20); - - switch(esp->int_no) { - case 0: - ++ticks; - break; - case 1: - c_kb = inb(0x60); - kputc(c_kb); - break; - default: - break; - } -} - -extern void isr_0(); -extern void isr_1(); -extern void isr_2(); -extern void isr_3(); -extern void isr_4(); -extern void isr_5(); -extern void isr_6(); -extern void isr_7(); -extern void isr_8(); -extern void isr_9(); -extern void isr_10(); -extern void isr_11(); -extern void isr_12(); -extern void isr_13(); -extern void isr_14(); -extern void isr_15(); -extern void isr_16(); -extern void isr_17(); -extern void isr_18(); -extern void isr_19(); -extern void isr_20(); -extern void isr_21(); -extern void isr_22(); -extern void isr_23(); -extern void isr_24(); -extern void isr_25(); -extern void isr_26(); -extern void isr_27(); -extern void isr_28(); -extern void isr_29(); -extern void isr_30(); -extern void isr_31(); - -extern void irq_0(); -extern void irq_1(); -extern void irq_2(); -extern void irq_3(); -extern void irq_4(); -extern void irq_5(); -extern void irq_6(); -extern void irq_7(); -extern void irq_8(); -extern void irq_9(); -extern void irq_10(); -extern void irq_11(); -extern void irq_12(); -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 ) - -#define IRQ_CALL(N) \ - idt_set_gate( 32 + N , (uint32_t) irq_##N , 0x08, 0x8E ) - -static 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); - - ISR_CALL(0); - ISR_CALL(1); - ISR_CALL(2); - ISR_CALL(3); - ISR_CALL(4); - ISR_CALL(5); - ISR_CALL(6); - ISR_CALL(7); - ISR_CALL(8); - ISR_CALL(9); - ISR_CALL(10); - ISR_CALL(11); - ISR_CALL(12); - ISR_CALL(13); - ISR_CALL(14); - ISR_CALL(15); - ISR_CALL(16); - ISR_CALL(17); - ISR_CALL(18); - ISR_CALL(19); - ISR_CALL(20); - ISR_CALL(21); - ISR_CALL(22); - ISR_CALL(23); - ISR_CALL(24); - ISR_CALL(25); - ISR_CALL(26); - ISR_CALL(27); - ISR_CALL(28); - ISR_CALL(29); - ISR_CALL(30); - ISR_CALL(31); - - outb(0x20, 0x11); - outb(0xA0, 0x11); - - outb(0x21, 0x20); - outb(0xA1, 0x28); - - outb(0x21, 0x04); - outb(0xA1, 0x02); - - outb(0x21, 0x01); - outb(0xA1, 0x01); - - outb(0x21, 0x0); - outb(0xA1, 0x0); - - IRQ_CALL(0); - IRQ_CALL(1); - IRQ_CALL(2); - IRQ_CALL(3); - IRQ_CALL(4); - IRQ_CALL(5); - IRQ_CALL(6); - IRQ_CALL(7); - IRQ_CALL(8); - IRQ_CALL(9); - IRQ_CALL(10); - IRQ_CALL(11); - IRQ_CALL(12); - IRQ_CALL(13); - IRQ_CALL(14); - IRQ_CALL(15); - - idt_flush((uint32_t)&idt_ptr); - - asm volatile ("sti"); -} - -int set_pitdiv(int freq) { - uint32_t div = 1193180 / freq; - outb(0x43, 0x36); - - // Divisor has to be sent byte-wise, so split here into upper/lower bytes. - uint8_t l = (uint8_t)(div & 0xFF); - uint8_t h = (uint8_t)( (div >> 8) & 0xFF ); - - // Send the frequency divisor. - outb(0x40, l); - outb(0x40, h); -} +void init_gdt(); +void init_idt(); +int set_pitdiv(int freq); void i686_init() { init_gdt(); diff --git a/include/module_console.h b/include/module_console.h index 02dbf94..4e0b137 100644 --- a/include/module_console.h +++ b/include/module_console.h @@ -1,30 +1,12 @@ #include -typedef void (*console_put_f) (char, char, char, uint16_t, uint16_t); -typedef void (*console_get_f) (char*, char*, char*, uint16_t, uint16_t); -typedef void (*console_cursor_f) (uint16_t, uint16_t); -typedef uint16_t (*console_width_f) (); -typedef uint16_t (*console_height_f) (); -typedef void (*console_refresh_f)(); -typedef int (*console_tty_f) (); +typedef void (*module_out_f) (char); -struct console_module { - console_put_f put; - console_get_f get; - console_cursor_f cursor; - console_width_f width; - console_height_f height; - console_refresh_f refresh; - console_tty_f tty; +struct output { + module_out_f out; }; -void console_register_module(struct console_module*); -void console_unregister_module(struct console_module*); +void console_reg(struct output*); +void console_unreg(struct output*); void console_init(); void console_deinit(); - -void kputc(char); -void kwrite(char*); -void kvsprintf(char *buffer, const char* fmt_con, va_list ap); -void kprintf(const char* fmt, ...); - diff --git a/include/stdc/stdio.h b/include/stdc/stdio.h new file mode 100644 index 0000000..2b5c7d3 --- /dev/null +++ b/include/stdc/stdio.h @@ -0,0 +1,22 @@ +#ifndef _STRING_H +#define _STRING_H 1 + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int dumphex (char* buf, const char* index, unsigned int num); +void putc (char c); +void puts (char* str); +void vsprintf (char *buffer, const char* fmt_con, va_list ap); +void printf (const char* fmt_con, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/stdc/string.h b/include/stdc/string.h index 31a6266..85fe20b 100644 --- a/include/stdc/string.h +++ b/include/stdc/string.h @@ -8,11 +8,12 @@ extern "C" { #endif -int memcmp(const void*, const void*, size_t); -void* memcpy(void* __restrict, const void* __restrict, size_t); -void* memmove(void*, const void*, size_t); -void* memset(void*, int, size_t); -size_t strlen(const char*); +int memcmp (const void*, const void*, size_t); +void* memcpy (void* __restrict, const void* __restrict, size_t); +void* memmove (void*, const void*, size_t); +void* memset (void*, int, size_t); +size_t strlen (const char*); +int strcatlen (char*, char*); #ifdef __cplusplus } diff --git a/module/biosvga/module.c b/module/biosvga/module.c index afea926..4f29b00 100644 --- a/module/biosvga/module.c +++ b/module/biosvga/module.c @@ -1,24 +1,16 @@ #include +#include #include #include -uint16_t *video_mem = (uint16_t*)0xC00B8000; - -void biosvga_put(char c, char color_fg, char color_bg, uint16_t x, uint16_t y) { - uint8_t attr = (color_bg << 4) | (color_fg & 0xF); - uint16_t write = (attr << 8) | c; +#define WIDTH 80 +#define HEIGHT 25 - video_mem[y * 80 + x] = write; -} +int x, y; -void biosvga_get(char* c, char* color_fg, char* color_bg, uint16_t x, uint16_t y) { - uint16_t write = video_mem[y * 80 + x]; - *c = (char)(write & 0xFF); - *color_bg = (write << 12) & 0xF; - *color_fg = (write << 8) & 0xF; -} +uint16_t *video_mem = (uint16_t*)0xC00B8000; -void biosvga_cursor(uint16_t x, uint16_t y) { +void cursor(uint16_t x, uint16_t y) { uint16_t loc = y * 80 + x; outb(0x3D4, 14); outb(0x3D5, loc >> 8); @@ -26,37 +18,54 @@ void biosvga_cursor(uint16_t x, uint16_t y) { outb(0x3D5, loc); } -uint16_t biosvga_width() { - return 80; -} +void biosvga_wb(char c) { + uint8_t color_bg = 0; + uint8_t color_fg = 0xF; + uint8_t attr = (color_bg << 4) | (color_fg & 0xF); + uint16_t write = (attr << 8) | c; -uint16_t biosvga_height() { - return 25; -} + switch(c) { + case '\n': + y++; + case '\r': + x = 0; + break; + case '\b': + if (x) --x; + break; + case '\t': + x += 4 - (x % 4); + break; + case ' ' ... '~': + video_mem[y * 80 + x] = write; + ++x; + break; + } -void biosvga_refresh() { + if (x >= WIDTH) { + x = 0; + ++y; + } -} + if (y >= HEIGHT) { + memcpy(video_mem, &video_mem[80], (HEIGHT - 1) * 80 * sizeof(uint16_t)); + --y; + memset(&video_mem[y * 80], 0, 160); + } -int biosvga_tty() { - return 1; + cursor(x, y); } -struct console_module biosvga_module = { - .put = biosvga_put, - .get = biosvga_get, - .tty = biosvga_tty, - .cursor = biosvga_cursor, - .width = biosvga_width, - .height = biosvga_height, - .refresh = biosvga_refresh +struct output biosvga_module = { + .out = biosvga_wb }; void biosvga_init() { - console_register_module(&biosvga_module); + x = y = 0; + console_reg(&biosvga_module); } void biosvga_deinit() { - console_unregister_module(&biosvga_module); + console_unreg(&biosvga_module); // Stub. } diff --git a/module/console.c b/module/console.c index 3f99798..22bfe6b 100644 --- a/module/console.c +++ b/module/console.c @@ -7,211 +7,26 @@ actually printing to; in the future, adding a new backend for framebuffer render #include #include -struct console_module *active; -struct console_module *reg[2]; -uint16_t x, y, tab_w; +struct output *active; -void biosvga_init(); -void biosvga_deinit(); - -void console_mark_active(int idx) { - active = reg[idx]; -} - -void console_register_module(struct console_module* module) { - reg[1] = reg[0]; - reg[0] = module; -} - -void console_unregister_module(struct console_module* module) { - if (reg[0] == module) - reg[0] = reg[1]; - if (reg[1] == module) - reg[1] = NULL; +void put_handler(char c) { + active->out(c); } -// TODO - Should this be part of the backend? Scrolling is slow. -void scroll() { - if (active->tty() == 0) - return; - - if (y >= active->height()) { - for(int cy = 1; cy <= active->height(); cy++) { - for(int cx = 0; cx <= active->width(); cx++) { - char c = 0; - uint8_t fg = 0, bg = 0; - active->get(&c, &fg, &bg, cx, cy); - active->put(c, 0xf, 0, cx, cy-1); - } - } - --y; - for(int cx = 0; cx < active->width(); cx++) { - active->put(' ', 0xf, 0, cx, y); - } - } +void console_reg(struct output* out) { + active = out; } -// TODO - Should this be part of the backend? Scrolling is slow. -void clear() { - if (active->tty() == 0) - return; - - x = y = 0; - for(int cy = 0; cy < active->height(); cy++) { - for(int cx = 0; cx < active->width(); cx++) { - active->put(' ', 0xf, 0x0, cx, cy); - } - } -} - -void kputc(char c) { - switch(c) { - case '\t': - x += tab_w - (x % tab_w); - break; - case '\b': - --x; - break; - case '\n': - ++y; - case '\r': - x = 0; - break; - case ' ' ... '~': - active->put(c, 0xf, 0x0, x, y); - default: - x += 1; - break; - } - - if (x > active->width()) { - x = 0; - ++y; - } - - scroll(); - if (active->tty() == 1) - active->cursor(x, y); -} - -void kwrite(char* str) { - while(*str != 0) { - kputc(*str); - ++str; - } -} - -int strcatlen(char* a, char* b) { - char* o = b; - while(*b != 0) { - *a = *b; - a++; - b++; - } - return b - o; -} - -int dumphex(char* buf, const char* index, unsigned int num) { - uint8_t *num_8 = (uint8_t *)# - char *obuf = buf; - for (int i = 3; i >= 0; i--) { - uint8_t high = (num_8[i] >> 4) & 0xf; - uint8_t low = num_8[i] & 0xf; - - *buf = (index)[high]; buf++; - *buf = (index)[low]; buf++; - } - - return buf - obuf; -} - -void kvsprintf(char *buffer, const char* fmt_con, va_list ap) { - char* fmt = (char*)fmt_con; - char* buf = buffer; - while(*fmt != 0) { - if (*fmt == '%') { - // Format string. - ++fmt; - switch (*fmt) { - case 'c': - *buf = (char)va_arg(ap, int); - buf++; - fmt++; - break; - case '%': - *buf = '%'; - buf++; - fmt++; - break; - case 's': - buf += strcatlen(buf, va_arg(ap, char*)); - fmt++; - break; - case 'x': - buf += dumphex(buf, "0123456789abcdef", va_arg(ap, unsigned int)); - ++fmt; - break; - case 'X': - buf += dumphex(buf, "0123456789ABCDEF", va_arg(ap, unsigned int)); - ++fmt; - break; - case 'd': - case 'u': - default: - ++fmt; - break; - } - } else { - *buf = *fmt; - ++buf; - ++fmt; - } - } - - *buf = 0; -} - -char buf[4096]; - -void kprintf(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - - kvsprintf(buf, fmt, ap); - - va_end(ap); - - kwrite(buf); -} - -void defer_kprintf(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - - kvsprintf(buf, fmt, ap); - - va_end(ap); -} - -void flush_defer_kprintf() { - kwrite(buf); +void console_unreg(struct output* out) { + active = out; } void console_init() { - x = y = 0; - tab_w = 4; - // Temporary - serial_init(); biosvga_init(); - - console_mark_active(0); - - clear(); } void console_deinit() { // Temporary biosvga_deinit(); - serial_deinit(); } diff --git a/module/serial/module.c b/module/serial/module.c index 2e7d2cf..98fa2f7 100644 --- a/module/serial/module.c +++ b/module/serial/module.c @@ -8,22 +8,17 @@ int is_transmit_empty() { return inb(PORT + 5) & 0x20; } -void serial_put(char c, char color_fg, char color_bg, uint16_t x, uint16_t y) { +void serial_wb(char c) { while (is_transmit_empty() == 0); outb(PORT, c); } -void serial_get(char* c, char* color_fg, char* color_bg, uint16_t x, uint16_t y) { +char serial_rb(void) { } -int serial_tty() { - return 0; -} - -struct console_module serial_module = { - .put = serial_put, - .get = serial_get, - .tty = serial_tty +struct port_module serial_module = { + .write = serial_wb, + .read = serial_rb, }; void serial_init() { @@ -34,11 +29,7 @@ void serial_init() { outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set - - console_register_module(&serial_module); } void serial_deinit() { - console_unregister_module(&serial_module); - // Stub. } -- 2.39.5