From 9904ac83d8104f7063983d733d6310df8e8825cd Mon Sep 17 00:00:00 2001 From: garrettmills Date: Sun, 22 Aug 2021 19:22:48 -0500 Subject: [PATCH] Start cleaning up kernel assembly mixins & start ISR/interrupts --- Makefile | 4 +-- asm/boot.asm | 2 +- asm/idt.asm | 89 ++++++++++++++++++++++++++++++++++++++++++++++ asm/kasm.asm | 5 +++ src/cpu/idt.cpp | 61 +++++++++++++++++++++++++++++++ src/cpu/idt.h | 77 +++++++++++++++++++++++++++++++++++++++ src/cpu/types.h | 7 +--- src/kernel/io.cpp | 12 +++---- src/kernel/io.h | 10 +++--- src/kernel/mem.cpp | 11 +++++- src/kernel/mem.h | 4 ++- 11 files changed, 261 insertions(+), 21 deletions(-) create mode 100644 asm/idt.asm create mode 100644 asm/kasm.asm create mode 100644 src/cpu/idt.cpp create mode 100644 src/cpu/idt.h diff --git a/Makefile b/Makefile index 0ee093b..596c86f 100644 --- a/Makefile +++ b/Makefile @@ -30,9 +30,9 @@ $(BUILD_DIR)/bootloader.bin: $(BOOTLOADER_DIR)/main16.asm cd $(BOOTLOADER_DIR); nasm -f bin -o ../../build/bootloader.bin main16.asm # Builds the kernel entry object file -$(BUILD_DIR)/kernel_entry.o: asm/boot.asm +$(BUILD_DIR)/kernel_entry.o: asm/kasm.asm $(MKDIR_P) $(dir $@) - nasm asm/boot.asm -f elf -o $@ + cd asm; nasm kasm.asm -f elf -o ../build/kernel_entry.o # Build C++ sources $(BUILD_DIR)/%.cpp.o: %.cpp diff --git a/asm/boot.asm b/asm/boot.asm index 407a3e8..0b5fa60 100644 --- a/asm/boot.asm +++ b/asm/boot.asm @@ -5,4 +5,4 @@ [extern main] ; going to call main in kernel.c call main -jmp $ \ No newline at end of file +jmp $ diff --git a/asm/idt.asm b/asm/idt.asm new file mode 100644 index 0000000..fb20323 --- /dev/null +++ b/asm/idt.asm @@ -0,0 +1,89 @@ +[bits 32] +[extern isr_handler] + +%macro ISR_NOERRORCODE 1 ; define a macro, taking one parameter + [GLOBAL isr%1] ; %1 accesses the first parameter. + isr%1: + cli + push byte 0 + push byte %1 + jmp isr_common_stub +%endmacro + +%macro ISR_ERRORCODE 1 + [GLOBAL isr%1] + isr%1: + cli + push byte %1 + jmp isr_common_stub +%endmacro + +ISR_NOERRORCODE 0 +ISR_NOERRORCODE 1 +ISR_NOERRORCODE 2 +ISR_NOERRORCODE 3 +ISR_NOERRORCODE 4 +ISR_NOERRORCODE 5 +ISR_NOERRORCODE 6 +ISR_NOERRORCODE 7 +ISR_ERRORCODE 8 +ISR_NOERRORCODE 9 +ISR_ERRORCODE 10 +ISR_ERRORCODE 11 +ISR_ERRORCODE 12 +ISR_ERRORCODE 13 +ISR_ERRORCODE 14 +ISR_NOERRORCODE 15 +ISR_NOERRORCODE 16 +ISR_NOERRORCODE 17 +ISR_NOERRORCODE 18 +ISR_NOERRORCODE 19 +ISR_NOERRORCODE 20 +ISR_NOERRORCODE 21 +ISR_NOERRORCODE 22 +ISR_NOERRORCODE 23 +ISR_NOERRORCODE 24 +ISR_NOERRORCODE 25 +ISR_NOERRORCODE 26 +ISR_NOERRORCODE 27 +ISR_NOERRORCODE 28 +ISR_NOERRORCODE 29 +ISR_NOERRORCODE 30 +ISR_NOERRORCODE 31 + + ; In isr.c +[EXTERN isr_handler] + +; This is our common ISR stub. It saves the processor state, sets +; up for kernel mode segments, calls the C-level fault handler, +; and finally restores the stack frame. +isr_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 + + call isr_handler + + 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 + sti + iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP + +[GLOBAL idt_flush] +idt_flush: + mov eax, [esp + 4] + lidt [eax] + ret diff --git a/asm/kasm.asm b/asm/kasm.asm new file mode 100644 index 0000000..aa12a82 --- /dev/null +++ b/asm/kasm.asm @@ -0,0 +1,5 @@ +; NOT part of the bootloader +; this is the kernel entry code that calls main() in kernel.cpp + +%include "boot.asm" +%include "idt.asm" diff --git a/src/cpu/idt.cpp b/src/cpu/idt.cpp new file mode 100644 index 0000000..bb8f328 --- /dev/null +++ b/src/cpu/idt.cpp @@ -0,0 +1,61 @@ +#include "idt.h" +#include "../kernel/mem.h" +#include "../drivers/vga.h" + +void isr_handler(registers_t regs) { + VGA vga; + vga.print("Received interrupt!"); +} + +static void init_idt() { + idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1; + idt_ptr.base = (uint32_t) &idt_entries; + + mem_set((uint8_t*) &idt_entries, 0, sizeof(idt_entry_t) * 256); + + idt_set_gate(0, (uint32_t) isr0, 0x08, 0x8e); + idt_set_gate(1, (uint32_t) isr1, 0x08, 0x8e); + idt_set_gate(2, (uint32_t) isr2, 0x08, 0x8e); + idt_set_gate(3, (uint32_t) isr3, 0x08, 0x8e); + idt_set_gate(4, (uint32_t) isr4, 0x08, 0x8e); + idt_set_gate(5, (uint32_t) isr5, 0x08, 0x8e); + idt_set_gate(6, (uint32_t) isr6, 0x08, 0x8e); + idt_set_gate(7, (uint32_t) isr7, 0x08, 0x8e); + idt_set_gate(8, (uint32_t) isr8, 0x08, 0x8e); + idt_set_gate(9, (uint32_t) isr9, 0x08, 0x8e); + idt_set_gate(10, (uint32_t) isr10, 0x08, 0x8e); + idt_set_gate(11, (uint32_t) isr11, 0x08, 0x8e); + idt_set_gate(12, (uint32_t) isr12, 0x08, 0x8e); + idt_set_gate(13, (uint32_t) isr13, 0x08, 0x8e); + idt_set_gate(14, (uint32_t) isr14, 0x08, 0x8e); + idt_set_gate(15, (uint32_t) isr15, 0x08, 0x8e); + idt_set_gate(16, (uint32_t) isr16, 0x08, 0x8e); + idt_set_gate(17, (uint32_t) isr17, 0x08, 0x8e); + idt_set_gate(18, (uint32_t) isr18, 0x08, 0x8e); + idt_set_gate(19, (uint32_t) isr19, 0x08, 0x8e); + idt_set_gate(20, (uint32_t) isr20, 0x08, 0x8e); + idt_set_gate(21, (uint32_t) isr21, 0x08, 0x8e); + idt_set_gate(22, (uint32_t) isr22, 0x08, 0x8e); + idt_set_gate(23, (uint32_t) isr23, 0x08, 0x8e); + idt_set_gate(24, (uint32_t) isr24, 0x08, 0x8e); + idt_set_gate(25, (uint32_t) isr25, 0x08, 0x8e); + idt_set_gate(26, (uint32_t) isr26, 0x08, 0x8e); + idt_set_gate(27, (uint32_t) isr27, 0x08, 0x8e); + idt_set_gate(28, (uint32_t) isr28, 0x08, 0x8e); + idt_set_gate(29, (uint32_t) isr29, 0x08, 0x8e); + idt_set_gate(30, (uint32_t) isr30, 0x08, 0x8e); + idt_set_gate(31, (uint32_t) isr31, 0x08, 0x8e); + + idt_flush((uint32_t) &idt_ptr); +} + +static void idt_set_gate(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; + + // We must uncomment the OR below when we get to using user-mode. + // It sets the interrupt gate's privilege level to 3. + idt_entries[num].flags = flags /* | 0x60 */; +} diff --git a/src/cpu/idt.h b/src/cpu/idt.h new file mode 100644 index 0000000..366ce29 --- /dev/null +++ b/src/cpu/idt.h @@ -0,0 +1,77 @@ +#ifndef KERNEL_CPU_IDT_H +#define KERNEL_CPU_IDT_H + +#include "types.h" + +typedef struct registers +{ + uint32_t ds; // Data segment selector + uint32_t edi, esi, ebp, 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, useresp, ss; // Pushed by the processor automatically. +} registers_t; + +void isr_handler(registers_t); + +// A struct describing an interrupt gate. +struct idt_entry_struct + { + uint16_t base_lo; // The lower 16 bits of the address to jump to when this interrupt fires. + uint16_t sel; // Kernel segment selector. + uint8_t always0; // This must always be zero. + uint8_t flags; // More flags. See documentation. + uint16_t base_hi; // The upper 16 bits of the address to jump to. + } __attribute__((packed)); +typedef struct idt_entry_struct idt_entry_t; + +// A struct describing a pointer to an array of interrupt handlers. +// This is in a format suitable for giving to 'lidt'. +struct idt_ptr_struct { + uint16_t limit; + uint32_t base; // The address of the first element in our idt_entry_t array. +} __attribute__((packed)); +typedef struct idt_ptr_struct idt_ptr_t; + +extern void idt_flush(uint32_t); + +static void init_idt(); +static void idt_set_gate(uint8_t, uint32_t, uint16_t, uint8_t); + +idt_entry_t idt_entries[256]; +idt_ptr_t idt_ptr; + +// References to ASM ISR handlers +extern void isr0(); +extern void isr1(); +extern void isr2(); +extern void isr3(); +extern void isr4(); +extern void isr5(); +extern void isr6(); +extern void isr7(); +extern void isr8(); +extern void isr9(); +extern void isr10(); +extern void isr11(); +extern void isr12(); +extern void isr13(); +extern void isr14(); +extern void isr15(); +extern void isr16(); +extern void isr17(); +extern void isr18(); +extern void isr19(); +extern void isr20(); +extern void isr21(); +extern void isr22(); +extern void isr23(); +extern void isr24(); +extern void isr25(); +extern void isr26(); +extern void isr27(); +extern void isr28(); +extern void isr29(); +extern void isr30(); +extern void isr31(); + +#endif //KERNEL_CPU_IDT_H diff --git a/src/cpu/types.h b/src/cpu/types.h index 1616746..f16bbba 100644 --- a/src/cpu/types.h +++ b/src/cpu/types.h @@ -2,12 +2,7 @@ #define KERNEL_CPU_TYPES_H // Non-semantic types specific to 32-bit Intel x86 -typedef unsigned int u32_t; -typedef int i32_t; -typedef unsigned short u16_t; -typedef short i16_t; -typedef unsigned char u8_t; -typedef char i8_t; +#include #define LOW16(address) (u16)((address) & 0xffff) #define HIGH16(address) (u16)(((address) >> 16) & 0xffff) diff --git a/src/kernel/io.cpp b/src/kernel/io.cpp index 428e6be..032eca6 100644 --- a/src/kernel/io.cpp +++ b/src/kernel/io.cpp @@ -9,8 +9,8 @@ * @param port * @return the read byte */ -u8_t io_byte_in(u16_t port) { - u8_t result; +uint8_t io_byte_in(uint16_t port) { + uint8_t result; __asm__("in %%dx, %%al" : "=a" (result) : "d" (port)); return result; } @@ -24,7 +24,7 @@ u8_t io_byte_in(u16_t port) { * @param port * @param data */ -void io_byte_out(u16_t port, u8_t data) { +void io_byte_out(uint16_t port, uint8_t data) { __asm__("out %%al, %%dx" : : "a" (data), "d" (port)); } @@ -37,8 +37,8 @@ void io_byte_out(u16_t port, u8_t data) { * @param port * @return the read word */ -u16_t io_word_in(u16_t port) { - u16_t result; +uint16_t io_word_in(uint16_t port) { + uint16_t result; __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port)); return result; } @@ -52,6 +52,6 @@ u16_t io_word_in(u16_t port) { * @param port * @param data */ -void io_word_out(u16_t port, u16_t data) { +void io_word_out(uint16_t port, uint16_t data) { __asm__("out %%ax, %%dx" : : "a" (data), "d" (port)); } diff --git a/src/kernel/io.h b/src/kernel/io.h index 45ba895..a9ee04a 100644 --- a/src/kernel/io.h +++ b/src/kernel/io.h @@ -1,6 +1,8 @@ #ifndef KERNEL_IO_H #define KERNEL_IO_H +#include + /** * Wrapper function that reads a byte from the specified I/O port. * @@ -10,7 +12,7 @@ * @param port * @return the read byte */ -u8_t io_byte_in(u16_t port); +uint8_t io_byte_in(uint16_t port); /** * Wrapper function that writes a byte to the specified I/O port. @@ -21,7 +23,7 @@ u8_t io_byte_in(u16_t port); * @param port * @param data */ -void io_byte_out(u16_t port, u8_t data); +void io_byte_out(uint16_t port, uint8_t data); /** * Wrapper function that reads a word from the specified I/O port. @@ -32,7 +34,7 @@ void io_byte_out(u16_t port, u8_t data); * @param port * @return the read word */ -u16_t io_word_in(u16_t port); +uint16_t io_word_in(uint16_t port); /** * Wrapper function that writes a word to the specified I/O port. @@ -43,6 +45,6 @@ u16_t io_word_in(u16_t port); * @param port * @param data */ -void io_word_out(u16_t port, u16_t data); +void io_word_out(uint16_t port, uint16_t data); #endif //KERNEL_IO_H diff --git a/src/kernel/mem.cpp b/src/kernel/mem.cpp index 90897b2..e4b8384 100644 --- a/src/kernel/mem.cpp +++ b/src/kernel/mem.cpp @@ -1,3 +1,4 @@ +#include "util.h" /** * Copy `num_bytes` many bytes from the `source` memory to the @@ -7,8 +8,16 @@ * @param destination * @param num_bytes */ -void mem_copy(char* source, char* destination, int num_bytes) { +void mem_copy(uint8_t* source, uint8_t* destination, int num_bytes) { for ( int i = 0; i < num_bytes; i += 1 ) { *(destination + i) = *(source + i); } } + +void mem_set(uint8_t* destination, uint8_t value, uint32_t length) { + uint8_t* temp = (uint8_t*) destination; + while ( length != 0 ) { + *temp++ = value; + length -= 1; + } +} \ No newline at end of file diff --git a/src/kernel/mem.h b/src/kernel/mem.h index 41526a0..5b9fbf5 100644 --- a/src/kernel/mem.h +++ b/src/kernel/mem.h @@ -1,6 +1,8 @@ #ifndef KERNEL_MEM_H #define KERNEL_MEM_H -void mem_copy(char* source, char* destination, int num_bytes); +void mem_copy(uint8_t* source, uint8_t* destination, int num_bytes); + +void mem_set(uint8_t* destination, uint8_t value, uint32_t length); #endif //KERNEL_MEM_H