feat: added basic ACPI support using LAI
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "lai"]
|
||||
path = lai
|
||||
url = https://github.com/managarm/lai.git
|
||||
@@ -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 "")
|
||||
14
include/myke/acpi/acpi.h
Normal file
14
include/myke/acpi/acpi.h
Normal file
@@ -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
|
||||
256
include/myke/acpi/structures.h
Normal file
256
include/myke/acpi/structures.h
Normal file
@@ -0,0 +1,256 @@
|
||||
//
|
||||
// Created by rick on 22-08-21.
|
||||
//
|
||||
|
||||
#ifndef NEW_KERNEL_STRUCTURES_H
|
||||
#define NEW_KERNEL_STRUCTURES_H
|
||||
|
||||
#include <attributes.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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
|
||||
@@ -5,10 +5,13 @@
|
||||
#ifndef NEW_KERNEL_PIC_H
|
||||
#define NEW_KERNEL_PIC_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
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
|
||||
276
kernel/acpi/acpi.c
Normal file
276
kernel/acpi/acpi.c
Normal file
@@ -0,0 +1,276 @@
|
||||
//
|
||||
// Created by rick on 22-08-21.
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <lai/core.h>
|
||||
#include <lai/helpers/pc-bios.h>
|
||||
|
||||
#include <myke/acpi/acpi.h>
|
||||
#include <myke/acpi/structures.h>
|
||||
#include <myke/cpu/lapic.h>
|
||||
#include <myke/libk/libk.h>
|
||||
|
||||
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();
|
||||
}
|
||||
80
kernel/acpi/lailayer.c
Normal file
80
kernel/acpi/lailayer.c
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Created by rick on 26-08-21.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <lai/host.h>
|
||||
#include <myke/acpi/acpi.h>
|
||||
#include <myke/drivers/ports.h>
|
||||
#include <myke/libk/libk.h>
|
||||
|
||||
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
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <readline/readline.h>
|
||||
|
||||
#include <myke/command.h>
|
||||
#include <myke/cpu/timer.h>
|
||||
#include <myke/cpu/pit.h>
|
||||
#include <myke/drivers/pci/ide.h>
|
||||
#include <myke/drivers/pci/pci.h>
|
||||
#include <myke/vfs/blockdev.h>
|
||||
|
||||
@@ -9,12 +9,9 @@
|
||||
#include <myke/cpu/idt.h>
|
||||
#include <myke/cpu/pic.h>
|
||||
#include <myke/cpu/syscall_handler.h>
|
||||
#include <myke/drivers/ports.h>
|
||||
#include <myke/libk/libk.h>
|
||||
#include <myke/tasks/task.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//
|
||||
// Created by rick on 22-08-21.
|
||||
//
|
||||
#include <stdbool.h>
|
||||
#include <myke/cpu/pic.h>
|
||||
#include <myke/drivers/ports.h>
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <myke/cpu/timer.h>
|
||||
#include <myke/cpu/pit.h>
|
||||
#include <myke/drivers/ports.h>
|
||||
#include <myke/cpu/isr.h>
|
||||
#include <myke/libk/libk.h>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <myke/cpu/timer.h>
|
||||
#include <myke/cpu/pit.h>
|
||||
#include <myke/debug/debug.h>
|
||||
#include <myke/drivers/pci/ide.h>
|
||||
#include <myke/drivers/pci/pci.h>
|
||||
@@ -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:
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
|
||||
#define DEBUG_INIT
|
||||
|
||||
#include <myke/acpi/acpi.h>
|
||||
#include <myke/command.h>
|
||||
#include <myke/cpu/cpuidx.h>
|
||||
#include <myke/cpu/gdt.h>
|
||||
#include <myke/cpu/isr.h>
|
||||
#include <myke/cpu/timer.h>
|
||||
#include <myke/cpu/pit.h>
|
||||
#include <myke/debug/debug.h>
|
||||
#include <myke/drivers/keyboard.h>
|
||||
#include <myke/drivers/pci/pci.h>
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
|
||||
#include <attributes.h>
|
||||
|
||||
#include <myke/drivers/ports.h>
|
||||
#include <lai/helpers/pm.h>
|
||||
|
||||
#include <myke/libk/libk.h>
|
||||
#include <myke/util/power.h>
|
||||
|
||||
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");
|
||||
}
|
||||
1
lai
Submodule
1
lai
Submodule
Submodule lai added at 432546ee09
Reference in New Issue
Block a user