|
miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
|
Local and I/O APIC initialisation, IPI dispatch, and LAPIC timer. More...
Macros | |
| #define | LAPIC_ID 0x020 /* Local APIC ID register */ |
| #define | LAPIC_EOI 0x0B0 /* End-of-Interrupt register */ |
| #define | LAPIC_SVR 0x0F0 /* Spurious Interrupt Vector Register */ |
| #define | LAPIC_ICR_LOW 0x300 /* Interrupt Command Register low */ |
| #define | LAPIC_ICR_HIGH 0x310 /* Interrupt Command Register high */ |
| #define | LAPIC_TIMER_LVT 0x320 /* LVT Timer register */ |
| #define | LAPIC_TIMER_ICR 0x380 /* Timer Initial Count Register */ |
| #define | LAPIC_TIMER_CCR 0x390 /* Timer Current Count Register */ |
| #define | LAPIC_TIMER_DCR 0x3E0 /* Timer Divide Configuration Register*/ |
| #define | LAPIC_SVR_ENABLE (1 << 8) /* Software enable bit */ |
| #define | LAPIC_SPURIOUS_VECTOR 0xFF /* Spurious interrupt vector */ |
| #define | IA32_APIC_BASE_MSR 0x1B |
| #define | IA32_APIC_BASE_ENABLE (1 << 11) /* Global enable bit */ |
| #define | IOAPIC_BASE 0xFEC00000UL |
| #define | IOAPIC_REGSEL 0x00 /* register select */ |
| #define | IOAPIC_IOWIN 0x10 /* data window */ |
| #define | IOAPIC_ID 0x00 |
| #define | IOAPIC_VER 0x01 |
| #define | IOAPIC_REDTBL_LO(n) |
| #define | IOAPIC_REDTBL_HI(n) |
| #define | IOAPIC_RTE_MASKED (1 << 16) /* set to mask (disable) this IRQ line */ |
| #define | IOAPIC_RTE_LEVEL (1 << 15) /* 0=edge, 1=level trigger */ |
| #define | IOAPIC_RTE_LOPOL (1 << 13) /* 0=active-high, 1=active-low polarity */ |
| #define | IRQ_VECTOR_BASE 32 |
| #define | LAPIC_TIMER_PERIODIC (1 << 17) /* LVT timer mode: periodic */ |
| #define | LAPIC_TIMER_ONESHOT (0 << 17) /* LVT timer mode: one-shot */ |
| #define | LAPIC_TIMER_MASKED (1 << 16) /* LVT: mask the timer */ |
| #define | LAPIC_TIMER_VECTOR 48 /* IDT vector for LAPIC timer */ |
| #define | SCHEDULER_KICK_VECTOR 50 /* IDT vector: scheduler-kick IPI from remote CPU */ |
| #define | TLB_SHOOTDOWN_VECTOR 51 /* IDT vector: TLB-shootdown IPI broadcast */ |
| #define | PANIC_HALT_VECTOR 52 /* IDT vector: panic-halt IPI broadcast */ |
| #define | LAPIC_TIMER_DIVBY_16 0x3 /* DCR divide-by-16 */ |
Functions | |
| void | lapic_init (void) |
| Detect, identity-map, and software-enable the local APIC. | |
| static void | lapic_write (uint32_t reg, uint32_t val) |
| Write a 32-bit value to a LAPIC MMIO register. | |
| static uint32_t | lapic_read (uint32_t reg) |
| Read a 32-bit value from a LAPIC MMIO register. | |
| static void | lapic_eoi (void) |
| Signal End-of-Interrupt to the local APIC. | |
| void | lapic_eoi_asm (void) |
| Non-inline wrapper for lapic_eoi(), callable from assembly. | |
| void | lapic_send_ipi (uint8_t target_lapic_id, uint8_t vector) |
| Send a Fixed IPI to a remote CPU. | |
| void | ioapic_init (void) |
| Map and initialise the I/O APIC. | |
| void | ioapic_mask_irq (uint8_t irq) |
| Mask (disable) an I/O APIC redirection entry. | |
| void | ioapic_unmask_irq (uint8_t irq) |
| Unmask (enable) an I/O APIC redirection entry. | |
| void | lapic_timer_idt_install (void) |
| Install the IDT entry for LAPIC_TIMER_VECTOR (48). | |
| void | lapic_timer_init (void) |
| Calibrate and start the BSP LAPIC timer. | |
| void | lapic_timer_init_ap (void) |
| Start the LAPIC timer on the calling AP. | |
Variables | |
| volatile uint32_t * | lapic_base |
| volatile uint64_t | lapic_tick_count |
| uint32_t | lapic_bsp_timer_icr |
Local and I/O APIC initialisation, IPI dispatch, and LAPIC timer.
Provides the public API for:
| #define IA32_APIC_BASE_ENABLE (1 << 11) /* Global enable bit */ |
| #define IA32_APIC_BASE_MSR 0x1B |
| #define IOAPIC_BASE 0xFEC00000UL |
| #define IOAPIC_ID 0x00 |
| #define IOAPIC_IOWIN 0x10 /* data window */ |
| #define IOAPIC_REDTBL_HI | ( | n | ) |
| #define IOAPIC_REDTBL_LO | ( | n | ) |
| #define IOAPIC_REGSEL 0x00 /* register select */ |
| #define IOAPIC_RTE_LEVEL (1 << 15) /* 0=edge, 1=level trigger */ |
| #define IOAPIC_RTE_LOPOL (1 << 13) /* 0=active-high, 1=active-low polarity */ |
| #define IOAPIC_RTE_MASKED (1 << 16) /* set to mask (disable) this IRQ line */ |
| #define IOAPIC_VER 0x01 |
| #define IRQ_VECTOR_BASE 32 |
| #define LAPIC_EOI 0x0B0 /* End-of-Interrupt register */ |
| #define LAPIC_ICR_HIGH 0x310 /* Interrupt Command Register high */ |
| #define LAPIC_ICR_LOW 0x300 /* Interrupt Command Register low */ |
| #define LAPIC_ID 0x020 /* Local APIC ID register */ |
| #define LAPIC_SPURIOUS_VECTOR 0xFF /* Spurious interrupt vector */ |
| #define LAPIC_SVR 0x0F0 /* Spurious Interrupt Vector Register */ |
| #define LAPIC_SVR_ENABLE (1 << 8) /* Software enable bit */ |
| #define LAPIC_TIMER_CCR 0x390 /* Timer Current Count Register */ |
| #define LAPIC_TIMER_DCR 0x3E0 /* Timer Divide Configuration Register*/ |
| #define LAPIC_TIMER_DIVBY_16 0x3 /* DCR divide-by-16 */ |
| #define LAPIC_TIMER_ICR 0x380 /* Timer Initial Count Register */ |
| #define LAPIC_TIMER_LVT 0x320 /* LVT Timer register */ |
| #define LAPIC_TIMER_MASKED (1 << 16) /* LVT: mask the timer */ |
| #define LAPIC_TIMER_ONESHOT (0 << 17) /* LVT timer mode: one-shot */ |
| #define LAPIC_TIMER_PERIODIC (1 << 17) /* LVT timer mode: periodic */ |
| #define LAPIC_TIMER_VECTOR 48 /* IDT vector for LAPIC timer */ |
| #define PANIC_HALT_VECTOR 52 /* IDT vector: panic-halt IPI broadcast */ |
| #define SCHEDULER_KICK_VECTOR 50 /* IDT vector: scheduler-kick IPI from remote CPU */ |
| #define TLB_SHOOTDOWN_VECTOR 51 /* IDT vector: TLB-shootdown IPI broadcast */ |
| void ioapic_init | ( | void | ) |
Map and initialise the I/O APIC.
Maps IOAPIC_BASE (0xFEC00000) into the kernel address space via the identity MMIO huge page. Masks all 24 redirection table entries, then unmasks the entries for PS/2 keyboard (IRQ1) and ATA primary (IRQ14) with edge-triggered, active-high, fixed-delivery mode.


