Skip to content

Commit 7183f4e

Browse files
add proper support for uacpi spinlocks and irqs
1 parent ae10e43 commit 7183f4e

3 files changed

Lines changed: 170 additions & 8 deletions

File tree

include/acpi.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,26 @@ bool pm_timer_available(void);
238238
* @return true if the PM timer is 32-bit, false if it is 24-bit.
239239
*/
240240
bool pm_timer_is_32_bit(void);
241+
242+
/**
243+
* @brief Claim and register deferred ACPI interrupt handlers.
244+
*
245+
* ACPI (via uACPI) requests installation of interrupt handlers very
246+
* early during initialisation, before Retro Rocket has brought up
247+
* its IDT and interrupt routing. At that stage it is not safe to
248+
* touch the IDT or unmask lines, so requests are deferred and stored
249+
* until interrupts can actually be enabled.
250+
*
251+
* This function processes the deferred list after the IDT and I/O APIC
252+
* setup is complete. It matches each requested GSI against the routing
253+
* table (pci_irq_routes[]), determines the correct vector, and binds
254+
* the handler into the kernel's ISR table. This ensures that when
255+
* interrupts are finally enabled, ACPI events (SCI, GPEs, etc.) are
256+
* routed correctly.
257+
*
258+
* @note This must be called once, immediately before enabling maskable
259+
* interrupts, to finalise ACPI interrupt setup. Without this step,
260+
* uACPI's requests would never become active.
261+
*/
262+
void acpi_claim_deferred_irqs(void);
263+

src/acpi.c

Lines changed: 146 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ extern size_t aps_online;
1919

2020
buddy_allocator_t acpi_pool = { 0 };
2121

22+
static bool uacpi_claim_phase = false;
23+
2224
static uint64_t pm_timer_port = 0;
2325
static bool pm_timer_32bit = 0;
2426
static bool pm_timer_is_io = 0;
@@ -37,6 +39,18 @@ uint32_t cpu_id_mapping[MAX_CPUS] = { 0 };
3739

3840
uint64_t mhz = 0, tsc_per_sec = 1;
3941

42+
typedef struct uacpi_irq_req {
43+
uint32_t gsi; /* GSI from uACPI (not a vector). */
44+
uacpi_interrupt_handler handler; /* uACPI handler: handler(ctx). */
45+
uacpi_handle ctx;
46+
uint8_t vector; /* Bound vector once claimed. */
47+
bool claimed;
48+
} uacpi_irq_req;
49+
50+
#define UACPI_DEFER_MAX 16
51+
static uacpi_irq_req *uacpi_deferred[UACPI_DEFER_MAX];
52+
static size_t uacpi_deferred_count = 0;
53+
4054
void enumerate_all_gsis(void);
4155

4256
uint32_t get_lapic_id_from_cpu_id(uint8_t cpu_id) {
@@ -496,29 +510,153 @@ void uacpi_kernel_signal_event(uacpi_handle) {}
496510

497511
void uacpi_kernel_reset_event(uacpi_handle) {}
498512

499-
uacpi_thread_id uacpi_kernel_get_thread_id(void) { return 1; }
513+
uacpi_thread_id uacpi_kernel_get_thread_id(void) {
514+
return 1;
515+
}
500516

501-
// Optional no-op spinlock support
502-
uacpi_handle uacpi_kernel_create_spinlock(void) { return (uacpi_handle) last_handle++; }
517+
uacpi_handle uacpi_kernel_create_spinlock(void) {
518+
spinlock_t *lock = (spinlock_t *)buddy_malloc(&acpi_pool, sizeof(spinlock_t));
519+
if (lock == NULL) {
520+
return (uacpi_handle)0;
521+
}
522+
init_spinlock(lock);
523+
return (uacpi_handle)(uintptr_t)lock;
524+
}
503525

504-
void uacpi_kernel_free_spinlock(uacpi_handle handle) {}
526+
void uacpi_kernel_free_spinlock(uacpi_handle handle) {
527+
spinlock_t *lock = (spinlock_t *)(uintptr_t)handle;
528+
if (lock == NULL) {
529+
return;
530+
}
531+
__atomic_store_n(lock, 0, __ATOMIC_RELEASE);
532+
buddy_free(&acpi_pool, lock);
533+
}
505534

506-
uacpi_cpu_flags uacpi_kernel_lock_spinlock(uacpi_handle handle) { return 0; }
535+
uacpi_cpu_flags uacpi_kernel_lock_spinlock(uacpi_handle handle) {
536+
spinlock_t *lock = (spinlock_t *)(uintptr_t)handle;
537+
uint64_t saved_flags = 0;
538+
if (lock == NULL) {
539+
return 0;
540+
}
541+
lock_spinlock_irq(lock, &saved_flags);
542+
return saved_flags;
543+
}
507544

508-
void uacpi_kernel_unlock_spinlock(uacpi_handle handle, uacpi_cpu_flags flags) {}
545+
void uacpi_kernel_unlock_spinlock(uacpi_handle handle, uacpi_cpu_flags flags) {
546+
spinlock_t *lock = (spinlock_t *)(uintptr_t)handle;
547+
if (lock == NULL) {
548+
return;
549+
}
550+
unlock_spinlock_irq(lock, flags);
551+
}
509552

510-
// RSDP (you already have this)
511553
uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr *out_rsdp_address) {
512554
*out_rsdp_address = rsdp_request.response->address;
513555
return UACPI_STATUS_OK;
514556
}
515557

