From: Alan Cox Date: Fri, 3 Nov 2017 23:36:59 +0000 (+0000) Subject: z80pack: add an extreme example of the mmu hooks X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=cedba5ef6eb51ea078fe99ee054a5329e8fd510a;p=FUZIX.git z80pack: add an extreme example of the mmu hooks --- diff --git a/Kernel/platform-z80pack/z80pack.s b/Kernel/platform-z80pack/z80pack.s index 1580fcda..e004b688 100644 --- a/Kernel/platform-z80pack/z80pack.s +++ b/Kernel/platform-z80pack/z80pack.s @@ -41,6 +41,13 @@ .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 @@ -115,7 +122,9 @@ init_hardware: 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 @@ -143,12 +152,14 @@ _program_vectors: 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 @@ -210,3 +221,180 @@ map_store: 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