commit fc760b94218ec72d9981a8cbaef193595545dd54
parent 89ba11ccf55bacbdb043171f8e526a5cb3c2de2d
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Sun, 30 Oct 2022 10:50:47 -0400
i386/pc: add exception handling and PIC remapping
Doing a division by zero now gives us a nice message+abort.
Diffstat:
7 files changed, 97 insertions(+), 19 deletions(-)
diff --git a/Makefile b/Makefile
@@ -2,7 +2,7 @@ TARGETS = dusk dis
BOOTFS_SRC = fs/xcomp/bootlo.fs posix/glue.fs fs/xcomp/boothi.fs
ALLSRCS = $(shell find fs)
QEMU_FLAGS = -accel kvm -accel tcg
-QEMU_DRVOPTS = format=raw,index=0,if=floppy
+QEMU_DRVOPTS = format=raw,index=0,if=ide
all: $(TARGETS)
fs/init.fs: posix/init.fs fs/xcomp/init.fs
diff --git a/fs/drv/pc/idt.fs b/fs/drv/pc/idt.fs
@@ -0,0 +1,40 @@
+\ Interrupt Descriptor Table
+
+: setISR ( w idx -- ) \ set interrupt "idx" to word w
+ over 16 rshift rot> 8 * IDT + tuck w! 6 + w! ;
+
+: _isr00 abort" Divide by zero" ;
+: _isr05 abort" Bound range exceeded" ;
+: _isr06 abort" Invalid opcode" ;
+: _isr07 abort" Device not available" ;
+\ To avoid triple faults, we don't do anything on double fault and go straight
+\ to (abort) on ISR08
+: _isr0a r> .x spc> abort" Invalid TSS" ;
+: _isr0b r> .x spc> abort" Segment not present" ;
+: _isr0c r> .x spc> abort" Stack segment fault" ;
+: _isr0d r> .x spc> abort" General protection fault" ;
+: _isr0e r> .x spc> abort" Page fault" ;
+: _isr10 abort" x87 floating-point exception" ;
+: _isr11 r> .x spc> abort" Alignment check" ;
+: _isr12 abort" Machine check" ;
+: _isr13 abort" SIMD floating-point exception" ;
+: _isr14 abort" Virtualization exception" ;
+: _isr15 r> .x spc> abort" Control protection exception" ;
+
+\ Only call this after you've moved PIC base vectors around!
+: idt$ ['] _isr00 $00 setISR
+ ['] _isr05 $05 setISR
+ ['] _isr06 $06 setISR
+ ['] _isr07 $07 setISR
+ ['] (abort) $08 setISR
+ ['] _isr0a $0a setISR
+ ['] _isr0b $0b setISR
+ ['] _isr0c $0c setISR
+ ['] _isr0d $0d setISR
+ ['] _isr0e $0e setISR
+ ['] _isr10 $10 setISR
+ ['] _isr11 $11 setISR
+ ['] _isr12 $12 setISR
+ ['] _isr13 $13 setISR
+ ['] _isr14 $14 setISR
+ ['] _isr15 $15 setISR ;
diff --git a/fs/drv/pc/pic.fs b/fs/drv/pc/pic.fs
@@ -0,0 +1,24 @@
+\ Programmable Interrupt Controller 8259 driver
+?f<< /drv/pc/idt.fs
+
+$20 const PIC1CMD
+$21 const PIC1DATA
+$a0 const PIC2CMD
+$a1 const PIC2DATA
+
+\ piceoi and piceoi2 are already defined in the kernel
+
+: pic$
+ \ Set $20-$2f ISRs to IRQ handlers that send back EOI to PICs
+ 8 >r begin ['] piceoi $20 r@ 1- + setISR next
+ 8 >r begin ['] piceoi2 $28 r@ 1- + setISR next
+ \ Re-initialize master and slave PIC chips
+ \ We send bytes to both PIC in parallel to have an "io_wait" effect
+ $11 PIC1CMD pc! \ INIT + ICW4
+ $11 PIC2CMD pc!
+ $20 PIC1DATA pc! \ $20 offset for master
+ $28 PIC2DATA pc! \ $28 offset for master
+ $04 PIC1DATA pc! \ PIC1 in master mode
+ $02 PIC2DATA pc! \ PIC2 in slave mode
+ $01 PIC1DATA pc! \ 8086/8088 mode
+ $01 PIC2DATA pc! ;
diff --git a/fs/xcomp/i386/kernel.fs b/fs/xcomp/i386/kernel.fs
@@ -41,13 +41,17 @@ PSTOP STACKSZ - const HEREMAX
forward16 jmp, to L1
pc to lblintnoop iret,
\ Interrupt Descriptor Table
-0 align4 pc $100 idtgen
+0 align4 pc to L2 $100 idtgen
pc to lblidt
-$100 8 * 1- w, ( pc ) ,
+$100 8 * 1- w, L2 ,
L1 forward!
lblidt m) lidt, sti,
forward16 jmp, to L1
+xcode IDT
+ L2 pspushN,
+ ret,
+
xcode noop pc to lblret ret,
xcode (cell)
diff --git a/fs/xcomp/i386/pc/init.fs b/fs/xcomp/i386/pc/init.fs
@@ -8,26 +8,32 @@
\ BIOS 64k limit and all hell breaks loose.
?f<< /asm/i386.fs
f<< /drv/pc/acpi.fs
-f<< /drv/pc/com.fs
+\ Serial communication
+\ f<< /drv/pc/com.fs
f<< /drv/pc/vga.fs
f<< /sys/grid.fs
' (emit) to emit
-f<< /drv/pc/pci.fs
\ Floppy boot drive
-f<< /drv/pc/fdc.fs
-floppy :init
-floppy :self bootfs to Filesystem drv
+\ f<< /drv/pc/fdc.fs
+\ floppy :init
+\ floppy :self bootfs to Filesystem drv
+f<< /drv/pc/pci.fs
\ IDE boot drive
-\ f<< /drv/pc/ata.fs
-\ ATADrive :reset drop ATA0:0 bootfs to Filesystem drv
+f<< /drv/pc/ata.fs
+ATADrive :reset drop ATA0:0 bootfs to Filesystem drv
\ AHCI boot drive
\ f<< /drv/pc/ahci.fs
\ 0 AHCIDrive :new dup bootfs to Filesystem drv ( drv )
\ AHCIDrive :enable
+\ Now that we don't ever go back to real mode anymore, we can remap the PIC
+\ and setup exception handlers
+f<< /drv/pc/pic.fs
+pic$ idt$
+
f<< /fs/fat.fs
f<< /drv/pc/ps28042.fs
diff --git a/fs/xcomp/i386/pc/inittest.fs b/fs/xcomp/i386/pc/inittest.fs
@@ -1,3 +1,4 @@
+f<< /drv/pc/com.fs
com$ ' >com to emit
f<< sys/scratch.fs
f<< lib/nfmt.fs
diff --git a/fs/xcomp/i386/pc/kernel.fs b/fs/xcomp/i386/pc/kernel.fs
@@ -22,7 +22,7 @@ pc to L1 \ segment with ffff limits
0 L2 jmpfar,
0 to realmode
-xcode int13h ( drv head cyl sec dst -- ) pc w>e lblsysdict pc>addr !
+xcode int13h ( drv head cyl sec dst -- )
BX pspop,
AX pspop, cl al mov, \ sec
AX pspop, ch al mov, \ cyl
@@ -30,13 +30,16 @@ xcode int13h ( drv head cyl sec dst -- ) pc w>e lblsysdict pc>addr !
AX pspop, dl al mov, \ drive
cli, $18 L1 jmpfar,
-\ When booting from floppy under QEMU, I get IRQs 0 and 6 from the PIC (mapped
-\ to vector 8 and 14) and if I don't handle it with an ACK to the PIC, the
-\ system freezes. (often, but not always). With these handlers below, we always
-\ boot.
-\ TODO: have proper and complete IRQ handling
-pc lblidt pc>addr 1+ 1+ @ pc>addr 8 8 * + 16b !
-pc lblidt pc>addr 1+ 1+ @ pc>addr 14 8 * + 16b !
-ax push, al $20 i) mov, $20 i) al out, ax pop, iret,
+\ IRQ 0 and 6 have to be mapped to End Of Interrupt handlers early because when
+\ booting from floppy, the system hangs early from those IRQs not being handled.
+\ The rest of PIC initialization is done in /drv/pc/pic.fs
+xcode piceoi pc
+ ax push, al $20 i) mov, $20 i) al out, ax pop, iret,
+
+( pc ) lblidt pc>addr 1+ 1+ @ pc>addr 8 8 * + 2dup w! 6 8 * + w!
+
+xcode piceoi2 \ slave IRQs have to EOI both master and slave.
+ pc w>e lblsysdict pc>addr ! \ last word of the kernel dict
+ ax push, al $20 i) mov, $a0 i) al out, $20 i) al out, ax pop, iret,
pc lblbootptr pc>addr !