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);
133 uint32_t icr_low = 0;
136 icr_low |= (0b101 << 8);
140 icr_low |= (1 << 14);
143 icr_low |= (1 << 15);
148 write(0x310, apic_id << 24);
151 write(0x300, icr_low);
154 while (
read(0x300) & (1 << 12))
155 asm volatile(
"pause");
175 write(0x310, apic_id << 24);
178 write(0x300, 0x4600 | vector);
181 while (
read(0x300) & (1 << 12))
182 asm volatile(
"pause");
203 m_madt = (
MADT*) m_acpi->
find(
"APIC");
211 m_address = io_apic->io_apic_address;
214 Logger::DEBUG() <<
"IO APIC Address: phy=0x" << m_address <<
", virt=0x" << m_address_high <<
"\n";
217 m_version =
read(0x1);
218 m_max_redirect_entry = (uint8_t) (m_version >> 16);
221 Logger::DEBUG() <<
"IO APIC Version: 0x" << (uint64_t) (m_version & 0xFF) <<
"\n";
222 Logger::DEBUG() <<
"IO APIC Max Redirection Entry: 0x" << (uint64_t) m_max_redirect_entry <<
"\n";
226 uint32_t total_length =
sizeof(
MADT);
227 while (total_length < m_madt->header.length && m_override_array_size < 0x10) {
229 total_length += source_override_item->
length;
232 if (source_override_item !=
nullptr && source_override_item->
type == 2) {
235 auto*
override = (
Override*) (source_override_item + 1);
236 m_override_array[m_override_array_size].
bus =
override->bus;
237 m_override_array[m_override_array_size].
source =
override->source;
239 m_override_array[m_override_array_size].
flags =
override->flags;
240 m_override_array_size++;
244 source_override_item =
get_madt_item(MADT_TYPE::IO_APIC, m_override_array_size);
245 if (source_override_item ==
nullptr)
249 Logger::DEBUG() <<
"IO APIC Source Overrides: 0x" << m_override_array_size <<
"\n";
252IOAPIC::~IOAPIC() =
default;
264 auto* item = (
MADTEntry*) ((uint64_t) m_madt +
sizeof(
MADT));
265 uint64_t total_length = 0;
266 uint8_t current_index = 0;
269 while (total_length +
sizeof(
MADT) < m_madt->
header.
length && current_index <= index) {
272 if (item->type == (uint8_t)type) {
275 if (current_index == index)
283 total_length += item->
length;
284 item = (
MADTEntry*) ((uint64_t) item + item->length);
300 *(
volatile uint32_t*) (m_address_high + 0x00) = reg;
303 return *(
volatile uint32_t*) (m_address_high + 0x10);
315 *(
volatile uint32_t*) (m_address_high + 0x00) = reg;
318 *(
volatile uint32_t*) (m_address_high + 0x10) = value;
330 if (index < 0x10 || index > 0x3F)
334 uint32_t low =
read(index);
335 uint32_t high =
read(index + 1);
336 entry->
raw = ((uint64_t) high << 32) | ((uint64_t) low);
348 if (index < 0x10 || index > 0x3F)
352 auto low = (uint32_t) entry->
raw;
353 auto high = (uint32_t) (entry->
raw >> 32);
357 write(index + 1, high);
371 entry.mask = redirect->
mask;
374 for (uint8_t i = 0; i < m_override_array_size; i++) {
376 if (m_override_array[i].source != redirect->
type)
380 entry.pin_polarity = ((m_override_array[i].
flags & 0b11) == 2) ? 0b1 : 0b0;
381 entry.pin_polarity = (((m_override_array[i].
flags >> 2) & 0b11) == 2) ? 0b1 : 0b0;
384 entry.trigger_mode = (((m_override_array[i].
flags >> 2) & 0b11) == 2);
390 write_redirect(redirect->
index, &entry);
403 read_redirect(index, &entry);
407 write_redirect(index, &entry);
416: m_pic_master_command_port(0x20),
417 m_pic_master_data_port(0x21),
418 m_pic_slave_command_port(0xA0),
419 m_pic_slave_data_port(0xA1)
436 m_io_apic =
new IOAPIC(acpi);
452void AdvancedProgrammableInterruptController::disable_pic() {
455 m_pic_master_command_port.
write(0x11);
456 m_pic_slave_command_port.
write(0x11);
459 m_pic_master_data_port.
write(0x20);
460 m_pic_slave_data_port.
write(0x28);
463 m_pic_master_data_port.
write(0x04);
464 m_pic_slave_data_port.
write(0x02);
467 m_pic_master_data_port.
write(0x01);
468 m_pic_slave_data_port.
write(0x01);
471 m_pic_master_data_port.
write(0xFF);
472 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 Logger DEBUG()
Gets active logger set to DEBUG level.
static Logger WARNING()
Gets active logger set to WARNING level.
static Logger INFO()
Gets active logger set to info level.
Stores the left, top, width and height of a rectangle.
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
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
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
void write(uint8_t data) final
write a byte to the port (slow)
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...
#define ASSERT(condition, format,...)
If the specified condition is not met then the kernel will crash with the specified message.
@ 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.