From 44e502f23b975342b948f1a24578b6c6696c2a3b Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 6 Feb 2019 14:02:02 +0000 Subject: [PATCH] 8080: core enabling (Incomplete) --- Kernel/lib/8080fixedbank-core.s | 243 +++++++++++++++ Kernel/lib/8080fixedbank.s | 15 + Kernel/lowlevel-8080.s | 529 ++++++++++++++++++++++++++++++++ Kernel/usermem_std-8080.s | 100 ++++++ 4 files changed, 887 insertions(+) create mode 100644 Kernel/lib/8080fixedbank-core.s create mode 100644 Kernel/lib/8080fixedbank.s create mode 100644 Kernel/lowlevel-8080.s create mode 100644 Kernel/usermem_std-8080.s diff --git a/Kernel/lib/8080fixedbank-core.s b/Kernel/lib/8080fixedbank-core.s new file mode 100644 index 00000000..0c7cb831 --- /dev/null +++ b/Kernel/lib/8080fixedbank-core.s @@ -0,0 +1,243 @@ +! +! For a purely bank based architecture this code is common and can be +! used by most platforms +! +! The caller needs to provide the standard map routines along with +! map_kernel_a which maps in the kernel bank in a. This code assumes +! that the bank can be encoded in 8bits. +! + +.sect .common + +.define _platform_switchout + +! +! Verify ABI exact rules but I think we don't need to stack any +! register state. +! + +! +! Switch a process out and run the next one +! +_platform_switchout: + lxi h,0 + push h ! Save a 0 argment + dad sp + shld U_DATA__U_SP ! Save the sp for a switch in + call map_process_always_di + ! + ! Save the udata into process state + ! + lxi h,U_DATA + lxi d,U_DATA_STASH + call copy512 ! No ldir 8( + ! Back to kernel + call map_kernel_di + call _getproc ! Who goes next + push h + call _switchin ! Run it + ! Should never hit this + call _platform_monitor + +! +! Switch a process back in +! +.define _switchin + +! +! Switch to a given process +! +_switchin: + di + pop b + pop d ! DE is now our process to run + push d + push b + + call map_kernel_di + + ! + ! Is it swapped (page 0) + ! + lxi h,P_TAB__P_PAGE_OFFSET + dad d + + lxi sp,_swapstack + mov a,m + ora a + jnz not_swapped + ! + ! Swapping time. Interrupts back on + ! + ei + xra a + sta _int_disabled + ! + ! Can we rely on the compiler not mashing the stacked var ? + ! + push h + push d + call _swapper + pop d + pop h + ! + ! It should now be back in memory + ! + mvi a,1 + sta _int_disabled + di + mov a,m + ! + ! Check if we need to recover the udata (we were last to run) + ! +not_swapped: + mov c,a + lhld U_DATA__U_PTAB + mov a,h + cmp d + jnz copyback + mov a,l + cmp e + jz skip_copyback + ! + ! Recover the udata + ! +copyback: + mov a,c + call map_process_a + + lxi h,U_DATA_STASH + lxi d,U_DATA + call copy512 + + lhld U_DATA__U_SP ! A valid stack to map on + sphl + + call map_kernel + ! + ! Did we find the right process ? + ! + lhld U_DATA__U_PTAB + mov a,h + cmp d + jnz switchinfail + mov a,l + cmp e + jnz switchinfail + +skip_copyback: + ! + ! Mark us as running, clear our preemption counter + ! and set the interrupt flags + ! + lhld U_DATA__U_PTAB + mvi a,P_RUNNING + mov m,a + lxi d,P_TAB__P_PAGE_OFFSET + dad d + mov a,m + sta U_DATA__U_PTAB + lxi h,0 + shld _runticks + lhld U_DATA__U_SP + sphl + ! + ! Recover our return code + ! + pop h + lda U_DATA__U_ININTERRUPT + sta _int_disabled + ora a + rnz + ei + ret + +switchinfail: + call outhl + lxi h,badswitchmsg + call outstring + call _platform_monitor + +badswitchmsg: + .asciz 'badsw' + + +fork_proc_ptr: + .data2 0 + +.define _dofork +! +! The heart of fork +! +_dofork: + pop d + pop h ! new process + push h + push d + + shld fork_proc_ptr + + lxi d,P_TAB__P_PID_OFFSET + dad d + mov a,m + inx h + mov h,m + mov l,a + ! + ! We don't have any state to save but the pid + ! + push h + lxi h,0 + dad sp + shld U_DATA__U_SP + ! + ! We are now in a safe state to work + ! + lhld fork_proc_ptr + lxi d,P_TAB__P_PAGE_OFFSET + dad d + mov c,m + lda U_DATA__U_PAGE + + call bankfork + + call map_process_always + ! + ! Clone the parent udata and stack into the child stash + ! + lxi h,U_DATA + lxi d,U_DATA_STASH + call copy512 + + call map_kernel + + pop h ! Get rid of saved pid + + ! + ! Manufacture the child udata state + ! + lxi h,_udata + push h + lhld fork_proc_ptr + push h + call _makeproc + pop b + pop b + ! + ! Timer ticks + ! + lxi h,0 + shld _runticks + ret + +.define bouncebuffer +.define _swapstack + +bouncebuffer: + .space 256 ! Do we really need 256 ? +_swapstack: + +.define _need_resched + +_need_resched: + .data1 0 diff --git a/Kernel/lib/8080fixedbank.s b/Kernel/lib/8080fixedbank.s new file mode 100644 index 00000000..191327d4 --- /dev/null +++ b/Kernel/lib/8080fixedbank.s @@ -0,0 +1,15 @@ +# + +#include "../lib/8080fixedbank-core.s" + +bankfork: +! +! FIXME: copy the user memory between bank a and c +! + ret +! +! Fast copy 512 bytes from H to D +! +copy512: +! FIXME: TODO + ret diff --git a/Kernel/lowlevel-8080.s b/Kernel/lowlevel-8080.s new file mode 100644 index 00000000..d8d345d7 --- /dev/null +++ b/Kernel/lowlevel-8080.s @@ -0,0 +1,529 @@ +# +! +! 8080 low level code +! +! Much the same as the Z80 code except we don't provide in and out +! helpers because it's impossible to make them re-entrant for any port +! + +#include "kernel-8080.def" + +.sect .common + +deliver_signals: + lda U_DATA__U_CURSIG + ora a + rz +deliver_signals_2: + mov l,a + mvi h,0 + push h + dad h + lxi d,U_DATA__U_SIGVEC + dad d + mov e,m + inx h + mov d,m + xra a + sta U_DATA__U_CURSIG + ! + ! Do we need to zero check de here ? + ! + lxi b,signal_return + push b + xchg + ei + pchl + +signal_return: + pop h + di + lxi h,0 + dad sp + shld U_DATA__U_SYSCALL_SP + lxi sp,kstack_top + mvi a,1 + sta _int_disabled + call map_kernel_di + call _chksigs + call map_process_always_di + lhld U_DATA__U_SYSCALL_SP + sphl + jmp deliver_signals + +.define unix_syscall_entry + +unix_syscall_entry: + di + push b ! for now + push d ! will go away when we fix the ABI + lxi h,8 ! Find arguments on stack frame FIXME: work out + ! right offset + dad sp + mov a,m + sta U_DATA__U_CALLNO + inx h + inx h + ! Oh for LDIR + ! Unroll this for speed. Syscall arguments into constant locations + mov a,m + sta U_DATA__U_ARGN + inx h + mov a,m + sta U_DATA__U_ARGN+1 + inx h + mov a,m + sta U_DATA__U_ARGN+2 + inx h + mov a,m + sta U_DATA__U_ARGN+3 + inx h + mov a,m + sta U_DATA__U_ARGN+4 + inx h + mov a,m + sta U_DATA__U_ARGN+5 + inx h + mov a,m + sta U_DATA__U_ARGN+6 + inx h + mov a,m + sta U_DATA__U_ARGN+7 + ! We are now in kernel space + mvi a,1 + sta U_DATA__U_INSYS + ! Switch stacks + ! On 8080 this is a bit more long winded as we have to go via HL + lxi h,0 + dad sp + shld U_DATA__U_SYSCALL_SP + lxi sp, kstack_top + ! + ! Now map the kernel and call it + ! + call map_kernel_di + ei + call _unix_syscall + ! + ! Remember fork and execve don't necessarily return this wand fork + ! can do it twice + ! + di + call map_process_always + xra a + sta U_DATA__U_INSYS + ! Switch stack back + lhld U_DATA__U_SYSCALL_SP + sphl + lhld U_DATA__U_RETVAL + xchg + lhld U_DATA__U_ERROR + ! + ! Signal check + ! + lda U_DATA__U_CURSIG + ora a + jnz via_signal +unix_return: + mov a,h + ora l + jnz not_error + stc + jmp unix_pop +not_error: + xchg +unix_pop: + pop d + pop b + ! ret must directly follow the ei + ei + ret +via_signal: + ! + ! Stack the state (a signal doing a syscall will change the + ! U_DATA fields but we must return the old error/status) + ! + lhld U_DATA__U_ERROR + push h + lhld U_DATA__U_RETVAL + push h + ! + ! And into the signal delivery path + ! + call deliver_signals_2 + pop d + pop h + jmp unix_return + +! +! Called when execve() completes to transition to the user, as we +! don't return from execve() via the syscall path +! +! +.define _doexec + +_doexec: + di + call map_process_always + pop b + pop d + lhld U_DATA__U_ISP + sphl + xra a + sta U_DATA__U_INSYS + xchg + lxi d,PROGLOAD + ei + pchl +! +! NULL trap. Must live in common space +! +! FIXME: Rewrite 68000 style as a synchronous trap +! +.define null_handler + +null_handler: + lda U_DATA__U_INSYS + ora a + jnz trap_illegal + lda _inint + ora a + jnz trap_illegal + lxi h,7 + push h + lhld U_DATA__U_PTAB + lxi d,P_TAB__P_PID_OFFSET + dad d + mov e,m + inx h + mov d,m + push d + lxi h,39 + push h + call unix_syscall_entry + lxi h,0xffff ! exit -1 + push h + dcx h + push h + call unix_syscall_entry + ! Never returns + +trap_illegal: + lxi h,illegalmsg +traphl: + call outstring + call _platform_monitor + +.define nmi_handler + +nmi_handler: + call map_kernel_di + lxi h,nmimsg + jmp traphl + +illegalmsg: + .asciz '[illegal]' +nmimsg: + .asciz '[NMI]' + +! +! Interrupts are similar to Z80 but we have a lot less state +! to store, and rather trickier juggling to get signals nice +! +.define interrupt_handler + +interrupt_handler: + push psw + push b + push d + push h + call platform_interrupt_all + ! Switch stacks + lxi h,0 + dad sp + shld istack_switched_sp + lxi sp,istack_top + ! + ! Map the kernel + ! + lda 0 + call map_save_kernel + cpi 0xC3 + cnz null_pointer_trap + ! + ! Set up state and enter kernel + ! + mvi a,1 + sta _inint + sta U_DATA__U_ININTERRUPT + sta _int_disabled + call _platform_interrupt + ! + ! Undo state + ! + xra a + sta _inint + ! + ! Do we need to task switch ? + ! + lda _need_resched + ora a + jnz preemption + ! + ! Switch stacks back + ! + call map_restore + lhld istack_switched_sp + sphl +intout: + xra a + sta U_DATA__U_ININTERRUPT + lda U_DATA__U_INSYS + ora a + jnz interrupt_pop + call deliver_signals + ! + ! Restore registers and done + ! +interrupt_pop: + xra a + sta _int_disabled + pop h + pop d + pop b + pop psw + ei + ret + +null_pointer_trap: + mvi a,0xc3 + sta 0 + lxi h,11 +trap_signal: + push h + lhld U_DATA__U_PTAB + push h + call _ssig + pop h + pop h + ret + +! +! Now the scary stuff - preempting +! +preemption: + xra a + sta _need_resched + call map_restore + ! + ! Save our original stack in syscall_s + ! Move to our kernel stack (free because we don't preempt + ! in kernel + ! + lhld istack_switched_sp + shld U_DATA__U_SYSCALL_SP + lxi sp,kstack_top + ! + ! Fix up the mappings + ! + call map_kernel_di + ! + ! Mark ourselves as in a system call + ! + mvi a,1 + sta U_DATA__U_INSYS + call _chksigs + lhld U_DATA__U_PTAB + mvi a,P_RUNNING + cmp m + jnz not_running + mvi m,P_READY +not_running: + ! + ! We will disappear into this and reappear somewhere else. In + ! time we will reappear here + ! + call _platform_switchout + ! + ! We are back in the land of the living so no longer in + ! syscall or interrupt state + ! + xra a + sta U_DATA__U_ININTERRUPT + sta U_DATA__U_INSYS + ! + ! Get our mapping back + ! + call map_process_always_di + ! + ! And our stack + ! + lhld U_DATA__U_SYSCALL_SP + sphl + lda U_DATA__U_CURSIG + ora a + cnz deliver_signals_2 + jmp interrupt_pop + +! +! Debug code +! +.define outstring + +outstring: + mov a,m + ora a + rz + call outchar + inx h + jmp outstring + +.define outstringhex + +outstringhex: + mov a,m + ora a + rz + call outcharhex + mvi a,0x20 + call outchar + inx h + jmp outstringhex + +.define outnewline + +outnewline: + mvi a,0x0d + call outchar + mvi a,0x0a + jmp outchar + +.define outhl + +outhl: + push psw + mov a,h + call outcharhex + mov a,l + call outcharhex + pop psw + ret + +.define outde + +outde: + push psw + mov a,d + call outcharhex + mov a,e + call outcharhex + pop psw + ret + +.define outbc + +outbc: + push psw + mov a,b + call outcharhex + mov a,c + call outcharhex + pop psw + ret + +.define outcharhex + +outcharhex: + push b + push psw + mov c,a + rar + rar + rar + rar + call outnibble + mov a,c + call outnibble + pop psw + pop b + ret + +outnibble: + ani 0x0f + cpi 10 + jc numeral + adi 7 +numeral: + adi 0x30 ! '0' + jmp outchar + + +.define ___hard_ei + +___hard_ei: + xra a + sta _int_disabled + ei + ret + +.define ___hard_di + +___hard_di: + lxi h, _int_disabled + di + mov a,m + mvi m,1 + mov l,a ! Check ABI + ret + +.define ___hard_irqrestore + +___hard_irqrestore: + pop d + pop h + push h + push d + di + mov a,l + sta _int_disabled + ora a + rnz + ei + ret + +! +! We need to worry about bits of this in interrupt save and restore +! + +.define .trapproc, .retadr,.bcreg,.areg,.tmp1 + +.trapproc: .data2 0 +.retadr: .data2 0 +.bcreg: .data2 0 +.areg: .data1 0 +.tmp1: .data2 0 + +! +! Errors from the runtime +! +.define eunimpl,eoddz,ecase,eidivz + +eunimpl: + lxi h,unimp + jmp kerboom +eoddz: + lxi h,ddz + jmp kerboom +ecase: + lxi h,case + jmp kerboom +eidivz: + lxi h,divz +kerboom: + call outstring + call _platform_monitor + +unimp: .asciz 'rt:unimp' +ddz: .asciz 'rt:ddz' +case: .asciz 'rt:case' +divz: .asciz 'rt:div0' diff --git a/Kernel/usermem_std-8080.s b/Kernel/usermem_std-8080.s new file mode 100644 index 00000000..2094fad7 --- /dev/null +++ b/Kernel/usermem_std-8080.s @@ -0,0 +1,100 @@ +! +! Simple implementation for now. Should be optimized +! + +.sect .commonmem + +.define __uputc + +__uputc: + pop b + pop d + pop h + push h + push d + push b + call map_process_always + mov m,e + jp map_kernel + +.define __uputw + +__uputw: + pop b + pop d + pop h + push h + push d + push b + call map_process_always + mov m,e + inx h + mov m,d + jp map_kernel + +.define __ugetc + +__ugetc: + pop b + pop d + pop h + push h + push d + push b + call map_process_always + mov l,m + jp map_kernel + +.define __ugetw + +__ugetw: + pop b + pop d + pop h + push h + push d + push b + call map_process_always + mov a,m + inx h + mov h,m + mov l,a + jmp map_kernel + +.define __uget + +__uget: + ! TODO + ret + +.define __uput + +__uput: + ! TODO + ret + +.define __uzero + +__uzero: + pop d + pop h + pop b + push b + push h + push d + mov a,b + ora c + rz +! +! Simple loop. Wants unrolling a bit +! + call map_process_always + xra a +zeroloop: + mov m,a + inx h + dcx b + mov a,b + ora c + jnz zeroloop + jmp map_kernel -- 2.34.1