diff --git a/Makefile b/Makefile index c2585fb..9615153 100644 --- a/Makefile +++ b/Makefile @@ -48,19 +48,19 @@ debug-nox: image.bin -ex "continue" fs.img: kernel.bin tools/mkfs user/false - tools/mkfs $@ $< + tools/mkfs $@ $< user/false LDFLAGS=-m elf_i386 user/%: user/%.o user/crt.o - $(LD) $(LDFLAGS) -o $@ -Ttext 0x101000 $^ + $(LD) $(LDFLAGS) -o $@ -Ttext 0x1000 $^ image.bin: mbr.bin fs.img cat $^ >$@ kernel.bin: kernel.o console.o drivers/vga.o drivers/keyboard.o \ drivers/ata.o cpu/vectors.o cpu/idt.o cpu/gdt.o drivers/uart.o \ - fs/fs.o lib/mem.o lib/string.o + fs/fs.o lib/mem.o lib/string.o proc.o cpu/swtch.o $(LD) $(LDFLAGS) -o $@ -Ttext 0x1000 $^ %.o: %.c diff --git a/cpu/gdt.h b/cpu/gdt.h index 6f3bce7..0f174b8 100644 --- a/cpu/gdt.h +++ b/cpu/gdt.h @@ -11,6 +11,8 @@ #define DPL_USER 3 +#define FL_IF 0x00000200 + #define SEG_KCODE 1 #define SEG_KDATA 2 #define SEG_UCODE 3 @@ -22,8 +24,9 @@ .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) -#define USER_BASE 0x400000 // 4 MB -#define KERN_STACK_BASE 0x90000 +#define USER_BASE 0x400000 // 4 MB +#define USER_STACK_BASE 0xf00000 // 15 MB +#define KERN_STACK_BASE 0x90000 #ifndef __ASSEMBLER__ void load_gdt(); diff --git a/cpu/idt.c b/cpu/idt.c index 7b855a2..9ae3674 100644 --- a/cpu/idt.c +++ b/cpu/idt.c @@ -42,27 +42,27 @@ void init_idt() { } const char * const exception_messages[] = { - "Division By Zero", - "Debug", - "Non Maskable Interrupt", - "Breakpoint", - "Into Detected Overflow", - "Out of Bounds", - "Invalid Opcode", - "No Coprocessor", + [0] = "Division By Zero", + [1] = "Debug", + [2] = "Non Maskable Interrupt", + [3] = "Breakpoint", + [4] = "Into Detected Overflow", + [5] = "Out of Bounds", + [6] = "Invalid Opcode", + [7] = "No Coprocessor", - "Double Fault", - "Coprocessor Segment Overrun", - "Bad TSS", - "Segment Not Present", - "Stack Fault", - "General Protection Fault", - "Page Fault", - "Unknown Interrupt", + [8] = "Double Fault", + [9] = "Coprocessor Segment Overrun", + [10] = "Bad TSS", + [11] = "Segment Not Present", + [12] = "Stack Fault", + [13] = "General Protection Fault", + [14] = "Page Fault", + [15] = "Unknown Interrupt", - "Coprocessor Fault", - "Alignment Check", - "Machine Check", + [16] = "Coprocessor Fault", + [17] = "Alignment Check", + [18] = "Machine Check", }; #define ARRLEN(a) (sizeof(a) / sizeof(a[0])) diff --git a/cpu/swtch.S b/cpu/swtch.S new file mode 100644 index 0000000..db6b56e --- /dev/null +++ b/cpu/swtch.S @@ -0,0 +1,20 @@ + // swtch(void** oldstack, void* newstack) + .global swtch +swtch: + mov 4(%esp), %eax // eax holds "oldstack" + mov 8(%esp), %ecx + + push %ebx + push %ebp + push %esi + push %edi + + mov %esp, (%eax) // save stack ptr to "oldstack" + mov %ecx, %esp // use "newstack" as stack ptr + + pop %edi + pop %esi + pop %ebp + pop %ebx + + ret diff --git a/cpu/vectors.S b/cpu/vectors.S index 896264e..21ddded 100644 --- a/cpu/vectors.S +++ b/cpu/vectors.S @@ -1,3 +1,5 @@ + .global trapret + alltraps: # Build trap frame. pushl %ds @@ -13,7 +15,9 @@ alltraps: pushl %esp call trap add $4, %esp + // execution falls through to trapret +trapret: popal popl %gs popl %fs diff --git a/kernel.c b/kernel.c index fbf61b8..90fdcff 100644 --- a/kernel.c +++ b/kernel.c @@ -10,6 +10,8 @@ asm(".asciz \"kernel start\\n\""); #include "drivers/uart.h" #include "fs/fs.h" #include "lib/string.h" +#include "proc.h" + void _start() { load_gdt(); @@ -28,20 +30,19 @@ void _start() { } else { printk("failed to read file\n"); } - printk("\n> "); - while (1) { if (kbd_buf_size > 0 && kbd_buf[kbd_buf_size-1] == '\n') { if (!strncmp("halt\n", kbd_buf, kbd_buf_size)) { qemu_shutdown(); - } else if (!strncmp("run ", kbd_buf, kbd_buf_size)) { + } else if (!strncmp("run ", kbd_buf, 4)) { kbd_buf[kbd_buf_size-1] = '\0'; - // const char* cmd = kbd_buf + 4; - // run_elf(cmd); + const char* cmd = kbd_buf + 4; + run_elf(cmd); } else { - printk("unknown command, try: halt\n> "); + printk("unknown command, try: halt"); } kbd_buf_size = 0; + printk("\n> "); } asm("hlt"); } diff --git a/lib/string.c b/lib/string.c index 99e1171..e269955 100644 --- a/lib/string.c +++ b/lib/string.c @@ -26,3 +26,10 @@ int strncmp(const char* s1, const char* s2, size_t size) { } return (unsigned char)(*s1) - (unsigned char)(*s2); } + +void memset(void* b, char c, size_t len) { + char* p = b; + for (size_t i = 0; i < len; ++i) { + p[i] = c; + } +} diff --git a/lib/string.h b/lib/string.h index 584f7d7..6184c33 100644 --- a/lib/string.h +++ b/lib/string.h @@ -4,3 +4,4 @@ typedef unsigned size_t; void kmemmove(char* dst, char* src, size_t size); int strncmp(const char* s1, const char* s2, size_t size); +void memset(void* b, char c, size_t len); diff --git a/proc.c b/proc.c new file mode 100644 index 0000000..3c19495 --- /dev/null +++ b/proc.c @@ -0,0 +1,62 @@ +#include "elf.h" +#include "proc.h" +#include "fs/fs.h" +#include "cpu/gdt.h" +#include "cpu/isr.h" +#include "lib/mem.h" +#include "lib/string.h" +#include "console.h" + +struct context { + // matches the behavior of swtch() + uint32_t edi, esi, ebp, ebx; + uint32_t eip; // return address for swtch() +}; + +struct kstack { + uint32_t space[400]; + struct context context; + registers_t trapframe; +}; + +struct vm { + void *kernel_thread; + void *user_thread; + struct kstack *user_kstack; +} *vm; + +void trapret(); +void swtch(void** oldstack, void* newstack); + +void run_elf(const char* name) { + if (!vm) { + vm = kmalloc(sizeof(struct vm)); + vm->user_kstack = kmalloc(sizeof(struct kstack)); + } + if (read_file(name, (void*)USER_BASE, 100 << 20) <= 0) { + printk(name); + printk(": file not found\n"); + return; + } + Elf32_Ehdr *hdr = (void*)USER_BASE; + + struct kstack *u = vm->user_kstack; + memset(u, 0, sizeof(*u)); + u->context.eip = (uint32_t)trapret; + + registers_t *tf = &u->trapframe; + tf->eip = hdr->e_entry; + tf->cs = (SEG_UCODE << 3) | DPL_USER; + tf->ds = (SEG_UDATA << 3) | DPL_USER; + tf->es = tf->ds; + tf->fs = tf->ds; + tf->gs = tf->ds; + tf->ss = tf->ds; + tf->eflags = FL_IF; + tf->useresp = USER_STACK_BASE; + + // initialization done, now switch to the process + swtch(&vm->kernel_thread, &u->context); + + // process has finished +} diff --git a/proc.h b/proc.h new file mode 100644 index 0000000..86a4322 --- /dev/null +++ b/proc.h @@ -0,0 +1,3 @@ +#pragma once + +void run_elf(const char* name);