os

Toy OS
git clone git://git.christosmarg.xyz
Log | Files | Refs | README | LICENSE

commit 3b623972a8fd45b2b3b28daafd72d754a852a805
parent 2fa7e11f715aa20c8015d54678a4c034269e485f
Author: Christos Margiolis <christos@margiolis.net>
Date:   Wed, 26 May 2021 19:02:24 +0300

writing printf

Diffstat:
MLICENSE | 2+-
MMakefile | 4++--
Mboot/Makefile | 7+++----
Mboot/boot.asm | 4++--
Mboot/extern.h | 11++++++++++-
Mboot/idt.c | 13++++++-------
Mboot/idt.h | 114++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mboot/int.asm | 401+++++++++++++------------------------------------------------------------------
Mboot/kbd.c | 4----
Mboot/kbd.h | 2+-
Mboot/kmain.c | 4++--
Dboot/loader.asm | 6------
Aboot/printf.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aboot/stdarg.h | 14++++++++++++++
Mboot/string.c | 2--
Mboot/string.h | 8++++----
Mboot/timer.h | 2+-
Mboot/tty.h | 14+++++++-------
Ahier | 11+++++++++++
19 files changed, 275 insertions(+), 436 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -1,6 +1,6 @@ MIT License -(c) 2021-Present Christos Margiolis <christos@christosmarg.xyz> +(c) 2021-Present Christos Margiolis <christos@margiolis.net> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in diff --git a/Makefile b/Makefile @@ -1,11 +1,11 @@ TGTDIR = build all: - cd boot && make install clean && cd .. + cd boot && make install clean && cd - run: qemu-system-i386 -hdd ${TGTDIR}/os.bin clean: rm -rf ${TGTDIR} - cd boot && make clean && cd .. + cd boot && make clean && cd - diff --git a/boot/Makefile b/boot/Makefile @@ -4,15 +4,14 @@ BINDIR = ../build CC = cc ASM = nasm LD = ld -CFLAGS = -g -m32 -ffreestanding -Wall -Wextra -std=c99 -O2 +CFLAGS = -g -m32 -nostdlib -ffreestanding -Wall -Wextra -std=c99 -O2 LDFLAGS = -Ttext 0x1000 --oformat binary BOOTFILE = boot.asm BOOT_BIN = boot.bin KERNEL_BIN = kernel.bin SRC = *.c *.asm -OBJ = loader.o \ - kmain.o \ +OBJ = kmain.o \ string.o \ tty.o \ idt.o \ @@ -49,4 +48,4 @@ install: all clean: rm -rf *.bin *.o -.PHONY: options all install clean +.PHONY: all options install clean diff --git a/boot/boot.asm b/boot/boot.asm @@ -34,7 +34,7 @@ _start: a20_test: pusha - mov ax, [0x7dfe] ; 0x7c00 + 510. The magic number is there. + mov ax, [0x7c00 + 510] ; The magic number is there. mov dx, ax ; We'll try to advance 1MB in memory. If the end result hasn't wrapped up @@ -243,7 +243,7 @@ gdt_ptr: GDT_CODESEG equ gdt_kernel_code - gdt GDT_DATASEG equ gdt_kernel_data - gdt -; Go into Protected Mode and set PAE Paging and the GDT. +; Set up the GDT and go into Protected Mode. pm_enter: cli ; Disable BIOS interrupts. lgdt [gdt_ptr] ; Load the GDT. diff --git a/boot/extern.h b/boot/extern.h @@ -1,12 +1,21 @@ #ifndef _KERNEL_EXTERN_H_ #define _KERNEL_EXTERN_H_ -#include <stdarg.h> #include <stddef.h> #include <stdint.h> +#include "stdarg.h" #include "io.h" #include "tty.h" #include "string.h" +#define BUFSIZ 1024 + +#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) +#define sizeof_field(s, f) (sizeof(((t *)0)->f)) + +int vsprintf(char *, const char *, va_list); +int sprintf(char *, const char *, ...); +int printf(const char *, ...); + #endif /* _KERNEL_EXTERN_H_ */ diff --git a/boot/idt.c b/boot/idt.c @@ -2,14 +2,14 @@ #include "idt.h" #include "port.h" -#define N_INT 256 /* There are 256 interrupts in total. */ -#define KERN_CODESEG 0x08 /* Kernel code segment. */ +#define N_INT 256 +#define KERN_CODESEG 0x08 static void idt_set_gate(uint8_t, uint32_t); static struct idt_gate idt[N_INT]; static void *isr[16] = {NULL}; -/* Exception messages for the first 32 ISRs. */ +/* Exception messages for the first 32 interrupts. */ static const char *except[] = { "Division By Zero Exception", "Debug Exception", @@ -60,8 +60,8 @@ void idt_init(void) { struct idt_reg { - uint16_t limit; /* Points at IDT[0]. */ - uint32_t base; /* Points at the end of the IDT. */ + uint16_t limit; /* IDT size in bytes. */ + uint32_t base; /* Points at `idt[0]`. */ } __attribute__((packed)) idtr; (void)memset(&idt, 0, sizeof(idt)); @@ -134,7 +134,6 @@ idt_init(void) /* https://wiki.osdev.org/Interrupt_Descriptor_Table#Location_and_Size */ idtr.base = (uint32_t)&idt; idtr.limit = N_INT * sizeof(struct idt_gate) - 1; - /* Load the IDT */ __asm__ __volatile__ ("lidtl (%0)" : : "r" (&idtr)); } @@ -147,7 +146,7 @@ int_handler(struct reg *r) * We'll call the handler only if the interrupt number is > 32, * which means that we're dealing with an IRQ and not an exception. */ - if (r->intno >= 32 && (handler = isr[r->intno - 32]) != 0) + if (r->intno >= 32 && (handler = isr[r->intno - 32]) != NULL) handler(r); /* Entries below index 32 in the IDT are exceptions, we need to hang. */ else if (r->intno < 32) { diff --git a/boot/idt.h b/boot/idt.h @@ -10,14 +10,14 @@ struct idt_gate { uint16_t off_hi; } __attribute__((packed)); -/* This will be populated by int_common_stub. */ +/* This will be populated by `int_common_stub` in `int.asm`. */ struct reg { - /* Segment registers. Will be popped last. */ + /* Will be popped last. */ uint32_t gs; uint32_t fs; uint32_t es; uint32_t ds; - /* General purpose registers. Pushed by `pusha`. */ + /* Pushed by `pusha`. */ uint32_t edi; uint32_t esi; uint32_t ebp; @@ -29,7 +29,7 @@ struct reg { /* Interrupt info. Pushed by `push byte`. */ uint32_t intno; uint32_t err; - /* Pushed by the processor. */ + /* Pushed by the CPU. */ uint32_t eip; uint32_t cs; uint32_t eflags; @@ -37,63 +37,63 @@ struct reg { uint32_t ss; }; -/* `kernel_main` calls this. */ -extern void idt_init(void); +/* Called by `kmain`. */ +void idt_init(void); -/* Called by drivers */ -extern void int_handler(struct reg *); -extern void int_add_handler(uint8_t, void (*)(struct reg *)); +/* Called by drivers. */ +void int_handler(struct reg *); +void int_add_handler(uint8_t, void (*)(struct reg *)); /* The first 32 interrupts are reserved for exceptions. */ -extern void ex0(void); -extern void ex1(void); -extern void ex2(void); -extern void ex3(void); -extern void ex4(void); -extern void ex5(void); -extern void ex6(void); -extern void ex7(void); -extern void ex8(void); -extern void ex9(void); -extern void ex10(void); -extern void ex11(void); -extern void ex12(void); -extern void ex13(void); -extern void ex14(void); -extern void ex15(void); -extern void ex16(void); -extern void ex17(void); -extern void ex18(void); -extern void ex19(void); -extern void ex20(void); -extern void ex21(void); -extern void ex22(void); -extern void ex23(void); -extern void ex24(void); -extern void ex25(void); -extern void ex26(void); -extern void ex27(void); -extern void ex28(void); -extern void ex29(void); -extern void ex30(void); -extern void ex31(void); +void ex0(void); +void ex1(void); +void ex2(void); +void ex3(void); +void ex4(void); +void ex5(void); +void ex6(void); +void ex7(void); +void ex8(void); +void ex9(void); +void ex10(void); +void ex11(void); +void ex12(void); +void ex13(void); +void ex14(void); +void ex15(void); +void ex16(void); +void ex17(void); +void ex18(void); +void ex19(void); +void ex20(void); +void ex21(void); +void ex22(void); +void ex23(void); +void ex24(void); +void ex25(void); +void ex26(void); +void ex27(void); +void ex28(void); +void ex29(void); +void ex30(void); +void ex31(void); /* IRQs */ -extern void irq0(void); -extern void irq1(void); -extern void irq2(void); -extern void irq3(void); -extern void irq4(void); -extern void irq5(void); -extern void irq6(void); -extern void irq7(void); -extern void irq8(void); -extern void irq9(void); -extern void irq10(void); -extern void irq11(void); -extern void irq12(void); -extern void irq13(void); -extern void irq14(void); -extern void irq15(void); +void irq0(void); +void irq1(void); +void irq2(void); +void irq3(void); +void irq4(void); +void irq5(void); +void irq6(void); +void irq7(void); +void irq8(void); +void irq9(void); +void irq10(void); +void irq11(void); +void irq12(void); +void irq13(void); +void irq14(void); +void irq15(void); #endif /* _KERNEL_IDT_H_ */ diff --git a/boot/int.asm b/boot/int.asm @@ -1,7 +1,7 @@ -; C functions defined in `idt.h`. +; Defined in `idt.h`. [extern int_handler] -; ISRs +; Exceptions global ex0 global ex1 global ex2 @@ -53,339 +53,70 @@ global irq13 global irq14 global irq15 -; ================== EXCEPTIONS ====================== - -; 0 - Division By Zero -ex0: - cli - push byte 0 - push byte 0 - jmp int_common_stub - -; 1 - Debug -ex1: - cli - push byte 0 - push byte 1 - jmp int_common_stub - -; 2 - Non Maskable Interrupt -ex2: - cli - push byte 0 - push byte 2 - jmp int_common_stub - -; 3 - Breakpoint -ex3: - cli - push byte 0 - push byte 3 - jmp int_common_stub - -; 4 - Into Detected Overflow -ex4: - cli - push byte 0 - push byte 4 - jmp int_common_stub - -; 5 - Out of Bounds -ex5: - cli - push byte 0 - push byte 5 - jmp int_common_stub - -; 6 - Invalid Opcode -ex6: - cli - push byte 0 - push byte 6 - jmp int_common_stub - -; 7 - No Coprocessor -ex7: - cli - push byte 0 - push byte 7 - jmp int_common_stub - -; 8 - Double Fault (with error code) -ex8: - cli - push byte 8 - jmp int_common_stub - -; 9 - Coprocessor Segment Overrrun -ex9: - cli - push byte 0 - push byte 9 - jmp int_common_stub - -; 10 - Bad TSS (with error code) -ex10: - cli - push byte 10 - jmp int_common_stub - -; 11 - Segment Not Present (with error code) -ex11: - cli - push byte 11 - jmp int_common_stub - -; 12 - Stack Fault (with error code) -ex12: - cli - push byte 12 - jmp int_common_stub - -; 13 - General Protection Fault (with error code) -ex13: - cli - push byte 13 - jmp int_common_stub - -; 14 - Page Fault (with error code) -ex14: - cli - push byte 14 - jmp int_common_stub - -; 15 - Unkown Interrupt -ex15: - cli - push byte 0 - push byte 15 - jmp int_common_stub - -; 16 - Coprocessor Fault -ex16: - cli - push byte 0 - push byte 16 - jmp int_common_stub - -; 17 - Alignment Check (486+) -ex17: - cli - push byte 0 - push byte 17 - jmp int_common_stub - -; 18 - Machine Check (Pentium/586+) -ex18: - cli - push byte 0 - push byte 18 - jmp int_common_stub - -; 19 - Reserved -ex19: - cli - push byte 0 - push byte 19 - jmp int_common_stub - -; 20 - Reserved -ex20: - cli - push byte 0 - push byte 20 - jmp int_common_stub - -; 21 - Reserved -ex21: - cli - push byte 0 - push byte 21 - jmp int_common_stub - -; 22 - Reserved -ex22: - cli - push byte 0 - push byte 22 - jmp int_common_stub - -; 23 - Reserved -ex23: - cli - push byte 0 - push byte 23 - jmp int_common_stub - -; 24 - Reserved -ex24: - cli - push byte 0 - push byte 24 - jmp int_common_stub - -; 25 - Reserved -ex25: - cli - push byte 0 - push byte 25 - jmp int_common_stub - -; 26 - Reserved -ex26: - cli - push byte 0 - push byte 26 - jmp int_common_stub - -; 27 - Reserved -ex27: - cli - push byte 0 - push byte 27 - jmp int_common_stub - -; 28 - Reserved -ex28: - cli - push byte 0 - push byte 28 - jmp int_common_stub - -; 29 - Reserved -ex29: - cli - push byte 0 - push byte 29 - jmp int_common_stub - -; 30 - Reserved -ex30: - cli - push byte 0 - push byte 30 - jmp int_common_stub - -; 31 - Reserved -ex31: - cli - push byte 0 - push byte 31 - jmp int_common_stub - -; ================== IRQ ====================== - -; 32 - Programmable Interrupt Timer -irq0: - cli - push byte 0 - push byte 32 - jmp int_common_stub - -; 33 - Keyboard -irq1: - cli - push byte 0 - push byte 33 - jmp int_common_stub - -; 34 Cascade (used internally by the two PICs, never raised) -irq2: - cli - push byte 0 - push byte 34 - jmp int_common_stub - -; 35 - COM2 (if enabled) -irq3: - cli - push byte 0 - push byte 35 - jmp int_common_stub - -; 36 - COM1 (if enabled) -irq4: - cli - push byte 0 - push byte 36 - jmp int_common_stub - -; 37 - LPT2 (if enabled) -irq5: - cli - push byte 0 - push byte 37 - jmp int_common_stub - -; 38 - Floppy Disk -irq6: - cli - push byte 0 - push byte 38 - jmp int_common_stub - -; 39 - LPT1 -irq7: - cli - push byte 0 - push byte 39 - jmp int_common_stub - -; 40 - CMOS real-time clock (if enabled) -irq8: - cli - push byte 0 - push byte 40 - jmp int_common_stub - -; 41 - Peripherals / Legacy SCSI / NIC -irq9: - cli - push byte 0 - push byte 41 - jmp int_common_stub - -; 42 - Peripherals / SCSI / NIC -irq10: - cli - push byte 0 - push byte 42 - jmp int_common_stub - -; 43 - Peripherals / SCSI / NIC -irq11: - cli - push byte 0 - push byte 43 - jmp int_common_stub - -; 44 - PS2 Mouse -irq12: - cli - push byte 0 - push byte 44 - jmp int_common_stub - -; 45 - FPU / Coprocessor / Inter-processor -irq13: - cli - push byte 0 - push byte 45 - jmp int_common_stub - -; 46 - Primary ATA Hard Disk -irq14: - cli - push byte 0 - push byte 46 - jmp int_common_stub - -; 47 - Secondary ATA Hard Disk -irq15: - cli - push byte 0 - push byte 47 - jmp int_common_stub +%macro intdef_noerr 1 + cli + push byte 0 + push byte %1 + jmp int_common_stub +%endmacro + +%macro intdef_err 1 + cli + push byte 0 + push byte %1 + jmp int_common_stub +%endmacro + +; Exceptions +ex0: intdef_noerr 0 ; Division By Zero +ex1: intdef_noerr 1 ; Debug +ex2: intdef_noerr 2 ; Non Maskable Interrupt +ex3: intdef_noerr 3 ; Breakpoint +ex4: intdef_noerr 4 ; Into Detected Overflow +ex5: intdef_noerr 5 ; Out of Bounds +ex6: intdef_noerr 6 ; Invalid Opcode +ex7: intdef_noerr 7 ; No Coprocessor +ex8: intdef_err 8 ; Double Fault (with error code) +ex9: intdef_noerr 9 ; Coprocessor Segment Overrrun +ex10: intdef_err 10 ; Bad TSS (with error code) +ex11: intdef_err 11 ; Segment Not Present (with error code) +ex12: intdef_err 12 ; Stack Fault (with error code) +ex13: intdef_err 13 ; General Protection Fault (with error code) +ex14: intdef_err 14 ; Page Fault (with error code) +ex15: intdef_noerr 15 ; Unkown Interrupt +ex16: intdef_noerr 16 ; Coprocessor Fault +ex17: intdef_noerr 17 ; Alignment Check (486+) +ex18: intdef_noerr 18 ; Machine Check (Pentium/586+) +ex19: intdef_noerr 19 ; Reserved +ex20: intdef_noerr 20 ; Reserved +ex21: intdef_noerr 21 ; Reserved +ex22: intdef_noerr 22 ; Reserved +ex23: intdef_noerr 23 ; Reserved +ex24: intdef_noerr 24 ; Reserved +ex25: intdef_noerr 25 ; Reserved +ex26: intdef_noerr 26 ; Reserved +ex27: intdef_noerr 27 ; Reserved +ex28: intdef_noerr 28 ; Reserved +ex29: intdef_noerr 29 ; Reserved +ex30: intdef_noerr 30 ; Reserved +ex31: intdef_noerr 31 ; Reserved +; IRQs +irq0: intdef_noerr 32 ; Programmable Interrupt Timer +irq1: intdef_noerr 33 ; Keyboard +irq2: intdef_noerr 34 ; Cascade (used internally by the two PICs, never raised) +irq3: intdef_noerr 35 ; COM2 (if enabled) +irq4: intdef_noerr 36 ; COM1 (if enabled) +irq5: intdef_noerr 37 ; LPT2 (if enabled) +irq6: intdef_noerr 38 ; Floppy Disk +irq7: intdef_noerr 39 ; LPT1 +irq8: intdef_noerr 40 ; CMOS real-time clock (if enabled) +irq9: intdef_noerr 41 ; Peripherals / Legacy SCSI / NIC +irq10: intdef_noerr 42 ; Peripherals / SCSI / NIC +irq11: intdef_noerr 43 ; Peripherals / SCSI / NIC +irq12: intdef_noerr 44 ; PS2 Mouse +irq13: intdef_noerr 45 ; FPU / Coprocessor / Inter-processor +irq14: intdef_noerr 46 ; Primary ATA Hard Disk +irq15: intdef_noerr 47 ; Secondary ATA Hard Disk ; Save the processor state, call the C interrupt handler and restore the ; stack frame. diff --git a/boot/kbd.c b/boot/kbd.c @@ -54,10 +54,6 @@ kbd_callback(struct reg *r) (void)r; } -/* - * Send `kbd_callback` to the `irq_routines` array to be called - * for IRQ 1. - */ void kbd_init(void) { diff --git a/boot/kbd.h b/boot/kbd.h @@ -3,6 +3,6 @@ #include "extern.h" -extern void kbd_init(void); +void kbd_init(void); #endif /* _KERNEL_KBD_H_ */ diff --git a/boot/kmain.c b/boot/kmain.c @@ -10,7 +10,7 @@ kmain(void) idt_init(); timer_init(50); kbd_init(); - /* Enable interrupts so that the handlers can work now. */ __asm__ __volatile__ ("sti"); - __asm__ __volatile__ ("hlt"); + + for (;;); } diff --git a/boot/loader.asm b/boot/loader.asm @@ -1,6 +0,0 @@ -[bits 32] -[extern kmain] - -_start: - call kmain - jmp $ diff --git a/boot/printf.c b/boot/printf.c @@ -0,0 +1,88 @@ +#include "extern.h" + +static char * +itoa(int n, char *buf, int base) +{ + (void)n; + (void)base; + + return buf; +} + +int +vsprintf(char *buf, const char *fmt, va_list args) +{ + char *str, *s; + int base, i, n; + + for (str = buf; *fmt != '\0'; fmt++) { + base = 10; + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + if (*fmt == '%') { + switch (*(++fmt)) { + case 'c': + *str++ = (unsigned char)va_arg(args, int); + continue; + case 's': + s = va_arg(args, char *); + n = strlen(s); + for (i = 0; i < n; i++) + *str++ = *s++; + continue; + case 'p': + continue; + case 'd': /* FALLTHROUGH */ + case 'i': + n = va_arg(args, int); + break; + case 'u': + n = va_arg(args, unsigned int); + break; + case 'o': + base = 8; + break; + case 'X': + base = 16; + break; + case '%': + *str++ = '%'; + continue; + } + str = itoa(n, str, base); + } + } + *str = '\0'; + + return str - buf; +} + +int +sprintf(char *buf, const char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(buf, fmt, args); + va_end(args); + + return n; +} + +int +printf(const char *fmt, ...) +{ + char buf[BUFSIZ]; + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(buf, fmt, args); + va_end(args); + tty_write(buf); + + return n; +} diff --git a/boot/stdarg.h b/boot/stdarg.h @@ -0,0 +1,14 @@ +#ifndef _KERNEL_STDARG_H +#define _KERNEL_STDARG_H + +#ifndef _VA_LIST_DECLARED +#define _VA_LIST_DECLARED +typedef __va_list va_list; +#endif /* _VA_LIST_DECLARED */ + +#define va_start(ap, last) __builtin_va_start((ap), (last)) +#define va_arg(ap, type) __builtin_va_arg((ap), type) +#define va_copy(dest, src) __builtin_va_copy((dest), (src)) +#define va_end(ap) __builtin_va_end(ap) + +#endif /* _KERNEL_STDARG_H */ diff --git a/boot/string.c b/boot/string.c @@ -8,7 +8,6 @@ memset(void *dst, int v, size_t len) dst0 = dst; while (len--) *dst0++ = v; - return dst; } @@ -23,7 +22,6 @@ memcpy(void *dst, const void *src, size_t len) while (len--) *dst0++ = *src0++; - return dst; } diff --git a/boot/string.h b/boot/string.h @@ -3,9 +3,9 @@ #include <stddef.h> -extern void *memset(void *, int, size_t); -extern void *memcpy(void *, const void *, size_t); -extern size_t strlen(const char *); -extern int strcmp(const char *, const char *); +void *memset(void *, int, size_t); +void *memcpy(void *, const void *, size_t); +size_t strlen(const char *); +int strcmp(const char *, const char *); #endif /* _KERNEL_STRING_H_ */ diff --git a/boot/timer.h b/boot/timer.h @@ -1,6 +1,6 @@ #ifndef _KERNEL_TIMER_H_ #define _KERNEL_TIMER_H_ -extern void timer_init(uint32_t); +void timer_init(uint32_t); #endif /* _KERNEL_TIMER_H_ */ diff --git a/boot/tty.h b/boot/tty.h @@ -36,12 +36,12 @@ enum vga_color { VGA_WHITE, }; -extern void tty_clear(void); -extern void tty_putc(char); -extern void tty_write(const char *); -extern void tty_curs_enable(uint8_t, uint8_t); -extern void tty_curs_disable(void); -extern void tty_curs_setpos(int, int); -extern uint16_t tty_curs_getpos(void); +void tty_clear(void); +void tty_putc(char); +void tty_write(const char *); +void tty_curs_enable(uint8_t, uint8_t); +void tty_curs_disable(void); +void tty_curs_setpos(int, int); +uint16_t tty_curs_getpos(void); #endif /* _KERNEL_TTY_H_ */ diff --git a/hier b/hier @@ -0,0 +1,11 @@ +/bin/ + boot/ +/dev/ +/sys/ + include/ + dev/ + kernel/ + sys/ + lib/ + src/ +/usr