.globl null_handler
.globl nmi_handler
.globl interrupt_handler
+ .globl _doexit
+ .globl _inint
+ .globl kstack_top
+ .globl _panic
+ .globl mmu_irq_ret
+ .globl _need_resched
+ .globl _ssig
.globl outcharhex
.globl outhl, outde, outbc
call _program_vectors
pop hl
- im 1 ; set CPU interrupt mode
+ ld a, #0xfe ; Use FEFF (currently free)
+ ld i, a
+ im 2 ; set CPU interrupt mode
ret
ld (hl), #0x00
ldir
- ; now install the interrupt vector at 0x0038
- ld a, #0xC3 ; JP instruction
- ld (0x0038), a
+ ; now install the interrupt vector at 0xFEFF
ld hl, #interrupt_handler
- ld (0x0039), hl
+ ld (0xFEFF), hl
+ ; now install the interrupt vector at 0xFEFF
+ ld hl, #interrupt_handler
+ ld (0xFEFF), hl
+ ld a,#0xC3 ; JP
; set restart vector for UZI system calls
ld (0x0030), a ; (rst 30h is unix function call vector)
ld hl, #unix_syscall_entry
outchar:
out (0x01), a
ret
+
+;
+; The entry logic is a bit scary. We want to make sure that we
+; don't get tricked into anything bad by messed up callers.
+;
+; At the point we are called the push hl and call to us might have
+; gone onto a dud stack, but if so that is ok as we won't be returning
+;
+mmu_kernel:
+ push hl
+ ld hl,#0
+ add hl,sp
+ ld a,h
+ or a ; 00xx is bad
+ jr z, badstack
+ cp #0xF0
+ jr nc, badstack ; Fxxx is bad
+ in a,(23)
+ bit 7,a ; Tripped MMU is bad if user
+ jr nz, badstackifu
+do_mmu_kernel:
+ xor a ; Switch MMU off
+ out (23),a
+ pop hl
+ ret
+;
+; We have been called with SP pointing into la-la land. That means
+; something bad has happened to our process (or the kernel)
+;
+badstack:
+ ld a, (U_DATA__U_INSYS)
+ or a
+ jr nz, badbadstack
+ ld a, (_inint)
+ or a
+ jr nz, badbadstack
+ ;
+ ; Ok we are in user mode, this is less bad.
+ ; Fake a sigkill
+ ;
+badstack_do:
+ ld sp, #kstack_top ; Our syscall stack
+ xor a
+ out (23),a ; MMU off
+ call map_kernel ; So we can _doexit
+ ld hl,#9 ; SIGKILL
+ push hl
+; ld a,#'@'
+; call outchar
+ call _doexit ; Will not return
+ ld hl,#zombieapocalypse
+ push hl
+ call _panic
+zombieapocalypse:
+ .asciz "ZombAp"
+
+badbadstack:
+ ld hl,#badbadstack_msg
+ push hl
+ call _panic
+
+badstackifu:
+ ld a, (U_DATA__U_INSYS)
+ or a
+ jr nz, do_mmu_kernel
+ ld a, (_inint)
+ or a
+ jr nz, do_mmu_kernel
+ jr badstack_do
+
+;
+; IRQ version - we need different error handling as we can't just
+; exit and have the IRQ vanish (we'd survive fine but the IRQ wouldn't
+; get processed).
+;
+mmu_kernel_irq:
+ ld hl,#0
+ add hl,sp
+ ld a,h
+ or a
+ jr z, badstackirq
+ inc a
+ jr z,badstackirq
+ in a,(23)
+ bit 7,a
+ jr nz, badstackirqifu
+do_mmu_kernel_irq:
+ in a,(23)
+ ld l,a
+ xor a
+ out (23),a
+ ld a,l
+ ld (mmusave),a
+ jp mmu_irq_ret
+
+ ld a, (U_DATA__U_INSYS)
+ or a
+ ld a, (_inint)
+ or a
+badstackirq:
+ ld a, (U_DATA__U_INSYS)
+ or a
+ jr nz, badbadstack_irq
+ ld a, (_inint)
+ or a
+ jr nz, badbadstack_irq
+badstack_doirq:
+ ;
+ ; If we get here we *are* interrupted from user space and
+ ; thus we can safely use map_save/map_restore
+ ;
+ ; Put the stack somewhere that will be safe - kstack will do
+ ; The user stack won't do as we're going to switch to kernel
+ ; mappings
+ ld sp,#kstack_top
+ xor a
+ out (23),a ; MMU off so we can do our job
+; ld a,#'!'
+; call outchar
+ call map_save
+ call map_kernel
+ ld hl,#9
+ push hl
+ ld hl,(U_DATA__U_PTAB)
+ push hl
+ call _ssig
+ pop hl
+ pop hl
+ ld a,#1
+ ld (_need_resched),a
+ call map_restore
+ ;
+ ; Ok this looks pretty wild but the idea is that the stack we
+ ; came in on could be completely hosed so we just need somewhere
+ ; in user memory to scribble freely. The pre-emption path will
+ ; kill us before we return to userland and use that stack for
+ ; anything non-kernel
+ ;
+ ld sp,#0x8000
+ jp mmu_irq_ret
+ ; This will complete the IRQ and then hit preemption at which
+ ; point it'll call switchout, chksigs and vanish forever
+badstackirqifu:
+ ld a, (U_DATA__U_INSYS)
+ or a
+ jr nz, do_mmu_kernel_irq
+ ld a, (_inint)
+ or a
+ jr nz, do_mmu_kernel_irq
+ jr badstack_doirq
+
+badbadstack_irq:
+ ld hl,#badbadstackirq_msg
+ push hl
+ call _panic
+
+badbadstackirq_msg:
+ .ascii 'IRQ:'
+badbadstack_msg:
+ .asciz 'MMU trap/bad stack'
+
+
+;
+; This side is easy. We are coming from a sane context (hopefully).
+; MMU on, clear flag.
+;
+mmu_restore_irq:
+ ld a,(mmusave)
+ and #0x01
+ out (23),a
+ ret
+mmu_user:
+ ld a,#1
+ out (23),a
+ ret
+mmusave:
+ .byte 0