From 8f5f6722fa924e99338e416bd7303a8a63d32ac5 Mon Sep 17 00:00:00 2001 From: Jon Feldman Date: Mon, 20 Feb 2017 04:12:58 -0500 Subject: [PATCH] GDT / IDT seem functional-ish --- Makefile | 14 ++- common/kernel_main.c | 32 ++---- common/stdc/memcmp.c | 13 +++ common/stdc/memcpy.c | 9 ++ common/stdc/memmove.c | 14 +++ common/stdc/memset.c | 8 ++ common/stdc/strlen.c | 8 ++ i686/entry.S | 159 ++++++++++++++++++++++++++-- i686/link.ld | 29 +++--- i686/utils.c | 218 +++++++++++++++++++++++++++++++++++++++ include/memory.h | 4 + include/module_console.h | 6 ++ include/stdc/cdefs.h | 6 ++ include/stdc/string.h | 21 ++++ module/biosvga/module.c | 7 +- module/console.c | 125 +++++++++++++++++++++- module/serial/module.c | 44 ++++++++ 17 files changed, 659 insertions(+), 58 deletions(-) create mode 100644 common/stdc/memcmp.c create mode 100644 common/stdc/memcpy.c create mode 100644 common/stdc/memmove.c create mode 100644 common/stdc/memset.c create mode 100644 common/stdc/strlen.c create mode 100644 include/memory.h create mode 100644 include/stdc/cdefs.h create mode 100644 include/stdc/string.h create mode 100644 module/serial/module.c diff --git a/Makefile b/Makefile index ee60ab5..c78b257 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,17 @@ # The only one that needs changing is the assembler # rule, as we use nasm instead of GNU as. +CONF=-DCONF_EARLY_KPRINTF=1 + TGT=i686 -SOURCES=$(TGT)/entry.o $(TGT)/utils.o module/biosvga/module.o module/console.o common/kernel_main.o +SOURCES= \ + $(TGT)/entry.o \ + $(TGT)/utils.o \ + module/biosvga/module.o module/serial/module.o module/console.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 + LDSC=$(TGT)/link.ld TGTNAM=$(TGT)-elf @@ -35,10 +43,10 @@ link: $(SOURCES) $(LD) $(LDFLAGS) -o kernel $(LIBS) $(SOURCES) %.o: %.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(CONF) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $< %.o: %.cxx - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $< + $(CXX) $(CXXFLAGS) $(CONF) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $< %.o: %.S $(AS) $(ASFLAGS) -c -o $@ $< diff --git a/common/kernel_main.c b/common/kernel_main.c index 308f747..53c994a 100644 --- a/common/kernel_main.c +++ b/common/kernel_main.c @@ -6,34 +6,14 @@ int kernel_main(struct multiboot *mboot_ptr) { console_init(); - kwrite("1\n"); - kwrite("2\n"); - kwrite("3\n"); - kwrite("4\n"); - kwrite("5\n"); - kwrite("6\n"); - kwrite("7\n"); - kwrite("8\n"); - kwrite("9\n"); - kwrite("10\n"); - kwrite("11\n"); - kwrite("12\n"); - kwrite("13\n"); - kwrite("14\n"); - kwrite("15\n"); - kwrite("16\n"); - kwrite("17\n"); - kwrite("18\n"); - kwrite("19\n"); - kwrite("20\n"); - kwrite("21\n"); - kwrite("22\n"); - kwrite("23\n"); - kwrite("24\n"); - kwrite("25\n"); - kwrite("26\n"); + kprintf("1%c%% %s %X\n", 'c', "whoop", 0xDEADBEEF); console_deinit(); + asm volatile("int $4"); + asm volatile("int $3"); + + while(1); + return 0xDEADBEEF; } diff --git a/common/stdc/memcmp.c b/common/stdc/memcmp.c new file mode 100644 index 0000000..576a242 --- /dev/null +++ b/common/stdc/memcmp.c @@ -0,0 +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; +} diff --git a/common/stdc/memcpy.c b/common/stdc/memcpy.c new file mode 100644 index 0000000..1834816 --- /dev/null +++ b/common/stdc/memcpy.c @@ -0,0 +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; +} diff --git a/common/stdc/memmove.c b/common/stdc/memmove.c new file mode 100644 index 0000000..ceac1e1 --- /dev/null +++ b/common/stdc/memmove.c @@ -0,0 +1,14 @@ +#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; +} diff --git a/common/stdc/memset.c b/common/stdc/memset.c new file mode 100644 index 0000000..449d1e7 --- /dev/null +++ b/common/stdc/memset.c @@ -0,0 +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; +} diff --git a/common/stdc/strlen.c b/common/stdc/strlen.c new file mode 100644 index 0000000..8ac0dbe --- /dev/null +++ b/common/stdc/strlen.c @@ -0,0 +1,8 @@ +#include + +size_t strlen(const char* str) { + size_t len = 0; + while (str[len]) + len++; + return len; +} diff --git a/i686/entry.S b/i686/entry.S index abb6a38..649c07d 100644 --- a/i686/entry.S +++ b/i686/entry.S @@ -1,3 +1,5 @@ +/* Multiboot garbage. */ + .set ALIGN, 1<<0 # align loaded modules on page boundaries .set MEMINFO, 1<<1 # provide memory map .set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field @@ -10,24 +12,163 @@ .long FLAGS .long CHECKSUM -.section .bss -.align 16 +/* Stack. */ +.section .bootstrap_stack, "aw", @nobits stack_bottom: -.skip 16384 # 16 KiB +.skip 16384 // 16 KiB stack_top: +.set KERNEL_VBASE, 0xC0000000 +.set KERNEL_PNUM, (KERNEL_VBASE >> 22) + +.section .data +.align 0x1000 +boot_pgdir: + .int 0x83 + .fill (KERNEL_PNUM - 1), 4, 0 + .int 0x83 + .fill (1024 - KERNEL_PNUM - 1), 4, 0 + +/* Our actual entrypoint. */ .section .text .global _start .type _start, @function _start: - mov $stack_top, %esp + // Map our kernel at KERNEL_VBASE and enable paging + mov $(boot_pgdir - KERNEL_VBASE), %ecx + mov %ecx,%cr3 + + mov %cr4,%ecx + or $0x10,%ecx + mov %ecx,%cr4 + + mov %cr0,%ecx + or $0x80000000,%ecx + mov %ecx,%cr0 + + lea .init, %ecx + jmp *%ecx - push %ebx +.init: + // Unmap page 0 (it's not needed now) + movl $0, boot_pgdir + invlpg 0 - call kernel_main + mov $stack_top, %esp - cli -.halt: hlt - jmp .halt + push %ebx + + call i686_init + + call kernel_main + + cli +.halt: + hlt + jmp .halt .size _start, . - _start + +.global gdt_flush +.type gdt_flush, @function +gdt_flush: + mov 0x4(%esp),%eax + lgdt (%eax) + mov $0x10,%ax + mov %eax,%ds + mov %eax,%es + mov %eax,%fs + mov %eax,%gs + mov %eax,%ss + lea .flush, %eax + jmp *%eax + .flush: + ret + +.size gdt_flush, . - gdt_flush + +.macro ISR index + .global isr_\index + .type isr_\index , @function + isr_\index : + push $0 + push $\index + jmp isr_stub +.endm + +.macro ISR_E index + .global isr_\index + .type isr_\index , @function + isr_\index : + push $\index + jmp isr_stub +.endm + +ISR 0 +ISR 1 +ISR 2 +ISR 3 +ISR 4 +ISR 5 +ISR 6 +ISR 7 +ISR_E 8 +ISR 9 +ISR_E 10 +ISR_E 11 +ISR_E 12 +ISR_E 13 +ISR_E 14 +ISR 15 +ISR 16 +ISR_E 17 +ISR 18 +ISR 19 +ISR 20 +ISR 21 +ISR 22 +ISR 23 +ISR 24 +ISR 25 +ISR 26 +ISR 27 +ISR 28 +ISR 29 +ISR_E 30 +ISR 31 + +isr_stub: + pusha + + mov %ds, %ax + push %eax + + mov $0x10,%ax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + + push %esp + + cld + call isr_handler + + pop %eax + + pop %eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + + popa + add $8, %esp + iret + +.global idt_flush +.type idt_flush, @function +idt_flush: + mov 0x4(%esp),%eax + lidt (%eax) + ret diff --git a/i686/link.ld b/i686/link.ld index 88b0e01..07074a9 100644 --- a/i686/link.ld +++ b/i686/link.ld @@ -6,38 +6,39 @@ ENTRY(_start) kernel image. */ SECTIONS { - /* Begin putting sections at 1 MiB, a conventional place for kernels to be - loaded at by the bootloader. */ - . = 1M; - - /* First put the multiboot header, as it is required to be put very early - early in the image or the bootloader won't recognize the file format. - Next we'll put the .text section. */ - .text BLOCK(4K) : ALIGN(4K) + /* Begin putting sections at 1 MiB (+3GB virt) */ + . = 0xC0100000; + + _kernel_start = .; + + .text ALIGN (4K) : AT (ADDR (.text) - 0xC0000000) { *(.multiboot) *(.text) } - /* Read-only data. */ - .rodata BLOCK(4K) : ALIGN(4K) + .rodata ALIGN (4K) : AT (ADDR (.rodata) - 0xC0000000) { *(.rodata) } - /* Read-write data (initialized) */ - .data BLOCK(4K) : ALIGN(4K) + .data ALIGN (4K) : AT (ADDR (.data) - 0xC0000000) { *(.data) } - /* Read-write data (uninitialized) and stack */ - .bss BLOCK(4K) : ALIGN(4K) + .bss ALIGN (4K) : AT (ADDR (.bss) - 0xC0000000) { + _sbss = .; *(COMMON) *(.bss) + *(.bootstrap_stack) + _ebss = .; } /* The compiler may produce other sections, by default it will put them in a segment with the same name. Simply add stuff here as needed. */ + + /* Add a symbol that indicates the end address of the kernel. */ + _kernel_end = .; } diff --git a/i686/utils.c b/i686/utils.c index dbef878..9c5382e 100644 --- a/i686/utils.c +++ b/i686/utils.c @@ -1,4 +1,7 @@ #include +#include + +#include void outb(uint16_t port, uint8_t val) { @@ -41,3 +44,218 @@ uint32_t inl(uint16_t port) : "Nd"(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[] = { + "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[esp->int_no]); + } else { + kprintf("reserved\n"); + } +} + +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(); + +#define ISR_CALL(N) \ + idt_set_gate( N , (uint32_t) isr_##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); + + idt_flush((uint32_t)&idt_ptr); +} + +void i686_init() { + init_gdt(); + init_idt(); +} diff --git a/include/memory.h b/include/memory.h new file mode 100644 index 0000000..2c73b82 --- /dev/null +++ b/include/memory.h @@ -0,0 +1,4 @@ +#define memcpy __builtin_memcpy +#define memcmp __builtin_memcmp +#define strcpy __builtin_strcpy +#define strcmp __builtin_strcmp diff --git a/include/module_console.h b/include/module_console.h index 895bcb6..02dbf94 100644 --- a/include/module_console.h +++ b/include/module_console.h @@ -1,9 +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) (); struct console_module { console_put_f put; @@ -12,6 +15,7 @@ struct console_module { console_width_f width; console_height_f height; console_refresh_f refresh; + console_tty_f tty; }; void console_register_module(struct console_module*); @@ -21,4 +25,6 @@ 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/cdefs.h b/include/stdc/cdefs.h new file mode 100644 index 0000000..7f51871 --- /dev/null +++ b/include/stdc/cdefs.h @@ -0,0 +1,6 @@ +#ifndef _SYS_CDEFS_H +#define _SYS_CDEFS_H 1 + +#define __eidos_kernel_stdc 1 + +#endif diff --git a/include/stdc/string.h b/include/stdc/string.h new file mode 100644 index 0000000..31a6266 --- /dev/null +++ b/include/stdc/string.h @@ -0,0 +1,21 @@ +#ifndef _STRING_H +#define _STRING_H 1 + +#include +#include + +#ifdef __cplusplus +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*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/module/biosvga/module.c b/module/biosvga/module.c index bbbaab4..afea926 100644 --- a/module/biosvga/module.c +++ b/module/biosvga/module.c @@ -2,7 +2,7 @@ #include #include -uint16_t *video_mem = (uint16_t*)0xB8000; +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); @@ -38,9 +38,14 @@ void biosvga_refresh() { } +int biosvga_tty() { + return 1; +} + struct console_module biosvga_module = { .put = biosvga_put, .get = biosvga_get, + .tty = biosvga_tty, .cursor = biosvga_cursor, .width = biosvga_width, .height = biosvga_height, diff --git a/module/console.c b/module/console.c index 6cc6ae9..3f99798 100644 --- a/module/console.c +++ b/module/console.c @@ -3,26 +3,38 @@ actually printing to; in the future, adding a new backend for framebuffer render #include #include +#include #include #include struct console_module *active; +struct console_module *reg[2]; uint16_t x, y, tab_w; void biosvga_init(); void biosvga_deinit(); +void console_mark_active(int idx) { + active = reg[idx]; +} + void console_register_module(struct console_module* module) { - active = module; + reg[1] = reg[0]; + reg[0] = module; } void console_unregister_module(struct console_module* module) { - if (active == module) - active = NULL; + if (reg[0] == module) + reg[0] = reg[1]; + if (reg[1] == module) + reg[1] = NULL; } // 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++) { @@ -41,6 +53,9 @@ void scroll() { // 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++) { @@ -75,7 +90,8 @@ void kputc(char c) { } scroll(); - active->cursor(x, y); + if (active->tty() == 1) + active->cursor(x, y); } void kwrite(char* str) { @@ -85,18 +101,117 @@ void kwrite(char* 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_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 new file mode 100644 index 0000000..2e7d2cf --- /dev/null +++ b/module/serial/module.c @@ -0,0 +1,44 @@ +#include +#include +#include + +#define PORT 0x3f8 /* COM1 */ + +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) { + 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) { +} + +int serial_tty() { + return 0; +} + +struct console_module serial_module = { + .put = serial_put, + .get = serial_get, + .tty = serial_tty +}; + +void serial_init() { + outb(PORT + 1, 0x00); // Disable all interrupts + outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + outb(PORT + 1, 0x00); // (hi byte) + 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