universalisos/kernel/gic.cpp
Fábio Coutada 9540b0528c feat(universalisos): PikeOS-style Phase B/C device drivers + Phase D microkernel
Phase B (Core Device Support) — all drivers verified in QEMU:
- Network: virtio-net cleanup, RTL8139, E1000, clause-22 MDIO PHY management,
  CAN bus, industrial protocols (Modbus/Profibus/EtherCAT), controller probe+dispatch
- Block storage: RAM disk backend (write->read->verify PASSED), virtio-blk transport,
  backend dispatch, real MBR+GPT partition parsers, SD/eMMC command framework
- GPIO: PL061 (verified), I2C: DesignWare (verified), SPI: PL022 (verified)

Phase C (Advanced Features):
- PCI: FULL PikeOS ARMv7 replica — transport-agnostic uos_pci_ops, config-address
  encoding, BAR sizing, capability walk, enumeration+bridge recursion, MSI/MSI-X
- USB: PikeOS-style layered stack — usb.h contract, usb_core.cpp (enumeration
  state machine), usb_ehci.cpp (EHCI transport)
- Display: FULL 1:1 PikeOS fbcon replica + copied font_8x16

Build foundation fixes:
- Freestanding aeabi_runtime.cpp (__aeabi_uidiv/__aeabi_uldivmod)
- PikeOS-style flat 4GB MMU section map + proper enable (unblocked device MMIO)
- guest.h MAX_GUEST_IMAGE_SIZE 256MB->16MB (BSS was 259MB)
- C/C++ linkage fixes, duplicate-virtio_net_init, MMIO access-size handling

Phase D (PikeOS ARMv7 Microkernel Port):
- D-1: Per-VM address spaces — cloned pgdirs, ASID-tagged TLB, 4K page walker,
  isolation PASSED (two guests, same VA->different PAs), guest fault recovery
- D-2: IRQ dispatch backbone — 1024-slot dispatch table, real GICv2 hardware
  (GICD_CTLR/GICC_CTLR/GICC_PMR/GICC_IAR/GICC_EOIR), arm_irq_handler wired
- D-3: Time subsystem — CNTVCT ns-since-boot, CNTP periodic ticker via D-2
- D-4: KDEV framework — linker-section driver registration, uos_kdev_init_all,
  name lookup
- D-5: VFP/NEON — lazy enable (undef trap->CPACR+FPEXC.EN), FPEXC=0x40000000
- D-6: SMP — per-CPU state, MPIDR, IPI/SGI framework (reschedule+TLB flush)

All uos_ naming (PikeOS p4_ convention adapted). Compiles -Werror freestanding C++17.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-09 09:10:53 +01:00

502 lines
No EOL
14 KiB
C++

