[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:
parent
dad4ff6a34
commit
7a1f072e4a
14 changed files with 380 additions and 12 deletions
|
|
@ -12,6 +12,7 @@ set(CMAKE_ASM_NASM_LINK_EXECUTABLE "i686-elf-ld <CMAKE_ASM_NASM_LINK_FLAGS> <LIN
|
|||
|
||||
# Set language flags
|
||||
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_NASM_OBJECT_FORMAT elf32)
|
||||
set(CMAKE_STATIC_LINKER_FLAGS "")
|
||||
|
|
|
|||
|
|
@ -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>")
|
||||
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)
|
||||
|
|
|
|||
45
stage1/acpi.c
Normal file
45
stage1/acpi.c
Normal 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
23
stage1/include/acpi.h
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
37
stage1/include/rsdp.h
Normal file
37
stage1/include/rsdp.h
Normal 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
|
||||
|
|
@ -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
|
||||
8
stage1/include/utils.h
Normal file
8
stage1/include/utils.h
Normal 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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
60
stage1/rsdp.c
Normal file
60
stage1/rsdp.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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) {
|
||||
}
|
||||
|
||||
|
|
|
|||
13
stage1/utils.c
Normal file
13
stage1/utils.c
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue