diff --git a/src/platform/x86_64/apic/apic.c b/src/platform/x86_64/apic/apic.c index 173b82a..d195ed6 100644 --- a/src/platform/x86_64/apic/apic.c +++ b/src/platform/x86_64/apic/apic.c @@ -133,6 +133,26 @@ int apicInit() { overrideIRQRegister(irqor); break; + case MADT_TYPE_LOCAL_NMI: + ACPIMADTLocalNMI *lnmiEntry = (ACPIMADTLocalNMI *) ptr; + KDEBUG("local APIC NMI on ACPI ID 0x%02X LINT#%d with flags 0x%04X (%s, %s)\n", + lnmiEntry->procID, lnmiEntry->lint & 1, lnmiEntry->flags, + lnmiEntry->flags & MADT_INTERRUPT_LEVEL ? "level" : "edge", + lnmiEntry->flags & MADT_INTERRUPT_LOW ? "low" : "high"); + + LocalNMI *lnmi = calloc(1, sizeof(LocalNMI)); + if(!lnmi) { + KERROR("could not allocate memory for local APIC NMI\n"); + while(1); + } + + lnmi->procID = lnmiEntry->procID; + lnmi->lint = lnmiEntry->lint; + if(override->flags & MADT_INTERRUPT_LEVEL) lnmi->level = 1; + if(override->flags & MADT_INTERRUPT_LOW) lnmi->low = 0; + + lnmiRegister(lnmi); + break; default: KWARN("unimplemented MADT entry type 0x%02X with length %d, skipping...\n", ptr[0], ptr[1]); } diff --git a/src/platform/x86_64/apic/nmi.c b/src/platform/x86_64/apic/nmi.c new file mode 100644 index 0000000..644b8d1 --- /dev/null +++ b/src/platform/x86_64/apic/nmi.c @@ -0,0 +1,49 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Platform-Specific Code for x86_64 + */ + +/* Non-Maskable Interrupt Implementation */ + +/* Intel Software Developer's Manual Volume 3A Part 1 Chapter 11.5.1: + * + * The trigger mode of local APIC NMIs is always set to be edge-sensitive, and + * that of local APIC ExtINTs is always set to level-sensitive. LINT1 is always + * hardwired to level-sensitive, and only LINT0 can be configured to use either + * edge or level according to the information from the ACPI MADT. + */ + +#include +#include +#include + +static LocalNMI *lnmis = NULL; +static BusNMI *bnmis = NULL; +static int nlnmi = 0, nbnmi = 0; + +/* lnmiRegister(): registers a local APIC NMI + * params: lnmi - local APIC NMI structure + * returns: count of local APIC NMIs + */ + +int lnmiRegister(LocalNMI *lnmi) { + if(!lnmis) lnmis = lnmi; + else { + LocalNMI *list = lnmis; + while(list->next) list = list->next; + list->next = lnmi; + } + + return nlnmi++; +} + +/* lnmiCount(): returns the number of local APIC NMIs + * params: none + * returns: number of local APIC NMIs + */ + +int lnmiCount() { + return nlnmi; +} \ No newline at end of file diff --git a/src/platform/x86_64/include/platform/apic.h b/src/platform/x86_64/include/platform/apic.h index 0715cfd..db2e36e 100644 --- a/src/platform/x86_64/include/platform/apic.h +++ b/src/platform/x86_64/include/platform/apic.h @@ -189,14 +189,14 @@ typedef struct IRQOverride { typedef struct BusNMI { uint8_t source; - uint16_t flags; + int level, low; uint32_t gsi; struct BusNMI *next; } BusNMI; typedef struct LocalNMI { uint8_t procID; - uint16_t flags; + int level, low; uint8_t lint; struct LocalNMI *next; } LocalNMI; @@ -217,6 +217,9 @@ void ioapicWrite(IOAPIC *, uint32_t, uint32_t); uint32_t ioapicRead(IOAPIC *, uint32_t); int ioapicMask(int, int); +int lnmiRegister(LocalNMI *); +int lnmiCount(); + int overrideIRQRegister(IRQOverride *); int overrideIRQCount(); IRQOverride *findOverrideIRQ(uint64_t);