| void ioapic_mask_irq | ( | uint8_t | irq | ) |
Mask (disable) an I/O APIC redirection entry.
| irq | IRQ line index (0-23) to mask. Sets IOAPIC_RTE_MASKED in the low 32 bits of the redirection table entry for @irq. |

| void ioapic_unmask_irq | ( | uint8_t | irq | ) |
Unmask (enable) an I/O APIC redirection entry.
| irq | IRQ line index (0-23) to unmask. Clears IOAPIC_RTE_MASKED in the low 32 bits of the redirection table entry for @irq. |


|
inlinestatic |
Signal End-of-Interrupt to the local APIC.
Writes 0 to LAPIC_EOI (offset 0x0B0). Must be called at the end of every LAPIC-delivered interrupt handler before returning.


| void lapic_eoi_asm | ( | void | ) |
Non-inline wrapper for lapic_eoi(), callable from assembly.
Provided because inline functions cannot be called by name from NASM/GAS assembly stubs (no symbol is emitted). Forwards to lapic_eoi().


| void lapic_init | ( | void | ) |
Detect, identity-map, and software-enable the local APIC.
Reads the IA32_APIC_BASE MSR to obtain the LAPIC physical base address, maps it into the kernel higher-half window via vmm_map_page(), writes the Spurious Interrupt Vector Register to set vector 0xFF and set the software-enable bit (LAPIC_SVR_ENABLE), and stores the mapped pointer in lapic_base. Also registers lapic_send_ipi for use by the scheduler.
Context: Called once by the BSP during early boot, before smp_boot_aps().


