diff --git a/Makefile b/Makefile index 861ddb1..57fb95d 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ clean: rm -f isodir/boot/myos.kernel $(ARCHDIR)/interrupt.o: CFLAGS += -mgeneral-regs-only -kernel/elf.o: CFLAGS += -masm=intel +# kernel/elf.o: CFLAGS += -masm=intel %.o : %.c i686-elf-gcc -c $< -o $@ $(CFLAGS) @@ -71,7 +71,7 @@ debug: CFLAGS += -g -O0 debug: ASFLAGS += -g debug: all -run: myos.iso +run: all qemu-system-i386 myos.iso run-debug: debug diff --git a/arch/i686/bootstrap.s b/arch/i686/bootstrap.s index 0c85bce..61875dc 100644 --- a/arch/i686/bootstrap.s +++ b/arch/i686/bootstrap.s @@ -70,7 +70,7 @@ _start: call gdt_init - movw 0x10, %ax + movw $0x10, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs diff --git a/arch/i686/gdt.c b/arch/i686/gdt.c index fdacbdf..f90c6cb 100644 --- a/arch/i686/gdt.c +++ b/arch/i686/gdt.c @@ -3,7 +3,7 @@ #include #include -#define NUM_ENTRIES 6 +#define NUM_ENTRIES 256 struct SegmentDescriptor { uint32_t limit; @@ -101,7 +101,7 @@ static void add_entry(struct SegmentDescriptor entry) static void load_gdt() { - gdt.size = NUM_ENTRIES * 8 - 1; + gdt.size = NUM_ENTRIES * sizeof(struct SegmentDescriptor) - 1; gdt.base = entries; asm ( "lgdt %0" : : "m"(gdt) ); @@ -125,7 +125,7 @@ void gdt_init() terminal_putchar('\n'); struct SegmentDescriptor kernel_code; - kernel_code.limit = 0x000003FF; + kernel_code.limit = 0xFFFFF; kernel_code.base = 0x00000000; kernel_code.access_byte = 0b10011010; kernel_code.flags = 0b1100; @@ -136,8 +136,8 @@ void gdt_init() terminal_putchar('\n'); struct SegmentDescriptor kernel_data; - kernel_data.limit = 0x000003FF; - kernel_data.base = 0x00400000; + kernel_data.limit = 0xFFFFF; + kernel_data.base = 0x00000000; kernel_data.access_byte = 0b10010010; kernel_data.flags = 0b1100; @@ -146,8 +146,8 @@ void gdt_init() terminal_putchar('\n'); struct SegmentDescriptor user_code; - user_code.limit = 0x000003FF; - user_code.base = 0x00800000; + user_code.limit = 0xFFFFF; + user_code.base = 0x00000000; user_code.access_byte = 0b11111010; user_code.flags = 0b1100; @@ -157,8 +157,8 @@ void gdt_init() terminal_putchar('\n'); struct SegmentDescriptor user_data; - user_data.limit = 0x000FFFFF; - user_data.base = 0x00c00000; + user_data.limit = 0xFFFFF; + user_data.base = 0x00000000; user_data.access_byte = 0b11110010; user_data.flags = 0b1100; @@ -179,4 +179,9 @@ void gdt_init() terminal_putchar('\n'); load_gdt(); + + tss.ss0 = 0x10; + asm("mov %%esp, %0" : "=r" (tss.esp0)); + + asm ("ltr %%ax" : : "a"(0x28)); } diff --git a/arch/i686/idt.c b/arch/i686/idt.c index 53ff948..8eb62f9 100644 --- a/arch/i686/idt.c +++ b/arch/i686/idt.c @@ -1,9 +1,10 @@ -#include #include +#include #include #include "interrupt.h" #include #include +#include "io.h" #define NUM_ENTRIES 0x100 @@ -101,20 +102,9 @@ struct InterruptDescriptor generate_entry(bool present, void isr(struct interrup return entry; } -static inline void outb(uint16_t port, uint8_t val) -{ - __asm__ volatile ( "outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory"); - /* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint). - * Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint). - * The outb %al, %dx encoding is the only option for all other cases. - * %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */ -} - void idt_init() { - outb(0x21,0xfd); - outb(0xa1,0xff); - + terminal_initialize(); struct InterruptDescriptor entry; entry = generate_entry(true, exception, 0xF, 0, 0x8); @@ -123,12 +113,6 @@ void idt_init() add_entry(entry, i); } - entry = generate_entry(true, irq, 0xF, 0, 0x8); - for (int i = 0x20; i < 0x28; i++) - { - add_entry(entry, i); - } - entry = generate_entry(true, divide_by_zero, 0xF, 0, 0x8); add_entry(entry, DivisionByZero); @@ -138,11 +122,18 @@ void idt_init() entry = generate_entry(true, double_fault, 0xF, 0, 0x8); add_entry(entry, DoubleFault); + outb(0x21,0x20); // Tell the PIC to use interrupts 0x20 - 0x27 + entry = generate_entry(true, irq, 0xE, 0, 0x8); + for (int i = 0x20; i < 0x28; i++) + { + add_entry(entry, i); + } + struct InterruptDescriptor print_entry; print_entry.present = true; print_entry.offset = (uint32_t)print; print_entry.gate_type = 0xE; - print_entry.ring = 3; + print_entry.ring = 0; print_entry.selector = 0x8; add_entry(print_entry, 0x80); @@ -157,9 +148,4 @@ void idt_init() add_entry(input_entry, 0x81); load_idt(); - - tss.ss0 = 0x10; - asm("mov %%esp, %0" : "=r" (tss.esp0)); - asm("mov $0x28, %ax"); - asm("ltr %ax"); } diff --git a/arch/i686/interrupt.c b/arch/i686/interrupt.c index e2e7c16..ef1e758 100644 --- a/arch/i686/interrupt.c +++ b/arch/i686/interrupt.c @@ -1,6 +1,7 @@ #include #include #include +#include "io.h" struct interrupt_frame { uint32_t eflags; @@ -25,35 +26,26 @@ static void stack_trace() __attribute__((interrupt)) void divide_by_zero(struct interrupt_frame* frame) { - terminal_initialize(); - stack_trace(); terminal_writestring("Yo dude u cant divide by zero yao\n"); while (1) { } } __attribute__((interrupt)) void general_protection_fault(struct interrupt_frame* frame) { - /* terminal_initialize(); - stack_trace(); - terminal_writestring("General protection fault\n"); - terminal_writestring("Error code:\n"); - print_hex_bytes(frame, sizeof(frame)); - terminal_putchar('\n'); */ + terminal_writestring("GPF handler called\n"); while (1) { } } __attribute__((interrupt)) void double_fault(struct interrupt_frame* frame) { - // terminal_writestring("2 Errors in a row, u better behave naughty naughty\n"); - // while (1) { } + terminal_writestring("2 Errors in a row, u better behave naughty naughty\n"); + while (1) { } } __attribute__((interrupt)) void exception(struct interrupt_frame* frame) { - /* terminal_initialize(); - stack_trace(); terminal_writestring("Some weird error code stuff\n"); - terminal_writestring("Error code:\n"); + /* terminal_writestring("Error code:\n"); print_hex_bytes(frame, sizeof(frame)); terminal_putchar('\n'); */ while (1) { } @@ -109,6 +101,7 @@ __attribute__((interrupt)) void input(struct interrupt_frame* frame) __attribute__((interrupt)) void irq(struct interrupt_frame* frame) { - + terminal_writestring("Test"); + outb(0x20, 0x20); } diff --git a/arch/i686/io.h b/arch/i686/io.h new file mode 100644 index 0000000..03c63a7 --- /dev/null +++ b/arch/i686/io.h @@ -0,0 +1,19 @@ +#include + +static inline void outb(uint16_t port, uint8_t val) +{ + __asm__ volatile ( "outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory"); + /* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint). + * Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint). + * The outb %al, %dx encoding is the only option for all other cases. + * %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */ +} + +static inline void inb(uint16_t port, uint8_t val) +{ + __asm__ volatile ( "inb %b0, %w1" : : "a"(val), "Nd"(port) : "memory"); + /* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint). + * Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint). + * The outb %al, %dx encoding is the only option for all other cases. + * %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */ +} diff --git a/arch/i686/pic.c b/arch/i686/pic.c new file mode 100644 index 0000000..2ebc53c --- /dev/null +++ b/arch/i686/pic.c @@ -0,0 +1,17 @@ +#include "io.h" + +#define ICW1_ICW4 0x01 /* Indicates that ICW4 will be present */ +#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ +#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ +#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ +#define ICW1_INIT 0x10 /* Initialization - required! */ + +#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ +#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ +#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ +#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ +#define ICW4_SFNM 0x10 /* Special fully nested (not) */ + +void init_pic() { + +} diff --git a/arch/i686/pic.h b/arch/i686/pic.h new file mode 100644 index 0000000..e69de29 diff --git a/kernel/elf.c b/kernel/elf.c index 682be8a..ee8f045 100644 --- a/kernel/elf.c +++ b/kernel/elf.c @@ -3,43 +3,35 @@ #include #include #include +#include + +static void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) { + unsigned char* dst = (unsigned char*) dstptr; + const unsigned char* src = (const unsigned char*) srcptr; + for (size_t i = 0; i < size; i++) + dst[i] = src[i]; + return dstptr; +} void run_program(uint8_t* program, size_t length) { - uint8_t* userland_code = (uint8_t*) 0x00800004; + uint8_t* userland_code = (uint8_t*) 0x0; + memcpy(userland_code, program, length); - for (size_t i = 0; i < length; i++) { - userland_code[i] = program[i]; - } + print_hex_bytes(userland_code, 1); + terminal_putchar('\n'); - tss.ss0 = 0x10; - - asm("sti"); - asm("int 0x80"); - - asm("mov %0, esp" : "=r" (tss.esp0)); - - // Generates segfault - // asm("mov esp, %0" : "=r" (tss.esp0)); - - asm("mov ax, 0x23 # Load registers with the correct GDT segments values"); - asm("mov ds, ax"); - asm("mov es, ax"); - asm("mov fs, ax"); - asm("mov gs, ax"); - - asm("push 0x23"); - asm("push 0x00c00100"); - - asm("pushfd"); - asm("pop eax"); - asm("or eax, 0x200"); - asm("push eax"); - - asm("push 0x1b"); - asm("push 0x00800000"); - - asm("iret"); - - asm("int 0x21"); + asm ("\ + mov $0x20 | 0x3, %%ax;\ + movw %%ax, %%ds;\ + movw %%ax, %%es;\ + movw %%ax, %%fs;\ + movw %%ax, %%gs;\ + pushl $0x20 | 0x3; /* SS selector */ \ + pushl $0x00c00100; /* ESP */ \ + pushf; /* EFLAGS */ \ + popl %%eax; orl $0x200, %%eax; pushl %%eax; /* Set interrupts in USERPACE */\ + pushl $0x18 | 0x3; /* CS selector */\ + pushl $0x0; /* EIP */ \ + iret;":::"eax"); } diff --git a/kernel/kernel.c b/kernel/kernel.c index f819f7b..aa33cb1 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -9,30 +9,8 @@ #endif uint8_t program[] = { -/* 0xcd, - 0x80, - 0xc6, - 0x05, - 0x00, - 0x80, - 0x0b, - 0x00, - 0x62, - 0xeb, - 0xfe, */ -/* 0x90, - 0xe9, - 0xfa, - 0x7f, - 0x7b, - 0xf8, */ -/* 0x90, - 0xeb, - 0xfd, */ - 0x6a, - 0x69, - 0xeb, - 0xfc, + 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, 0x0 (Just a simple NOP-like instruction) + 0xF4 // hlt (halts the CPU, should trap to kernel if interrupts enabled) }; void kernel_main(void) @@ -42,6 +20,12 @@ void kernel_main(void) idt_init(); + // asm("int $13"); + // asm("ljmp $0x18, $0x00c00100"); // Example: Far jump to user code segment with selector 0x18 + + print_hex_bytes(idt_init, 4); + terminal_putchar('\n'); + run_program(program, 15); /*