/*
* Universalisos Interrupt Controller Implementation - Stage 4
* PikeOS 5.0 Feature Parity - Interrupt Virtualization
*
* Stage 4: Device Virtualization + Interrupt Handling
* Author: PortugalFuturista Hypervisor Development Team
* Version: 1.0.0
*/
#include "gic.h"
#include "arch/arm/uart.h"
#include <stdint.h>
// Global GIC state
static gic_state_t g_gic_state = {
.distributor = {
.enable = 0,
.enable_set = {},
.enable_clear = {},
.pending_set = {},
.pending_clear = {},
.active = {},
.priority = {},
.targets = {},
.config = {},
.sgi = {}
},
.cpu_interface = {
.enable = 0,
.priority_mask = 0xFF,
.irq_ack = 0,
.eoi = 0,
.running_priority = 0,
.highest_priority = 0,
.binary_point = 0
},
.virtual_gics = {},
.active_virtual_gic_count = 0,
.interrupt_configs = {},
.configured_interrupts = 0,
.total_interrupts = 0,
.spurious_interrupts = 0,
.virtual_interrupts_injected = 0,
.interrupt_masked = 0
};
// GIC physical base addresses for QEMU virt platform
#define GIC_DIST_BASE 0x08000000 // GIC Distributor base
#define GIC_CPU_BASE 0x08010000 // GIC CPU Interface base
/* Real GICv2 register offsets (for driving actual hardware). */
#define GICD_CTLR 0x000u
#define GICD_ISENABLER(n) (0x100u + 4u*(n))
#define GICD_ICENABLER(n) (0x180u + 4u*(n))
#define GICD_IPRIORITYR(n) (0x400u + (n))
#define GICD_ITARGETSR(n) (0x800u + (n))
#define GICD_ICFGR(n) (0xC00u + 4u*(n))
#define GICC_CTLR 0x000u
#define GICC_PMR 0x004u
#define GICC_IAR 0x00Cu
#define GICC_EOIR 0x010u
#define GIC_REG32(base, off) (*((volatile uint32_t*)((base) + (off))))
/**
* Initialize GIC
*/
extern "C" void gic_init(void) {
uart_puts("GIC: Initializing ARMv7 GIC\n");
// Initialize GIC state
g_gic_state.distributor.enable = 0;
g_gic_state.cpu_interface.enable = 0;
g_gic_state.cpu_interface.priority_mask = 0xFF;
g_gic_state.cpu_interface.binary_point = 0;
// Clear all interrupt configurations
for (int i = 0; i < GIC_MAX_INTERRUPTS; i++) {
g_gic_state.interrupt_configs[i].interrupt_id = i;
g_gic_state.interrupt_configs[i].type = INTERRUPT_TYPE_SPI;
g_gic_state.interrupt_configs[i].priority = GIC_PRIORITY_NORMAL;
g_gic_state.interrupt_configs[i].target_cpu = TARGET_CPU0;
g_gic_state.interrupt_configs[i].enabled = false;
g_gic_state.interrupt_configs[i].pending = false;
g_gic_state.interrupt_configs[i].active = false;
g_gic_state.interrupt_configs[i].edge_triggered = false;
g_gic_state.interrupt_configs[i].is_virtual = false;
g_gic_state.interrupt_configs[i].owner_vm_id = 0xFFFFFFFF;
g_gic_state.interrupt_configs[i].virq = 0;
}
// Configure SGI interrupts (0-15)
for (int i = 0; i < GIC_SGI_MAX; i++) {
g_gic_state.interrupt_configs[i].type = INTERRUPT_TYPE_SGI;
g_gic_state.interrupt_configs[i].priority = GIC_PRIORITY_HIGHEST;
}
// Configure PPI interrupts (16-31)
for (int i = GIC_SGI_MAX; i < GIC_PPI_MAX; i++) {
g_gic_state.interrupt_configs[i].type = INTERRUPT_TYPE_PPI;
g_gic_state.interrupt_configs[i].priority = GIC_PRIORITY_HIGH;
}
g_gic_state.configured_interrupts = 0;
g_gic_state.active_virtual_gic_count = 0;
g_gic_state.total_interrupts = 0;
g_gic_state.spurious_interrupts = 0;
g_gic_state.virtual_interrupts_injected = 0;
g_gic_state.interrupt_masked = 0;
uart_puts("GIC: ARMv7 GIC initialized\n");
uart_puts("GIC: Maximum interrupts: ");
uart_print_dec(GIC_MAX_INTERRUPTS);
uart_puts("\n");
uart_puts("GIC: SGI range: 0-15\n");
uart_puts("GIC: PPI range: 16-31\n");
uart_puts("GIC: SPI range: 32-1020\n");
}
/**
* Enable GIC
*/
extern "C" void gic_enable(void) {
uart_puts("GIC: Enabling GIC\n");
// Enable distributor
g_gic_state.distributor.enable = 1;
// Enable CPU interface
g_gic_state.cpu_interface.enable = 1;
g_gic_state.cpu_interface.priority_mask = 0xFF; // Allow all priorities
/* Drive the real GICv2 hardware. */
GIC_REG32(GIC_DIST_BASE, GICD_CTLR) = 1u; /* enable distributor */
GIC_REG32(GIC_CPU_BASE, GICC_PMR) = 0xFFu; /* allow all priorities */
GIC_REG32(GIC_CPU_BASE, GICC_CTLR) = 1u; /* enable CPU interface */
uart_puts("GIC: GIC enabled (hardware)\n");
}
/**
* Disable GIC
*/
extern "C" void gic_disable(void) {
uart_puts("GIC: Disabling GIC\n");
// Disable CPU interface
g_gic_state.cpu_interface.enable = 0;
// Disable distributor
g_gic_state.distributor.enable = 0;
uart_puts("GIC: GIC disabled\n");
}
/**
* Configure interrupt
*/
extern "C" bool gic_configure_interrupt(uint32_t irq_id, interrupt_type_t type,
uint32_t priority, uint32_t target_cpu,
bool edge_triggered) {
if (irq_id >= GIC_MAX_INTERRUPTS) {
uart_puts("GIC: Invalid interrupt ID ");
uart_print_dec(irq_id);
uart_puts("\n");
return false;
}
uart_puts("GIC: Configuring interrupt ");
uart_print_dec(irq_id);
uart_puts("\n");
interrupt_config_t* config = &g_gic_state.interrupt_configs[irq_id];
config->type = type;
config->priority = priority & 0xFF;
config->target_cpu = target_cpu;
config->edge_triggered = edge_triggered;
config->enabled = true;
/* Real GIC hardware: write priority + target (SPI only; PPI/SGI are fixed). */
volatile uint8_t *prio = (volatile uint8_t *)(GIC_DIST_BASE + GICD_IPRIORITYR(irq_id));
*prio = (uint8_t)(priority & 0xFFu);
if (irq_id >= 32u) {
/* SPI: write target CPU. PPI/SGI targets are fixed. */
volatile uint8_t *tgt = (volatile uint8_t *)(GIC_DIST_BASE + GICD_ITARGETSR(irq_id));
*tgt = (uint8_t)(1u << target_cpu);
}
g_gic_state.configured_interrupts++;
uart_puts("GIC: Interrupt ");
uart_print_dec(irq_id);
uart_puts(" configured (priority ");
uart_print_dec(priority);
uart_puts(")\n");
return true;
}
/**
* Enable interrupt
*/
extern "C" void gic_enable_interrupt(uint32_t irq_id) {
if (irq_id >= GIC_MAX_INTERRUPTS) return;
g_gic_state.interrupt_configs[irq_id].enabled = true;
/* Real GIC: set-enable register (one bit per 32 IRQs). */
GIC_REG32(GIC_DIST_BASE, GICD_ISENABLER(irq_id / 32u)) = 1u << (irq_id % 32u);
}
/**
* Disable interrupt
*/
extern "C" void gic_disable_interrupt(uint32_t irq_id) {
if (irq_id >= GIC_MAX_INTERRUPTS) return;
g_gic_state.interrupt_configs[irq_id].enabled = false;
/* Real GIC: clear-enable register. */
GIC_REG32(GIC_DIST_BASE, GICD_ICENABLER(irq_id / 32u)) = 1u << (irq_id % 32u);
}
/**
* Set interrupt priority
*/
extern "C" void gic_set_priority(uint32_t irq_id, uint32_t priority) {
if (irq_id >= GIC_MAX_INTERRUPTS) return;
g_gic_state.interrupt_configs[irq_id].priority = priority & 0xFF;
}
/**
* Get interrupt priority
*/
extern "C" uint32_t gic_get_priority(uint32_t irq_id) {
if (irq_id >= GIC_MAX_INTERRUPTS) return GIC_PRIORITY_LOWEST;
return g_gic_state.interrupt_configs[irq_id].priority;
}
/**
* Set interrupt target
*/
extern "C" void gic_set_target(uint32_t irq_id, uint32_t target_cpu) {
if (irq_id >= GIC_MAX_INTERRUPTS) return;
g_gic_state.interrupt_configs[irq_id].target_cpu = target_cpu;
}
/**
* Generate Software Generated Interrupt (SGI)
*/
extern "C" void gic_generate_sgi(uint32_t sgi_id, uint32_t target_cpu) {
if (sgi_id >= GIC_SGI_MAX) {
uart_puts("GIC: Invalid SGI ID\n");
return;
}
uart_puts("GIC: Generating SGI ");
uart_print_dec(sgi_id);
uart_puts(" to CPU ");
uart_print_dec(target_cpu);
uart_puts("\n");
// Mark interrupt as pending
g_gic_state.interrupt_configs[sgi_id].pending = true;
}
/**
* Acknowledge interrupt
*/
extern "C" uint32_t gic_acknowledge_interrupt(void) {
/* Read the real GICC_IAR — atomically acknowledges the highest-priority
* pending interrupt and returns its ID (1023 = spurious). */
uint32_t irq_id = GIC_REG32(GIC_CPU_BASE, GICC_IAR) & 0x3FFu;
/* Track in software model for diagnostics. */
if (irq_id < GIC_MAX_IRQ) {
g_gic_state.interrupt_configs[irq_id].active = true;
g_gic_state.total_interrupts++;
} else {
g_gic_state.spurious_interrupts++;
}
return irq_id;
}
/**
* End of interrupt
*/
extern "C" void gic_end_of_interrupt(uint32_t irq_id) {
/* Write the real GICC_EOIR to signal end-of-interrupt. */
GIC_REG32(GIC_CPU_BASE, GICC_EOIR) = irq_id;
if (irq_id >= GIC_MAX_IRQ) return;
/* Update software model. */
g_gic_state.interrupt_configs[irq_id].active = false;
g_gic_state.cpu_interface.eoi = irq_id;
}
/**
* Get interrupt configuration
*/
extern "C" interrupt_config_t* gic_get_interrupt_config(uint32_t irq_id) {
if (irq_id >= GIC_MAX_INTERRUPTS) return nullptr;
return &g_gic_state.interrupt_configs[irq_id];
}
/**
* Assign interrupt to VM
*/
extern "C" bool gic_assign_interrupt_to_vm(uint32_t irq_id, uint32_t vm_id, uint32_t virq) {
if (irq_id >= GIC_MAX_INTERRUPTS) return false;
uart_puts("GIC: Assigning interrupt ");
uart_print_dec(irq_id);
uart_puts(" to VM ");
uart_print_dec(vm_id);
uart_puts(" as virq ");
uart_print_dec(virq);
uart_puts("\n");
interrupt_config_t* config = &g_gic_state.interrupt_configs[irq_id];
config->is_virtual = true;
config->owner_vm_id = vm_id;
config->virq = virq;
return true;
}
/**
* Create virtual interrupt controller for VM
*/
extern "C" virtual_interrupt_controller_t* gic_create_virtual_gic(uint32_t vm_id) {
if (vm_id >= 16) return nullptr;
uart_puts("GIC: Creating virtual GIC for VM ");
uart_print_dec(vm_id);
uart_puts("\n");
virtual_interrupt_controller_t* v_gic = &g_gic_state.virtual_gics[vm_id];
v_gic->vm_id = vm_id;
// Clear interrupt bitmaps
for (int i = 0; i < 32; i++) {
v_gic->pending_interrupts[i] = 0;
v_gic->enabled_interrupts[i] = 0;
v_gic->masked_interrupts[i] = 0;
}
v_gic->virtual_interrupt_count = 0;
g_gic_state.active_virtual_gic_count++;
uart_puts("GIC: Virtual GIC created\n");
return v_gic;
}
/**
* Inject virtual interrupt into VM
*/
extern "C" bool gic_inject_virtual_interrupt(uint32_t vm_id, uint32_t virq) {
if (vm_id >= 16 || virq >= 1024) return false;
virtual_interrupt_controller_t* v_gic = &g_gic_state.virtual_gics[vm_id];
// Set bit in pending interrupts
v_gic->pending_interrupts[virq / 32] |= (1U << (virq % 32));
g_gic_state.virtual_interrupts_injected++;
uart_puts("GIC: Injected virtual interrupt ");
uart_print_dec(virq);
uart_puts(" to VM ");
uart_print_dec(vm_id);
uart_puts("\n");
return true;
}
/**
* Mask virtual interrupt for VM
*/
extern "C" void gic_mask_virtual_interrupt(uint32_t vm_id, uint32_t virq) {
if (vm_id >= 16 || virq >= 1024) return;
virtual_interrupt_controller_t* v_gic = &g_gic_state.virtual_gics[vm_id];
// Set bit in masked interrupts
v_gic->masked_interrupts[virq / 32] |= (1U << (virq % 32));
g_gic_state.interrupt_masked++;
uart_puts("GIC: Masked virtual interrupt ");
uart_print_dec(virq);
uart_puts(" for VM ");
uart_print_dec(vm_id);
uart_puts("\n");
}
/**
* Get pending virtual interrupt for VM
*/
extern "C" uint32_t gic_get_pending_virtual_interrupt(uint32_t vm_id) {
if (vm_id >= 16) return 1023; // Spurious
virtual_interrupt_controller_t* v_gic = &g_gic_state.virtual_gics[vm_id];
// Find first pending, enabled, unmasked interrupt
for (int i = 0; i < 32; i++) {
uint32_t pending = v_gic->pending_interrupts[i];
uint32_t enabled = v_gic->enabled_interrupts[i];
uint32_t masked = v_gic->masked_interrupts[i];
uint32_t available = pending & enabled & ~masked;
if (available) {
// Find first set bit
for (int j = 0; j < 32; j++) {
if (available & (1U << j)) {
return i * 32 + j;
}
}
}
}
return 1023; // No pending interrupts
}
/**
* Handle IRQ interrupt
*/
extern "C" void gic_handle_irq(void) {
uart_puts("\n>>> GIC IRQ HANDLER <<<\n");
// Acknowledge interrupt
uint32_t irq_id = gic_acknowledge_interrupt();
if (irq_id >= GIC_MAX_IRQ) {
uart_puts("GIC: Spurious interrupt\n");
return;
}
uart_puts("GIC: Handling interrupt ");
uart_print_dec(irq_id);
uart_puts("\n");
// Get interrupt configuration
interrupt_config_t* config = &g_gic_state.interrupt_configs[irq_id];
// Check if this is a virtual interrupt
if (config->is_virtual && config->owner_vm_id != 0xFFFFFFFF) {
// Inject into target VM
gic_inject_virtual_interrupt(config->owner_vm_id, config->virq);
} else {
// Handle as physical interrupt
uart_puts("GIC: Physical interrupt (would dispatch to handler)\n");
}
// End of interrupt
gic_end_of_interrupt(irq_id);
}
/**
* Print GIC statistics
*/
extern "C" void gic_print_statistics(void) {
uart_puts("\n=== GIC Statistics ===\n");
uart_puts("Total Interrupts: ");
uart_print_dec(g_gic_state.total_interrupts);
uart_puts("\n");
uart_puts("Spurious Interrupts: ");
uart_print_dec(g_gic_state.spurious_interrupts);
uart_puts("\n");
uart_puts("Virtual Interrupts Injected: ");
uart_print_dec(g_gic_state.virtual_interrupts_injected);
uart_puts("\n");
uart_puts("Interrupts Masked: ");
uart_print_dec(g_gic_state.interrupt_masked);
uart_puts("\n");
uart_puts("Configured Interrupts: ");
uart_print_dec(g_gic_state.configured_interrupts);
uart_puts("\n");
uart_puts("Active Virtual GICs: ");
uart_print_dec(g_gic_state.active_virtual_gic_count);
uart_puts("\n");
uart_puts("======================\n\n");
}