lowlevel-z80-thunked: Fix pre-emption crashes
authorAlan Cox <alan@linux.intel.com>
Fri, 16 Nov 2018 20:56:49 +0000 (20:56 +0000)
committerAlan Cox <alan@linux.intel.com>
Fri, 16 Nov 2018 20:56:49 +0000 (20:56 +0000)
This changes the way things work between the stubs and core code as they were
broken.

The stubs are now responsible for saving all the register state on the user
stack. The istack cannot be used for this as it was before because it may be
blown away by another interrupt. Instead the stubs carefully shuffle the two
bytes of return address onto the kstack of the process and return on that stack
in the pre-emption case.

It's not pretty but it's hard to do anything more elegant, and speedwise it's
a fast way to handle it.

A 'You are not expected to understand this code' moment, but it's buried in
support assembly code that nobody else has to understand.

Kernel/lowlevel-z80-thunked.s
Kernel/platform-sam/README
Kernel/platform-sam/sam.s

index f06b7b8..e4ca5b0 100644 (file)
@@ -202,15 +202,6 @@ traphl:
 ;
 interrupt_handler:
        call map_save_low       ; save old and map kernel
-       ex af,af'
-       push af
-       push bc
-       exx
-       push bc
-       push de
-       push hl
-       push ix
-       push iy
        ld a,#1
        ld (_inint),a
        ld (U_DATA__U_ININTERRUPT),a
@@ -233,8 +224,8 @@ intreti:di
        ld a, (U_DATA__U_INSYS)
        or a
        jr nz, interrupt_kernel
-       call map_user_low
 intsig:
+       call map_user_low
        ld a,(U_DATA__U_CURSIG)
        or a
        jr nz, interrupt_sig
@@ -245,17 +236,6 @@ no_sig:
        ld e,a
        ld a,(U_DATA__U_PAGE+1)
 intret:
-       ex af,af'
-       exx
-       pop iy
-       pop ix
-       pop hl
-       pop de
-       pop bc
-       exx
-       pop bc
-       pop af
-       ex af,af'
        ret
 
 interrupt_kernel:
@@ -290,13 +270,27 @@ interrupt_sig:
 ;
 ;      The horrible case - task switching time
 ;
+;      Everything important is on the user stack, except that there is
+;      a vital stubs return address top of our current stack
+;
+;      We move the return address onto the kstack, switch to the kstack
+;      and then park ourselves in platform_switchout. On our return the
+;      istack has been lost but our kstack (private to us) still has the
+;      needed return address to the stubs and we can unwind everything
+;      via that stack.
+;
+.globl preemption
+
 preemption:
+       pop de                          ; return address to stubs
        xor a
        ld (_need_resched),a            ; we are doing it thank you
        ld hl,(istack_switched_sp)
        ld (U_DATA__U_SYSCALL_SP), hl   ; save the stack save
        ld sp, #kstack_top              ; free because we are not pre-empted
                                        ; during a system call
+       push de                         ; return address onto our kstack
+                                       ; istack will be lost
        ld hl,#intret2
        push hl
        reti                            ; reti M1 cycle for IM2
@@ -311,14 +305,15 @@ intret2:
        ; Give up the CPU
        ; FIXME: can we get here on timers when only one thing is running
        ; and we don't need to pre-empt ????? Is this more generally busted
-       ; ?
+       ; ? It is .... review timer interrupt logic... FIXME
        call _platform_switchout
        ; Undo the fakery
        xor a
        ld (U_DATA__U_ININTERRUPT),a
        ld (U_DATA__U_INSYS),a
-       ld hl,(U_DATA__U_SYSCALL_SP)
-       ld (istack_switched_sp),hl
+       ; The istack was lost but that is ok as we saved the return onto the
+       ; kernel stack, so when we finally ret we end up in the right place
+       ld sp,#kstack_top - 2           ; saved return address
        ; Now continue on the interrupt return path
        ; looking for signals
        jr intsig
index cb01022..f1a9d2a 100644 (file)
@@ -39,6 +39,7 @@ and all the bank juggling tricks
 Stub code is in the low parts of the low banks and the top of the high banks
 so we have two copier routines one for each half.
 
+DONE   -       Crashes on interrupt preempt (Fixed I hope)
        -       Fix signal handling crashes
        -       Sometimes we seem to pre-empt in the middle of a pre-empt
                and crash ?? we see a kprintf from an interrupt interrupted
@@ -51,7 +52,7 @@ DONE  -       Move fonts to video bank after frame buffer
        -       Floppy driver (at least for read)
 DONE   -       Get to init (but not much further)
 IP     -       Debug all the new banking code and stubs
-       -       Atom IDE driver
+       -       Atom IDE driver (prob need minimal copiers in high stubs)
 DONE   -       Atom-lite IDE driver
 DONE   -       Look at how to preserve high colour bits
 
index de2cdd3..f94cd24 100644 (file)
@@ -370,6 +370,17 @@ interrupt_high:
            push af
            push de
            push hl
+
+           ex af,af'
+           push af
+           push bc
+           exx
+           push bc
+           push de
+           push hl
+           push ix
+           push iy
+
            in a,(251)
            and #0x60
            or #KERNEL_HIGH
@@ -398,6 +409,18 @@ interrupt_high:
            cp e
            call nz, sigpath
 kernout:
+           ex af,af'
+           exx
+           pop iy
+           pop ix
+           pop hl
+           pop de
+           pop bc
+           exx
+           pop bc
+           pop af
+           ex af,af'
+
            pop hl
            pop de
            pop af