Storage system: AHCI, IDE rework, VFS, volume manager, flatfs, async IO, IOAPIC
This commit is contained in:
1 parent
9fa1c859ac
commit
00a9da42f1
43 files changed
+11194
-2308
No files matched your search
@@ -0,0 +1,144 @@
|
||||
{
|
||||
ISR->IOAPIC - I/O APIC and Local APIC minimal support.
|
||||
|
||||
On systems where VirtualBox (or real hardware) routes PCI interrupts
|
||||
through the I/O APIC instead of the legacy 8259 PIC, we must program
|
||||
the IOAPIC redirection entry for each PCI IRQ we want to receive.
|
||||
|
||||
ISA interrupts (timer, keyboard) continue to work through the 8259
|
||||
PIC via Virtual Wire mode (PIC -> LINT0 -> Local APIC -> CPU).
|
||||
|
||||
@author(Aaron Hance <[email protected]>)
|
||||
}
|
||||
unit ioapic;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
util,
|
||||
lmemorymanager,
|
||||
console;
|
||||
|
||||
{ Initialise IOAPIC/LAPIC support — maps MMIO regions, ensures LAPIC
|
||||
is enabled. Safe to call even if the hardware doesn't have an IOAPIC
|
||||
(will detect and bail out). }
|
||||
procedure init();
|
||||
|
||||
{ Route a PCI interrupt through the IOAPIC.
|
||||
irq — PCI IRQ number (the value from PCI config interrupt_line)
|
||||
vector — IDT vector to deliver (typically irq + 32) }
|
||||
procedure route_pci_irq(irq : uint8; vector : uint8);
|
||||
|
||||
{ Send End-of-Interrupt to the Local APIC.
|
||||
Must be called for every IOAPIC-delivered (Fixed mode) interrupt.
|
||||
Safe no-op if IOAPIC support was not initialised. }
|
||||
procedure lapic_eoi();
|
||||
|
||||
{ True after init() succeeds — ISR_N checks this to know whether LAPIC
|
||||
EOI is needed. }
|
||||
var
|
||||
ioapic_present : boolean;
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
IOAPIC_PHYS = $FEC00000;
|
||||
LAPIC_PHYS = $FEE00000;
|
||||
|
||||
{ IOAPIC register offsets (indirect via IOREGSEL / IOWIN) }
|
||||
IOREGSEL = $00;
|
||||
IOWIN = $10;
|
||||
|
||||
{ IOAPIC registers }
|
||||
IOAPIC_ID = $00;
|
||||
IOAPIC_VER = $01;
|
||||
IOAPIC_REDTBL = $10; { base — each entry is 2 dwords }
|
||||
|
||||
{ LAPIC register offsets }
|
||||
LAPIC_SVR = $F0; { Spurious Interrupt Vector Register }
|
||||
LAPIC_EOI_REG = $B0; { End-of-Interrupt register }
|
||||
|
||||
{ ---- low-level IOAPIC register access ---- }
|
||||
|
||||
procedure ioapic_write(reg : uint32; val : uint32);
|
||||
begin
|
||||
puint32(IOAPIC_PHYS + IOREGSEL)^ := reg;
|
||||
puint32(IOAPIC_PHYS + IOWIN)^ := val;
|
||||
end;
|
||||
|
||||
function ioapic_read(reg : uint32) : uint32;
|
||||
begin
|
||||
puint32(IOAPIC_PHYS + IOREGSEL)^ := reg;
|
||||
ioapic_read := puint32(IOAPIC_PHYS + IOWIN)^;
|
||||
end;
|
||||
|
||||
{ ---- public API ---- }
|
||||
|
||||
procedure init();
|
||||
var
|
||||
ver : uint32;
|
||||
svr : uint32;
|
||||
begin
|
||||
ioapic_present := false;
|
||||
|
||||
{ Map the IOAPIC and LAPIC MMIO pages so we can access them }
|
||||
kpalloc(IOAPIC_PHYS);
|
||||
kpalloc(LAPIC_PHYS);
|
||||
|
||||
{ Probe: read IOAPIC version register — should return non-zero/non-$FF }
|
||||
ver := ioapic_read(IOAPIC_VER);
|
||||
if (ver = 0) or (ver = $FFFFFFFF) then begin
|
||||
console.outputln('IOAPIC', 'Not detected — PCI interrupts rely on 8259 PIC.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
console.outputln('IOAPIC', 'Detected.');
|
||||
|
||||
{ Ensure the Local APIC is software-enabled (bit 8 of SVR).
|
||||
We set the spurious vector to $FF which is unused. }
|
||||
svr := puint32(LAPIC_PHYS + LAPIC_SVR)^;
|
||||
if (svr and $100) = 0 then begin
|
||||
svr := svr or $100; { Enable APIC }
|
||||
svr := (svr and $FFFFFF00) or $FF; { Spurious vector = 0xFF }
|
||||
puint32(LAPIC_PHYS + LAPIC_SVR)^ := svr;
|
||||
console.outputln('IOAPIC', 'LAPIC software-enabled.');
|
||||
end;
|
||||
|
||||
ioapic_present := true;
|
||||
end;
|
||||
|
||||
procedure route_pci_irq(irq : uint8; vector : uint8);
|
||||
var
|
||||
lo : uint32;
|
||||
begin
|
||||
if not ioapic_present then exit;
|
||||
|
||||
{ Build low dword of redirection entry:
|
||||
bits 7:0 — delivery vector
|
||||
bits 10:8 — delivery mode (000 = Fixed)
|
||||
bit 11 — destination mode (0 = Physical)
|
||||
bit 13 — pin polarity (1 = active-low for PCI)
|
||||
bit 15 — trigger mode (1 = level for PCI)
|
||||
bit 16 — mask (0 = not masked) }
|
||||
lo := uint32(vector);
|
||||
lo := lo or (1 shl 13); { active-low }
|
||||
lo := lo or (1 shl 15); { level-triggered }
|
||||
|
||||
{ Write low dword first, then high dword (dest APIC = 0, the BSP) }
|
||||
ioapic_write(IOAPIC_REDTBL + uint32(irq) * 2, lo);
|
||||
ioapic_write(IOAPIC_REDTBL + uint32(irq) * 2 + 1, 0);
|
||||
|
||||
console.output('IOAPIC', 'Routed IRQ ');
|
||||
console.writeint(irq);
|
||||
console.writestring(' -> vector ');
|
||||
console.writeint(vector);
|
||||
console.writestringln('');
|
||||
end;
|
||||
|
||||
procedure lapic_eoi();
|
||||
begin
|
||||
if ioapic_present then
|
||||
puint32(LAPIC_PHYS + LAPIC_EOI_REG)^ := 0;
|
||||
end;
|
||||
|
||||
end.
|
||||
@@ -34,6 +34,8 @@ procedure registerISR(INT_N : uint8; callback : TISRHook);
|
||||
procedure dispatchHooks(INT_N : uint8);
|
||||
|
||||
implementation
|
||||
uses
|
||||
console, ioapic;
|
||||
|
||||
var
|
||||
Hooks : TISRHookArray;
|
||||
@@ -66,9 +68,20 @@ var
|
||||
i : uint8;
|
||||
|
||||
begin
|
||||
|
||||
// if int_n <> $20 then begin
|
||||
// console.writestring('ISR: ');
|
||||
// console.writehexpair(Int_N);
|
||||
// console.writestringln(' called');
|
||||
// end;
|
||||
|
||||
for i:=0 to MAX_HOOKS do begin
|
||||
if Hooks[INT_N][i] <> nil then Hooks[INT_N][i]();
|
||||
end;
|
||||
{ Send EOI to Local APIC (needed for IOAPIC-delivered interrupts).
|
||||
Safe no-op when IOAPIC is not present. }
|
||||
ioapic.lapic_eoi();
|
||||
{ Send EOI to 8259 PIC (slave then master) }
|
||||
if (INT_N >= 40) then outb($A0, $20);
|
||||
outb($20, $20);
|
||||
end;
|
||||
|
||||
Reference in new issue
Block a user