// SPDX-License-Identifier: MPL-2.0 #ifndef SH_LIB_IOAPIC_H #define SH_LIB_IOAPIC_H #include "std/stdlib.h" #include "memory/page.h" #define SH_IOAPIC_OFFSET_IOREGSEL 0x00 #define SH_IOAPIC_OFFSET_IOWIN 0x10 #define SH_IOAPIC_REGISTER_IOAPICID 0x00 #define SH_IOAPIC_REGISTER_IOAPICVER 0x01 #define SH_IOAPIC_REGISTER_IOAPICARB 0x02 #define SH_IOAPIC_REGISTER_IOREDTBL_BASE 0x10 // IOAPIC device structure typedef struct { volatile sh_uint32 *base; sh_uint8 ioapic_id; sh_uint32 gsi_base; sh_uint32 gsi_count; // must be completed by reading the IOAPICVER register in the sh_ioapic_init call sh_SPIN_LOCK lock; } sh_ioapic_DEVICE; // Initialize an IOAPIC device structure, intented to initialize all IOAPIC devices structures during MADT parsing SH_STATUS sh_ioapic_init(sh_uint32 base,sh_uint8 ioapic_id,sh_uint32 gsi_base,sh_ioapic_DEVICE *ioapic); // Initialize DevS IOAPIC backend (max_ioapic_id is the max IOAPIC id, not the number of IOAPIC counted) SH_STATUS sh_ioapic_init_devs(sh_uint8 max_ioapic_id); // Bind a LAPIC device to DevS LAPIC backend SH_STATUS sh_ioapic_bind(sh_ioapic_DEVICE *lapic_dev); // Return a pointer to an IOAPIC device based on the provided IOAPIC id sh_ioapic_DEVICE *sh_ioapic_get_dev_ioapic_id(sh_uint64 ioapic_id); #define SH_IOAPIC_IOREDTBL_DELIVERY_FIXED 0b000 #define SH_IOAPIC_IOREDTBL_DELIVERY_LOWEST_PRIORITY 0b001 #define SH_IOAPIC_IOREDTBL_DELIVERY_NMI 0b100 #define SH_IOAPIC_IOREDTBL_DELIVERY_INIT 0b101 #define SH_IOAPIC_IOREDTBL_DELIVERY_EXTINT 0b111 #define SH_IOAPIC_IOREDTBL_TRIGGER_EDGE 0b0 #define SH_IOAPIC_IOREDTBL_TRIGGER_LEVEL 0b1 #define SH_IOAPIC_IOREDTBL_POLARITY_HIGH 0b0 #define SH_IOAPIC_IOREDTBL_POLARITY_LOW 0b1 #define SH_IOAPIC_IOREDTBL_DEST_MODE_PHYSICAL 0b0 #define SH_IOAPIC_IOREDTBL_DEST_MODE_LOGICAL 0b1 // IOREDTBL entry structure typedef struct { sh_uint32 low; sh_uint32 high; } sh_ioapic_IOREDTBL_ENTRY; // Create an IOREDTBL entry inline sh_ioapic_IOREDTBL_ENTRY sh_ioapic_make_ioredtbl_entry(sh_uint8 vector,sh_uint8 delivery_mode,sh_uint8 destination_mode,sh_uint8 polarity,sh_uint8 trigger_mode,sh_bool mask,sh_uint8 apic_id) { sh_ioapic_IOREDTBL_ENTRY e={0}; e.low=(e.low& ~0xFFU)|vector; e.low=(e.low& ~(0x7U<<8))|((delivery_mode&0x7U)<<8); e.low=(e.low& ~(1U<<11))|((destination_mode&0x1U)<<11); e.low=(e.low& ~(1U<<13))|((polarity&0x1U)<<13); e.low=(e.low& ~(1U<<15))|((trigger_mode&0x1U)<<15); e.low=(e.low& ~(1U<<16))|((mask&0x1U)<<16); e.high=(e.high& ~(0xFFU<<24))|((sh_uint32)apic_id<<24); return e; } // Mask an IOREDTBL entry for the provided GSI SH_STATUS sh_ioapic_mask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi); // Unmask an IOREDTBL entry for the provided GSI SH_STATUS sh_ioapic_unmask_gsi(sh_ioapic_DEVICE *dev,sh_uint32 gsi); // Read an IOREDTBL entry for the provided GSI SH_STATUS sh_ioapic_read_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry); // Write an IOREDTBL entry for the provided GSI SH_STATUS sh_ioapic_write_ioredtbl_entry(sh_ioapic_DEVICE *ioapic_dev,sh_uint32 gsi,sh_ioapic_IOREDTBL_ENTRY *entry); // Mask all IOREDTBL entries for all IOAPIC SH_STATUS sh_ioapic_mask_all(); // Return the IOAPIC device corresponding to the provided GSI sh_ioapic_DEVICE *sh_ioapic_get_dev_by_gsi(sh_uint32 gsi); // Parse an IOAPIC DevS query SH_STATUS sh_ioapic_devs_query(char *sub_path,sh_devs_RESULT *result); #endif