aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile8
-rw-r--r--kernel/config.h1
-rw-r--r--kernel/include/dbglog.h2
-rw-r--r--kernel/include/gdt.h64
-rw-r--r--kernel/include/idt.h40
-rw-r--r--kernel/include/multiboot.h1
-rw-r--r--kernel/include/printf.h1
-rw-r--r--kernel/include/string.h2
-rw-r--r--kernel/include/sys.h5
-rw-r--r--kernel/l0/dbglog.c2
-rw-r--r--kernel/l0/gdt.c35
-rw-r--r--kernel/l0/idt.c187
-rw-r--r--kernel/l0/interrupt.s126
-rw-r--r--kernel/l0/kmain.c16
-rw-r--r--kernel/l0/loader.s106
-rwxr-xr-xkernel/launch-qemu.sh3
-rw-r--r--kernel/lib/printf.c17
-rw-r--r--kernel/linker.ld34
18 files changed, 577 insertions, 73 deletions
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 <stddef.h>
+#include <stdint.h>
+
+/* 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 <config.h>
+
+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 <gdt.h>
+#include <string.h>
+
+#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 <idt.h>
+#include <sys.h>
+#include <string.h>
+#include <dbglog.h>
+
+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 <config.h>
#include <dbglog.h>
#include <sys.h>
+
+#include <gdt.h>
+#include <idt.h>
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 :*/