/* * Copyright (c) 2026, Chloe M. * Provided under the BSD-3 clause. * * Description: Interrupt management * Author: Chloe M. */ #include #include #include #include /* Interrupt priority level shift */ #define IPL_SHIFT 4 /* Globals */ static INTR_HANDLER Handlers[256]; /* * Set a new IRQL */ static inline VOID SetIrql(IRQL Irql) { ASMV( "mov %0, %%cr8" : : "r" ((UQUAD)Irql) : "memory" ); } ST_STATUS HalRegisterIntr(const INTR_HANDLER *Handler, BOOLEAN IsUser) { UCHAR Vector, Idx; INTR_HANDLER *HandlerSlot; if (Handler == NULL) { return STATUS_INVALID_PARAM; } /* Must have a valid handler */ if (Handler->Handler == NULL) { return STATUS_INVALID_PARAM; } /* Ensure that the priority is valid */ switch (Handler->Irql) { case IRQL_PASSIVE: case IRQL_APC: case IRQL_DEVICE: case IRQL_HIGH: break; default: return STATUS_INVALID_PARAM; } /* * We have 16 priorities at every band as 4-bits makes up * the interrupt priority level. Our job is to find a slot * that is free for our interrupt handler at its given IRQL. */ Vector = MAX(0x20, Handler->Irql << IPL_SHIFT); for (Idx = Vector; Idx < Vector + 16; ++Idx) { HandlerSlot = &Handlers[Idx]; /* This entry is present, don't overwrite */ if (HandlerSlot->Present) { continue; } /* Fill the slot */ *HandlerSlot = *(INTR_HANDLER *)Handler; HandlerSlot->Present = 1; /* Register the interrupt */ MdIdtSetEntry( Idx, (UPTR)Handler->Handler, (IsUser) ? IDT_USER_GATE : IDT_INT_GATE, 0 ); return STATUS_SUCCESS; } /* No entry found */ return STATUS_NOT_FOUND; } IRQL HalGetIrql(VOID) { UQUAD CurrentIrql; ASMV( "mov %%cr8, %0" : "=r" (CurrentIrql) : : "memory" ); return (IRQL)CurrentIrql; } IRQL HalRaiseIrql(IRQL Irql) { IRQL CurrentIrql; CurrentIrql = HalGetIrql(); if (Irql < CurrentIrql) { KeKnot(KNOT_IRQL_NOT_GTE, "got bad irql\n"); } SetIrql(Irql); return CurrentIrql; } IRQL HalLowerIrql(IRQL Irql) { IRQL CurrentIrql; CurrentIrql = HalGetIrql(); if (Irql > CurrentIrql) { KeKnot(KNOT_IRQL_NOT_LTE, "got bad irql\n"); } return CurrentIrql; }