[Stage1] Add RSDP and basic ACPI parsing

[Stage1] Add HEX display to screen.h
[Stage1] Handle IRQ1 semi-gracefully
[Stage1] Try (unsuccessfully) to "wait" for IRQ 1 (os_interrupt_wait())
This commit is contained in:
John Stefanelli 2023-06-05 13:13:37 +02:00
parent dad4ff6a34
commit 7a1f072e4a
Signed by: jstefanelli
GPG key ID: 60EDE2437640D2AA
14 changed files with 380 additions and 12 deletions

View file

@ -12,6 +12,7 @@ set(CMAKE_ASM_NASM_LINK_EXECUTABLE "i686-elf-ld <CMAKE_ASM_NASM_LINK_FLAGS> <LIN
# Set language flags # Set language flags
set(CMAKE_C_FLAGS "-Wall -mtune=i386 -gdwarf -m32 -Os") set(CMAKE_C_FLAGS "-Wall -mtune=i386 -gdwarf -m32 -Os")
set(CMAKE_CXX_FLAGS "-Wall -nostdlib")
set(CMAKE_ASM_FLAGS "-felf32 -F dwarf -g") set(CMAKE_ASM_FLAGS "-felf32 -F dwarf -g")
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf32) set(CMAKE_ASM_NASM_OBJECT_FORMAT elf32)
set(CMAKE_STATIC_LINKER_FLAGS "") set(CMAKE_STATIC_LINKER_FLAGS "")

View file

@ -1,4 +1,4 @@
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) 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 include/rsdp.h rsdp.c include/utils.h utils.c include/acpi.h acpi.c)
target_compile_options(stage1 PUBLIC "$<$<COMPILE_LANGUAGE:C>:-ffreestanding>") target_compile_options(stage1 PUBLIC "$<$<COMPILE_LANGUAGE:C>:-ffreestanding>")
set_target_properties(stage1 PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld) 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) target_link_options(stage1 PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)

45
stage1/acpi.c Normal file
View file

@ -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;
}

23
stage1/include/acpi.h Normal file
View file

@ -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

View file

@ -1,9 +1,18 @@
#ifndef OS3_INTERRUPTS_H #ifndef OS3_INTERRUPTS_H
#define OS3_INTERRUPTS_H #define OS3_INTERRUPTS_H
#include "../os3_common/datatypes.h"
extern void setup_interrupts(); extern void setup_interrupts();
// Defined in interrupt_utils.asm // Defined in interrupt_utils.asm
extern void enable_interrupts(); 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 #endif //OS3_INTERRUPTS_H

37
stage1/include/rsdp.h Normal file
View file

@ -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

View file

@ -8,6 +8,9 @@ extern void screen_write_error(const char* str, int length);
extern void screen_clear(); extern void screen_clear();
extern void screen_write_number(os_u32 number); extern void screen_write_number(os_u32 number);
extern void screen_write_number_error(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 void screen_set_pos(int x, int y);
extern int screen_get_pos_x();
extern int screen_get_pos_y();
#endif #endif

8
stage1/include/utils.h Normal file
View file

@ -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

View file

@ -3,19 +3,51 @@ extern interrupt_service_list
; IDTR structure ; IDTR structure
extern main_idt_ptr extern main_idt_ptr
%macro interrupt_service_routine 1 %macro interrupt_service_routine 2
isr_stub_%+%1: isr_stub_%+%1:
MOV EAX, i ; load interrupt number MOV EAX, %1 ; load interrupt number
PUSH EAX ; push parameter "interrupt number" PUSH EAX ; push parameter "interrupt number"
CALL [interrupt_service_list + (%1*4)] ; call interrupt subroutine CALL [interrupt_service_list + (%1*4)] ; call interrupt subroutine
ADD ESP, 4 ; clear parameters ADD ESP, (4 * %2) ; clear parameters
IRET IRET
%endmacro %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 ; Entry points for generic/custom interrupt service routines
%assign i 0 %assign i 32
%rep 256 %rep 224
interrupt_service_routine i interrupt_service_routine i, 1
%assign i i+1 %assign i i+1
%endrep %endrep

View file

@ -45,6 +45,18 @@ idt_entry main_idt[EFFECTIVE_INTERRUPT_AMOUNT];
idt_ptr main_idt_ptr; idt_ptr main_idt_ptr;
volatile void* interrupt_service_list[EFFECTIVE_INTERRUPT_AMOUNT]; 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) { void generic_exception(os_u32 interrupt_id) {
//screen_clear(); //screen_clear();
screen_set_pos(0, 0); 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); 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 */ /* The following is defined in interrupt_utils.asm */
extern void* interrupt_service_table[]; extern void* interrupt_service_table[];
extern void load_idt(); extern void load_idt();
@ -85,7 +113,36 @@ void setup_interrupts() {
interrupt_service_list[i] = (void*)&generic_exception; 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[32] = (void*)&handle_irq0;
interrupt_service_list[33] = (void*)&handle_irq1;
load_idt(); 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;
} }

60
stage1/rsdp.c Normal file
View file

@ -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;
}

View file

@ -89,6 +89,34 @@ void screen_write_number_impl(os_u32 number, os_u8 color) {
screen_write(buffer_2, 0, 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) { void screen_write_number(os_u32 number) {
screen_write_number_impl(number, 0x0A); screen_write_number_impl(number, 0x0A);
} }
@ -97,7 +125,19 @@ void screen_write_number_error(os_u32 number) {
screen_write_number_impl(number, 0x0C); 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) { void screen_set_pos(int nx, int ny) {
x = nx; x = nx;
y = ny; y = ny;
}
int screen_get_pos_x() {
return x;
}
int screen_get_pos_y() {
return y;
} }

View file

@ -1,19 +1,59 @@
#include "../os3_common/datatypes.h" #include "../os3_common/datatypes.h"
#include "../os3_common/packing.h"
#include "include/screen.h" #include "include/screen.h"
#include "include/interrupts.h" #include "include/interrupts.h"
#include "include/pic_8259.h" #include "include/pic_8259.h"
#include "include/rsdp.h"
#include "include/acpi.h"
int main() { int main() {
screen_clear(); 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(); setup_interrupts();
screen_write_string("Interrupts OK\n", 0);
setup_pic(); setup_pic();
screen_write_string("PIC OK\n", 0);
enable_interrupts(); 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) { while(1) {
} }

13
stage1/utils.c Normal file
View file

@ -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;
}