stos/amd64: cpu: Add HAL interrupt registration
Signed-off-by: Chloe M. <chloe@mensia.org>
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
@@ -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_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user