// SPDX-License-Identifier: MPL-2.0 #ifndef SH_LIB_LAPIC_H #define SH_LIB_LAPIC_H #include "std/status.h" #include "std/type.h" #include "memory/page.h" #include "devs/devs.h" #define SH_LAPIC_OFFSET_ID 0x020 #define SH_LAPIC_OFFSET_VERSION 0x030 #define SH_LAPIC_OFFSET_EOI 0x0B0 #define SH_LAPIC_OFFSET_SVR 0x0F0 #define SH_LAPIC_OFFSET_ESR 0x280 #define SH_LAPIC_OFFSET_ICR_LOW 0x300 #define SH_LAPIC_OFFSET_ICR_HIGH 0x310 #define SH_LAPIC_OFFSET_LVT_TIMER 0x320 #define SH_LAPIC_OFFSET_LVT_ERROR 0x370 #define SH_LAPIC_OFFSET_TIMER_INIT 0x380 #define SH_LAPIC_OFFSET_TIMER_CURR 0x390 #define SH_LAPIC_OFFSET_TIMER_DIV 0x3E0 #define SH_LAPIC_TIMER_DIVIDER 0x3 // LAPIC device structure typedef struct { volatile sh_uint32 *base; sh_uint8 apic_id; sh_uint8 acpi_processor_id; sh_uint32 flags; sh_uint32 spurious_vector; } sh_lapic_DEVICE; // Initialize a LAPIC device structure, intented to initialize all LAPIC devices structures during MADT parsing SH_STATUS sh_lapic_init(sh_uint64 lapic_phys,sh_uint8 spurious_vector,sh_uint8 apic_id,sh_uint8 apic_processor_id,sh_uint32 flags,sh_lapic_DEVICE *lapic); // Initialize LAPIC for this CPU, intended to be used once by each CPU SH_STATUS sh_lapic_init_dev(sh_uint8 spurious_vector,sh_lapic_DEVICE *lapic); // Initialize DevS LAPIC backend (max_lapic_id is the max LAPIC id, not the number of LAPIC counted) SH_STATUS sh_lapic_init_devs(sh_uint16 max_lapic_id,sh_uint16 max_acpi_processor_id); // Bind a LAPIC device to DevS LAPIC backend SH_STATUS sh_lapic_bind(sh_lapic_DEVICE *lapic_dev); // Write 0 in provided LAPIC device EOI register void sh_lapic_eoi(sh_lapic_DEVICE *lapic); // Return a pointer to a LAPIC device based on the provided APIC id sh_lapic_DEVICE *sh_lapic_get_dev_apic_id(sh_uint64 apic_id); // Return a pointer to a LAPIC device based on the provided ACPI processor id sh_lapic_DEVICE *sh_lapic_get_dev_acpi_cpu_id(sh_uint64 acpi_processor_id); // Launch a LAPIC one-shot timer, independantely of the calibrated state of the LAPIC SH_STATUS sh_lapic_timer_one_shot(sh_lapic_DEVICE *lapic_dev,sh_uint32 initial_value); // Calibrate the LAPIC frequency SH_STATUS sh_lapic_calibrate(sh_lapic_DEVICE *lapic_dev,sh_uint64 cpu_freq); // Return the LAPIC frequency sh_uint64 sh_lapic_get_frequency(); // Launch a LAPIC one-shot timer, LAPIC frequency need to be set SH_STATUS sh_lapic_timer_one_shot_us(sh_lapic_DEVICE *lapic_dev,sh_uint64 microseconds_count); // Return LAPIC DevS array sh_lapic_DEVICE **sh_lapic_get_by_apic_id_array(); // Return max LAPIC APIC id sh_uint64 sh_lapic_get_max_apic_id(); // Return max ACPI processor id sh_uint64 sh_lapic_get_max_acpi_processor_id(); // Return LAPIC count sh_uint64 sh_lapic_get_lapic_count(); #define SH_LAPIC_IPI_TYPE_NMI 0b100 #define SH_LAPIC_IPI_TYPE_INIT 0b101 #define SH_LAPIC_IPI_TYPE_STARTUP 0b110 #define SH_LAPIC_IPI_TYPE_FIXED 0b000 #define SH_LAPIC_IPI_DESTINATION_SPECIFIC (0b00<<18) #define SH_LAPIC_IPI_DESTINATION_SELF (0b01<<18) #define SH_LAPIC_IPI_DESTINATION_ALL (0b10<<18) #define SH_LAPIC_IPI_DESTINATION_ALL_EXCLUDING_SELF (0b11<<18) #define SH_LAPIC_IPI_NO_DESTINATION (sh_int16)(-1) // Return SH_TRUE if LAPIC IPI feature is busy sh_bool sh_lapic_ipi_is_busy(sh_lapic_DEVICE *lapic_dev); // Return LAPIC id of current core, return -1 if error happened sh_int16 sh_lapic_get_current_core(); // Send a fixed IPI with the specified vector. lapic_dev must be the struct of the current CPU. // If destination_mode!=SH_LAPIC_IPI_DESTINATION_SPECIFIC, target_lapic_id must be SH_LAPIC_IPI_NO_DESTINATION SH_STATUS sh_lapic_send_fixed_ipi(sh_lapic_DEVICE *lapic_dev,sh_uint8 vector,sh_uint32 destination_mode,sh_int16 target_lapic_id); // Send any IPI other than a fixed IPI to specified destination. lapic_dev must be the struct of the current CPU. // ipi_type must be either SH_LAPIC_IPI_TYPE_INIT, SH_LAPIC_IPI_TYPE_STARTUP or SH_LAPIC_IPI_TYPE_NMI // If ipi_type is SH_LAPIC_IPI_TYPE_STARTUP, start_address must contain the starting address. Address constraint (compatible with 16 bits mode) are checked. // If ipi_type isn't SH_LAPIC_IPI_TYPE_STARTUP, start_address must be zero. // If destination_mode!=SH_LAPIC_IPI_DESTINATION_SPECIFIC, target_lapic_id must be SH_LAPIC_IPI_NO_DESTINATION SH_STATUS sh_lapic_send_ipi(sh_lapic_DEVICE *lapic_dev,sh_uint32 ipi_type,sh_uint32 destination_mode,sh_int16 target_lapic_id,sh_page_PHYSICAL_ADDRESS start_address); // Parse a LAPIC DevS query SH_STATUS sh_lapic_devs_query(char *sub_path,sh_devs_RESULT *result); #endif