z80pack: add an extreme example of the mmu hooks
authorAlan Cox <alan@linux.intel.com>
Fri, 3 Nov 2017 23:36:59 +0000 (23:36 +0000)
committerAlan Cox <alan@linux.intel.com>
Fri, 3 Nov 2017 23:36:59 +0000 (23:36 +0000)
Kernel/platform-z80pack/z80pack.s

index 1580fcd..e004b68 100644 (file)
             .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