miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
Loading...
Searching...
No Matches
LAPIC / IOAPIC

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_tlapic_base
volatile uint64_t lapic_tick_count
uint32_t lapic_bsp_timer_icr

Detailed Description

Local and I/O APIC initialisation, IPI dispatch, and LAPIC timer.

Provides the public API for:

  • Local APIC (LAPIC): software-enable, EOI, IPI send.
  • I/O APIC (IOAPIC): redirection table setup, IRQ mask/unmask.
  • LAPIC timer: BSP calibration and AP reuse.

Macro Definition Documentation

◆ IA32_APIC_BASE_ENABLE

#define IA32_APIC_BASE_ENABLE   (1 << 11) /* Global enable bit */

◆ IA32_APIC_BASE_MSR

#define IA32_APIC_BASE_MSR   0x1B

◆ IOAPIC_BASE

#define IOAPIC_BASE   0xFEC00000UL

◆ IOAPIC_ID

#define IOAPIC_ID   0x00

◆ IOAPIC_IOWIN

#define IOAPIC_IOWIN   0x10 /* data window */

◆ IOAPIC_REDTBL_HI

#define IOAPIC_REDTBL_HI ( n)
Value:
(0x10 + (n)*2 + 1) /* high 32 bits of redirection entry n */

◆ IOAPIC_REDTBL_LO

#define IOAPIC_REDTBL_LO ( n)
Value:
(0x10 + (n)*2) /* low 32 bits of redirection entry n */

◆ IOAPIC_REGSEL

#define IOAPIC_REGSEL   0x00 /* register select */

◆ IOAPIC_RTE_LEVEL

#define IOAPIC_RTE_LEVEL   (1 << 15) /* 0=edge, 1=level trigger */

◆ IOAPIC_RTE_LOPOL

#define IOAPIC_RTE_LOPOL   (1 << 13) /* 0=active-high, 1=active-low polarity */

◆ IOAPIC_RTE_MASKED

#define IOAPIC_RTE_MASKED   (1 << 16) /* set to mask (disable) this IRQ line */

◆ IOAPIC_VER

#define IOAPIC_VER   0x01

◆ IRQ_VECTOR_BASE

#define IRQ_VECTOR_BASE   32

◆ LAPIC_EOI

#define LAPIC_EOI   0x0B0 /* End-of-Interrupt register */

◆ LAPIC_ICR_HIGH

#define LAPIC_ICR_HIGH   0x310 /* Interrupt Command Register high */

◆ LAPIC_ICR_LOW

#define LAPIC_ICR_LOW   0x300 /* Interrupt Command Register low */

◆ LAPIC_ID

#define LAPIC_ID   0x020 /* Local APIC ID register */

◆ LAPIC_SPURIOUS_VECTOR

#define LAPIC_SPURIOUS_VECTOR   0xFF /* Spurious interrupt vector */

◆ LAPIC_SVR

#define LAPIC_SVR   0x0F0 /* Spurious Interrupt Vector Register */

◆ LAPIC_SVR_ENABLE

#define LAPIC_SVR_ENABLE   (1 << 8) /* Software enable bit */

◆ LAPIC_TIMER_CCR

#define LAPIC_TIMER_CCR   0x390 /* Timer Current Count Register */

◆ LAPIC_TIMER_DCR

#define LAPIC_TIMER_DCR   0x3E0 /* Timer Divide Configuration Register*/

◆ LAPIC_TIMER_DIVBY_16

#define LAPIC_TIMER_DIVBY_16   0x3 /* DCR divide-by-16 */

◆ LAPIC_TIMER_ICR

#define LAPIC_TIMER_ICR   0x380 /* Timer Initial Count Register */

◆ LAPIC_TIMER_LVT

#define LAPIC_TIMER_LVT   0x320 /* LVT Timer register */

◆ LAPIC_TIMER_MASKED

#define LAPIC_TIMER_MASKED   (1 << 16) /* LVT: mask the timer */

◆ LAPIC_TIMER_ONESHOT

#define LAPIC_TIMER_ONESHOT   (0 << 17) /* LVT timer mode: one-shot */

◆ LAPIC_TIMER_PERIODIC

#define LAPIC_TIMER_PERIODIC   (1 << 17) /* LVT timer mode: periodic */

◆ LAPIC_TIMER_VECTOR

#define LAPIC_TIMER_VECTOR   48 /* IDT vector for LAPIC timer */

◆ PANIC_HALT_VECTOR

#define PANIC_HALT_VECTOR   52 /* IDT vector: panic-halt IPI broadcast */

◆ SCHEDULER_KICK_VECTOR

#define SCHEDULER_KICK_VECTOR   50 /* IDT vector: scheduler-kick IPI from remote CPU */

◆ TLB_SHOOTDOWN_VECTOR

#define TLB_SHOOTDOWN_VECTOR   51 /* IDT vector: TLB-shootdown IPI broadcast */

Function Documentation

◆ ioapic_init()

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.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ioapic_mask_irq()

void ioapic_mask_irq ( uint8_t irq)

Mask (disable) an I/O APIC redirection entry.

Parameters
irqIRQ line index (0-23) to mask. Sets IOAPIC_RTE_MASKED in the low 32 bits of the redirection table entry for @irq.
Here is the call graph for this function:

◆ ioapic_unmask_irq()

void ioapic_unmask_irq ( uint8_t irq)

Unmask (enable) an I/O APIC redirection entry.

Parameters
irqIRQ line index (0-23) to unmask. Clears IOAPIC_RTE_MASKED in the low 32 bits of the redirection table entry for @irq.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ lapic_eoi()

void lapic_eoi ( void )
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.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lapic_eoi_asm()

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().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lapic_init()

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().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lapic_read()

uint32_t lapic_read ( uint32_t reg)
inlinestatic

Read a 32-bit value from a LAPIC MMIO register.

Parameters
regRegister offset in bytes from lapic_base (e.g. LAPIC_ID = 0x020).
Returns
32-bit value at the register.
Here is the caller graph for this function:

◆ lapic_send_ipi()

void lapic_send_ipi ( uint8_t target_lapic_id,
uint8_t vector )

Send a Fixed IPI to a remote CPU.

Parameters
target_lapic_idHardware LAPIC ID of the destination CPU (from g_cpus[i].lapic_id).
vectorIDT 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.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lapic_timer_idt_install()

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].

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lapic_timer_init()

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.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lapic_timer_init_ap()

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.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lapic_write()

void lapic_write ( uint32_t reg,
uint32_t val )
inlinestatic

Write a 32-bit value to a LAPIC MMIO register.

Parameters
regRegister offset in bytes from lapic_base (e.g. LAPIC_EOI = 0x0B0).
val32-bit value to write.
Here is the caller graph for this function:

Variable Documentation

◆ lapic_base

volatile uint32_t* lapic_base
extern

◆ lapic_bsp_timer_icr

uint32_t lapic_bsp_timer_icr
extern

◆ lapic_tick_count

volatile uint64_t lapic_tick_count
extern