diff --git a/bin/shade.bin b/bin/shade.bin index 567cd2c..3d2c531 100755 Binary files a/bin/shade.bin and b/bin/shade.bin differ diff --git a/bin/shade.iso b/bin/shade.iso index 85b49a1..c0efe35 100644 Binary files a/bin/shade.iso and b/bin/shade.iso differ diff --git a/include/shade/platform/gdt.h b/include/shade/platform/gdt.h new file mode 100644 index 0000000..4ad3f8a --- /dev/null +++ b/include/shade/platform/gdt.h @@ -0,0 +1,9 @@ +#ifndef GDT_H +#define GDT_H + +#define KERNEL_CODE 0x08 +#define KERNEL_DATA 0x10 +#define USERLAND_CODE 0x18 +#define USERLAND_DATA 0x20 + +#endif \ No newline at end of file diff --git a/include/shade/platform/interrupts/idt.h b/include/shade/platform/interrupts/idt.h new file mode 100644 index 0000000..b3b328e --- /dev/null +++ b/include/shade/platform/interrupts/idt.h @@ -0,0 +1,38 @@ +#ifndef IDT_H +#define IDT_H + +#include +#include +#include + +#define IDT_DESCRIPTORS 256 + +extern void* isr_stub_table[]; + +typedef struct idt_entry_struct { + uint16_t isr_low; // Low 16 bits of handler address + uint16_t kernel_cs; // The selector in the GDT that the CPU will load into CS before calling the handler + uint8_t ist; // The IST in the TSS that the CPU will load into RSP; set to zero for now + uint8_t attributes; // Type and attributes + uint16_t isr_mid; // Middle 16 bits of handler address + uint32_t isr_high; // Upper 32 bits of handler address + uint32_t reserved; // Reserved, set to 0 +} __attribute__((packed)) idt_descriptor_t; + +typedef struct idt_ptr_struct { + uint16_t limit; + uint64_t base; +} __attribute__((packed)) idt_ptr_t; + +__attribute__((aligned(0x10))) +static idt_descriptor_t idt[IDT_DESCRIPTORS]; +static idt_ptr_t idt_ptr; +static bool vectors[IDT_DESCRIPTORS]; + +void idt_set_gate(uint8_t index, void* isr, uint8_t flags); +void idt_assemble(); + +void idt_enable_interrupts(); +void idt_disable_interrupts(); + +#endif \ No newline at end of file diff --git a/include/shade/platform/interrupts/isr.h b/include/shade/platform/interrupts/isr.h new file mode 100644 index 0000000..1f341d8 --- /dev/null +++ b/include/shade/platform/interrupts/isr.h @@ -0,0 +1,45 @@ +#ifndef ISR_H +#define ISR_H + +#include + +#define ERR_MAX 5 + +static int err_count = 0; + +typedef struct { + struct { + uint64_t cr4; + uint64_t cr3; + uint64_t cr2; + uint64_t cr0; + } control_registers; + + struct { + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + } general_registers; + + struct { + uint64_t rbp; + uint64_t vector; + uint64_t error_code; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t dss; + } base_frame; +} isr_xframe_t; + +__attribute__((noreturn)) +void exception_handler(isr_xframe_t frame); + +__attribute__((noreturn)) +void interrupt_handler(isr_xframe_t frame); + +#endif \ No newline at end of file diff --git a/include/shade/platform/interrupts/pic.h b/include/shade/platform/interrupts/pic.h new file mode 100644 index 0000000..568e15a --- /dev/null +++ b/include/shade/platform/interrupts/pic.h @@ -0,0 +1,40 @@ +#ifndef PIC_H +#define PIC_H + +#include + +#define PIC1 0x20 /* IO base address for master PIC */ +#define PIC2 0xA0 /* IO base address for slave PIC */ +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1+1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2+1) + +#define PIC_EOI 0x20 /* End-of-interrupt command code */ + +#define ICW1_ICW4 0x01 /* ICW4 (not) needed */ +#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) */ + +#define PIC_READ_IRR 0x0a /* OCW3 irq ready next CMD read */ +#define PIC_READ_ISR 0x0b /* OCW3 irq service next CMD read */ + + +void pic_send_eoi(uint8_t irq); +void pic_remap(int offset1, int offset2); +void pic_mask_irq(uint8_t irq); +void pic_unmask_irq(uint8_t irq); +static uint16_t __pic_get_irq_reg(int ocw3); +uint16_t pic_get_irr(); +uint16_t pic_get_isr(); + + +#endif \ No newline at end of file diff --git a/include/shade/platform/ports.h b/include/shade/platform/ports.h index d616f0e..b5b0524 100644 --- a/include/shade/platform/ports.h +++ b/include/shade/platform/ports.h @@ -1,4 +1,11 @@ -unsigned char port_byte_in(unsigned short port); -void port_byte_out(unsigned short port, unsigned char data); -unsigned short port_word_in(unsigned short port); -void port_word_out(unsigned short port, unsigned short data); \ No newline at end of file +#ifndef PORTS_H +#define PORTS_H + +unsigned char inb(unsigned short port); +void outb(unsigned short port, unsigned char data); +unsigned short inw(unsigned short port); +void outw(unsigned short port, unsigned short data); + +void io_wait(); + +#endif \ No newline at end of file diff --git a/include/shade/util.h b/include/shade/util.h index 889ccb0..7ffca01 100644 --- a/include/shade/util.h +++ b/include/shade/util.h @@ -3,6 +3,5 @@ void memcpy(char *source, char *dest, int nbytes); void memset(char *dest, char val, int len); -void int_to_ascii(int n, char str[]); #endif \ No newline at end of file diff --git a/include/strings.h b/include/strings.h index ee4402a..8fca198 100644 --- a/include/strings.h +++ b/include/strings.h @@ -1,10 +1,17 @@ #ifndef STRINGS_H #define STRINGS_H +#include + void itoa(int n, char str[]); void strrev(char s[]); int strlen(char s[]); char* strcpy(char* strDest, const char* strSrc); char* strcnc(char* str1, char* str2); +char* u8_hex(const uint8_t x); +char* u16_hex(const uint16_t x); +char* u32_hex(const uint32_t x); +char* u64_hex(const uint64_t x); + #endif \ No newline at end of file diff --git a/obj/kernel/kernel.o b/obj/kernel/kernel.o index 66bfda7..aec1acb 100644 Binary files a/obj/kernel/kernel.o and b/obj/kernel/kernel.o differ diff --git a/obj/kernel/print.o b/obj/kernel/print.o index 99394ea..34e5753 100644 Binary files a/obj/kernel/print.o and b/obj/kernel/print.o differ diff --git a/obj/kernel/util.o b/obj/kernel/util.o index 7032cdd..242f41f 100644 Binary files a/obj/kernel/util.o and b/obj/kernel/util.o differ diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 84b5789..eaa1d47 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -1,5 +1,7 @@ #include #include +#include +#include void kernel_welcome() { print_str("Welcome to "); @@ -43,4 +45,10 @@ void kmain() { print_str("This program is provided \"as-is\" and no express or implied warranty is provided.\n"); print_str("The full license can be found at /sys/LICENCE on this system or ./LICENCE in the source tree.\n"); + pic_remap(0x20, 0x28); + idt_assemble(); + kernel_msg_ok("Enabled interrupts"); + __asm__ __volatile__("int $2"); + + for (;;) {} } \ No newline at end of file diff --git a/src/kernel/platform/interrupts/idt.c b/src/kernel/platform/interrupts/idt.c new file mode 100644 index 0000000..4f79e3e --- /dev/null +++ b/src/kernel/platform/interrupts/idt.c @@ -0,0 +1,33 @@ +#include + +void idt_set_gate(uint8_t index, void* isr, uint8_t flags) { + idt_descriptor_t* descriptor = &idt[index]; + + descriptor->isr_low = (uint64_t)isr & 0xFFFF; + descriptor->kernel_cs = KERNEL_CODE; + descriptor->ist = 0; + descriptor->attributes = flags; + descriptor->isr_mid = ((uint64_t)isr >> 16) & 0xFFFF; + descriptor->isr_high = ((uint64_t)isr >> 32) & 0xFFFFFFFF; + descriptor->reserved = 0; +} + +void idt_assemble() { + idt_ptr.base = (uintptr_t)&idt[0]; + idt_ptr.limit = (uint16_t)sizeof(idt_descriptor_t) * IDT_DESCRIPTORS - 1; + + for (uint8_t vector = 0; vector < 47; vector++) { + idt_set_gate(vector, isr_stub_table[vector], 0x8E); + vectors[vector] = true; + } + + __asm__ __volatile__ ("lidt %0" : : "m"(idt_ptr)); + idt_enable_interrupts(); +} + +void idt_enable_interrupts() { + __asm__ __volatile__("sti"); +} +void idt_disable_interrupts() { + __asm__ __volatile__("cli"); +} \ No newline at end of file diff --git a/src/kernel/platform/interrupts/int.asm b/src/kernel/platform/interrupts/int.asm new file mode 100644 index 0000000..e7485c8 --- /dev/null +++ b/src/kernel/platform/interrupts/int.asm @@ -0,0 +1,145 @@ +extern exception_handler + +%macro isr_err_stub 1 +isr_stub_%+%1: + push %1 + jmp isr_xframe_assembler +%endmacro + +%macro isr_no_err_stub 1 +isr_stub_%+%1: + push 0 + push %1 + jmp isr_xframe_assembler +%endmacro + +%macro interrupt_stub 1 +isr_stub_%+%1: + push 0 + push %1 + jmp isr_xframe_assembler +%endmacro + +%macro pushagrd 0 +push rax +push rbx +push rcx +push rdx +push rsi +push rdi +%endmacro + +%macro popagrd 0 +pop rdi +pop rsi +pop rdx +pop rcx +pop rbx +pop rax +%endmacro + +%macro pushacrd 0 +mov rax, cr0 +push rax +mov rax, cr2 +push rax +mov rax, cr3 +push rax +mov rax, cr4 +push rax +%endmacro + +%macro popacrd 0 +pop rax +mov cr4, rax +pop rax +mov cr3, rax +pop rax +mov cr2, rax +pop rax +mov cr0, rax +%endmacro + +isr_xframe_assembler: + push rbp + mov rbp, rsp + pushagrd + pushacrd + mov ax, ds + push rax + push qword 0 + mov ax, 0x10 + mov ds, ax + mov es, ax + mov ss, ax + + lea rdi, [rsp + 0x10] + call exception_handler + + pop rax + pop rax + mov ds, ax + mov es, ax + popacrd + popagrd + pop rbp + add rsp, 0x10 + iretq + +isr_no_err_stub 0 +isr_no_err_stub 1 +isr_no_err_stub 2 +isr_no_err_stub 3 +isr_no_err_stub 4 +isr_no_err_stub 5 +isr_no_err_stub 6 +isr_no_err_stub 7 +isr_err_stub 8 +isr_no_err_stub 9 +isr_err_stub 10 +isr_err_stub 11 +isr_err_stub 12 +isr_err_stub 13 +isr_err_stub 14 +isr_no_err_stub 15 +isr_no_err_stub 16 +isr_err_stub 17 +isr_no_err_stub 18 +isr_no_err_stub 19 +isr_no_err_stub 20 +isr_no_err_stub 21 +isr_no_err_stub 22 +isr_no_err_stub 23 +isr_no_err_stub 24 +isr_no_err_stub 25 +isr_no_err_stub 26 +isr_no_err_stub 27 +isr_no_err_stub 28 +isr_no_err_stub 29 +isr_err_stub 30 +isr_no_err_stub 31 + +interrupt_stub 32 +interrupt_stub 33 +interrupt_stub 34 +interrupt_stub 35 +interrupt_stub 36 +interrupt_stub 37 +interrupt_stub 38 +interrupt_stub 39 +interrupt_stub 40 +interrupt_stub 41 +interrupt_stub 42 +interrupt_stub 43 +interrupt_stub 44 +interrupt_stub 45 +interrupt_stub 46 +interrupt_stub 47 + +global isr_stub_table +isr_stub_table: +%assign i 0 +%rep 47 + dq isr_stub_%+i +%assign i i+1 +%endrep \ No newline at end of file diff --git a/src/kernel/platform/interrupts/isr.c b/src/kernel/platform/interrupts/isr.c new file mode 100644 index 0000000..0b26405 --- /dev/null +++ b/src/kernel/platform/interrupts/isr.c @@ -0,0 +1,24 @@ +#include +#include + +void exception_handler(isr_xframe_t frame) { + err_count++; + char s[256]; + itoa(err_count, s); + print_str(" "); + print_str(s); + print_str(": cpu: check_exception "); + itoa(frame.base_frame.vector, s); + print_str(s); + print_str(" @ "); + itoa(frame.base_frame.rip, s); + print_str(s); + print_str(" err_code => "); + itoa(frame.base_frame.error_code, s); + print_str(s); + print_str("\n"); + if (err_count > ERR_MAX) { + print_str("cpu: ierr hit err_max, halt"); + __asm__ __volatile__("cli; hlt"); + } +} \ No newline at end of file diff --git a/src/kernel/platform/interrupts/pic.c b/src/kernel/platform/interrupts/pic.c new file mode 100644 index 0000000..e312c8a --- /dev/null +++ b/src/kernel/platform/interrupts/pic.c @@ -0,0 +1,79 @@ +#include +#include + +void pic_send_eoi(uint8_t irq) { + if (irq >= 8) { + outb(PIC2_COMMAND, PIC_EOI); + } + outb(PIC1_COMMAND, PIC_EOI); +} + +void pic_remap(int offset1, int offset2) { + uint8_t a1, a2; + + a1 = inb(PIC1_DATA); // Save the current masks for later use + a2 = inb(PIC2_DATA); // Save the current masks for later use + + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode) + io_wait(); + outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + io_wait(); + outb(PIC1_DATA, offset1); // ICW2: Master PIC vector offset + io_wait(); + outb(PIC2_DATA, offset2); // ICW2: Slave PIC vector offset + io_wait(); + outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100) + io_wait(); + outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010) + io_wait(); + + outb(PIC1_DATA, ICW4_8086); + io_wait(); + outb(PIC2_DATA, ICW4_8086); + io_wait(); + + outb(PIC1_DATA, a1); // restore saved masks. + outb(PIC2_DATA, a2); +} + +void pic_mask_irq(uint8_t irq) { + uint16_t port; + uint8_t value; + + if (irq < 8) { + port = PIC1_DATA; + } else { + port = PIC2_DATA; + irq -= 8; + } + value = inb(port) | (1 << irq); + outb(port, value); +} + +void pic_unmask_irq(uint8_t irq) { + uint16_t port; + uint8_t value; + + if (irq < 8) { + port = PIC1_DATA; + } else { + port = PIC2_DATA; + irq -= 8; + } + value = inb(port) & ~(1 << irq); + outb(port, value); +} + +static uint16_t __pic_get_irq_reg(int ocw3) { + outb(PIC1_COMMAND, ocw3); + outb(PIC2_COMMAND, ocw3); + return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND); +} + +uint16_t pic_get_irr() { + return __pic_get_irq_reg(PIC_READ_IRR); +} + +uint16_t pic_get_isr() { + return __pic_get_irq_reg(PIC_READ_ISR); +} \ No newline at end of file diff --git a/src/kernel/platform/ports.c b/src/kernel/platform/ports.c index 34a48db..9e061fe 100644 --- a/src/kernel/platform/ports.c +++ b/src/kernel/platform/ports.c @@ -1,7 +1,7 @@ /* * Read 1 byte from specified port */ -unsigned char port_byte_in(unsigned short port) { +unsigned char inb(unsigned short port) { unsigned char result; // source and dest are backwards. // "=a (result)" set the C variable to the value of register e'a'x @@ -9,18 +9,22 @@ unsigned char port_byte_in(unsigned short port) { __asm__("in %%dx, %%al" : "=a" (result) : "d" (port)); } -void port_byte_out(unsigned short port, unsigned char data) { +void outb(unsigned short port, unsigned char data) { // both regs are C vars, nothing is returned, so no '=' in asm syntax // comma because two vars in input area and none in return area __asm__("out %%al, %%dx" : : "a" (data), "d" (port)); } -unsigned short port_word_in(unsigned short port) { +unsigned short inw(unsigned short port) { unsigned short result; __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port)); return result; } -void port_word_out(unsigned short port, unsigned short data) { +void outw(unsigned short port, unsigned short data) { __asm__("out %%ax, %%dx" : : "a" (data), "d" (port)); +} + +void io_wait() { + outb(0x80, 0); } \ No newline at end of file diff --git a/src/kernel/print.c b/src/kernel/print.c index 0ee30b7..fb4213a 100644 --- a/src/kernel/print.c +++ b/src/kernel/print.c @@ -87,10 +87,10 @@ void print_set_color(char foreground, char background) { void set_cursor_pos(int col, int row) { int offset = col + NUM_COLS * row; - port_byte_out(REG_SCREEN_CTRL, 14); - port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8)); - port_byte_out(REG_SCREEN_CTRL, 15); - port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff)); + outb(REG_SCREEN_CTRL, 14); + outb(REG_SCREEN_DATA, (unsigned char)(offset >> 8)); + outb(REG_SCREEN_CTRL, 15); + outb(REG_SCREEN_DATA, (unsigned char)(offset & 0xff)); } void kernel_msg_ok(char* msg) { diff --git a/src/kernel/util.c b/src/kernel/util.c index 5063a05..f36d9ad 100644 --- a/src/kernel/util.c +++ b/src/kernel/util.c @@ -10,16 +10,4 @@ void memcpy(char *source, char *dest, int nbytes) { void memset(char *dest, char val, int len) { char *temp = (char *)dest; for(; len !=0; len--) *temp++ = val; -} - -void int_to_ascii(int n, char str[]) { - int i, sign; - if ((sign = n) < 0) n = -n; - i = 0; - do { - str[i++] = n % 10 + '0'; - } while ((n /= 10) > 0); - - if (sign < 0) str[i++] = '-'; - str[i] = '\0'; } \ No newline at end of file diff --git a/src/libc/strings.c b/src/libc/strings.c index d148672..899fe9f 100644 --- a/src/libc/strings.c +++ b/src/libc/strings.c @@ -1,5 +1,6 @@ #include #include +#include void itoa(int n, char str[]) { int i, sign;