From 0921a33fc9f3724cb36a03a24b58b0a5bfc519b1 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Mon, 1 Dec 2014 17:24:38 +0100 Subject: Advance HH, GDT, IDT (details below) - Implement higher-half in loader with paging (using 4Mb pages) - Add GDT installation code - Add IDT installation code (spend a loong time debugging the ISRs!) - Add CDROM generation scripts - Add scripts to launch bochs (debug) and qemu (debug) --- kernel/Makefile | 8 +- kernel/config.h | 1 + kernel/include/dbglog.h | 2 + kernel/include/gdt.h | 64 ++++++++++++++++ kernel/include/idt.h | 40 ++++++++++ kernel/include/multiboot.h | 1 + kernel/include/printf.h | 1 + kernel/include/string.h | 2 + kernel/include/sys.h | 5 +- kernel/l0/dbglog.c | 2 + kernel/l0/gdt.c | 35 +++++++++ kernel/l0/idt.c | 187 +++++++++++++++++++++++++++++++++++++++++++++ kernel/l0/interrupt.s | 126 ++++++++++++++++++++++++++++++ kernel/l0/kmain.c | 16 ++++ kernel/l0/loader.s | 106 +++++++++++++------------ kernel/launch-qemu.sh | 3 - kernel/lib/printf.c | 17 ++++- kernel/linker.ld | 34 +++++---- 18 files changed, 577 insertions(+), 73 deletions(-) create mode 100644 kernel/include/gdt.h create mode 100644 kernel/include/idt.h create mode 100644 kernel/l0/gdt.c create mode 100644 kernel/l0/idt.c create mode 100644 kernel/l0/interrupt.s delete mode 100755 kernel/launch-qemu.sh (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index 04721ba..43b8c7e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,15 +1,17 @@ AS = nasm -ASFLAGS = -felf +ASFLAGS = -felf -g CC = i586-elf-gcc -CFLAGS = -ffreestanding -O2 -std=gnu99 -Wall -Wextra -I . -I ./include +CFLAGS = -ffreestanding -O2 -std=gnu99 -Wall -Wextra -I . -I ./include -g # CXX = i586-elf-g++ # CXFLAGS = -ffreestanding -O3 -Wall -Wextra -I . -I ./include -fno-exceptions -fno-rtti LD = i586-elf-gcc LDFLAGS = -T linker.ld -ffreestanding -O2 -nostdlib -lgcc -OBJ = lib/string.o lib/printf.o l0/loader.o l0/kmain.o l0/dbglog.o l0/sys.o +OBJ = lib/string.o lib/printf.o \ + l0/loader.o l0/kmain.o l0/dbglog.o l0/sys.o \ + l0/gdt.o l0/idt.o l0/interrupt.o OUT = kernel.bin all: $(OUT) diff --git a/kernel/config.h b/kernel/config.h index 5ea242e..da2956a 100644 --- a/kernel/config.h +++ b/kernel/config.h @@ -25,3 +25,4 @@ extern char k_highhalf_addr; // defined in linker script : 0xC0000000 #define DBGLOG_TO_SCREEN +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/include/dbglog.h b/kernel/include/dbglog.h index c8904c6..2f670e8 100644 --- a/kernel/include/dbglog.h +++ b/kernel/include/dbglog.h @@ -5,3 +5,5 @@ void dbglog_setup(); void dbg_print(const char* str); void dbg_printf(const char* format, ...); + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/include/gdt.h b/kernel/include/gdt.h new file mode 100644 index 0000000..cd66676 --- /dev/null +++ b/kernel/include/gdt.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include + +/* The GDT is one of the x86's descriptor tables. It is used for memory segmentation. + Here, we don't use segmentation to separate processes from one another (this is done with paging). + We only use segmentation to make the difference between kernel mode (ring 3) and user mode (ring 0) */ + +/* One entry of the table */ +struct gdt_entry { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t granularity; + uint8_t base_high; +} __attribute__((packed)); +typedef struct gdt_entry gdt_entry_t; + +/* Structure defining the whole table : address and size (in bytes). */ +struct gdt_ptr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); +typedef struct gdt_ptr gdt_ptr_t; + +/* The TSS is used for hardware multitasking. + We don't use that, but we still need a TSS so that user mode process exceptions + can be handled correctly by the kernel. */ +struct tss_entry { + uint32_t prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list. + uint32_t esp0; // The stack pointer to load when we change to kernel mode. + uint32_t ss0; // The stack segment to load when we change to kernel mode. + uint32_t esp1; // Unused... + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; // The value to load into ES when we change to kernel mode. + uint32_t cs; // The value to load into CS when we change to kernel mode. + uint32_t ss; // The value to load into SS when we change to kernel mode. + uint32_t ds; // The value to load into DS when we change to kernel mode. + uint32_t fs; // The value to load into FS when we change to kernel mode. + uint32_t gs; // The value to load into GS when we change to kernel mode. + uint32_t ldt; // Unused... + uint16_t trap; + uint16_t iomap_base; +} __attribute__((packed)); +typedef struct tss_entry tss_entry_t; + +void gdt_init(); + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/include/idt.h b/kernel/include/idt.h new file mode 100644 index 0000000..5730f5e --- /dev/null +++ b/kernel/include/idt.h @@ -0,0 +1,40 @@ +#pragma once + +/* The IDT is the system descriptor table that tells the CPU what to do when an interrupt fires. + There are three categories of interrupts : + - Exceptions ; eg page fault, divide by 0 + - IRQ : interrupts caused by hardware + - System calls : when an applications asks the system to do something */ + +#include + +struct idt_entry { + uint16_t base_lo; //Low part of address to jump to + uint16_t sel; //Kernel segment selector + uint8_t always0; + uint8_t flags; //Flags + uint16_t base_hi; //High part of address to jump to +} __attribute__((packed)); +typedef struct idt_entry idt_entry_t; + +struct idt_ptr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); +typedef struct idt_ptr idt_ptr_t; + +struct registers { + uint32_t ds; // Data segment selector + uint32_t edi, esi, ebp, useless_esp, 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 struct registers registers_t; + +typedef void (*isr_handler_t)(registers_t*); + +void idt_init(); +//void idt_handleIrq(int number, isr_handler_t func); //Set IRQ handler + + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/include/multiboot.h b/kernel/include/multiboot.h index 8fd9dee..581337a 100644 --- a/kernel/include/multiboot.h +++ b/kernel/include/multiboot.h @@ -60,3 +60,4 @@ struct memory_map_t { unsigned long type; }; +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/include/printf.h b/kernel/include/printf.h index b37816d..b4e1c1b 100644 --- a/kernel/include/printf.h +++ b/kernel/include/printf.h @@ -7,3 +7,4 @@ int snprintf(char* s, size_t n, const char* format, ...); int vsnprintf(char* s, size_t n, const char* format, va_list arg); +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/include/string.h b/kernel/include/string.h index 3cb0db3..682b25a 100644 --- a/kernel/include/string.h +++ b/kernel/include/string.h @@ -13,3 +13,5 @@ char *strchr(const char *str, char c); char *strcpy(char *dest, const char *src); char *strcat(char *dest, const char *src); int strcmp(const char *s1, const char *s2); + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/include/sys.h b/kernel/include/sys.h index 85cbee6..319cbef 100644 --- a/kernel/include/sys.h +++ b/kernel/include/sys.h @@ -7,8 +7,11 @@ void outw(uint16_t port, uint16_t value); uint8_t inb(uint16_t port); uint16_t inw(uint16_t port); - void panic(const char* message, const char* file, int line); void panic_assert(const char* assertion, const char* file, int line); #define PANIC(s) panic(s, __FILE__, __LINE__); #define ASSERT(s) { if (!(s)) panic_assert(#s, __FILE__, __LINE__); } + +#define BOCHS_BREAKPOINT asm volatile("xchg %bx, %bx") + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/l0/dbglog.c b/kernel/l0/dbglog.c index 47098a0..377e6c8 100644 --- a/kernel/l0/dbglog.c +++ b/kernel/l0/dbglog.c @@ -149,3 +149,5 @@ void dbg_printf(const char* fmt, ...) { dbg_print(buffer); } + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/l0/gdt.c b/kernel/l0/gdt.c new file mode 100644 index 0000000..9ed5210 --- /dev/null +++ b/kernel/l0/gdt.c @@ -0,0 +1,35 @@ +#include +#include + +#define GDT_ENTRIES 6 // The contents of each entry is defined in gdt_init. + +static gdt_entry_t gdt_entries[GDT_ENTRIES]; +static gdt_ptr_t gdt_ptr; + +/* For internal use only. Writes one entry of the GDT with given parameters. */ +static void gdt_setGate(int 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; +} + +/* Write data to the GDT and enable it. */ +void gdt_init() { + gdt_ptr.limit = (sizeof(gdt_entry_t) * GDT_ENTRIES) - 1; + gdt_ptr.base = (uint32_t)&gdt_entries; + + gdt_setGate(0, 0, 0, 0, 0); //Null segment + gdt_setGate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); //Kernel code segment 0x08 + gdt_setGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Kernel data segment 0x10 + gdt_setGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment 0x18 + gdt_setGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment 0x20 + + asm volatile ("lgdt %0"::"m"(gdt_ptr):"memory"); +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/l0/idt.c b/kernel/l0/idt.c new file mode 100644 index 0000000..a0e19dd --- /dev/null +++ b/kernel/l0/idt.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include + +void isr0(); +void isr1(); +void isr2(); +void isr3(); +void isr4(); +void isr5(); +void isr6(); +void isr7(); +void isr8(); +void isr9(); +void isr10(); +void isr11(); +void isr12(); +void isr13(); +void isr14(); +void isr15(); +void isr16(); +void isr17(); +void isr18(); +void isr19(); +void isr20(); +void isr21(); +void isr22(); +void isr23(); +void isr24(); +void isr25(); +void isr26(); +void isr27(); +void isr28(); +void isr29(); +void isr30(); +void isr31(); + +void irq0(); +void irq1(); +void irq2(); +void irq3(); +void irq4(); +void irq5(); +void irq6(); +void irq7(); +void irq8(); +void irq9(); +void irq10(); +void irq11(); +void irq12(); +void irq13(); +void irq14(); +void irq15(); + +void syscall64(); + +// ************************************************************ +// Handler code + +static idt_entry_t idt_entries[256]; +static idt_ptr_t idt_ptr; + +static isr_handler_t irq_handlers[16] = {0}; + +/* Called in idt_.asm when an exception fires (interrupt 0 to 31). + Tries to handle the exception, panics if fails. */ +void idt_isrHandler(registers_t *regs) { + dbg_printf("/ ISR %i\n", regs->int_no); + dbg_printf("| EAX: 0x%p EBX: 0x%p ECX: 0x%p EDX: 0x%p\n", regs->eax, regs->ebx, regs->ecx, regs->edx); + dbg_printf("| EDI: 0x%p ESI: 0x%p ESP: 0x%p EBP: 0x%p\n", regs->edi, regs->esi, regs->esp, regs->ebp); + dbg_printf("| EIP: 0x%p CS : 0x%p DS : 0x%p SS : 0x%p\n", regs->eip, regs->cs, regs->ds, regs->ss); + dbg_printf("\\ EFl: 0x%p I# : 0x%p Err: 0x%p\n", regs->eflags, regs->int_no, regs->err_code); +} + +/* Called in interrupt.asm when an IRQ fires (interrupt 32 to 47) + Possibly wakes up a thread that was waiting, possibly calls a handler. */ +void idt_irqHandler(registers_t *regs) { + if (regs->err_code > 7) { + outb(0xA0, 0x20); + } + outb(0x20, 0x20); + + dbg_printf("IRQ %i\n", regs->err_code); + if (irq_handlers[regs->err_code] != 0) { + irq_handlers[regs->err_code](regs); + } +} + +/* syscall handler */ +void idt_syscallHandler(registers_t *regs) { + dbg_printf("Syscall %i\n", regs->int_no); + // do nothing... +} + +/* For internal use only. Sets up an entry of the IDT with given parameters. */ +static void idt_setGate(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; + idt_entries[num].flags = flags | 0x60; +} + +/* Remaps the IRQs. Sets up the IDT. */ +void idt_init() { + memset((uint8_t*)&idt_entries, 0, sizeof(idt_entry_t) * 256); + + //Remap the IRQ table + 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); + + idt_setGate(0, (int32_t)isr0, 0x08, 0x8E); + idt_setGate(1, (int32_t)isr1, 0x08, 0x8E); + idt_setGate(2, (int32_t)isr2, 0x08, 0x8E); + idt_setGate(3, (int32_t)isr3, 0x08, 0x8E); + idt_setGate(4, (int32_t)isr4, 0x08, 0x8E); + idt_setGate(5, (int32_t)isr5, 0x08, 0x8E); + idt_setGate(6, (int32_t)isr6, 0x08, 0x8E); + idt_setGate(7, (int32_t)isr7, 0x08, 0x8E); + idt_setGate(8, (int32_t)isr8, 0x08, 0x8E); + idt_setGate(9, (int32_t)isr9, 0x08, 0x8E); + idt_setGate(10, (int32_t)isr10, 0x08, 0x8E); + idt_setGate(11, (int32_t)isr11, 0x08, 0x8E); + idt_setGate(12, (int32_t)isr12, 0x08, 0x8E); + idt_setGate(13, (int32_t)isr13, 0x08, 0x8E); + idt_setGate(14, (int32_t)isr14, 0x08, 0x8E); + idt_setGate(15, (int32_t)isr15, 0x08, 0x8E); + idt_setGate(16, (int32_t)isr16, 0x08, 0x8E); + idt_setGate(17, (int32_t)isr17, 0x08, 0x8E); + idt_setGate(18, (int32_t)isr18, 0x08, 0x8E); + idt_setGate(19, (int32_t)isr19, 0x08, 0x8E); + idt_setGate(20, (int32_t)isr20, 0x08, 0x8E); + idt_setGate(21, (int32_t)isr21, 0x08, 0x8E); + idt_setGate(22, (int32_t)isr22, 0x08, 0x8E); + idt_setGate(23, (int32_t)isr23, 0x08, 0x8E); + idt_setGate(24, (int32_t)isr24, 0x08, 0x8E); + idt_setGate(25, (int32_t)isr25, 0x08, 0x8E); + idt_setGate(26, (int32_t)isr26, 0x08, 0x8E); + idt_setGate(27, (int32_t)isr27, 0x08, 0x8E); + idt_setGate(28, (int32_t)isr28, 0x08, 0x8E); + idt_setGate(29, (int32_t)isr29, 0x08, 0x8E); + idt_setGate(30, (int32_t)isr30, 0x08, 0x8E); + idt_setGate(31, (int32_t)isr31, 0x08, 0x8E); + + idt_setGate(32, (int32_t)irq0, 0x08, 0x8E); + idt_setGate(33, (int32_t)irq1, 0x08, 0x8E); + idt_setGate(34, (int32_t)irq2, 0x08, 0x8E); + idt_setGate(35, (int32_t)irq3, 0x08, 0x8E); + idt_setGate(36, (int32_t)irq4, 0x08, 0x8E); + idt_setGate(37, (int32_t)irq5, 0x08, 0x8E); + idt_setGate(38, (int32_t)irq6, 0x08, 0x8E); + idt_setGate(39, (int32_t)irq7, 0x08, 0x8E); + idt_setGate(40, (int32_t)irq8, 0x08, 0x8E); + idt_setGate(41, (int32_t)irq9, 0x08, 0x8E); + idt_setGate(42, (int32_t)irq10, 0x08, 0x8E); + idt_setGate(43, (int32_t)irq11, 0x08, 0x8E); + idt_setGate(44, (int32_t)irq12, 0x08, 0x8E); + idt_setGate(45, (int32_t)irq13, 0x08, 0x8E); + idt_setGate(46, (int32_t)irq14, 0x08, 0x8E); + idt_setGate(47, (int32_t)irq15, 0x08, 0x8E); + + idt_setGate(64, (int32_t)syscall64, 0x08, 0x8E); + + idt_ptr.limit = (sizeof(idt_entry_t) * 256) - 1; + idt_ptr.base = (uint32_t)&idt_entries; + + asm volatile ("lidt %0"::"m"(idt_ptr):"memory"); +} + +/* Sets up an IRQ handler for given IRQ. */ +void idt_handleIrq(int number, isr_handler_t func) { + if (number < 16 && number >= 0) { + irq_handlers[number] = func; + } +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/l0/interrupt.s b/kernel/l0/interrupt.s new file mode 100644 index 0000000..ddd1e76 --- /dev/null +++ b/kernel/l0/interrupt.s @@ -0,0 +1,126 @@ +;************************************************************************************ + +%macro COMMONSTUB 1 +[EXTERN idt_%1Handler] +%1_common_stub: + + pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax + + mov ax, ds ; Lower 16-bits of eax = ds. + push eax ; save the data segment descriptor + + mov ax, 0x10 ; load the kernel data segment descriptor + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; pass the register data structure as a pointer to the function + ; (passing it directly results in GCC trashing the data when doing optimisations) + mov eax, esp + push eax + call idt_%1Handler + add esp, 4 + + pop eax ; reload the original data segment descriptor + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + popa ; Pops edi,esi,ebp... + add esp, 8 ; Cleans up the pushed error code and pushed ISR number + iret +%endmacro + +COMMONSTUB isr +COMMONSTUB irq +COMMONSTUB syscall + +;************************************************************************************ + +%macro ISR_NOERRCODE 1 ; define a macro, taking one parameter + [GLOBAL isr%1] ; %1 accesses the first parameter. + isr%1: + push byte 0 + push byte %1 + jmp isr_common_stub +%endmacro + +%macro ISR_ERRCODE 1 + [GLOBAL isr%1] + isr%1: + push byte %1 + jmp isr_common_stub +%endmacro + +%macro IRQ 2 + [GLOBAL irq%1] + irq%1: + push byte %1 ;push irq number + push byte %2 ;push int number + jmp irq_common_stub +%endmacro + +%macro SYSCALL 1 + [GLOBAL syscall%1] + syscall%1: + cli + push byte 0 + push byte %1 + jmp syscall_common_stub +%endmacro + +ISR_NOERRCODE 0 +ISR_NOERRCODE 1 +ISR_NOERRCODE 2 +ISR_NOERRCODE 3 +ISR_NOERRCODE 4 +ISR_NOERRCODE 5 +ISR_NOERRCODE 6 +ISR_NOERRCODE 7 +ISR_ERRCODE 8 +ISR_NOERRCODE 9 +ISR_ERRCODE 10 +ISR_ERRCODE 11 +ISR_ERRCODE 12 +ISR_ERRCODE 13 +ISR_ERRCODE 14 +ISR_NOERRCODE 15 +ISR_NOERRCODE 16 +ISR_NOERRCODE 17 +ISR_NOERRCODE 18 +ISR_NOERRCODE 19 +ISR_NOERRCODE 20 +ISR_NOERRCODE 21 +ISR_NOERRCODE 22 +ISR_NOERRCODE 23 +ISR_NOERRCODE 24 +ISR_NOERRCODE 25 +ISR_NOERRCODE 26 +ISR_NOERRCODE 27 +ISR_NOERRCODE 28 +ISR_NOERRCODE 29 +ISR_NOERRCODE 30 +ISR_NOERRCODE 31 + +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 + +SYSCALL 64 + +; vim: set ts=4 sw=4 tw=0 noet : diff --git a/kernel/l0/kmain.c b/kernel/l0/kmain.c index 74945e4..854a2b7 100644 --- a/kernel/l0/kmain.c +++ b/kernel/l0/kmain.c @@ -2,6 +2,9 @@ #include #include #include + +#include +#include void kmain(struct multiboot_info_t *mbd, int32_t mb_magic) { dbglog_setup(); @@ -9,6 +12,19 @@ void kmain(struct multiboot_info_t *mbd, int32_t mb_magic) { dbg_printf("Hello, kernel World!\n"); dbg_printf("This is %s, version %s.\n", OS_NAME, OS_VERSION); + ASSERT(mb_magic == MULTIBOOT_BOOTLOADER_MAGIC); + + gdt_init(); dbg_printf("GDT set up.\n"); + + idt_init(); dbg_printf("IDT set up.\n"); + + asm volatile("int $0x3"); + + size_t total_ram = ((mbd->mem_upper + mbd->mem_lower) * 1024); + dbg_printf("Total ram: %d Kb\n", total_ram / 1024); + // paging_init(totalRam); + PANIC("Reached kmain end! Falling off the edge."); } +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/kernel/l0/loader.s b/kernel/l0/loader.s index a31fcf5..0f57549 100644 --- a/kernel/l0/loader.s +++ b/kernel/l0/loader.s @@ -1,69 +1,79 @@ -[EXTERN k_highhalf_addr] - +[EXTERN kmain] ; kmain is defined in kmain.c [GLOBAL loader] ; making entry point visible to linker -[EXTERN kmain] ; kmain is defined in kmain.c +; higher-half kernel setup +K_HIGHHALF_ADDR equ 0xC0000000 +K_PAGE_NUMBER equ (K_HIGHHALF_ADDR >> 22) ; loader stack size -LOADER_STACK_SIZE equ 0x8000 ; 8Kb +LOADER_STACK_SIZE equ 0x8000 ; 8Kb ; setting up the Multiboot header - see GRUB docs for details -MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries -MEMINFO equ 1<<1 ; provide memory map -FLAGS equ MODULEALIGN | MEMINFO ; this is the Multiboot 'flag' field -MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header -CHECKSUM equ -(MAGIC + FLAGS) ; checksum required - -section .text +MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries +MEMINFO equ 1<<1 ; provide memory map +FLAGS equ MODULEALIGN | MEMINFO ; this is the Multiboot 'flag' field +MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header +CHECKSUM equ -(MAGIC + FLAGS) ; checksum required + +[section .setup] align 4 -MultiBootHeader: - dd MAGIC - dd FLAGS - dd CHECKSUM - -section .setup -loader: ;here, we load our false GDT, used for having the kernel in higher half - lgdt [trickgdt] - mov cx, 0x10; - mov ds, cx; - mov es, cx; - mov fs, cx; - mov gs, cx; - mov ss, cx; - - jmp 0x08:higherhalf - -section .text -higherhalf: ; now we're running in higher half - mov esp, stack_top ; set up the stack +multiboot_header: + dd MAGIC + dd FLAGS + dd CHECKSUM - push eax ; pass Multiboot magic number - add ebx, k_highhalf_addr ; update the MB info structure so that it is in the new seg - push ebx ; pass Multiboot info structure +loader: + ; setup the boot page directory used for higher-half + mov ecx, boot_pagedir + mov cr3, ecx - call kmain ; call kernel proper + ; Set PSE bit in CR4 to enable 4MB pages. + mov ecx, cr4 + or ecx, 0x00000010 + mov cr4, ecx - cli ; disable interupts + ; Set PG bit in CR0 to enable paging. + mov ecx, cr0 + or ecx, 0x80000000 + mov cr0, ecx -hang: - hlt ; halt machine should kernel return - jmp hang + ; long jump required + lea ecx, [higherhalf] + jmp ecx -[section .setup] ; this is included in the .setup section, so that it thinks it is at 0x00100000 +align 0x1000 +boot_pagedir: + ; uses 4MB pages + ; identity-maps the first 4Mb of RAM, and also maps them with offset += k_highhalf_addr + dd 0x00000083 + times (K_PAGE_NUMBER - 1) dd 0 + dd 0x00000083 + times (1024 - K_PAGE_NUMBER - 1) dd 0 -trickgdt: ; our false GDT - dw gdt_end - gdt - 1 ; gdt limit - dd gdt ; gdt base +[section .text] +higherhalf: ; now we're running in higher half + ; unmap first 4Mb + mov dword [boot_pagedir], 0 + invlpg [0] + + mov esp, stack_top ; set up the stack -gdt: - dd 0, 0 ; null GDT entry - db 0xFF, 0xFF, 0, 0, 0, 10011010b, 11001111b, 0x40 ; kernel code segment - db 0xFF, 0xFF, 0, 0, 0, 10010010b, 11001111b, 0x40 ; kernel data segment + push eax ; pass Multiboot magic number + add ebx, K_HIGHHALF_ADDR ; update the MB info structure so that it is in higher half + push ebx ; pass Multiboot info structure -gdt_end: + call kmain ; call kernel proper + +hang: + ; halt machine should kernel return + cli + hlt + jmp hang [section .bss] align 4 stack_bottom: resb LOADER_STACK_SIZE stack_top: + +; vim: set ts=4 sw=4 tw=0 noet : diff --git a/kernel/launch-qemu.sh b/kernel/launch-qemu.sh deleted file mode 100755 index bc77868..0000000 --- a/kernel/launch-qemu.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -qemu-system-i386 -kernel kernel.bin -serial stdio diff --git a/kernel/lib/printf.c b/kernel/lib/printf.c index fdf474d..c1ef83b 100644 --- a/kernel/lib/printf.c +++ b/kernel/lib/printf.c @@ -71,8 +71,7 @@ int vsnprintf(char *buff, size_t len, const char* format, va_list ap){ unsigned int hexa = va_arg(ap,int); unsigned int nb; int j, had_nonzero = 0; - for(j = 0; j < 8; j++) - { + for(j = 0; j < 8; j++) { nb = (unsigned int)(hexa << (j*4)); nb = (nb >> 28) & 0xf; // Skip the leading zeros @@ -91,6 +90,20 @@ int vsnprintf(char *buff, size_t len, const char* format, va_list ap){ PUTCHAR('0'); break; } + case 'p': { + unsigned int hexa = va_arg(ap,int); + unsigned int nb; + int j; + for (j = 0; j < 8; j++) { + nb = (unsigned int)(hexa << (j*4)); + nb = (nb >> 28) & 0xf; + if (nb < 10) + PUTCHAR('0'+nb); + else + PUTCHAR('a'+(nb-10)); + } + break; + } default: PUTCHAR('%'); PUTCHAR(format[i]); diff --git a/kernel/linker.ld b/kernel/linker.ld index 00f4dff..8ea7854 100644 --- a/kernel/linker.ld +++ b/kernel/linker.ld @@ -3,7 +3,7 @@ ENTRY (loader) SECTIONS{ k_highhalf_addr = 0xC0000000; - . = 0x00100000; + . = 0x00100000; .setup : { *(.setup) @@ -11,30 +11,32 @@ SECTIONS{ . += k_highhalf_addr; - .text : AT(ADDR(.text) - k_highhalf_addr) { - *(.text) - } + .text : AT(ADDR(.text) - k_highhalf_addr) { + *(.text) + } - .rodata ALIGN (0x1000) : AT(ADDR(.rodata) - k_highhalf_addr) { - *(.rodata) - } + .rodata ALIGN (0x1000) : AT(ADDR(.rodata) - k_highhalf_addr) { + *(.rodata) + } - .data ALIGN (0x1000) : AT(ADDR(.data) - k_highhalf_addr) { + .data ALIGN (0x1000) : AT(ADDR(.data) - k_highhalf_addr) { start_ctors = .; *(.ctor*) end_ctors = .; start_dtors = .; *(.dtor*) end_dtors = .; - *(.data) - } + *(.data) + } - .bss : AT(ADDR(.bss) - k_highhalf_addr) { - sbss = .; - *(COMMON) - *(.bss) - ebss = .; - } + .bss : AT(ADDR(.bss) - k_highhalf_addr) { + sbss = .; + *(COMMON) + *(.bss) + ebss = .; + } end = .; _end = .; __end = .; } + +/* vim: set ts=4 sw=4 tw=0 noet :*/ -- cgit v1.2.3