14using namespace MaxOS::hardwarecommunication;
15using namespace MaxOS::system;
16using namespace MaxOS::memory;
25 m_apic_base = msr_info & 0xFFFFF000;
28 static bool bsp_setup =
false;
33 uint32_t ignored, xleaf, x2leaf;
34 CPU::cpuid(0x01, &ignored, &ignored, &x2leaf, &xleaf);
36 if (x2leaf & (1 << 21)) {
40 msr_info |= (1 << 10);
44 }
else if (xleaf & (1 << 9)) {
52 Logger::DEBUG() <<
"APIC Base: phy=0x" << m_apic_base <<
", virt=0x" << m_apic_base_high <<
"\n";
54 ASSERT(
false,
"CPU does not support xAPIC");
57 if (!(msr_info & (1 << 11))) {
63 write(0xF0, (1 << 8) | 0x100);
68LocalAPIC::~LocalAPIC() =
default;
82 return *(
volatile uint32_t*) ((uintptr_t) m_apic_base_high + reg);
100 *(
volatile uint32_t*) ((uintptr_t) m_apic_base_high + reg) = value;
111 uint32_t
id =
read(0x20);
114 return m_x2apic ?
id : (
id >> 24);
138 write(0x310, icr_high << 24);
141 write(0x300, icr_low);
144 while (
read(0x300) & (1 << 12))
145 asm volatile(
"pause");
150 uint64_t icr = icr_low;
152 icr |= (uint64_t)icr_high << 32;
167 uint32_t icr_low = 0;
168 uint32_t icr_high = apic_id;
171 icr_low |= (0b101 << 8);
175 icr_low |= (1 << 14);
178 icr_low |= (1 << 15);
192 uint32_t icr_low = 0;
193 uint32_t icr_high = apic_id;
199 icr_low |= (0b110 << 8);
215 uint32_t icr_low = 0;
216 uint32_t icr_high = 0;
222 bool use_shorthand =
true;
223 if (flags & SEND_ALL) {
225 icr_low |= (0b11 << 18);
226 }
else if (flags & EXCLUDE_SELF) {
228 icr_low |= (0b10 << 18);
231 icr_high = ((uint32_t)apic_id) << 24;
232 use_shorthand =
false;
236 send_icr(icr_low, icr_high, use_shorthand);
250 m_madt = (
MADT*) m_acpi->
find(
"APIC");
258 m_address = io_apic->io_apic_address;
261 Logger::DEBUG() <<
"IO APIC Address: phy=0x" << m_address <<
", virt=0x" << m_address_high <<
"\n";
264 m_version =
read(0x1);
265 m_max_redirect_entry = (uint8_t) (m_version >> 16);
268 Logger::DEBUG() <<
"IO APIC Version: 0x" << (uint64_t) (m_version & 0xFF) <<
"\n";
269 Logger::DEBUG() <<
"IO APIC Max Redirection Entry: 0x" << (uint64_t) m_max_redirect_entry <<
"\n";
273 uint32_t total_length =
sizeof(
MADT);
274 while (total_length < m_madt->header.length && m_override_array_size < 0x10) {
276 total_length += source_override_item->
length;
279 if (source_override_item !=
nullptr && source_override_item->
type == 2) {
282 auto*
override = (
Override*) (source_override_item + 1);
283 m_override_array[m_override_array_size].
bus =
override->bus;
284 m_override_array[m_override_array_size].
source =
override->source;
286 m_override_array[m_override_array_size].
flags =
override->flags;
287 m_override_array_size++;
291 source_override_item =
get_madt_item(MADT_TYPE::IO_APIC, m_override_array_size);
292 if (source_override_item ==
nullptr)
296 Logger::DEBUG() <<
"IO APIC Source Overrides: 0x" << m_override_array_size <<
"\n";
299IOAPIC::~IOAPIC() =
default;
311 auto* item = (
MADTEntry*) ((uint64_t) m_madt +
sizeof(
MADT));
312 uint64_t total_length = 0;
313 uint8_t current_index = 0;
316 while (total_length +
sizeof(
MADT) < m_madt->
header.
length && current_index <= index) {
319 if (item->type == (uint8_t)type) {
322 if (current_index == index)
330 total_length += item->
length;
331 item = (
MADTEntry*) ((uint64_t) item + item->length);
347 *(
volatile uint32_t*) (m_address_high + 0x00) = reg;
350 return *(
volatile uint32_t*) (m_address_high + 0x10);
362 *(
volatile uint32_t*) (m_address_high + 0x00) = reg;
365 *(
volatile uint32_t*) (m_address_high + 0x10) = value;
377 if (index < 0x10 || index > 0x3F)
381 uint32_t low =
read(index);
382 uint32_t high =
read(index + 1);
383 entry->
raw = ((uint64_t) high << 32) | ((uint64_t) low);
395 if (index < 0x10 || index > 0x3F)
399 auto low = (uint32_t) entry->
raw;
400 auto high = (uint32_t) (entry->
raw >> 32);
404 write(index + 1, high);
418 entry.mask = redirect->
mask;
421 for (uint8_t i = 0; i < m_override_array_size; i++) {
423 if (m_override_array[i].source != redirect->
type)
427 entry.pin_polarity = ((m_override_array[i].
flags & 0b11) == 2) ? 0b1 : 0b0;
428 entry.pin_polarity = (((m_override_array[i].
flags >> 2) & 0b11) == 2) ? 0b1 : 0b0;
431 entry.trigger_mode = (((m_override_array[i].
flags >> 2) & 0b11) == 2);
437 write_redirect(redirect->
index, &entry);
450 read_redirect(index, &entry);
454 write_redirect(index, &entry);
463: m_pic_master_command_port(0x20),
464 m_pic_master_data_port(0x21),
465 m_pic_slave_command_port(0xA0),
466 m_pic_slave_data_port(0xA1)
483 m_io_apic =
new IOAPIC(acpi);
499void AdvancedProgrammableInterruptController::disable_pic() {
502 m_pic_master_command_port.write(0x11);
503 m_pic_slave_command_port.write(0x11);
506 m_pic_master_data_port.write(0x20);
507 m_pic_slave_data_port.write(0x28);
510 m_pic_master_data_port.write(0x04);
511 m_pic_slave_data_port.write(0x02);
514 m_pic_master_data_port.write(0x01);
515 m_pic_slave_data_port.write(0x01);
518 m_pic_master_data_port.write(0xFF);
519 m_pic_slave_data_port.write(0xFF);
Defines classes and structures for handling the Advanced Programmable Interrupt Controller (APIC) in ...
MADT_TYPE
The types of MADT entries.
static LogRecord DEBUG()
Gets the active logger for debug logs.
static LogRecord INFO()
Gets the active logger for info logs.
static LogRecord WARNING()
Gets the active logger for warnings.
Handles ACPI table parsing and retrieval.
acpi_sdt_header_t * find(const char *signature)
Finds a table with the given signature.
IOAPIC * io_apic() const
Get the io apic.
~AdvancedProgrammableInterruptController()
Destroy the Advanced Programmable Interrupt Controller object and frees the Local APIC and IO APIC.
AdvancedProgrammableInterruptController(AdvancedConfigurationAndPowerInterface *acpi)
Construct a new Advanced Programmable Interrupt Controller object and initialises the Local APIC and ...
LocalAPIC * local_apic() const
Get the local apic.
Handles the IO APIC in the system (one per system)
void write(uint32_t reg, uint32_t value) const
write a value to an IO Apic register
void set_redirect(interrupt_redirect_t *redirect)
Redirect a system interrupt to a different IRQ.
MADTEntry * get_madt_item(MADT_TYPE type, uint8_t index)
Get an item in the MADT.
void set_redirect_mask(uint8_t index, bool mask)
Enables/Disables an interrupt redirect by masking it.
uint32_t read(uint32_t reg) const
read a value from a IO Apic register
IOAPIC(AdvancedConfigurationAndPowerInterface *acpi)
Construct a new IO APIC object. Maps the IO APIC registers and reads the MADT to get information abou...
static InterruptManager * active_interrupt_manager()
Gets the active interrupt manager.
void set_apic(AdvancedProgrammableInterruptController *apic)
Sets the APIC.
Handles the local APIC for the current core.
void send_eoi() const
Acknowledge that the interrupt has been handled, allowing the PIC to process the next interrupt.
void write(uint32_t reg, uint32_t value) const
write a value to the apic register using the MSR or memory I/O depending on the local apic version
void send_icr(uint32_t icr_low, uint32_t icr_high, bool use_shorthand) const
Send an Interrupt Command Register (ICR) to the local apic.
uint32_t id() const
Get the id of the local apic.
LocalAPIC()
Construct a new Local APIC object and map the APIC base address to the higher half if needed as well ...
void send_startup(uint8_t apic_id, uint8_t vector) const
Send the start up IPI to another apic.
void send_interrupt(uint8_t apic_id, uint8_t vector, size_t flags) const
Send an interrupt to a specific core.
uint32_t read(uint32_t reg) const
read a value from the apic register using the MSR or memory I/O depending on the local apic version
void send_init(uint8_t apic_id, bool assert) const
send the init IPI to another apic
static void * to_io_region(uintptr_t physical_address)
Converts a physical address to an IO region address if it is in the lower region using the higher hal...
void reserve(uint64_t address)
Reserves a physical address.
virtual_address_t * map(virtual_address_t *virtual_address, size_t flags)
Allocates a physical address to a virtual address.
static PhysicalMemoryManager * s_current_manager
The current physical memory manager in use.
static void cpuid(uint32_t leaf, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
Executes the CPUID instruction with the specified leaf and returns the results in the provided pointe...
static uint64_t read_msr(uint32_t msr)
Reads the value of the specified MSR.
static void write_msr(uint32_t msr, uint64_t value)
Writes the specified value to the specified MSR.
Defines a InterruptManager and InterruptHandler for managing hardware and software interrupts.
Defines a Logger class for logging messages with different severity levels to multiple output streams...
void virtual_address_t
A type representing a virtual address (used for readability)
void physical_address_t
A type representing a physical address (used for readability)
@ PRESENT
The page is present in memory.
@ WRITE
Memory in this page is writable.
Defines how an interrupt input is redirected to a specific processor via the I/O APIC.
uint8_t index
Where in the IO APIC redirection table this redirect should be placed.
uint8_t interrupt
The interrupt number to trigger when this redirect is used.
uint32_t flags
Configuration flags for the interrupt (see MADT override flags)
bool mask
Should the interrupt be disabled initially.
uint8_t type
The type of redirect (should be 0 for normal interrupts)
uint8_t destination
The ID of the core the interrupt should be sent to.
An item in the MADT table.
uint8_t type
The type of the MADT entry (see MADT_TYPE)
uint8_t length
How many bytes this entry takes up (including the type and length fields)
An entry in the MADT table describing an IO APIC.
Multiple APIC Description Table (MADT) (ACPI 2 or higher). Provides information about the APICs in th...
ACPISDTHeader header
Common ACPI SDT header.
Specifies how a specific interrupt source is mapped to a global system interrupt.
uint8_t source
The interrupt source number on the specified bus.
uint32_t global_system_interrupt
The global system interrupt that the source is mapped to.
uint8_t bus
Identifies the hardware bus the interrupt comes from (0 = ISA, 1 = PCI)
uint16_t flags
Flags describing the polarity and trigger mode of the interrupt source (see MADT override flags)
An IO APIC redirection entry. Describes how an interrupt is routed.
uint64_t raw
The raw 64-bit value of the redirection entry.