Read a 32-bit value from a LAPIC MMIO register.
| reg | Register offset in bytes from lapic_base (e.g. LAPIC_ID = 0x020). |

Send a Fixed IPI to a remote CPU.
| target_lapic_id | Hardware LAPIC ID of the destination CPU (from g_cpus[i].lapic_id). |
| vector | IDT vector the remote CPU should execute (e.g. SCHEDULER_KICK_VECTOR). |
Writes destination to ICR_HIGH[31:24], then writes the fixed-delivery, level-assert ICR_LOW to trigger the IPI. Writing ICR_LOW sends the interrupt.
Context: Must be called with interrupts disabled or with spinlock protection to prevent ICR_HIGH/ICR_LOW write from being interleaved.
lapic_send_ipi() - Send a Fixed IPI to target_lapic_id at vector.
ICR encoding: ICR_HIGH[31:24] = target LAPIC ID ICR_LOW[7:0] = vector ICR_LOW[10:8] = 0b000 (Fixed delivery mode) ICR_LOW[14] = 1 (Assert level) Writing ICR_LOW triggers the IPI.


| void lapic_timer_idt_install | ( | void | ) |
Install the IDT entry for LAPIC_TIMER_VECTOR (48).
Must be called before smp_boot_aps() so that APs find a valid timer handler from the moment they enable their LAPIC timers. Installs a DPL-0 interrupt gate at IDT[LAPIC_TIMER_VECTOR].


| void lapic_timer_init | ( | void | ) |
Calibrate and start the BSP LAPIC timer.
Uses the PIT (8254) as a reference to measure the LAPIC timer frequency, computes an ICR value for a ~10 ms periodic tick, stores it in lapic_bsp_timer_icr, configures the LVT timer in periodic mode at LAPIC_TIMER_VECTOR (48), and starts counting. Called once on the BSP.


| void lapic_timer_init_ap | ( | void | ) |
Start the LAPIC timer on the calling AP.
Reads lapic_bsp_timer_icr (calibrated by the BSP) and writes it directly to LAPIC_TIMER_ICR, avoiding a second PIT calibration which would cause contention. Sets LVT timer to periodic mode at LAPIC_TIMER_VECTOR. Called from ap_entry() on each AP after LAPIC software-enable.


Write a 32-bit value to a LAPIC MMIO register.
| reg | Register offset in bytes from lapic_base (e.g. LAPIC_EOI = 0x0B0). |
| val | 32-bit value to write. |

|
extern |
|
extern |
|
extern |