z80: single process banked kernel
authorAlan Cox <alan@linux.intel.com>
Wed, 20 Feb 2019 22:33:14 +0000 (22:33 +0000)
committerAlan Cox <alan@linux.intel.com>
Wed, 20 Feb 2019 22:33:14 +0000 (22:33 +0000)
Kernel/lib/z80single-banked.s [new file with mode: 0644]

diff --git a/Kernel/lib/z80single-banked.s b/Kernel/lib/z80single-banked.s
new file mode 100644 (file)
index 0000000..38a121e
--- /dev/null
@@ -0,0 +1,300 @@
+;
+;      Generic handling for single process in memory Z80 systems.
+;
+;      This code could really do with some optimizing.
+;
+;      FIXME: IRQ enable logic during swap
+;
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _makeproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _platform_monitor
+        .globl _platform_switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+       .globl _swapper
+       .globl _swapout
+       .globl _swapout_new
+       .globl _int_disabled
+       .globl _udata
+       .globl _tmpbuf
+       .globl _tmpfree
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .area _COMMONMEM
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; This function can have no arguments or auto variables.
+_platform_switchout:
+        di
+        ; save machine state
+
+        ld hl, #0 ; return code set here is ignored, but _switchin can 
+
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+        push hl ; return code
+        push ix
+        push iy
+        ld (_udata + U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; find another process to run (may select this one again)
+       push af
+        call _getproc
+       pop af
+
+        push hl
+       push af
+        call _switchin
+       pop af
+
+        ; we should never get here
+       push af
+        call _platform_monitor
+       pop af
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+swapped: .ascii "_switchin: SWAPPED"
+            .db 13, 10, 0
+
+_switchin:
+        di
+       ld a,#1
+       ld (_int_disabled),a
+       pop hl  ; bank
+        pop bc  ; return address
+        pop de  ; new process pointer
+
+        push de ; restore stack
+        push bc ; restore stack
+       push hl
+
+       push de
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+       pop de
+
+        ld a, (hl)
+
+       or a
+       jr nz, not_swapped
+       ;
+       ;       We are still on the departing processes stack, which is
+       ;       fine for now.
+       ;
+       ld sp, #_swapstack
+       ;
+       ;       The process we are switching from is not resident. In
+       ;       practice that means it exited. We don't need to write
+       ;       it back out as it's dead.
+       ;
+       ld ix,(_udata + U_DATA__U_PTAB)
+       ld a,P_TAB__P_PAGE_OFFSET(ix)
+
+       or a
+       jr z, not_resident
+       ;
+       ;       DE = process we are switching to
+       ;
+       push de ; save process
+       ; We will always swap out the current process
+       ld hl, (_udata + U_DATA__U_PTAB)
+       push hl
+       push af
+       call _swapout
+       pop af
+       pop hl
+       pop de  ; process to swap to
+not_resident:
+       push de ; called function may modify on stack arg so make
+       push de ; two copies
+       push af
+       call _swapper
+       pop af
+       pop de
+       pop de
+
+not_swapped:        
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (_udata + U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==HL
+        jr nz, switchinfail
+
+       ; wants optimising up a bit
+       ld ix, (_udata + U_DATA__U_PTAB)
+        ; next_process->p_status = P_RUNNING
+        ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING
+
+       ; Fix the moved page pointers
+       ; Just do one byte as that is all we use on this platform
+       ld a, P_TAB__P_PAGE_OFFSET(ix)
+       ld (_udata + U_DATA__U_PAGE), a
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (_udata + U_DATA__U_SP)
+
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (_udata + U_DATA__U_ININTERRUPT)
+       ; put th einterrupt status flag back correctly
+       ld (_int_disabled),a
+        or a
+        ret nz ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+       call outhl
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _platform_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        di ; should already be the case ... belt and braces.
+
+       pop bc
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+       push bc
+
+        ld (fork_proc_ptr), hl
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+       ld hl,#0
+        push hl                ;       #0 child
+        push ix
+        push iy
+
+        ; save kernel stack pointer -- when it comes back in the child we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        ld (_udata + U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+
+        ; Make a new process table entry, etc.
+
+       ; Copy the parent properties into the temporary udata copy
+       push af
+       call _tmpbuf
+       pop af
+       ld a,h
+       or l
+       jp z,ohpoo
+       push hl
+       ex de,hl
+       ld hl, #_udata
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+
+       ; Recover the buffer pointer
+       pop hl
+       push hl
+
+       ; Make the child udata out of the temporary buffer
+       push hl
+        ld hl, (fork_proc_ptr)
+        push hl
+       push af
+        call _makeproc
+       pop af
+        pop bc
+       pop bc
+
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child assembled in the
+       ; copy area as if it had done a switchout, the parent meanwhile
+       ; continues happily on
+
+        ; now we're in a safe state for _switchin to return in the child
+       ; process swap out the image and the new udata
+
+       ; Stack the buffer as a second argument
+       pop hl
+       push hl
+       push hl
+
+       ld hl, (fork_proc_ptr)
+       push hl
+       push af
+       call _swapout_new
+       pop af
+       pop hl
+       pop hl
+
+       ; Buffer pointer is sitting top of stack still
+       ; so use it as an argument to tmpfree
+       push af
+       call _tmpfree
+       pop af
+
+       pop hl
+
+       ld hl, (fork_proc_ptr)
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+       ; Return pid of child we forked into swap
+        ret
+
+ohpoo:
+       ld hl,#nobufs
+       call outstring
+       jp _platform_monitor
+
+nobufs:
+       .asciz 'nobufs'
+;
+;      We can keep a stack in common because we will complete our
+;      use of it before we switch common block. In this case we have
+;      a true common so it's even easier.
+;
+       .ds 128
+_swapstack: