diff --git a/host/kernelcopy/kernelcopy.c b/host/kernelcopy/kernelcopy.c index 9410afc..c9df617 100644 --- a/host/kernelcopy/kernelcopy.c +++ b/host/kernelcopy/kernelcopy.c @@ -52,6 +52,11 @@ int main(int argc, char** argv) { return 1; } + if (kernel == NULL) { + fprintf(stderr, "Failed to open kernel file\n"); + return 1; + } + LFFileHandle image_handle = libhost_create_handle(image); LFControlBlock fat; diff --git a/libfat/libfat.c b/libfat/libfat.c index 36f2a85..4d24330 100644 --- a/libfat/libfat.c +++ b/libfat/libfat.c @@ -85,6 +85,11 @@ os_bool libfat_write_fat_cluster(LFControlBlock* fat, os_u32 cluster_id, os_u32 fat->handle.seek(second_fat_cluster_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data); fat->handle.write(sizeof(os_u32), (void*)&cluster_value, fat->handle.user_data); + if (fat->first_loaded_cluster <= cluster_id && (fat->first_loaded_cluster + fat->loaded_fat_cluster_amount) > cluster_id) { + os_u32 cluster_offset = cluster_id - fat->first_loaded_cluster; + fat->loaded_fat_segment[cluster_offset] = cluster_value; + } + return OS_TRUE; } @@ -113,7 +118,7 @@ os_u32 libfat_write_cluster(LFControlBlock* fat, os_u32 cluster, void* buffer, o os_u32 cluster_size = fat->header.base.bytes_per_sector * fat->header.base.sectors_per_cluster; os_u32 data_offset = (fat->header.base.reserved_sectors + (fat->header.sectors_per_fat_32 * fat->header.base.number_of_fats)) * fat->header.base.bytes_per_sector; - if (offset_in_cluster + buffer_size >= cluster_size) { + if (offset_in_cluster + buffer_size > cluster_size) { return 0; } @@ -596,7 +601,7 @@ os_u32 libfat_write(LFFile* f, void* buffer, os_u32 buffer_size) { f->in_cluster_position = 0; os_u32 next = libfat_read_cluster(f->fat, f->current_cluster); if (next >= FAT_LAST_CLUSTER_32_2) { - next = libfat_add_cluster_to_chain(f->fat, next); + next = libfat_add_cluster_to_chain(f->fat, f->current_cluster); } f->current_cluster = next; } diff --git a/stage1/CMakeLists.txt b/stage1/CMakeLists.txt index 3bc195c..da37676 100644 --- a/stage1/CMakeLists.txt +++ b/stage1/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(stage1 stage1.c screen.c include/interrupts.h interrupts.c interrupt_utils.asm) +add_executable(stage1 stage1.c screen.c include/interrupts.h interrupts.c interrupt_utils.asm include/io.h io.asm include/pic_8259.h pic_8259.c) target_compile_options(stage1 PUBLIC "$<$:-ffreestanding>") set_target_properties(stage1 PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld) target_link_options(stage1 PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/linker.ld) diff --git a/stage1/include/interrupts.h b/stage1/include/interrupts.h index 636c5ab..eda7a41 100644 --- a/stage1/include/interrupts.h +++ b/stage1/include/interrupts.h @@ -1,43 +1,9 @@ #ifndef OS3_INTERRUPTS_H #define OS3_INTERRUPTS_H -#include "datatypes.h" -#include "packing.h" -#include "screen.h" +extern void setup_interrupts(); -OS_PACK_START -typedef struct __idt_attributes { - os_u8 gate_type: 4; - os_u8 empty : 1; - os_u8 dpl : 2; - os_u8 present: 1; -} OS_PACK_MID idt_attributes; -OS_PACK_END - -#define IDT_GATE_TYPE_TASK 0x5 -#define IDT_GATE_TYPE_INTERRUPT_16 0x6 -#define IDT_GATE_TYPE_TRAP_16 0x7 -#define IDT_GATE_TYPE_INTERRUPT_32 0xE -#define IDT_GATE_TYPE_TRAP_32 0xF - -OS_PACK_START -typedef struct __idt_entry { - os_u16 isr_low; - os_u16 kernel_gdt_code_segment; - os_u8 reserved; - //idt_attributes attributes; - os_u8 attributes; - os_u16 isr_high; -} OS_PACK_MID idt_entry; -OS_PACK_END - -OS_PACK_START -typedef struct __idt_ptr { - os_u16 limit; - os_u32 base; -} OS_PACK_MID idt_ptr; -OS_PACK_END - -extern void fill_idt(); +// Defined in interrupt_utils.asm +extern void enable_interrupts(); #endif //OS3_INTERRUPTS_H diff --git a/stage1/include/io.h b/stage1/include/io.h new file mode 100644 index 0000000..d0c9065 --- /dev/null +++ b/stage1/include/io.h @@ -0,0 +1,18 @@ +// +// Created by John Stefanelli on 18/01/23. +// + +#ifndef OS3_IO_H +#define OS3_IO_H + +#include "datatypes.h" + +extern void outb(os_u16 port, os_u8 data); +extern void outw(os_u16 port, os_u16 data); +extern void outd(os_u16 port, os_u32 data); + +extern os_u8 inb(os_u16 port); +extern os_u16 inw(os_u16 port); +extern os_u32 ind(os_u16 port); + +#endif //OS3_IO_H diff --git a/stage1/include/pic_8259.h b/stage1/include/pic_8259.h new file mode 100644 index 0000000..aeedf12 --- /dev/null +++ b/stage1/include/pic_8259.h @@ -0,0 +1,13 @@ +// +// Created by John Stefanelli on 18/01/23. +// + +#ifndef OS3_PIC_8259_H +#define OS3_PIC_8259_H + +#include "datatypes.h" + +extern void pic_sendEOI(os_u8 irq); +extern void setup_pic(); + +#endif //OS3_PIC_8259_H diff --git a/stage1/include/screen.h b/stage1/include/screen.h index 4cc34bb..906c1d9 100644 --- a/stage1/include/screen.h +++ b/stage1/include/screen.h @@ -3,8 +3,11 @@ #include "datatypes.h" -extern void write_string(const char*, int); -extern void clear_screen(); -extern void write_number(os_u32 number); +extern void screen_write_string(const char* str, int length); +extern void screen_write_error(const char* str, int length); +extern void screen_clear(); +extern void screen_write_number(os_u32 number); +extern void screen_write_number_error(os_u32 number); +extern void screen_set_pos(int x, int y); #endif \ No newline at end of file diff --git a/stage1/interrupt_utils.asm b/stage1/interrupt_utils.asm index fd70a5a..09c9483 100644 --- a/stage1/interrupt_utils.asm +++ b/stage1/interrupt_utils.asm @@ -1,10 +1,14 @@ ; list of 256 void* to call when the corresponding interrupt is received -extern interrupt_service_list, generic_exception +extern interrupt_service_list +; IDTR structure +extern main_idt_ptr %macro interrupt_service_routine 1 isr_stub_%+%1: - ;CALL interrupt_service_list + (%1*4) - CALL generic_exception + MOV EAX, i ; load interrupt number + PUSH EAX ; push parameter "interrupt number" + CALL [interrupt_service_list + (%1*4)] ; call interrupt subroutine + ADD ESP, 4 ; clear parameters IRET %endmacro @@ -24,11 +28,11 @@ interrupt_service_table: %assign i i+1 %endrep -; void load_idt(void* idt_ptr) +; void load_idt() global load_idt load_idt: - LIDT [ESP+4] ; load idt with SP+4 - RET ; return + LIDT [main_idt_ptr] ; load idt with SP+4 + RET ; return ; void enable_interrupts() global enable_interrupts diff --git a/stage1/interrupts.c b/stage1/interrupts.c index 2570961..07134cf 100644 --- a/stage1/interrupts.c +++ b/stage1/interrupts.c @@ -1,56 +1,91 @@ #include "include/interrupts.h" +#include "datatypes.h" +#include "packing.h" +#include "include/screen.h" +#include "include/pic_8259.h" -#define EFFECTIVE_INTERRUPT_AMOUNT 32 +OS_PACK_START +typedef struct __idt_attributes { + os_u8 gate_type: 4; + os_u8 empty : 1; + os_u8 dpl : 2; + os_u8 present: 1; +} OS_PACK_MID idt_attributes; +OS_PACK_END + +#define IDT_GATE_TYPE_TASK 0x5 +#define IDT_GATE_TYPE_INTERRUPT_16 0x6 +#define IDT_GATE_TYPE_TRAP_16 0x7 +#define IDT_GATE_TYPE_INTERRUPT_32 0xE +#define IDT_GATE_TYPE_TRAP_32 0xF + +OS_PACK_START +typedef struct __idt_entry { + os_u16 isr_low; + os_u16 kernel_gdt_code_segment; + os_u8 reserved; + idt_attributes attributes; + //os_u8 attributes; + os_u16 isr_high; +} OS_PACK_MID idt_entry; +OS_PACK_END + +OS_PACK_START +typedef struct __idt_ptr { + os_u16 limit; + os_u32 base; +} OS_PACK_MID idt_ptr; +OS_PACK_END + + +#define EFFECTIVE_INTERRUPT_AMOUNT 256 __attribute__((aligned(0x10))) idt_entry main_idt[EFFECTIVE_INTERRUPT_AMOUNT]; idt_ptr main_idt_ptr; volatile void* interrupt_service_list[EFFECTIVE_INTERRUPT_AMOUNT]; -void generic_exception() { - //clear_screen(); - write_string("Exception received: ", 0); - write_number(0); - write_string("\n", 0); - __asm__("cli; hlt;"); +void generic_exception(os_u32 interrupt_id) { + //screen_clear(); + screen_set_pos(0, 0); + screen_write_error("Exception received: ", 0); + screen_write_number_error(interrupt_id); + screen_write_string("\n", 0); while(1) { } } +void handle_irq0(os_u32) { + pic_sendEOI(0); +} + /* The following is defined in interrupt_utils.asm */ extern void* interrupt_service_table[]; -extern void load_idt(void* idtr_ptr); -extern void enable_interrupts(); +extern void load_idt(); /* --- */ -void fill_idt() { +void setup_interrupts() { main_idt_ptr.base = (os_u32) &main_idt[0]; main_idt_ptr.limit = ((os_u16) (sizeof(idt_entry) * EFFECTIVE_INTERRUPT_AMOUNT)) - 1; - os_u32 val = (os_u32) interrupt_service_table[0]; - write_string("ISR address: ", 0); - write_number(val); - write_string("\n", 1); for (int i = 0; i < EFFECTIVE_INTERRUPT_AMOUNT; i++) { - //os_u32 val = (os_u32) interrupt_service_table[0]; - os_u32 val = (os_u32) &generic_exception; + os_u32 val = (os_u32) interrupt_service_table[i]; + //os_u32 val = (os_u32) &generic_exception; main_idt[i].isr_low = (os_u16)(val & 0xFFFF); main_idt[i].isr_high = (os_u16)(val >> 16); main_idt[i].kernel_gdt_code_segment = 0x08; main_idt[i].reserved = 0; - /* + main_idt[i].attributes.present = 1; main_idt[i].attributes.gate_type = IDT_GATE_TYPE_INTERRUPT_32; main_idt[i].attributes.empty = 0; main_idt[i].attributes.dpl = i == 0x49 ? 3 : 0; - */ - main_idt[i].attributes = 0x8e; interrupt_service_list[i] = (void*)&generic_exception; } + interrupt_service_list[32] = (void*)&handle_irq0; - load_idt((void*)&main_idt_ptr); - enable_interrupts(); + load_idt(); } \ No newline at end of file diff --git a/stage1/io.asm b/stage1/io.asm new file mode 100644 index 0000000..1ba8165 --- /dev/null +++ b/stage1/io.asm @@ -0,0 +1,50 @@ + +section .text + +; void outb(os_u16 port, os_u8 data); +global outb +outb: + MOV EDX, [ESP + 4] ; load parameter 'port' + MOV EAX, [ESP + 8] ; load parameter 'data' + OUT DX, AL ; output byte in AL to port in DX + RET ; return + +; void outw(os_u16 port, os_u16 data) +global outw +outw: + MOV EDX, [ESP + 4] ; load parameter 'port' + MOV EAX, [ESP + 8] ; load parameter 'data' + OUT DX, AX ; output word in AX to port in DX + RET ; return + +; void outd(os_u16 port, os_u32 data) +global outd +outd: + MOV EDX, [ESP + 4] ; load parameter 'port' + MOV EAX, [ESP + 8] ; load parameter 'data' + OUT DX, EAX ; output double word in EAX to port in DX + RET ; return + +; os_u8 inb(os_u16 port) +global inb +inb: + MOV EDX, [ESP + 4] ; load parameter 'port' + XOR EAX, EAX ; reset EAX + IN AL, DX ; read byte from port 'DX' + RET ; return + +; os_u16 inw(os_u16 port) +global inw +inw: + MOV EDX, [ESP + 4] ; load parameter 'port' + XOR EAX, EAX ; reset EAX + IN AX, DX ; read word from port 'DX' + RET ; return + +; os_u32 ind(os_u16 port) +global ind +ind: + MOV EDX, [ESP + 4] ; load parameter 'port' + XOR EAX, EAX ; reset EAX + IN EAX, DX ; read double word from port 'DX' + RET ; return \ No newline at end of file diff --git a/stage1/pic_8259.c b/stage1/pic_8259.c new file mode 100644 index 0000000..239268e --- /dev/null +++ b/stage1/pic_8259.c @@ -0,0 +1,50 @@ +#include "include/pic_8259.h" +#include "include/io.h" + +#define PIC0 0x20 +#define PIC1 0xA0 +#define PIC0_COMMAND (PIC0) +#define PIC0_DATA (PIC0 + 1) +#define PIC1_COMMAND (PIC1) +#define PIC1_DATA (PIC1 + 1) + +#define PIC_EOI 0x20 //PIC end-of-interrupt command + +#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) */ + +void pic_sendEOI(os_u8 irq) { + if (irq >= 8) { + outb(PIC1_COMMAND, PIC_EOI); + } + + outb(PIC0_COMMAND, PIC_EOI); +} + +void setup_pic() { + os_u8 a1, a2; + + a1 = inb(PIC0_DATA); // save current interrupt masks + a2 = inb(PIC1_DATA); + + outb(PIC0_COMMAND, ICW1_INIT | ICW1_ICW4); //Start init sequence in cascade mode + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); + outb(PIC0_DATA, 0x20); // 0x20: Offset of IRQ 0 + outb(PIC1_DATA, 0x28); // 0x28: Offset of IRQ 8 + outb(PIC0_DATA, 4); //Master PIC should handle cascade at IRQ 2 + outb(PIC1_DATA, 2); //Salve PIC should handle cascade identity '2' + outb(PIC0_DATA, ICW4_8086); //Set master to 8086 mode + outb(PIC1_DATA, ICW4_8086); //Set slave to 8086 mode + + outb(PIC0_DATA, a1); //restore interrupt masks + outb(PIC1_DATA, a2); +} \ No newline at end of file diff --git a/stage1/screen.c b/stage1/screen.c index 9ecdc32..71b96a4 100644 --- a/stage1/screen.c +++ b/stage1/screen.c @@ -1,18 +1,17 @@ -#include "include/screen.h" #include "../os3_common/datatypes.h" #include "../os3_common/packing.h" +#include "include/screen.h" int x = 0; int y = 0; -void write_character(char c) { - os_u16 color_byte = 0x0A; +void write_character(char c, os_u8 color) { os_u16* vram = (os_u16*) 0xB8000; os_u16* cursor_pos = vram + ((y * 80) + x); - *cursor_pos = c | (color_byte << 8); + *cursor_pos = c | (color << 8); } -void write_string(const char* str, int max_len) { +void screen_write(const char* str, int max_len, os_u8 color) { int i = 0; do { char c = *str; @@ -22,7 +21,7 @@ void write_string(const char* str, int max_len) { if (c == '\n') { if (y == 24) { - clear_screen(); + screen_clear(); } y = (y + 1) % 25; x = 0; @@ -30,11 +29,11 @@ void write_string(const char* str, int max_len) { continue; } - write_character(c); + write_character(c, color); x++; if (x >= 80) { if (y == 24) { - clear_screen(); + screen_clear(); } y = (y + 1) % 25; x = 0; @@ -44,7 +43,15 @@ void write_string(const char* str, int max_len) { } while(i < max_len || max_len == 0); } -void clear_screen() { +void screen_write_string(const char* str, int length) { + screen_write(str, length, 0x0A); +} + +void screen_write_error(const char* str, int length) { + screen_write(str, length, 0x0C); +} + +void screen_clear() { os_u16* ptr = (os_u16*) 0xB8000; for (int y = 0; y < 25; y++) { for (int x = 0; x < 80; x++) { @@ -56,7 +63,7 @@ void clear_screen() { y = 0; } -void write_number(os_u32 number) { +void screen_write_number_impl(os_u32 number, os_u8 color) { char buffer[32]; char buffer_2[32]; @@ -79,5 +86,18 @@ void write_number(os_u32 number) { i--; } - write_string(buffer_2, 0); + screen_write(buffer_2, 0, color); +} + +void screen_write_number(os_u32 number) { + screen_write_number_impl(number, 0x0A); +} + +void screen_write_number_error(os_u32 number) { + screen_write_number_impl(number, 0x0C); +} + +void screen_set_pos(int nx, int ny) { + x = nx; + y = ny; } \ No newline at end of file diff --git a/stage1/stage1.c b/stage1/stage1.c index ecf598d..f2ef95e 100644 --- a/stage1/stage1.c +++ b/stage1/stage1.c @@ -2,17 +2,20 @@ #include "../os3_common/packing.h" #include "include/screen.h" #include "include/interrupts.h" +#include "include/pic_8259.h" int main() { - clear_screen(); - write_string("OS3 Booted into stage 1!\n", 0); - write_string("Looking for stage 2....\n", 0); - fill_idt(); - os_u32 i = 0; + screen_clear(); + screen_write_string("OS3 Booted into stage 1!\n", 0); + screen_write_string("Looking for stage 2....\n", 0); + setup_interrupts(); + + setup_pic(); + + enable_interrupts(); + while(1) { - write_number(i++); - write_string("\n", 0); - }; + } return 0; }