diff --git a/CMakeToolchain.txt b/CMakeToolchain.txt index 469cb5b..9d70505 100644 --- a/CMakeToolchain.txt +++ b/CMakeToolchain.txt @@ -12,6 +12,7 @@ set(CMAKE_ASM_NASM_LINK_EXECUTABLE "i686-elf-ld :-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/acpi.c b/stage1/acpi.c new file mode 100644 index 0000000..3964a3d --- /dev/null +++ b/stage1/acpi.c @@ -0,0 +1,45 @@ +#include "include/acpi.h" +#include "include/utils.h" + +OS_ACPI_Header* acpi_rsdt; +OS_ACPI_Header** acpi_root_tables; +os_u32 acpi_root_tables_amount; + +os_bool os_check_acpi(OS_ACPI_Header* header) { + os_u32 len = header->length; + os_u8* ptr = (os_u8*)header; + os_u8 sum = 0; + for(os_u32 i = 0; i < len; i++) { + sum += *ptr; + ++ptr; + } + + return sum == 0 ? OS_TRUE : OS_FALSE; +} + +os_bool os_acpi_init(OS_RSDPDescriptor* desc) { + OS_ACPI_Header* rsdt_header = (OS_ACPI_Header*)desc->rsdt_address; + + if (os_check_acpi(rsdt_header) == OS_FALSE) { + return OS_FALSE; + } + + acpi_rsdt = rsdt_header; + acpi_root_tables = (OS_ACPI_Header**) (((os_u32)acpi_rsdt) + sizeof(OS_ACPI_Header)); + acpi_root_tables_amount = (acpi_rsdt->length - sizeof(OS_ACPI_Header)) / sizeof(OS_ACPI_Header*); + + return OS_TRUE; +} + +OS_ACPI_Header* os_acpi_find_table(os_u8* sig) { + for(os_u32 i = 0; i < acpi_root_tables_amount; i++) { + OS_ACPI_Header* h = acpi_root_tables[i]; + + if(os_data_compare(sig, (os_u8*)h->signature, 4) == OS_TRUE && + os_check_acpi(h) == OS_TRUE) { + return h; + } + } + + return (OS_ACPI_Header*)0; +} \ No newline at end of file diff --git a/stage1/include/acpi.h b/stage1/include/acpi.h new file mode 100644 index 0000000..11f2176 --- /dev/null +++ b/stage1/include/acpi.h @@ -0,0 +1,23 @@ +#ifndef OS3_ACPI_H +#define OS3_ACPI_H + +#include "rsdp.h" + +OS_PACK_START +typedef struct _OS_ACPI_Header { + char signature[4]; + os_u32 length; + os_u8 revision; + os_u8 checksum; + char oem_id[6]; + char oem_table_id[8]; + os_u32 oem_revision; + os_u32 creator_id; + os_u32 creator_revision; +} OS_PACK_MID OS_ACPI_Header; +OS_PACK_END + +extern os_bool os_acpi_init(OS_RSDPDescriptor* desc); +extern OS_ACPI_Header* os_acpi_find_table(os_u8* sig); + +#endif //OS3_ACPI_H diff --git a/stage1/include/interrupts.h b/stage1/include/interrupts.h index eda7a41..8275fb6 100644 --- a/stage1/include/interrupts.h +++ b/stage1/include/interrupts.h @@ -1,9 +1,18 @@ #ifndef OS3_INTERRUPTS_H #define OS3_INTERRUPTS_H +#include "../os3_common/datatypes.h" + extern void setup_interrupts(); // Defined in interrupt_utils.asm extern void enable_interrupts(); +/// Waits for an interrupt +/// \param interrupt The interrupt to wait for +/// \param timeout The maximum amount of time (in PIT ticks) to wait +/// \return OS_TRUE if interrupt was wait-able, received AND no other os_interrupt_wait call was in progress, +/// OS_FALSE otherwise +extern os_bool os_interrupt_wait(os_u32 interrupt, os_u64 timeout); + #endif //OS3_INTERRUPTS_H diff --git a/stage1/include/rsdp.h b/stage1/include/rsdp.h new file mode 100644 index 0000000..b200745 --- /dev/null +++ b/stage1/include/rsdp.h @@ -0,0 +1,37 @@ +#ifndef OS3_RSDP_H +#define OS3_RSDP_H + +#include "../../os3_common/packing.h" +#include "../../os3_common/datatypes.h" + +#define OS_RSDP_SIG "RSD PTR " + +OS_PACK_START +struct _OS_RSDPDescriptor { + char signature[8]; + os_u8 checksum; + char oem_id[6]; + os_u8 revision; + os_u32 rsdt_address; +} OS_PACK_MID; +OS_PACK_END + +typedef struct _OS_RSDPDescriptor OS_RSDPDescriptor; + +OS_PACK_START +struct _OS_RSDPDescriptor_20 { + OS_RSDPDescriptor first_part; + + os_u32 length; + os_u64 xstd_address; + os_u8 extended_checksum; + os_u8 reserved[3]; +} OS_PACK_MID; +OS_PACK_END + +typedef struct _OS_RSDPDescriptor_20 OS_RSDPDescriptor_20; + +extern OS_RSDPDescriptor* os_find_RSDP(); +extern OS_RSDPDescriptor_20* os_find_RSDP_20(); + +#endif //OS3_RSDP_H diff --git a/stage1/include/screen.h b/stage1/include/screen.h index 906c1d9..befe6dd 100644 --- a/stage1/include/screen.h +++ b/stage1/include/screen.h @@ -8,6 +8,9 @@ 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_write_number_hex(os_u32 number); extern void screen_set_pos(int x, int y); +extern int screen_get_pos_x(); +extern int screen_get_pos_y(); #endif \ No newline at end of file diff --git a/stage1/include/utils.h b/stage1/include/utils.h new file mode 100644 index 0000000..57e41cf --- /dev/null +++ b/stage1/include/utils.h @@ -0,0 +1,8 @@ +#ifndef OS3_UTILS_H +#define OS3_UTILS_H + +#include "../../os3_common/datatypes.h" + +extern os_bool os_data_compare(os_u8* str0, os_u8* str1, os_u32 length); + +#endif //OS3_UTILS_H diff --git a/stage1/interrupt_utils.asm b/stage1/interrupt_utils.asm index 09c9483..f289bd2 100644 --- a/stage1/interrupt_utils.asm +++ b/stage1/interrupt_utils.asm @@ -3,19 +3,51 @@ extern interrupt_service_list ; IDTR structure extern main_idt_ptr -%macro interrupt_service_routine 1 +%macro interrupt_service_routine 2 isr_stub_%+%1: - MOV EAX, i ; load interrupt number + MOV EAX, %1 ; load interrupt number PUSH EAX ; push parameter "interrupt number" CALL [interrupt_service_list + (%1*4)] ; call interrupt subroutine - ADD ESP, 4 ; clear parameters + ADD ESP, (4 * %2) ; clear parameters IRET %endmacro +; Standard x86 interrupts +interrupt_service_routine 0, 1 ; division error +interrupt_service_routine 1, 1 ; DEBUG +interrupt_service_routine 2, 1 ; NMI +interrupt_service_routine 3, 1 ; Breakpoint +interrupt_service_routine 4, 1 ; Overflow +interrupt_service_routine 5, 1 ; Bound Range Exceeded +interrupt_service_routine 6, 1 ; Invalid OPCODE +interrupt_service_routine 7, 1 ; Device not available +interrupt_service_routine 8, 2 ; Double fault +interrupt_service_routine 9, 1 ; Coprocessor Segment Overrun (Unused) +interrupt_service_routine 10, 2 ; Invalid TSS +interrupt_service_routine 11, 2 ; Segment not Present +interrupt_service_routine 12, 2 ; Stack segment fault +interrupt_service_routine 13, 2 ; General protection fault +interrupt_service_routine 14, 2 ; Page Fault +interrupt_service_routine 15, 1 ; Reserved +interrupt_service_routine 16, 1 ; x87 Floating-Point exception +interrupt_service_routine 17, 2 ; Alignment check +interrupt_service_routine 18, 1 ; Machine Check +interrupt_service_routine 19, 1 ; SIMD Float exception +interrupt_service_routine 20, 1 ; Virtualization exception +interrupt_service_routine 21, 2 ; Control Point exception +%assign i 22 +%rep 6 +interrupt_service_routine i, 1 ; Reserved +%assign i i+1 +%endrep +interrupt_service_routine 28, 1 ; Hypervisor injection exception +interrupt_service_routine 29, 2 ; VMM Communication exception +interrupt_service_routine 30, 2 ; Security exception +interrupt_service_routine 31, 1 ; Reserved -; Generate entry points for interrupt service routines -%assign i 0 -%rep 256 -interrupt_service_routine i +; Entry points for generic/custom interrupt service routines +%assign i 32 +%rep 224 +interrupt_service_routine i, 1 %assign i i+1 %endrep diff --git a/stage1/interrupts.c b/stage1/interrupts.c index 07134cf..5666d08 100644 --- a/stage1/interrupts.c +++ b/stage1/interrupts.c @@ -45,6 +45,18 @@ idt_entry main_idt[EFFECTIVE_INTERRUPT_AMOUNT]; idt_ptr main_idt_ptr; volatile void* interrupt_service_list[EFFECTIVE_INTERRUPT_AMOUNT]; +os_u64 os_ticks = 0; + +os_u32 target_waiting_interrupt = 0; +os_u32 target_waiting_flag = 0; + +void os_interrupt_signal(os_u32 interrupt_id) { + if (target_waiting_interrupt == interrupt_id && target_waiting_flag != 0) { + target_waiting_flag = 0; + target_waiting_interrupt = 0; + } +} + void generic_exception(os_u32 interrupt_id) { //screen_clear(); screen_set_pos(0, 0); @@ -56,10 +68,26 @@ void generic_exception(os_u32 interrupt_id) { } } -void handle_irq0(os_u32) { +void handle_irq0(os_u32 interrupt_id) { + os_ticks++; + pic_sendEOI(0); } +void handle_irq1(os_u32 interrupt_id) { + os_interrupt_signal(interrupt_id); + + pic_sendEOI(1); +} + +void handle_double_fault(os_u32 interrupt_id) { + screen_set_pos(0, 0); + screen_write_error("Double fault.\n", 0); + while(1) { + + } +} + /* The following is defined in interrupt_utils.asm */ extern void* interrupt_service_table[]; extern void load_idt(); @@ -85,7 +113,36 @@ void setup_interrupts() { interrupt_service_list[i] = (void*)&generic_exception; } + + main_idt[3].attributes.gate_type = IDT_GATE_TYPE_TRAP_32; + main_idt[4].attributes.gate_type = IDT_GATE_TYPE_TRAP_32; + + interrupt_service_list[8] = (void*)&handle_double_fault; interrupt_service_list[32] = (void*)&handle_irq0; + interrupt_service_list[33] = (void*)&handle_irq1; + load_idt(); +} + +os_bool os_interrupt_wait(os_u32 interrupt, os_u64 timeout) { + if (interrupt != 33) //Keyboard interrupt + return OS_FALSE; + + if (target_waiting_interrupt != 0 || target_waiting_flag != (os_u32*)0) { + return OS_FALSE; + } + + os_u64 start_ticks = os_ticks; + target_waiting_interrupt = interrupt; + target_waiting_flag = 1; + while(target_waiting_flag) { + if(timeout != 0 && (os_ticks - start_ticks) >= timeout) { + target_waiting_flag = 0; + target_waiting_interrupt = 0; + return OS_FALSE; + } + } + + return OS_TRUE; } \ No newline at end of file diff --git a/stage1/rsdp.c b/stage1/rsdp.c new file mode 100644 index 0000000..f16d5f6 --- /dev/null +++ b/stage1/rsdp.c @@ -0,0 +1,60 @@ +#include "include/rsdp.h" +#include "include/utils.h" +#include "include/screen.h" + +OS_RSDPDescriptor* os_find_RSDP() { + os_u16* ebda_addr_raw = (os_u16*)0x40E; + os_u32 ebda_addr_0 = ((os_u32)(*ebda_addr_raw)); + os_u32 ebda_addr = ebda_addr_0 << 4; + os_u8* ebda = (os_u8*)ebda_addr; + os_u8* current_ptr = ebda; + + while((os_u32)(current_ptr - ebda) < 1024) { + if (os_data_compare(current_ptr, (os_u8*)OS_RSDP_SIG, 8) == OS_TRUE) { + OS_RSDPDescriptor* ptr = (OS_RSDPDescriptor*)current_ptr; + + os_u32 sum = 0; + for(os_u32 i = 0; i < sizeof(OS_RSDPDescriptor); i++) { + sum += current_ptr[i]; + } + + if (((os_u8) sum) != 0) { + current_ptr += 16; + continue; + } + + return ptr; + } + current_ptr += 16; + } + + os_u8* bios_area_ptr = (os_u8*)0x000E0000; + os_u8* bios_end_ptr = (os_u8*)0x000E0000 + 0x20000; + current_ptr = bios_area_ptr; + + while(current_ptr < bios_end_ptr) { + if (os_data_compare(current_ptr, (os_u8*)OS_RSDP_SIG, 8) == OS_TRUE) { + OS_RSDPDescriptor* ptr = (OS_RSDPDescriptor*)current_ptr; + + os_u32 sum = 0; + for(os_u32 i = 0; i < sizeof(OS_RSDPDescriptor); i++) { + sum += current_ptr[i]; + } + + if (((os_u8) sum) != 0) { + current_ptr += 16; + continue; + } + + return ptr; + } + current_ptr += 16; + } + + + return (OS_RSDPDescriptor*)0; +} + +OS_RSDPDescriptor_20* os_find_RSDP_20() { + return (OS_RSDPDescriptor_20*)0; +} \ No newline at end of file diff --git a/stage1/screen.c b/stage1/screen.c index 71b96a4..824adfb 100644 --- a/stage1/screen.c +++ b/stage1/screen.c @@ -89,6 +89,34 @@ void screen_write_number_impl(os_u32 number, os_u8 color) { screen_write(buffer_2, 0, color); } +void screen_write_number_hex_impl(os_u32 number, os_u8 color) { + char buffer[32]; + char buffer_2[32]; + + os_s32 i = 0; + while(i < 32) { + if (i > 0 && number == 0) { + break; + } + + buffer[i] = ((char)(number % 16)); + i++; + number /= 16; + } + + i--; + char* buffer_2_ptr = buffer_2; + while(i >= 0) { + char val = (char)(buffer[i] >= 10 ? (buffer[i] - 10) + 'A' : buffer[i] + '0'); + *buffer_2_ptr = val; + buffer_2_ptr++; + i--; + } + *buffer_2_ptr = 0; + + screen_write(buffer_2, 0, color); +} + void screen_write_number(os_u32 number) { screen_write_number_impl(number, 0x0A); } @@ -97,7 +125,19 @@ void screen_write_number_error(os_u32 number) { screen_write_number_impl(number, 0x0C); } +void screen_write_number_hex(os_u32 number) { + screen_write_number_hex_impl(number, 0x0A); +} + void screen_set_pos(int nx, int ny) { x = nx; y = ny; +} + +int screen_get_pos_x() { + return x; +} + +int screen_get_pos_y() { + return y; } \ No newline at end of file diff --git a/stage1/stage1.c b/stage1/stage1.c index f2ef95e..6304933 100644 --- a/stage1/stage1.c +++ b/stage1/stage1.c @@ -1,19 +1,59 @@ #include "../os3_common/datatypes.h" -#include "../os3_common/packing.h" #include "include/screen.h" #include "include/interrupts.h" #include "include/pic_8259.h" +#include "include/rsdp.h" +#include "include/acpi.h" int main() { screen_clear(); - screen_write_string("OS3 Booted into stage 1!\n", 0); - screen_write_string("Looking for stage 2....\n", 0); + + screen_write_string("-------- OS3 Stage 1 --------\n", 0);; setup_interrupts(); + screen_write_string("Interrupts OK\n", 0); + setup_pic(); + screen_write_string("PIC OK\n", 0); + enable_interrupts(); + screen_write_string("STI OK\n", 0); + + OS_RSDPDescriptor* rsdp = os_find_RSDP(); + + if (rsdp == 0) { + screen_write_string("ERROR: RSDP Not found", 0); + while (1) { + + } + } + + screen_write_string("RSDP OK\n", 0); + + os_bool acpi_ok = os_acpi_init(rsdp); + + if (acpi_ok != OS_TRUE) { + screen_write_string("ERROR: ACPI Init failed.", 0); + while(1) { + + } + } + + screen_write_string("ACPI Ok\n", 0); + + screen_write_string("Waiting for any key....\n", 0); + os_bool res = os_interrupt_wait(33, 300); + if (res == OS_TRUE) { + screen_write_string("Keyboard interrupt OK\n", 0); + } else { + screen_write_error("Keyboard interrupt timed out\n", 0); + while(1) { + + } + } + while(1) { } diff --git a/stage1/utils.c b/stage1/utils.c new file mode 100644 index 0000000..7be2ec2 --- /dev/null +++ b/stage1/utils.c @@ -0,0 +1,13 @@ +#include "include/utils.h" + +os_bool os_data_compare(os_u8* str0, os_u8* str1, os_u32 length) { + os_u32 count = 0; + while(count < length) { + if (str0[count] != str1[count]) { + return OS_FALSE; + } + count++; + } + + return OS_TRUE; +} \ No newline at end of file