558+
static void uacpi_irq_trampoline(uint8_t isr, uint64_t error, uint64_t vec, void *opaque) {
559+
uacpi_irq_req *r = (uacpi_irq_req *)opaque;
560+
if (r != NULL) {
561+
r->handler(r->ctx);
562+
}
563+
}
564+
516565
uacpi_status uacpi_kernel_install_interrupt_handler(uacpi_u32 irq, uacpi_interrupt_handler handler, uacpi_handle ctx, uacpi_handle *out_irq_handle) {
566+
567+
if (!out_irq_handle) {
568+
return UACPI_STATUS_INVALID_ARGUMENT;
569+
}
570+
if (uacpi_deferred_count >= UACPI_DEFER_MAX) {
571+
return UACPI_STATUS_INTERNAL_ERROR;
572+
}
573+
574+
uacpi_irq_req *r = buddy_malloc(&acpi_pool, sizeof(uacpi_irq_req));
575+
if (r == NULL) {
576+
return UACPI_STATUS_OUT_OF_MEMORY;
577+
}
578+
579+
r->gsi = irq;
580+
r->handler = handler;
581+
r->ctx = ctx;
582+
r->vector = 0;
583+
r->claimed = false;
584+
585+
/* If claim phase already started, bind immediately using pci_irq_routes[]. */
586+
if (uacpi_claim_phase) {
587+
for (size_t j = 0; j < MAX_PCI_ROUTES; j++) {
588+
pci_irq_route_t *route = &pci_irq_routes[j];
589+
if (!route->exists || route->gsi != r->gsi) {
590+
continue;
591+
}
592+
uint8_t vector = (uint8_t)(IRQ_START + (uint32_t)j);
593+
dprintf("[uACPI] Attached interrupt on GSI %d (ISR %d)\n", r->gsi, vector);
594+
if (register_interrupt_handler(vector, uacpi_irq_trampoline, (pci_dev_t){0}, r)) {
595+
r->vector = vector;
596+
r->claimed = true;
597+
} else {
598+
dprintf("acpi: failed to register vector %u for GSI %u\n", vector, route->gsi);
599+
}
600+
break;
601+
}
602+
} else {
603+
dprintf("[uACPI] Attached interrupt on GSI %d (deferred)\n", r->gsi);
604+
}
605+
606+
uacpi_deferred[uacpi_deferred_count++] = r;
607+
608+
*out_irq_handle = (uacpi_handle)(uintptr_t)r;
517609
return UACPI_STATUS_OK;
518610
}
519611

520612
uacpi_status uacpi_kernel_uninstall_interrupt_handler(uacpi_interrupt_handler handler, uacpi_handle irq_handle) {
521-
return UACPI_STATUS_OK;
613+
614+
uacpi_irq_req *r = (uacpi_irq_req *)(uintptr_t)irq_handle;
615+
if (r == NULL) {
616+
return UACPI_STATUS_INVALID_ARGUMENT;
617+
}
618+
619+
for (size_t i = 0; i < uacpi_deferred_count; i++) {
620+
if (uacpi_deferred[i] == r) {
621+
if (r->claimed) {
622+
deregister_interrupt_handler(r->vector, uacpi_irq_trampoline);
623+
}
624+
uacpi_deferred[i] = uacpi_deferred[uacpi_deferred_count - 1];
625+
uacpi_deferred[uacpi_deferred_count - 1] = NULL;
626+
uacpi_deferred_count--;
627+
buddy_free(&acpi_pool, r);
628+
return UACPI_STATUS_OK;
629+
}
630+
}
631+
632+
return UACPI_STATUS_INTERNAL_ERROR;
633+
}
634+
635+
void acpi_claim_deferred_irqs(void) {
636+
if (uacpi_claim_phase) {
637+
return;
638+
}
639+
for (size_t i = 0; i < uacpi_deferred_count; i++) {
640+
uacpi_irq_req *r = uacpi_deferred[i];
641+
if (r == NULL || r->claimed) {
642+
continue;
643+
}
644+
for (size_t j = 0; j < MAX_PCI_ROUTES; j++) {
645+
pci_irq_route_t *route = &pci_irq_routes[j];
646+
if (!route->exists || route->gsi != r->gsi) {
647+
continue;
648+
}
649+
uint8_t vector = (uint8_t)(IRQ_START + (uint32_t)j);
650+
if (register_interrupt_handler(vector, uacpi_irq_trampoline, (pci_dev_t){0}, r)) {
651+
r->vector = vector;
652+
r->claimed = true;
653+
} else {
654+
dprintf("acpi: failed to register vector %u for GSI %u\n", vector, route->gsi);
655+
}
656+
break;
657+
}
658+
}
659+
uacpi_claim_phase = true;
522660
}
523661

524662
uacpi_status uacpi_kernel_handle_firmware_request(uacpi_firmware_request *req) {

src/idt.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ void init_idt() {
113113
pic_enable();
114114
#endif
115115

116+
acpi_claim_deferred_irqs();
116117
interrupts_on();
117118

118119
dprintf("Interrupts enabled!\n");

0 commit comments

Comments
 (0)