stos/amd64: cpu: Add HAL interrupt registration

Signed-off-by: Chloe M. <chloe@mensia.org>
This commit is contained in:
Chloe M.
2026-06-23 21:20:09 +00:00
parent e1a115cccc
commit 27c6ca8125
2 changed files with 122 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2026, Chloe M.
* Provided under the BSD-3 clause.
*
* Description: Interrupt management
* Author: Chloe M.
*/
#include <hal/intr.h>
#include <machine/idt.h>
#include <stdef.h>
/* Interrupt priority level shift */
#define IPL_SHIFT 4
/* Globals */
static INTR_HANDLER Handlers[256];
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;
}
+46
View File
@@ -9,6 +9,9 @@
#ifndef _HAL_INTR_H_ #ifndef _HAL_INTR_H_
#define _HAL_INTR_H_ 1 #define _HAL_INTR_H_ 1
#include <stdef.h>
#include <stapi/status.h>
/* /*
* Valid interrupt request levels * Valid interrupt request levels
* *
@@ -23,4 +26,47 @@
#define IRQL_DEVICE 3 #define IRQL_DEVICE 3
#define IRQL_HIGH 4 #define IRQL_HIGH 4
/* IRQLs are of this type */
typedef UCHAR IRQL;
/*
* Interrupt data that is given to a service routine
*
* @Vector: Interrupt vector that fired
* @Data: Driver specific data
*/
typedef struct {
UCHAR Vector;
VOID *Data;
} INTR_DATA;
/*
* Interrupt handler descriptor
*
* @Irql: Prioirty of handler
* @Present: Must be 1 to be valid
* @Data: Driver specific data
* @Handler: Reference to interrupt handler
*
* XXX: There is no need to set the present bit when
* creating an instance as it is set automatically.
*/
typedef struct {
IRQL Irql;
UCHAR Present : 1;
VOID *Data;
LONG(*Handler)(INTR_DATA *Data);
} INTR_HANDLER;
/*
* Register an interrupt handler
*
* @Handler: Interrupt handler to register
* @IsUser: Should be set if user interrupt
*
* XXX: Most of the times, @IsUser should remain unset,
* it is mostly there for the sake of scalability.
*/
ST_STATUS HalRegisterIntr(const INTR_HANDLER *Handler, BOOLEAN IsUser);
#endif /* !_HAL_INTR_H_ */ #endif /* !_HAL_INTR_H_ */