aboutsummaryrefslogtreecommitdiff
path: root/kernel/l0
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2014-12-01 17:24:38 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2014-12-01 17:24:38 +0100
commit0921a33fc9f3724cb36a03a24b58b0a5bfc519b1 (patch)
tree6f3db52ba8c38928749806cb2d94ca548b3b19bd /kernel/l0
parent6f11c9e5c15cc8ef936741e5ee7575b731a47e0f (diff)
downloadmacroscope-0921a33fc9f3724cb36a03a24b58b0a5bfc519b1.tar.gz
macroscope-0921a33fc9f3724cb36a03a24b58b0a5bfc519b1.zip
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)
Diffstat (limited to 'kernel/l0')
-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
6 files changed, 424 insertions, 48 deletions
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 :