From e37222c34681b3e8bef5871c96d134ad2f12afee Mon Sep 17 00:00:00 2001 From: Rick Rongen Date: Mon, 30 Aug 2021 19:56:36 +0200 Subject: [PATCH] feat: added basic ACPI support using LAI --- .gitmodules | 3 + CMakeLists.txt | 19 +- include/myke/acpi/acpi.h | 14 ++ include/myke/acpi/structures.h | 256 ++++++++++++++++++++++++++ include/myke/cpu/pic.h | 5 +- include/myke/cpu/{timer.h => pit.h} | 6 +- kernel/acpi/acpi.c | 276 ++++++++++++++++++++++++++++ kernel/acpi/lailayer.c | 80 ++++++++ kernel/command.c | 2 +- kernel/cpu/isr.c | 14 +- kernel/cpu/pic.c | 18 +- kernel/cpu/{timer.c => pit.c} | 50 ++++- kernel/drivers/pci/ide.c | 12 +- kernel/kernel.c | 9 +- kernel/libc/kprintf.c | 1 + kernel/util/power.c | 7 +- lai | 1 + 17 files changed, 729 insertions(+), 44 deletions(-) create mode 100644 .gitmodules create mode 100644 include/myke/acpi/acpi.h create mode 100644 include/myke/acpi/structures.h rename include/myke/cpu/{timer.h => pit.h} (65%) create mode 100644 kernel/acpi/acpi.c create mode 100644 kernel/acpi/lailayer.c rename kernel/cpu/{timer.c => pit.c} (54%) create mode 160000 lai diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..04f49ee --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lai"] + path = lai + url = https://github.com/managarm/lai.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a12ff8..c2e5b08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,17 +7,18 @@ SET(CMAKE_C_COMPILER ${COMPILER_RT}/i686-elf-gcc) SET(CMAKE_ASM_COMPILER ${COMPILER_RT}/i686-elf-gcc) # Optionally enable cmake debugging -#SET(CMAKE_VERBOSE_MAKEFILE ON) +SET(CMAKE_VERBOSE_MAKEFILE ON) # Set compile flags SET(CMAKE_C_FLAGS "-g -ffreestanding -Wall -Wextra -fno-exceptions -fstack-protector -fno-pie -m32") SET(CMAKE_ASM_FLAGS "${CFLAGS} -m32 -x assembler-with-cpp") -SET(CMAKE_EXE_LINKER_FLAGS "-T${CMAKE_CURRENT_LIST_DIR}/linker.ld -lgcc -ffreestanding -nostdlib -no-pie") +SET(CMAKE_EXE_LINKER_FLAGS "-T${CMAKE_CURRENT_LIST_DIR}/linker.ld -nostdlib -lgcc") -include_directories(AFTER include) +include_directories(AFTER include lai/include) set(CMAKE_C_STANDARD 99) +FILE(GLOB lai lai/core/*.c lai/helpers/*.c lai/driver/*.c) FILE(GLOB_RECURSE kernel_src kernel/**.c) FILE(GLOB_RECURSE kernel_asm kernel/**.S) FILE(GLOB_RECURSE boot_asm boot/boot.S) @@ -31,9 +32,11 @@ add_compile_definitions(ENABLE_SELF_TEST) # Support for pretty printing pci cla add_compile_definitions(ENABLE_PCIPP) # Support for pretty printing pci class/subclass/interface add_compile_definitions(K_SHELL) -add_executable(my-kernel.bin ${kernel_src} ${kernel_asm} ${boot_asm}) +# find libgcc.a +add_library(libgcc STATIC IMPORTED) +set_target_properties(libgcc PROPERTIES IMPORTED_LOCATION ${COMPILER_RT}/../lib/gcc/i686-elf/10.2.0/libgcc.a) + +add_executable(my-kernel.bin ${kernel_src} ${kernel_asm} ${boot_asm} ${lai}) +target_link_libraries(my-kernel.bin libgcc) set_source_files_properties(${kernel_src} PROPERTIES LANGUAGE C COMPILE_FLAGS "") -set_target_properties(my-kernel.bin PROPERTIES LINKER_LANGUAGE C PREFIX "" SUFFIX "" LINK_FLAGS "") - - - +set_target_properties(my-kernel.bin PROPERTIES LINKER_LANGUAGE C PREFIX "" SUFFIX "" LINK_FLAGS "") \ No newline at end of file diff --git a/include/myke/acpi/acpi.h b/include/myke/acpi/acpi.h new file mode 100644 index 0000000..b4563a4 --- /dev/null +++ b/include/myke/acpi/acpi.h @@ -0,0 +1,14 @@ +// +// Created by rick on 22-08-21. +// + +#ifndef NEW_KERNEL_ACPI_H +#define NEW_KERNEL_ACPI_H + +void acpi_parse(); + +void acpi_init(); + +void* acpi_find_table_by_name(const char* name, int skip); + +#endif //NEW_KERNEL_ACPI_H diff --git a/include/myke/acpi/structures.h b/include/myke/acpi/structures.h new file mode 100644 index 0000000..effbf5b --- /dev/null +++ b/include/myke/acpi/structures.h @@ -0,0 +1,256 @@ +// +// Created by rick on 22-08-21. +// + +#ifndef NEW_KERNEL_STRUCTURES_H +#define NEW_KERNEL_STRUCTURES_H + +#include +#include +#include + +#define RDSP_SIGNATURE_LENGTH 8 +#define RSDP_SIGNATURE "RSD PTR " + +enum generic_address_structure_address_space { + system_memory = 0, + system_io = 1, + pci_config_space = 2, + embedded_controller = 3, + system_management_bus = 4, + system_cmos = 5, + pci_device_bar = 6, + ipmi = 7, + gpio = 8, + gsb = 9, + pmc = 0x0A +}; + +enum generic_address_structure_access_size { + undefined = 0, + uint8 = 1, + uint16 = 2, + uint32 = 3, + uint64 = 4, +}; + +struct generic_address_structure { + uint8_t address_space; + uint8_t bit_width; + uint8_t bit_offset; + uint8_t access_size; + uint64_t address; +}; + +struct acpi_rsdp_descriptor { + char signature[8]; + uint8_t checksum; + char oem_id[6]; + uint8_t revision; + uint32_t rsdt_address; +} att_packed; + +struct acpi_rsdp_descriptor_20 { + struct acpi_rsdp_descriptor rsdp; + + uint32_t length; + uint64_t xsdt_address; + uint8_t extended_checksum; + uint32_t: 24; // reserved +} att_packed; + +struct acpi_sdt_header { + char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oem_id[6]; + char oem_table_id[8]; + uint32_t oem_revision; + uint32_t creator_id; + uint32_t creator_revision; +} att_packed; + +struct acpi_rsdt { + struct acpi_sdt_header header; + uint32_t pointer_to_other_sdt[]; +} att_packed; + +struct acpi_xsdt { + struct acpi_sdt_header header; + uint64_t pointer_to_other_sdt[]; +} att_packed; + +struct acpi_fadt { + struct acpi_sdt_header header; + uint32_t firmware_ctrl; + uint32_t dsdt; + + // field used in ACPI 1.0; no longer in use, for compatibility only + uint8_t: 8; + + uint8_t preferred_power_management_profile; + uint16_t sci_interrupt; + uint32_t smi_command_port; + uint8_t acpi_enable; + uint8_t acpi_disable; + uint8_t s4bios_req; + uint8_t pstate_control; + uint32_t pm1a_event_block; + uint32_t pm1b_event_block; + uint32_t pm1a_control_block; + uint32_t pm1b_control_block; + uint32_t pm2_control_block; + uint32_t pm_timer_block; + uint32_t gpe0_block; + uint32_t gpe1_block; + uint8_t pm1_event_length; + uint8_t pm1_control_length; + uint8_t pm2_control_length; + uint8_t pm_timer_length; + uint8_t gpe0_length; + uint8_t gpe1_length; + uint8_t gpe1_base; + uint8_t cstate_control; + uint16_t worst_c2_latency; + uint16_t worst_c3_latency; + uint16_t flush_size; + uint16_t flush_stride; + uint8_t duty_offset; + uint8_t duty_width; + uint8_t day_alarm; + uint8_t month_alarm; + uint8_t century; + + // reserved in ACPI 1.0; used since ACPI 2.0+ + uint16_t boot_architecture_flags; + + uint8_t: 8; + uint32_t flags; + + // 12 byte structure; see below for details + struct generic_address_structure reset_reg; + uint8_t reset_value; + uint16_t arm_boot_arch; + uint8_t fadt_minor_version; + + // 64bit pointers - Available on ACPI 2.0+ + uint64_t x_firmware_control; + uint64_t x_dsdt; + + struct generic_address_structure x_pm1a_event_block; + struct generic_address_structure x_pm1b_event_block; + struct generic_address_structure x_pm1a_control_block; + struct generic_address_structure x_pm1b_control_block; + struct generic_address_structure x_pm2_control_block; + struct generic_address_structure x_pm_timer_block; + struct generic_address_structure x_gpe0_block; + struct generic_address_structure x_gpe1_block; + struct generic_address_structure sleep_control_register; + struct generic_address_structure sleep_status_register; + uint64_t hypervisor_id; +} att_packed; + +#define MADT_TYPE_PROCESSOR_LOCAL_APIC 0 +#define MADT_TYPE_IO_APIC 1 +#define MADT_TYPE_IO_APIC_INTERRUPT_SOURCE_OVERRIDE 2 +#define MADT_TYPE_IO_APIC_NON_MASKABLE_INTERRUPT_SOURCE 3 +#define MADT_TYPE_LOCAL_APIC_NON_MASKABLE_INTERRUPTS 4 +#define MADT_TYPE_LOCAL_APIC_ADDRESS_OVERRIDE 5 +#define MADT_TYPE_PROCESSOR_LOCAL_X2_APIC 9 + +union madt_local_apic_flags { + uint32_t flags_int; + struct { + bool processor_enabled: 1; + bool online_capable: 1; + } flags; +}; + +union madt_interrupt_flags { + uint16_t flags_int; + struct { + bool: 1; // 1 + bool active_low: 1; // 2 + bool: 1; // 4 + bool level_triggered: 1; // 8 + } att_packed; +}; + +struct acpi_madt { + struct acpi_sdt_header header; + uint32_t local_apic_addr; + union { + uint32_t flags_int; + struct { + bool dual_8259_legacy_pics: 1; + }; + }; + uint8_t entries[]; +} att_packed; + +struct acpi_madt_entry_header { + uint8_t type; + uint8_t length; +} att_packed; + +struct acpi_madt_local_apic { // type 0 + struct acpi_madt_entry_header header; + uint8_t processor_id; + uint8_t apic_id; + union madt_local_apic_flags flags; +} att_packed; + +struct acpi_madt_io_apic { // type 1 + struct acpi_madt_entry_header header; + uint8_t apic_id; + uint8_t: 8; // reserved + uint32_t io_apic_address; + uint32_t global_system_interrupt_base; +} att_packed; + +struct acpi_madt_io_apic_interrupt_source_override { // type 2 + struct acpi_madt_entry_header header; + uint8_t bus_source; + uint8_t irq_source; + uint32_t global_system_interrupt; + union madt_interrupt_flags flags; +} att_packed; + +struct acpi_madt_io_apic_non_maskable_interrupt { // type 3 + struct acpi_madt_entry_header header; + uint8_t nmi_source; + uint8_t: 8; // reserved + union madt_interrupt_flags flags; + uint32_t global_system_interrupt; +} att_packed; + +struct acpi_madt_local_apic_non_maskable_interrupts { + struct acpi_madt_entry_header header; + uint8_t acpi_processor_id; + union madt_interrupt_flags flags; + uint8_t lint_no; +} att_packed; + +struct acpi_madt_local_apic_address_override { + struct acpi_madt_entry_header header; + uint16_t: 16; // reserved + uint64_t physical_address_local_apic; +} att_packed; + +struct acpi_madt_processor_local_x2_apic { + struct acpi_madt_entry_header header; + uint16_t: 16; // reserved + uint32_t processors_local_x2_apic_id; + union madt_local_apic_flags flags; + uint32_t acpi_id; +} att_packed; + +struct acpi_type { + char name[4]; + char *description; + + void (*handle_table)(const struct acpi_sdt_header *addr); +}; + +#endif //NEW_KERNEL_STRUCTURES_H diff --git a/include/myke/cpu/pic.h b/include/myke/cpu/pic.h index 87911f5..8a704ba 100644 --- a/include/myke/cpu/pic.h +++ b/include/myke/cpu/pic.h @@ -5,10 +5,13 @@ #ifndef NEW_KERNEL_PIC_H #define NEW_KERNEL_PIC_H +#include #include -void pic_init(); +void pic_init(uint8_t isr_offset); void pic_set_mask(uint16_t mask); +void pic_eoi(bool slave); + #endif //NEW_KERNEL_PIC_H diff --git a/include/myke/cpu/timer.h b/include/myke/cpu/pit.h similarity index 65% rename from include/myke/cpu/timer.h rename to include/myke/cpu/pit.h index e9c4656..6d7081b 100644 --- a/include/myke/cpu/timer.h +++ b/include/myke/cpu/pit.h @@ -7,12 +7,12 @@ #include -int init_timer(uint32_t freq); +int pit_init(uint32_t freq); void print_current_tick(); -uint32_t timer_get_tick(); +uint32_t pit_get_tick(); -void sleep(uint32_t milliseconds); +void pit_sleep(uint32_t milliseconds); #endif //MY_KERNEL_TIMER_H diff --git a/kernel/acpi/acpi.c b/kernel/acpi/acpi.c new file mode 100644 index 0000000..41751a5 --- /dev/null +++ b/kernel/acpi/acpi.c @@ -0,0 +1,276 @@ +// +// Created by rick on 22-08-21. +// + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +void acpi_handle_facp(const struct acpi_sdt_header *addr); + +void acpi_handle_apic(const struct acpi_sdt_header *addr); + +struct acpi_type acpi_types[] = { + {"APIC", "Multiple APIC Description Table (MADT)", acpi_handle_apic}, + {"BGRT", "Boot Graphics Resource Table (BGRT; only supported on UEFI systems)", NULL}, + {"BERT", "Boot Error Record Table (BERT)", NULL}, + {"CPEP", "Corrected Platform Error Polling Table (CPEP)", NULL}, + {"DSDT", "Differentiated System Description Table (DSDT)", NULL}, + {"ECDT", "Embedded Controller Boot Resources Table (ECDT)", NULL}, + {"EINJ", "Error Injection Table (EINJ)", NULL}, + {"ERST", "Error Record Serialization Table (ERST)", NULL}, + {"FACP", "Fixed ACPI Description Table (FADT)", acpi_handle_facp}, + {"FACS", "Firmware ACPPI Control Structure (FACS)", NULL}, + {"HEST", "Hardware Error Source Table (HEST)", NULL}, + {"MSCT", "Maximum System Characteristics Table (MSCT)", NULL}, + {"MPST", "Memory Power State Table (MPST)", NULL}, +// {"OEMx", "OEM Specific Information Tables (Any table with a signature beginning with \"OEM\" falls into this definition)", NULL}, + {"PMTT", "latform Memory Topology Table (PMTT)", NULL}, + {"PSDT", "Persistent System Description Table (PSDT)", NULL}, + {"RASF", "ACPI RAS FeatureTable (RASF)", NULL}, + {"RSDT", "Root System Description Table (RSDT; 32-bit version of the XSDT)", NULL}, + {"SBST", "Smart Battery Specification Table (SBST)", NULL}, + {"SLIT", "System Locality System Information Table (SLIT)", NULL}, + {"SRAT", "System Resource Affinity Table (SRAT)", NULL}, + {"SSDT", "Secondary System Description Table (SSDT)", NULL}, + {"XSDT", "Extended System Description Table (This wiki page; included for completeness)", NULL}, + {"\0\0\0\0", NULL, NULL}, +}; + +bool acpi_checksum(const void *table_addr, const size_t table_size) { + if (table_size < 1) { + return false; // invalid input + } + const uint8_t *table = table_addr; + uint8_t val = 0; + for (size_t i = 0; i < table_size; ++i) { + val += table[i]; + } + return val == 0; +} + +const struct acpi_rsdt *rsdt_table = NULL; +const struct acpi_xsdt *xsdt_table = NULL; + +const struct acpi_fadt_t *fadt; +const struct acpi_sdt_header *dsdt; + +void acpi_handle_facp(const struct acpi_sdt_header *addr) { + // parse the FACP/FADT + fadt = (const struct acpi_fadt_t *) addr; + if (fadt->header.revision > 5) { + // minor since 5.1 + printf("ACPI Revision: %i.%i %.6s\n", fadt->header.revision, fadt->minor_version, fadt->header.oem); + } else { + printf("ACPI Revision: %i.0 %.6s\n", fadt->header.revision, fadt->header.oem); + } + if (fadt->x_dsdt != 0 && fadt->x_dsdt < UINT32_MAX) { + dsdt = (struct acpi_sdt_header *) fadt->x_dsdt; + } else if (fadt->dsdt != 0) { + dsdt = (struct acpi_sdt_header *) fadt->dsdt; + } else { + k_panics("No DSDT"); + } + if (!acpi_checksum(dsdt, dsdt->length)) { + k_panics("DSDT is not valid"); + } +} + +void acpi_handle_apic(const struct acpi_sdt_header *addr) { + const struct acpi_madt *madt = (const struct acpi_madt *) addr; + printf("Local apic: %p %i\n", madt->local_apic_addr, madt->flags_int); + lapic_set_addr(madt->local_apic_addr); + const uint8_t *current = madt->entries; + const uint8_t *end = (const uint8_t *) (madt) + madt->header.length; + while (current < end) { + struct acpi_madt_entry_header *current_header = (struct acpi_madt_entry_header *) current; + switch (current_header->type) { + case MADT_TYPE_PROCESSOR_LOCAL_APIC: { + const struct acpi_madt_local_apic *la = (const struct acpi_madt_local_apic *) current_header; + printf("Local APIC %x for %x %x\n", la->apic_id, la->processor_id, la->flags); + break; + } + case MADT_TYPE_IO_APIC: { + const struct acpi_madt_io_apic *ia = (const struct acpi_madt_io_apic *) current_header; + printf("IO APIC %x at %x with %x\n", ia->apic_id, ia->io_apic_address, + ia->global_system_interrupt_base); + break; + } + case MADT_TYPE_IO_APIC_INTERRUPT_SOURCE_OVERRIDE: { + const struct acpi_madt_io_apic_interrupt_source_override *override = (const struct acpi_madt_io_apic_interrupt_source_override *) current_header; + printf("IO APIC Interrupt source override %x:%x -> %x %x\n", override->bus_source, override->irq_source, + override->global_system_interrupt, override->flags); + break; + } + case MADT_TYPE_IO_APIC_NON_MASKABLE_INTERRUPT_SOURCE: { + const struct acpi_madt_io_apic_non_maskable_interrupt *nmi = (const struct acpi_madt_io_apic_non_maskable_interrupt *) current_header; + printf("IO APIC NMI source %x %x %x\n", nmi->nmi_source, nmi->flags, nmi->global_system_interrupt); + break; + } + case MADT_TYPE_LOCAL_APIC_NON_MASKABLE_INTERRUPTS: { + const struct acpi_madt_local_apic_non_maskable_interrupts *nmi = (const struct acpi_madt_local_apic_non_maskable_interrupts *) current_header; + printf("Local APIC NMI CPU %x %x %x\n", nmi->acpi_processor_id, nmi->flags, nmi->lint_no); + break; + } + case MADT_TYPE_LOCAL_APIC_ADDRESS_OVERRIDE: { + const struct acpi_madt_local_apic_address_override *ao = (const struct acpi_madt_local_apic_address_override *) current_header; + printf("Local APIC addr override %x%x\n", ao->physical_address_local_apic >> 32, + ao->physical_address_local_apic & UINT32_MAX); + if (ao->physical_address_local_apic > UINT32_MAX) { + printf("Override above 4GB!"); + } else { + lapic_set_addr(ao->physical_address_local_apic & UINT32_MAX); + } + break; + } + case MADT_TYPE_PROCESSOR_LOCAL_X2_APIC: { + const struct acpi_madt_processor_local_x2_apic *x2 = (const struct acpi_madt_processor_local_x2_apic *) current_header; + printf("Local x2APIC %x %x %x\n", x2->processors_local_x2_apic_id, x2->flags, x2->acpi_id); + break; + } + default: + printf("Unknown MADT entry %x", current_header->type); + break; + } + current += current_header->length; + } + printf("Lapic id %x v%x\n", lapic_get_id(), lapic_get_version()); +} + +void acpi_parse_table(uint32_t table_addr, uint32_t index) { + struct acpi_sdt_header *s_header = (struct acpi_sdt_header *) table_addr; + if (!acpi_checksum(s_header, s_header->length)) { + printf("%i: invalid acpi entry\n", index); + return; + } + struct acpi_type *c = &acpi_types[0]; + while (c->name[0] != '\0') { + if (strncmp(s_header->signature, c->name, 4) == 0) { + printf("%i: %.4s %s\n", index, c->name, c->description); + if (c->handle_table != NULL) { + c->handle_table(s_header); + } + break; + } + c += 1; + } + if (c->name[0] == '\0') { + printf("%i: %.4s unknown\n", index, s_header->signature); + } + +} + +void acpi_parse_rsdt(uint32_t address) { + printf("Parsing RSDT\n"); + rsdt_table = (const struct acpi_rsdt *) address; + if (!acpi_checksum(rsdt_table, rsdt_table->header.length)) { + k_panics("Malformed RSDT"); + } + if (strncmp(rsdt_table->header.signature, "RSDT", 4) != 0) { + k_panics("RSDT pointer is not RSDT"); + } + uint32_t entries = (rsdt_table->header.length - sizeof(struct acpi_sdt_header)) / sizeof(uint32_t); + for (uint32_t i = 0; i < entries; ++i) { + acpi_parse_table(rsdt_table->pointer_to_other_sdt[i], i); + } +} + +void acpi_parse_xsdt(uint64_t address) { + printf("Parsing XSDT\n"); + if (address > UINT32_MAX) { + k_panics("acpi table above 4GB"); + } + xsdt_table = (const struct acpi_xsdt *) (uint32_t) address; + if (!acpi_checksum(xsdt_table, xsdt_table->header.length)) { + k_panics("Malformed XSDT"); + } + if (strncmp(xsdt_table->header.signature, "XSDT", 4) != 0) { + k_panics("XSDT pointer is not XSDT"); + } + uint32_t entries = (xsdt_table->header.length - sizeof(struct acpi_sdt_header)) / sizeof(uint64_t); + for (uint32_t i = 0; i < entries; ++i) { + const uint64_t entry_addr = xsdt_table->pointer_to_other_sdt[i]; + if (entry_addr > UINT32_MAX) { + printf("%i: Above 4GB\n", i); + continue; + } + acpi_parse_table(xsdt_table->pointer_to_other_sdt[i], i); + } +} + +void *acpi_find_table_by_name(const char *name, int skip) { + if (xsdt_table != NULL) { + uint32_t entries = (xsdt_table->header.length - sizeof(struct acpi_sdt_header)) / sizeof(uint64_t); + for (uint32_t i = 0; i < entries; ++i) { + const uint64_t entry_addr = xsdt_table->pointer_to_other_sdt[i]; + if (entry_addr > UINT32_MAX) { + printf("%i: Above 4GB\n", i); + continue; + } + struct acpi_sdt_header *header = (struct acpi_sdt_header *) xsdt_table->pointer_to_other_sdt[i]; + if (!acpi_checksum(header, header->length)) { + printf("Invalid header %d", i); + continue; + } + if (strncmp(header->signature, name, 4) == 0) { + if (skip > 0) { + skip--; + continue; + } + return header; + } + } + } + if (rsdt_table != NULL) { + uint32_t entries = (rsdt_table->header.length - sizeof(struct acpi_sdt_header)) / sizeof(uint32_t); + for (uint32_t i = 0; i < entries; ++i) { + struct acpi_sdt_header *header = (struct acpi_sdt_header *) rsdt_table->pointer_to_other_sdt[i]; + if (!acpi_checksum(header, header->length)) { + printf("Invalid header %d", i); + continue; + } + if (strncmp(header->signature, name, 4) == 0) { + if (skip > 0) { + skip--; + continue; + } + return header; + } + } + } + // check if DSDT is requested, but was not present as normal table + if (strncmp(name, "DSDT", 4) == 0) { + return (void *) dsdt; + } + return NULL; +} + +void acpi_parse() { + struct lai_rsdp_info lai_rsdp_info; + lai_api_error_t result = lai_bios_detect_rsdp(&lai_rsdp_info); + if (result != LAI_ERROR_NONE) { + printf("LAI: could not find rsdp: %s\n", lai_api_error_to_string(result)); + k_panics("Could not init ACPI"); + } + lai_set_acpi_revision(lai_rsdp_info.acpi_version); + + if (lai_rsdp_info.xsdt_address != 0) { + acpi_parse_xsdt(lai_rsdp_info.xsdt_address); + } else if (lai_rsdp_info.rsdt_address != 0) { + acpi_parse_rsdt(lai_rsdp_info.rsdt_address); + } else { + k_panics("No rsdt nor xsdt"); + } +} + +void acpi_init() { + lai_create_namespace(); +} \ No newline at end of file diff --git a/kernel/acpi/lailayer.c b/kernel/acpi/lailayer.c new file mode 100644 index 0000000..f4eabef --- /dev/null +++ b/kernel/acpi/lailayer.c @@ -0,0 +1,80 @@ +// +// Created by rick on 26-08-21. +// + +#include +#include +#include +#include +#include +#include + +const char *lai_loglevel_str(int level) { + switch (level) { + case LAI_DEBUG_LOG: + return "debug "; + case LAI_WARN_LOG: + return "warn "; + default: + return "unknown"; + } +} + +void laihost_log(int level, const char *msg) { + printf("lai [%s]: %s\n", lai_loglevel_str(level), msg); +} + +void laihost_panic(const char *msg) { + k_panics(msg); +} + +void *laihost_malloc(size_t size) { + return malloc(size); +} + +void *laihost_realloc(void *data, size_t size, size_t old_size) { + return realloc(data, size); +} + +void laihost_free(void *data, size_t size) { + free(data); +} + +void *laihost_map(size_t address, size_t size) { + return (void *) address; +} + +void laihost_unmap(void *pointer, size_t count) { +} + +void *laihost_scan(const char *sig, size_t index) { + return acpi_find_table_by_name(sig, (int)index); +} + +void laihost_outb(uint16_t port, uint8_t val) { + port_byte_out(port, val); +} + +void laihost_outw(uint16_t port, uint16_t val) { + port_word_out(port, val); +} + +void laihost_outd(uint16_t port, uint32_t val) { + port_double_word_out(port, val); +} + +uint8_t laihost_inb(uint16_t port) { + return port_byte_in(port); +} + +uint16_t laihost_inw(uint16_t port) { + return port_word_in(port); +} + +uint32_t laihost_ind(uint16_t port) { + return port_double_word_in(port); +} + +void laihost_sleep(uint64_t ms) { + return; // todo implement for real system +} \ No newline at end of file diff --git a/kernel/command.c b/kernel/command.c index 9c7be2b..27d753e 100644 --- a/kernel/command.c +++ b/kernel/command.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/kernel/cpu/isr.c b/kernel/cpu/isr.c index 1f4ce18..245f08e 100644 --- a/kernel/cpu/isr.c +++ b/kernel/cpu/isr.c @@ -9,12 +9,9 @@ #include #include #include -#include #include #include -#define PIC_END_OF_INTERRUPT 0x20 - isr_t interrupt_handlers[256]; void isr_install() { @@ -52,8 +49,7 @@ void isr_install() { set_idt_gate(31, (uint32_t) isr31); // Remap the PIC - // todo make readable - pic_init(); + pic_init(IRQ0); // Install the IRQs set_idt_gate(32, (uint32_t) irq0); // 0x20 @@ -73,6 +69,7 @@ void isr_install() { set_idt_gate(46, (uint32_t) irq14); set_idt_gate(47, (uint32_t) irq15); + // 0x80 SYSCALL set_idt_gate(128, (uint32_t) isr128); set_idt(); // Load with ASM @@ -116,7 +113,7 @@ char *exception_messages[] = { "Reserved" }; -void isr_handler(isr_registers_t r) { +void att_used isr_handler(isr_registers_t r) { char msg[256]; if (r.int_no == 128) { syscall_handle(&r); @@ -131,11 +128,10 @@ void register_interrupt_handler(uint8_t n, isr_t handler) { interrupt_handlers[n] = handler; } -void irq_handler(isr_registers_t r) { +void att_used irq_handler(isr_registers_t r) { /* After every interrupt we need to send an EOI to the PICs * or they will not send another interrupt again */ - if (r.int_no >= 40) port_byte_out(PORT_PIC_SLAVE_COMMAND, PIC_END_OF_INTERRUPT); /* slave */ - port_byte_out(PORT_PIC_MASTER_COMMAND, PIC_END_OF_INTERRUPT); /* master */ + pic_eoi(r.int_no >= IRQ8); if (r.int_no >= IRQ0 && r.int_no < IRQ15) { task_notify_irq(r.int_no - IRQ0); diff --git a/kernel/cpu/pic.c b/kernel/cpu/pic.c index 4c83b70..c73d278 100644 --- a/kernel/cpu/pic.c +++ b/kernel/cpu/pic.c @@ -1,6 +1,7 @@ // // Created by rick on 22-08-21. // +#include #include #include @@ -17,15 +18,17 @@ #define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ #define ICW4_SFNM 0x10 /* Special fully nested (not) */ -void pic_init() { +#define PIC_END_OF_INTERRUPT 0x20 + +void pic_init(uint8_t isr_offset) { // init both master and slave pic's port_byte_out(PORT_PIC_MASTER_COMMAND, ICW1_INIT | ICW1_ICW4); port_byte_out(PORT_PIC_SLAVE_COMMAND, ICW1_INIT | ICW1_ICW4); - // master with ICW4 offset 20, Slave on IRQ2, 8086 mode, + // master with ICW4 offset isr_offset, Slave on IRQ2, 8086 mode, // ICW2 - port_byte_out(PORT_PIC_MASTER_DATA, 0x20); // offset master - port_byte_out(PORT_PIC_SLAVE_DATA, 0x28); // offset slave + port_byte_out(PORT_PIC_MASTER_DATA, isr_offset); // offset master + port_byte_out(PORT_PIC_SLAVE_DATA, isr_offset + 8); // offset slave // ICW3 port_byte_out(PORT_PIC_MASTER_DATA, 0x04); // slave PIC at IRQ2 port_byte_out(PORT_PIC_SLAVE_DATA, 0x02); // cascade identity @@ -39,5 +42,10 @@ void pic_init() { void pic_set_mask(uint16_t mask) { port_byte_out(PORT_PIC_MASTER_DATA, mask & 0xFF); - port_byte_out(PORT_PIC_SLAVE_DATA, mask << 8); + port_byte_out(PORT_PIC_SLAVE_DATA, mask >> 8); +} + +void pic_eoi(bool slave) { + if (slave) port_byte_out(PORT_PIC_SLAVE_COMMAND, PIC_END_OF_INTERRUPT); /* slave */ + port_byte_out(PORT_PIC_MASTER_COMMAND, PIC_END_OF_INTERRUPT); /* master */ } \ No newline at end of file diff --git a/kernel/cpu/timer.c b/kernel/cpu/pit.c similarity index 54% rename from kernel/cpu/timer.c rename to kernel/cpu/pit.c index 3d086ea..1c84484 100644 --- a/kernel/cpu/timer.c +++ b/kernel/cpu/pit.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include @@ -33,19 +33,37 @@ #define PIT_CHANNEL_1 (0b01 << 6) #define PIT_CHANNEL_2 (0b10 << 6) #define PIT_CHANNEL_READ_BACK (0b11 << 6) +#define PIT_RB_LATCH_COUNT (0) +#define PIT_RB_LATCH_NO_COUNT (1 << 5) +#define PIT_RB_LATCH_STATUS (0) +#define PIT_RB_LATCH_NO_STATUS (1 << 4) +#define PIT_RB_CHANNEL_2 (1 << 3) +#define PIT_RB_CHANNEL_1 (1 << 2) +#define PIT_RB_CHANNEL_0 (1 << 1) +#define PIT_STATUS_OUTPUT_STATE (1 << 7) +#define PIT_STATUS_NULL_COUNT (1 << 6) +#define PIT_STATUS_ACCESS_MODE (0b11 >> 4) +#define PIT_STATUS_OPERATING_MODE (0b111 < 1) +#define PIT_STATUS_BCD_BIN (1) +#define PIT_FREQUENCY 1193182 /*Hz*/ uint32_t tick = 0; -static void timer_callback(isr_registers_t *regs) { +uint32_t pit_ms_to_div(uint32_t ms) { + uint32_t divisor = PIT_FREQUENCY / ms; + return divisor; +} + +static void pit_callback(isr_registers_t *regs) { tick++; task_switch_next(); } -uint32_t timer_get_tick() { +uint32_t pit_get_tick() { return tick; } -void sleep(uint32_t milliseconds) { +void pit_sleep(uint32_t milliseconds) { uint32_t done = tick + milliseconds; while (tick != done) { k_wait_for_interrupt(); @@ -60,10 +78,10 @@ void print_current_tick() { kprint("\n"); } -int init_timer(uint32_t freq) { - register_interrupt_handler(IRQ0, timer_callback); +int pit_init(uint32_t freq) { + register_interrupt_handler(IRQ0, pit_callback); - uint32_t divisor = 1193180 / freq; + uint32_t divisor = PIT_FREQUENCY / freq; uint8_t low = (uint8_t) (divisor & 0xFF); uint8_t high = (uint8_t) ((divisor >> 8) & 0xFF); port_byte_out(PORT_PIT_COMMAND, @@ -72,3 +90,21 @@ int init_timer(uint32_t freq) { port_byte_out(PORT_PIT_DATA_0, high); return 0; } + +// pit_sleep without interrupts +void pit_sleep_ms(const uint32_t sleep) { + // todo locking + uint32_t divider = pit_ms_to_div(sleep); + if (divider > UINT16_MAX) { + k_panics("Sleep for to long"); + } + port_byte_out(PORT_PIT_COMMAND, + PIT_MODE_BIN | PIT_MODE_INTERRUPT_ON_TERMINAL_COUNT | PIT_ACCESS_MODE_LH | PIT_CHANNEL_0); + port_byte_out(PORT_PIT_DATA_0, divider & 0xFF); + port_byte_out(PORT_PIT_DATA_0, divider >> 8); + do { + __builtin_ia32_pause(); + port_byte_out(PORT_PIT_COMMAND, + PIT_CHANNEL_READ_BACK | PIT_RB_CHANNEL_0 | PIT_RB_LATCH_NO_COUNT | PIT_RB_LATCH_STATUS); + } while (port_byte_in(PORT_PIT_DATA_0) & PIT_STATUS_OUTPUT_STATE); +} diff --git a/kernel/drivers/pci/ide.c b/kernel/drivers/pci/ide.c index 2db9c1d..c4dec7d 100644 --- a/kernel/drivers/pci/ide.c +++ b/kernel/drivers/pci/ide.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include @@ -395,6 +395,10 @@ void ide_register_block_devices() { if (!ide_devices[i].reserved) { continue; } + if (ide_devices[i].type == IDE_ATAPI) { + // skip ATAPI for now + continue; + } ide_block_device_info *info = malloc(sizeof(ide_block_device_info)); // todo free for this one info->device_number = i; @@ -451,11 +455,11 @@ uint8_t att_used ide_pci_initialize(pci_device *device) { // (I) Select Drive: ide_write(i, ATA_REG_HDDEVSEL, 0xA0 | (j << 4)); // Select Drive. - sleep(1); // Wait 1ms for drive select to work. + pit_sleep(1); // Wait 1ms for drive select to work. // (II) Send ATA Identify Command: ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY); - sleep(1); // This function should be implemented in your OS. which waits for 1 ms. + pit_sleep(1); // This function should be implemented in your OS. which waits for 1 ms. // it is based on System Timer Device Driver. // (III) Polling: @@ -485,7 +489,7 @@ uint8_t att_used ide_pci_initialize(pci_device *device) { } ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET); - sleep(1); + pit_sleep(1); } // (V) Read Identification Space of the Device: diff --git a/kernel/kernel.c b/kernel/kernel.c index 3197cfe..79bd15a 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -4,11 +4,12 @@ #define DEBUG_INIT +#include #include #include #include #include -#include +#include #include #include #include @@ -64,6 +65,10 @@ void att_noreturn att_used kmain(multiboot_info_t *multiboot_info, uint32_t mb_n // initialize kprint functionality kprint_init(); + // todo earlier in boot + acpi_parse(); + acpi_init(); + debug_store_info(multiboot_info); // identify cpu @@ -72,7 +77,7 @@ void att_noreturn att_used kmain(multiboot_info_t *multiboot_info, uint32_t mb_n // enable interrupts __asm__ __volatile__("sti"); // start the timer - init_timer(1000); + pit_init(1000); // initialize devices init_keyboard(); init_pci_system(); diff --git a/kernel/libc/kprintf.c b/kernel/libc/kprintf.c index da942d9..5642648 100644 --- a/kernel/libc/kprintf.c +++ b/kernel/libc/kprintf.c @@ -85,6 +85,7 @@ uint32_t vasprintf(char *buf, const char *fmt, va_list args) { buf[ptr++] = (char) va_arg(args, int); break; case 'x': + case 'p': case 'X': // todo capitalize print_int((uint32_t) va_arg(args, uint32_t), field_width, buf, &ptr, 16); break; diff --git a/kernel/util/power.c b/kernel/util/power.c index 6b52d34..d77a300 100644 --- a/kernel/util/power.c +++ b/kernel/util/power.c @@ -4,13 +4,12 @@ #include -#include +#include + #include #include void att_noreturn power_shutdown() { - port_word_out(PORT_ACPI, PORT_ACPI_SHUTDOWN); - port_word_out(PORT_QEMU_COMMAND, PORT_QEMU_COMMAND_SHUTDOWN); - port_word_out(PORT_VBOX, PORT_VBOX_SHUTDOWN); + lai_enter_sleep(5); k_panics("Failed to shut down!\n"); } \ No newline at end of file diff --git a/lai b/lai new file mode 160000 index 0000000..432546e --- /dev/null +++ b/lai @@ -0,0 +1 @@ +Subproject commit 432546ee092f5e263b6eef00de5b3065471e8f88