From 493fa7a718e35f9ff4410a3ff4f39964bf2bfad8 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 25 Oct 2023 22:46:11 +0100 Subject: [PATCH] z80pack: move to new compiler --- Kernel/platform/platform-z80pack/Makefile | 47 +- .../{bootblock.s => bootblock.S} | 37 +- Kernel/platform/platform-z80pack/commonmem.S | 7 + Kernel/platform/platform-z80pack/commonmem.s | 58 +- Kernel/platform/platform-z80pack/crt0.S | 40 ++ Kernel/platform/platform-z80pack/crt0.s | 92 +-- Kernel/platform/platform-z80pack/kernel.def | 19 - Kernel/platform/platform-z80pack/kernelu.def | 11 + Kernel/platform/platform-z80pack/target.mk | 3 +- Kernel/platform/platform-z80pack/tricks.S | 4 + Kernel/platform/platform-z80pack/tricks.s | 357 +++++++++- Kernel/platform/platform-z80pack/z80pack.S | 402 +++++++++++ Kernel/platform/platform-z80pack/z80pack.s | 630 +++++++++--------- 13 files changed, 1267 insertions(+), 440 deletions(-) rename Kernel/platform/platform-z80pack/{bootblock.s => bootblock.S} (73%) create mode 100644 Kernel/platform/platform-z80pack/commonmem.S create mode 100644 Kernel/platform/platform-z80pack/crt0.S delete mode 100644 Kernel/platform/platform-z80pack/kernel.def create mode 100644 Kernel/platform/platform-z80pack/kernelu.def create mode 100644 Kernel/platform/platform-z80pack/tricks.S create mode 100644 Kernel/platform/platform-z80pack/z80pack.S diff --git a/Kernel/platform/platform-z80pack/Makefile b/Kernel/platform/platform-z80pack/Makefile index 37360387c0..f694a31a02 100644 --- a/Kernel/platform/platform-z80pack/Makefile +++ b/Kernel/platform/platform-z80pack/Makefile @@ -5,42 +5,57 @@ NSRCS = ../../dev/net/net_native.c #NSRCS = ../../dev/net/net_z80pack.c CSRCS += devices.c main.c -ASRCS = crt0.s z80pack.s -ASRCS += tricks.s commonmem.s +ASRCS = crt0.S z80pack.S +ASRCS += tricks.S commonmem.S -AOBJS = $(ASRCS:.s=.rel) -COBJS = $(CSRCS:.c=.rel) -DOBJS = $(patsubst ../../dev/z80pack/%.c,%.rel, $(DSRCS)) -NOBJS = $(patsubst ../../dev/net/%.c,%.rel, $(NSRCS)) +AOBJS = $(ASRCS:.S=.o) +COBJS = $(CSRCS:.c=.o) +DOBJS = $(patsubst ../../dev/z80pack/%.c,%.o, $(DSRCS)) +NOBJS = $(patsubst ../../dev/net/%.c,%.o, $(NSRCS)) OBJS = $(AOBJS) $(COBJS) $(DOBJS) $(NOBJS) CROSS_CCOPTS += -I../../dev/z80pack/ -JUNK = *.rel *.lst *.asm *.sym *.rst - all: $(OBJS) -$(AOBJS): %.rel: %.s +$(AOBJS): %.o: %.S $(CROSS_AS) $(ASOPTS) $< -$(COBJS): %.rel: %.c +$(COBJS): %.o: %.c $(CROSS_CC) $(CROSS_CCOPTS) -c $< -$(DOBJS): %.rel: ../../dev/z80pack/%.c +$(DOBJS): %.o: ../../dev/z80pack/%.c $(CROSS_CC) $(CROSS_CCOPTS) -c $< -$(NOBJS): %.rel: ../../dev/net/%.c +$(NOBJS): %.o: ../../dev/net/%.c $(CROSS_CC) $(CROSS_CCOPTS) -c $< clean: - rm -f $(OBJS) $(JUNK) core *~ + rm -f *.o core *~ + rm -f bootblock.bin image: - sdasz80 -o bootblock.s - sdldz80 -m -i bootblock.rel - makebin -s 128 bootblock.ihx > bootblock.bin + $(CROSS_LD) -b -C 0x0088 -S 0xF400 -X 0xE900 -f CLDBbXSs -o fuzix.bin \ + crt0.o commonmem.o z80pack.o main.o \ + ../../start.o ../../version.o \ + ../../cpu-z80u/lowlevel-z80u.o ../../cpu-z80u/usermem_std-z80u.o \ + tricks.o ../../timer.o ../../kdata.o ../../usermem.o \ + ../../dev/z80pack/devfd.o devices.o ../../devio.o ../../filesys.o \ + ../../blk512.o ../../process.o ../../inode.o ../../syscall_exec16.o \ + ../../syscall_exec.o ../../syscall_fs.o ../../syscall_fs2.o \ + ../../syscall_fs3.o ../../syscall_proc.o ../../syscall_other.o \ + ../../tty.o ../../mm.o ../../mm/memalloc_none.o ../../mm/bankfixed.o \ + ../../swap.o ../../devsys.o ../../dev/z80pack/devlpr.o \ + ../../dev/z80pack/devtty.o ../../dev/z80pack/devrtc.o \ + ../../level2.o ../../syscall_level2.o ../../syscall_net.o \ + ../../select.o ../../dev/net/net_native.o \ + /opt/ccz80/lib/libz80.a -m fuzix.tmpmap + perl -lpe '$$_=hex' fuzix.tmpmap | paste -d" " - fuzix.tmpmap | sort -n | cut -d" " -f 2- >../../fuzix.map + ../../tools/pack85 <../../fuzix.map fuzix.bin ../../fuzix.bin + asz80 bootblock.S -o bootblock.o + ldz80 -b bootblock.o -o bootblock.bin IMAGES = $(FUZIX_ROOT)/Images/$(TARGET) diff --git a/Kernel/platform/platform-z80pack/bootblock.s b/Kernel/platform/platform-z80pack/bootblock.S similarity index 73% rename from Kernel/platform/platform-z80pack/bootblock.s rename to Kernel/platform/platform-z80pack/bootblock.S index 79e7cfd9df..53fe175c8b 100644 --- a/Kernel/platform/platform-z80pack/bootblock.s +++ b/Kernel/platform/platform-z80pack/bootblock.S @@ -11,44 +11,45 @@ ; ; assemble with sdasz80 ; - .area ASEG(ABS) + .abs + .org 0 start: jr diskload -rootdev: .dw 0 ; patched by hand -swapdev: .dw 0 ; ditto - .dw 0 ; spare +rootdev: .word 0 ; patched by hand +swapdev: .word 0 ; ditto + .word 0 ; spare -progress: .db '/', '-', '\', '|' +progress: .byte '/', '-', '\', '|' diskload: di - ld sp, #stack - ld hl, #0x88 + ld sp, stack + ld hl, 0x88 exx xor a ld h, a ld b, a out (17), a ; sector high always 0 out (10), a ; drive always 0 - ld a, #57 ; start on track 58 + ld a, 57 ; start on track 58 out (11), a exx - ld c, #19 ; number of tracks to load (56Kish) + ld c, 19 ; number of tracks to load (56Kish) load_tracks: in a, (11) inc a ; track out (11), a xor a out (12), a - ld b, #26 ; sectors + ld b, 26 ; sectors load_sectors: exx ld a, b - and #3 - add #progress + and 3 + add a,progress ld l, a ld a, (hl) out (01), a - ld a, #8 + ld a, 8 out (01), a inc b exx @@ -63,19 +64,19 @@ load_sectors: exx xor a ; read out (13), a ; go in a, (14) ; status - ld de, #128 + ld de, 128 add hl, de djnz load_sectors ; 26 sectors = 3328 bytes dec c jr nz, load_tracks - ld a, #0xc9 ; to help debug + ld a, 0xc9 ; to help debug ld (start), a - ld a, #13 + ld a, 13 out (1), a - ld a, #10 + ld a, 10 out (1), a jp 0x88 .ds 26 stack: - .db 0xff + .byte 0xff diff --git a/Kernel/platform/platform-z80pack/commonmem.S b/Kernel/platform/platform-z80pack/commonmem.S new file mode 100644 index 0000000000..5ed2418949 --- /dev/null +++ b/Kernel/platform/platform-z80pack/commonmem.S @@ -0,0 +1,7 @@ +; +; Common on z80pack is at 0xF000 as defined by hardware. +; + + .common + +#include "../../cpu-z80u/std-commonmem.s" diff --git a/Kernel/platform/platform-z80pack/commonmem.s b/Kernel/platform/platform-z80pack/commonmem.s index a9df4f36bd..299dfc6214 100644 --- a/Kernel/platform/platform-z80pack/commonmem.s +++ b/Kernel/platform/platform-z80pack/commonmem.s @@ -1,9 +1,59 @@ +# 0 "commonmem.S" +# 0 "" +# 0 "" +# 1 "commonmem.S" ; -; Common on z80pack is at 0xF000 as defined by hardware. +; Common on z80pack is at 0xF000 as defined by hardware. ; - .module commonmem + .common - .area _COMMONMEM +# 1 "../../cpu-z80u/std-commonmem.s" 1 +; +; +; Standard Z80 common memory area blocks. +; +; Must remain a multiple of 256 bytes +; + ; exported symbols + .export _ub + .export _udata + .export kstack_top + .export istack_top + .export istack_switched_sp + + +_ub: ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above +_udata: +kstack_base: + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +kstack_top: - .include "../../cpu-z80/std-commonmem.s" + ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer +istack_base: + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +istack_top: +istack_switched_sp: .word 0 +# 8 "commonmem.S" 2 diff --git a/Kernel/platform/platform-z80pack/crt0.S b/Kernel/platform/platform-z80pack/crt0.S new file mode 100644 index 0000000000..d68481ded1 --- /dev/null +++ b/Kernel/platform/platform-z80pack/crt0.S @@ -0,0 +1,40 @@ + ; startup code + .code + +init: + di + ld sp, kstack_top + + ; Configure memory map + call init_early + + ; move the common memory where it belongs + ld hl, __bss + ld de, __common + ld bc, __common_size + ldir + ld de, __commondata + ld bc, __commondata_size + ldir + ; and the discard + ld de, __discard + ld bc, __discard_size + ldir + ; then zero the data area + ld hl, __bss + ld de, __bss + 1 + ld bc, __bss_size - 1 + ld (hl), 0 + ldir + + ; Hardware setup + call init_hardware + + ; Call the C main routine + call _fuzix_main + + ; main shouldn't return, but if it does... + di +stop: halt + jr stop + diff --git a/Kernel/platform/platform-z80pack/crt0.s b/Kernel/platform/platform-z80pack/crt0.s index c3060e0069..c0a20854b0 100644 --- a/Kernel/platform/platform-z80pack/crt0.s +++ b/Kernel/platform/platform-z80pack/crt0.s @@ -1,79 +1,45 @@ -; 2013-12-18 William R Sowerbutts - - .module crt0 - - ; Ordering of segments for the linker. - ; WRS: Note we list all our segments here, even though - ; we don't use them all, because their ordering is set - ; when they are first seen. - .area _CODE - .area _CODE2 - .area _CONST - .area _INITIALIZED - .area _DATA - .area _BSEG - .area _BSS - .area _HEAP - ; note that areas below here may be overwritten by the heap at runtime, so - ; put initialisation stuff in here - .area _INITIALIZER - .area _GSINIT - .area _GSFINAL - .area _DISCARD - .area _COMMONMEM - .area _COMMONDATA - - ; imported symbols - .globl _fuzix_main - .globl init_early - .globl init_hardware - .globl s__INITIALIZER - .globl s__COMMONMEM - .globl l__COMMONMEM - .globl s__COMMONDATA - .globl l__COMMONDATA - .globl s__DISCARD - .globl l__DISCARD - .globl s__DATA - .globl l__DATA - .globl kstack_top - +# 0 "crt0.S" +# 0 "" +# 0 "" +# 1 "/usr/include/stdc-predef.h" 1 3 4 +# 0 "" 2 +# 1 "crt0.S" ; startup code - .area _CODE + .code + init: di - ld sp, #kstack_top + ld sp, kstack_top ; Configure memory map call init_early - ; move the common memory where it belongs - ld hl, #s__DATA - ld de, #s__COMMONMEM - ld bc, #l__COMMONMEM - ldir - ld de, #s__COMMONDATA - ld bc, #l__COMMONDATA - ldir - ; and the discard - ld de, #s__DISCARD - ld bc, #l__DISCARD - ldir - ; then zero the data area - ld hl, #s__DATA - ld de, #s__DATA + 1 - ld bc, #l__DATA - 1 - ld (hl), #0 - ldir + ; move the common memory where it belongs + ld hl, __bss + ld de, __common + ld bc, __common_size + ldir + ld de, __commondata + ld bc, __commondata_size + ldir + ; and the discard + ld de, __discard + ld bc, __discard_size + ldir + ; then zero the data area + ld hl, __bss + ld de, __bss + 1 + ld bc, __bss_size - 1 + ld (hl), 0 + ldir ; Hardware setup call init_hardware ; Call the C main routine call _fuzix_main - + ; main shouldn't return, but if it does... di -stop: halt +stop: halt jr stop - diff --git a/Kernel/platform/platform-z80pack/kernel.def b/Kernel/platform/platform-z80pack/kernel.def deleted file mode 100644 index 6cb4f54171..0000000000 --- a/Kernel/platform/platform-z80pack/kernel.def +++ /dev/null @@ -1,19 +0,0 @@ -; UZI mnemonics for memory addresses etc - -U_DATA__TOTALSIZE .equ 0x200 ; 256+256 bytes @ F400 - -U_DATA_STASH .equ 0xEE00 ; EE00-EFFF - -PROGBASE .equ 0x0000 -PROGLOAD .equ 0x0100 - -Z80_TYPE .equ 1 - -Z80_MMU_HOOKS .equ 1 - -CONFIG_SWAP .equ 1 - - .globl mmu_user - .globl mmu_kernel - .globl mmu_kernel_irq - .globl mmu_restore_irq diff --git a/Kernel/platform/platform-z80pack/kernelu.def b/Kernel/platform/platform-z80pack/kernelu.def new file mode 100644 index 0000000000..eaa7c8f156 --- /dev/null +++ b/Kernel/platform/platform-z80pack/kernelu.def @@ -0,0 +1,11 @@ +; UZI mnemonics for memory addresses etc + +#define U_DATA__TOTALSIZE 0x0200 /* 256+256 bytes @ F400 */ + +#define U_DATA_STASH 0xEE00 /* EE00-EFFF */ + +#define PROGBASE 0x0000 +#define PROGLOAD 0x0100 + +#define Z80_MMU_HOOKS +#define CONFIG_SWAP diff --git a/Kernel/platform/platform-z80pack/target.mk b/Kernel/platform/platform-z80pack/target.mk index 3bffcde0c7..75b9e1402c 100644 --- a/Kernel/platform/platform-z80pack/target.mk +++ b/Kernel/platform/platform-z80pack/target.mk @@ -1 +1,2 @@ -export CPU = z80 +export CPU = z80u +export USERCPU = z80 diff --git a/Kernel/platform/platform-z80pack/tricks.S b/Kernel/platform/platform-z80pack/tricks.S new file mode 100644 index 0000000000..88b83662c7 --- /dev/null +++ b/Kernel/platform/platform-z80pack/tricks.S @@ -0,0 +1,4 @@ +#include "kernelu.def" +#include "../../cpu-z80u/kernel-z80.def" + +#include "../../lib/z80ufixedbank.S" diff --git a/Kernel/platform/platform-z80pack/tricks.s b/Kernel/platform/platform-z80pack/tricks.s index e088f0161a..86f15b8f21 100644 --- a/Kernel/platform/platform-z80pack/tricks.s +++ b/Kernel/platform/platform-z80pack/tricks.s @@ -1,5 +1,356 @@ +# 0 "tricks.S" +# 0 "" +# 0 "" +# 1 "tricks.S" +# 1 "kernelu.def" 1 +; UZI mnemonics for memory addresses etc +# 2 "tricks.S" 2 +# 1 "../../cpu-z80u/kernel-z80.def" 1 +# 3 "tricks.S" 2 - .include "kernel.def" - .include "../../cpu-z80/kernel-z80.def" +# 1 "../../lib/z80ufixedbank.S" 1 - .include "../../lib/z80fixedbank.s" +# 1 "../../lib/../lib/z80ufixedbank-core.s" 1 +; +; 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. +; + .export _plt_switchout + .export _switchin + .export _dofork + + .export _need_resched + + .common + +; __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. +; +_plt_switchout: + ld hl, #0 ; return code set here is ignored, but _switchin can + ; return from either _switchout OR _dofork, so they must both write + ; 14 with the following on the stack: + push hl ; return code + push bc ; register variable + push ix + push iy + ld (_udata + 14), sp ; this is where the SP is restored in _switchin + + ; Stash the uarea back into process memory + call map_proc_always + ld hl, #_udata + ld de, #0xEE00 + ld bc, #0x0200 + ldir + call map_kernel + + ; find another process to run (may select this one again) + call _getproc + + push hl + call _switchin + + ; we should never get here + call _plt_monitor + +badswitchmsg: .ascii "_switchin: FAIL" + .byte 13, 10, 0 +swapped: .ascii "_switchin: SWAPPED" + .byte 13, 10, 0 + +_switchin: + di + pop bc ; return address (we can trash bc here - we will restore one) + pop de ; new process pointer +; +; FIXME: do we actually *need* to restore the stack ! +; + push de ; restore stack + push bc ; restore stack + + ld a,#1 + ld (_int_disabled),a + +; +; FIXME: map_kernel_di ? +; + call map_kernel + + ld hl, #15 + add hl, de ; process ptr + + + + ; + ; Always use the swapstack, otherwise when we call map_kernel + ; having copied the udata stash back to udata we will crap + ; somewhere up the stackframe and it's then down to luck + ; if those bytes are discarded or not. + ; + ; Yes - this was a bitch to debug, please don't break it ! + ; + ld sp, #_swapstack + + ld a, (hl) + + or a + jr nz, not_swapped + + ; + ; Re-enable interrupts while we swap. This is ok because + ; we are not on the IRQ stack when switchin is invoked. + ; + ; There are two basic cases + ; #1: pre-emption. Not in a system call, must avoid + ; re-entering pre-emption logic, Z80 lowlevel code sets U_INSYS + ; #2: kernel syscall. Also protected by 6 + ; + ei + xor a + ld (_int_disabled),a + push hl + push de + call _swapper + pop de + pop hl + ld a,#1 + ld (_int_disabled),a + di + + ld a, (hl) +not_swapped: + push hl + ld hl, (_udata + 0) + or a + sbc hl, de + pop hl + jr z, skip_copyback ; Tormod's optimisation: don't copy the + ; the stash back if we are the task who + ; last owned the real udata + ld a,(hl) + ; Pages please ! + call map_proc_a + + ; bear in mind that the stack will be switched now, so we can't use it + ; to carry values over this point + + exx ; thank goodness for exx 8) + ld hl, #0xEE00 + ld de, #_udata + ld bc, #0x0200 + ldir + exx + + ; In the non swap case we must set so before we use the stack + ; otherwise we risk corrupting the restored stack frame + ld sp, (_udata + 14) + call map_kernel + + ; check u_data->u_ptab matches what we wanted + ld hl, (_udata + 0) ; u_data->u_ptab + or a ; clear carry flag + sbc hl, de ; subtract, result will be zero if DE==HL + jr nz, switchinfail + +skip_copyback: + ; wants optimising up a bit + ld ix, (_udata + 0) + ; next_process->p_status = 1 + ld (ix + 0), #1 + + ; Fix the moved page pointers + ; Just do one byte as that is all we use on this platform + ld a, (ix + 15) + ld (_udata + 2), 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 + 14) + + pop iy ; register variables + pop ix + pop bc + pop hl ; return code + + ; enable interrupts, if we didn't pre-empt in an ISR + ld a, (_udata + 16) + ld (_int_disabled),a + or a + ret nz ; Not an 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 _plt_monitor + + +; +; 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. + + ; + ; FIXME: we should no longer need interrupts off for most of a + ; fork() call. + ; + pop de ; return address + pop hl ; new process p_tab* + push hl + push de + + ld (fork_proc_ptr), hl + + ; prepare return value in parent process -- HL = p->p_pid; + ld de, #3 + add hl, de + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; 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. + push hl ; HL still has p->p_pid from above, the return value in the parent + push ix + push iy + push bc + + ; save kernel stack pointer -- when it comes back in the parent 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 + 14), sp + + ; now we're in a safe state for _switchin to return in the parent + ; process. + + ; --------- copy process --------- + + ld hl, (fork_proc_ptr) + ld de, #15 + add hl, de + ; load p_page + ld c, (hl) + ; load existing page ptr + ld a, (_udata + 2) + + ; FIXME: We will redefine this to expect udata as parent and (hl) + ; as child so it's also clean for multibank. For now just make + ; sure HL happens to be right + call bankfork ; do the bank to bank copy + + ; Copy done + + call map_proc_always + + ; We are going to copy the uarea into the parents uarea stash + ; we must not touch the parent uarea after this point, any + ; changes only affect the child + ld hl, #_udata ; copy the udata from common into the + ld de, #0xEE00 ; target process + ld bc, #0x0200 + ldir + ; Return to the kernel mapping + call map_kernel + + ; now the copy operation is complete we can get rid of the stuff + ; _switchin will be expecting from our copy of the stack. + ; ix/iy are untouched so don't need a restore BC is not so does + pop bc + pop af + pop af + pop af ; and the pid + + ; Make a new process table entry, etc. + ld hl,#_udata + push hl + ld hl, (fork_proc_ptr) + push hl + call _makeproc + pop af + pop af + + ; runticks = 0; + ld hl, #0 + ld (_runticks), hl + ; in the child process, fork() returns zero. + ; + ; And we exit, with the kernel mapped, the child now being deemed + ; to be the live uarea. The parent is frozen in time and space as + ; if it had done a switchout(). + ret + + .commondata +; +; For the moment +; +bouncebuffer: + .ds 256 +; +; 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. This can share with the bounce +; buffer used by bankfork as we won't switchin mid way through the +; banked fork() call. +; +_swapstack: +_need_resched: .byte 0 +fork_proc_ptr: .word 0 ; (C type is struct p_tab *) -- address of child process p_tab entry +# 3 "../../lib/z80ufixedbank.S" 2 +; +; This is related so we will keep it here. Copy the process memory +; for a fork. a is the page base of the parent, c of the child +; +; Assumption - fits into a fixed number of whole 256 byte blocks +; + + .common + +bankfork: + ld bc, 0xEE00 - 0x0000 + ld hl, 0x0000 ; base of memory to fork (vectors included) +bankfork_1: + push bc ; Save our counter and also child offset + push hl + call map_proc_a + ld de, bouncebuffer + ld bc, 256 + ldir ; copy into the bounce buffer + pop de ; recover source of copy to bounce + ; as destination in new bank + pop bc ; recover child page number + push bc + ld b, a ; save the parent bank id + ld a, c ; switch to the child + call map_proc_a + push bc ; save the bank pointers + ld hl, bouncebuffer + ld bc, 256 + ldir ; copy into the child + pop bc ; recover the bank pointers + ex de, hl ; destination is now source for next bank + ld a, b ; parent bank is wanted in a + pop bc + djnz bankfork_1 ; rinse, repeat + ret +# 5 "tricks.S" 2 diff --git a/Kernel/platform/platform-z80pack/z80pack.S b/Kernel/platform/platform-z80pack/z80pack.S new file mode 100644 index 0000000000..121aa3b6b4 --- /dev/null +++ b/Kernel/platform/platform-z80pack/z80pack.S @@ -0,0 +1,402 @@ +; +; Z80Pack hardware support +; +; +; This goes straight after udata for common. +; + + + ; exported symbols + .export init_early + .export init_hardware + .export _program_vectors + .export plt_interrupt_all + + .export map_kernel + .export map_kernel_di + .export map_kernel_restore + .export map_proc + .export map_proc_di + .export map_proc_always + .export map_proc_always_di + .export map_proc_a + .export map_save_kernel + .export map_restore + + .export mmu_user + .export mmu_kernel + .export mmu_kernel_irq + .export mmu_restore_irq + + .export _fd_bankcmd + + .export _int_disabled + + .export _plt_reboot + + ; exported debugging tools + .export _plt_monitor + .export outchar + +#include "kernelu.def" +#include "../../cpu-z80u/kernel-z80.def" + +; ----------------------------------------------------------------------------- +; COMMON MEMORY BANK (0xF000 upwards) +; ----------------------------------------------------------------------------- + + .common + +_plt_monitor: + ld a, 128 + out (29), a +plt_interrupt_all: + ret + +_plt_reboot: + ld a, 1 + out (29), a + +; +; We need the right bank present when we cause the transfer +; +_fd_bankcmd: + ld de,#5 + add hl,de + ld d,(hl) + dec hl + ld h,(hl) + dec hl + dec hl + ld l,(hl) + + ex de,hl ; bank to HL command to E + + ld a, (_int_disabled) + di + push af ; save DI state + call map_proc_di ; HL alread holds our bank + ld a, e ; issue the command + out (13), a ; + call map_kernel_di ; return to kernel mapping + pop af + or a + ret nz + ei + ret + +; ----------------------------------------------------------------------------- +; KERNEL MEMORY BANK (below 0xC000, only accessible when the kernel is mapped) +; ----------------------------------------------------------------------------- + .code + +init_early: + ld a, 240 ; 240 * 256 bytes (60K) + out (22), a ; set up memory banking + ld a, 8 + out (20), a ; 8 segments + ret + +init_hardware: + ; set system RAM size + ld hl, 484 + ld (_ramsize), hl + ld hl, (484-64) ; 64K for kernel + ld (_procmem), hl + + ld a, 1 + out (27), a ; 100Hz timer on + + ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused) + ld hl, 0 + push hl + call _program_vectors + pop hl + + ld a, 0xfe ; Use FEFF (currently free) + ld i, a + im 2 ; set CPU interrupt mode + ret + + +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + .common + +_int_disabled: + .byte 1 + +_program_vectors: + ; we are called, with interrupts disabled, by both newproc() and crt0 + ; will exit with interrupts off + di ; just to be sure + pop de ; temporarily store return address + pop hl ; function argument -- base page number + push hl ; put stack back as it was + push de + + call map_proc + + ; write zeroes across all vectors + ld hl, 0 + ld de, 1 + ld bc, 0x007f ; program first 0x80 bytes only + ld (hl), 0x00 + ldir + + ; 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 + ld (0x0031), hl + + ; Set vector for jump to NULL + ld (0x0000), a + ld hl, null_handler ; to Our Trap Handler + ld (0x0001), hl + + ld (0x0066), a ; Set vector for NMI + ld hl, nmi_handler + ld (0x0067), hl + + ; our platform has a "true" common area, if it did not we would + ; need to copy the "common" code into the common area of the new + ; process. + + ; falls through + + ; put the paging back as it was -- we're in kernel mode so this is predictable +map_kernel: +map_kernel_di: +map_kernel_restore: + push af + xor a + out (21), a + pop af + ret +map_proc: +map_proc_di: + ld a, h + or l + jr z, map_kernel + ld a, (hl) +map_proc_a: + out (21), a + ret +map_proc_always: +map_proc_always_di: + push af + ld a, (_udata + U_DATA__U_PAGE) + out (21), a + pop af + ret +map_save_kernel: + push af + in a, (21) + ld (map_store), a + xor a + out (21),a + pop af + ret +map_restore: + push af + ld a, (map_store) + out (21), a + pop af + ret + +map_store: + .byte 0 + + .common + +; outchar: Wait for UART TX idle, then print the char in A +; destroys: AF +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 af + 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 + pop af + 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, (_udata + U_DATA__U_INSYS) + or a + jr nz, badbadstack + ld a, (_udata + U_DATA__U_ININTERRUPT) + 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: + .ascii "ZombAp" + .byte 0 + +badbadstack: + ld hl,#badbadstack_msg + push hl + call _panic + +badstackifu: + ld a, (_udata + U_DATA__U_INSYS) + or a + jr nz, do_mmu_kernel + ld a, (_udata + U_DATA__U_ININTERRUPT) + 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, (_udata + U_DATA__U_INSYS) + or a + ld a, (_udata + U_DATA__U_ININTERRUPT) + or a +badstackirq: + ld a, (_udata + U_DATA__U_INSYS) + or a + jr nz, badbadstack_irq + ld a, (_udata + U_DATA__U_ININTERRUPT) + 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_kernel + ld hl,9 + push hl + ld hl,(_udata + 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, (_udata + U_DATA__U_INSYS) + or a + jr nz, do_mmu_kernel_irq + ld a, (_udata + U_DATA__U_ININTERRUPT) + 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: + .ascii 'MMU trap/bad stack' + .byte 0 + + +; +; 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 diff --git a/Kernel/platform/platform-z80pack/z80pack.s b/Kernel/platform/platform-z80pack/z80pack.s index 2fe270fa9d..88b9cd40ab 100644 --- a/Kernel/platform/platform-z80pack/z80pack.s +++ b/Kernel/platform/platform-z80pack/z80pack.s @@ -1,411 +1,409 @@ +# 0 "z80pack.S" +# 0 "" +# 0 "" +# 1 "z80pack.S" ; -; Z80Pack hardware support +; Z80Pack hardware support ; ; -; This goes straight after udata for common. +; This goes straight after udata for common. ; - .module z80pack + ; exported symbols + .export init_early + .export init_hardware + .export _program_vectors + .export plt_interrupt_all - ; exported symbols - .globl init_early - .globl init_hardware - .globl _program_vectors - .globl plt_interrupt_all + .export map_kernel + .export map_kernel_di + .export map_kernel_restore + .export map_proc + .export map_proc_di + .export map_proc_always + .export map_proc_always_di + .export map_proc_a + .export map_save_kernel + .export map_restore - .globl map_kernel - .globl map_kernel_di - .globl map_kernel_restore - .globl map_proc - .globl map_proc_di - .globl map_proc_always - .globl map_proc_always_di - .globl map_proc_a - .globl map_save_kernel - .globl map_restore + .export mmu_user + .export mmu_kernel + .export mmu_kernel_irq + .export mmu_restore_irq - .globl _fd_bankcmd + .export _fd_bankcmd - .globl _int_disabled + .export _int_disabled - .globl _plt_reboot + .export _plt_reboot - ; exported debugging tools - .globl _plt_monitor - .globl outchar + ; exported debugging tools + .export _plt_monitor + .export outchar - ; imported symbols - .globl _ramsize - .globl _procmem - - .globl unix_syscall_entry - .globl null_handler - .globl nmi_handler - .globl interrupt_handler - .globl _doexit - .globl kstack_top - .globl _panic - .globl mmu_irq_ret - .globl _need_resched - .globl _ssig - - .globl outcharhex - .globl outhl, outde, outbc - .globl outnewline - .globl outstring - .globl outstringhex - - .include "kernel.def" - .include "../../cpu-z80/kernel-z80.def" +# 1 "kernelu.def" 1 +; UZI mnemonics for memory addresses etc +# 42 "z80pack.S" 2 +# 1 "../../cpu-z80u/kernel-z80.def" 1 +# 43 "z80pack.S" 2 ; ----------------------------------------------------------------------------- ; COMMON MEMORY BANK (0xF000 upwards) ; ----------------------------------------------------------------------------- - .area _COMMONMEM + + .common _plt_monitor: - ld a, #128 - out (29), a + ld a, 128 + out (29), a plt_interrupt_all: - ret + ret _plt_reboot: - ld a, #1 - out (29), a + ld a, 1 + out (29), a ; -; We need the right bank present when we cause the transfer +; We need the right bank present when we cause the transfer ; -_fd_bankcmd:pop de ; return - pop bc ; command - pop hl ; bank - push hl - push bc - push de ; fix stack - ld a, (_int_disabled) - di - push af ; save DI state - call map_proc_di ; HL alread holds our bank - ld a, c ; issue the command - out (13), a ; - call map_kernel_di ; return to kernel mapping - pop af - or a - ret nz - ei - ret +_fd_bankcmd: + ld de,#5 + add hl,de + ld d,(hl) + dec hl + ld h,(hl) + dec hl + dec hl + ld l,(hl) + + ex de,hl ; bank to HL command to E + + ld a, (_int_disabled) + di + push af ; save DI state + call map_proc_di ; HL alread holds our bank + ld a, e ; issue the command + out (13), a ; + call map_kernel_di ; return to kernel mapping + pop af + or a + ret nz + ei + ret ; ----------------------------------------------------------------------------- ; KERNEL MEMORY BANK (below 0xC000, only accessible when the kernel is mapped) ; ----------------------------------------------------------------------------- - .area _CODE + .code init_early: - ld a, #240 ; 240 * 256 bytes (60K) - out (22), a ; set up memory banking - ld a, #8 - out (20), a ; 8 segments - ret + ld a, 240 ; 240 * 256 bytes (60K) + out (22), a ; set up memory banking + ld a, 8 + out (20), a ; 8 segments + ret init_hardware: - ; set system RAM size - ld hl, #484 - ld (_ramsize), hl - ld hl, #(484-64) ; 64K for kernel - ld (_procmem), hl + ; set system RAM size + ld hl, 484 + ld (_ramsize), hl + ld hl, (484-64) ; 64K for kernel + ld (_procmem), hl - ld a, #1 - out (27), a ; 100Hz timer on + ld a, 1 + out (27), a ; 100Hz timer on - ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused) - ld hl, #0 - push hl - call _program_vectors - pop hl + ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused) + ld hl, 0 + push hl + call _program_vectors + pop hl - ld a, #0xfe ; Use FEFF (currently free) - ld i, a - im 2 ; set CPU interrupt mode - ret + ld a, 0xfe ; Use FEFF (currently free) + ld i, a + im 2 ; set CPU interrupt mode + ret ;------------------------------------------------------------------------------ ; COMMON MEMORY PROCEDURES FOLLOW - .area _COMMONMEM + .common _int_disabled: - .byte 1 + .byte 1 _program_vectors: - ; we are called, with interrupts disabled, by both newproc() and crt0 - ; will exit with interrupts off - di ; just to be sure - pop de ; temporarily store return address - pop hl ; function argument -- base page number - push hl ; put stack back as it was - push de - - call map_proc - - ; write zeroes across all vectors - ld hl, #0 - ld de, #1 - ld bc, #0x007f ; program first 0x80 bytes only - ld (hl), #0x00 - ldir - - ; now install the interrupt vector at 0xFEFF - ld hl, #interrupt_handler - 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 - ld (0x0031), hl - - ; Set vector for jump to NULL - ld (0x0000), a - ld hl, #null_handler ; to Our Trap Handler - ld (0x0001), hl - - ld (0x0066), a ; Set vector for NMI - ld hl, #nmi_handler - ld (0x0067), hl - - ; our platform has a "true" common area, if it did not we would - ; need to copy the "common" code into the common area of the new - ; process. - - ; falls through - - ; put the paging back as it was -- we're in kernel mode so this is predictable + ; we are called, with interrupts disabled, by both newproc() and crt0 + ; will exit with interrupts off + di ; just to be sure + pop de ; temporarily store return address + pop hl ; function argument -- base page number + push hl ; put stack back as it was + push de + + call map_proc + + ; write zeroes across all vectors + ld hl, 0 + ld de, 1 + ld bc, 0x007f ; program first 0x80 bytes only + ld (hl), 0x00 + ldir + + ; 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 + ld (0x0031), hl + + ; Set vector for jump to NULL + ld (0x0000), a + ld hl, null_handler ; to Our Trap Handler + ld (0x0001), hl + + ld (0x0066), a ; Set vector for NMI + ld hl, nmi_handler + ld (0x0067), hl + + ; our platform has a "true" common area, if it did not we would + ; need to copy the "common" code into the common area of the new + ; process. + + ; falls through + + ; put the paging back as it was -- we're in kernel mode so this is predictable map_kernel: map_kernel_di: map_kernel_restore: - push af - xor a - out (21), a - pop af - ret + push af + xor a + out (21), a + pop af + ret map_proc: map_proc_di: - ld a, h - or l - jr z, map_kernel - ld a, (hl) + ld a, h + or l + jr z, map_kernel + ld a, (hl) map_proc_a: - out (21), a - ret + out (21), a + ret map_proc_always: map_proc_always_di: - push af - ld a, (_udata + U_DATA__U_PAGE) - out (21), a - pop af - ret + push af + ld a, (_udata + 2) + out (21), a + pop af + ret map_save_kernel: - push af - in a, (21) - ld (map_store), a - xor a - out (21),a - pop af - ret + push af + in a, (21) + ld (map_store), a + xor a + out (21),a + pop af + ret map_restore: - push af - ld a, (map_store) - out (21), a - pop af - ret + push af + ld a, (map_store) + out (21), a + pop af + ret + map_store: - .db 0 + .byte 0 + + .common ; outchar: Wait for UART TX idle, then print the char in A ; destroys: AF outchar: - out (0x01), a - ret + 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. +; 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 +; 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 af - 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 + push af + 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 - pop af - ret + xor a ; Switch MMU off + out (23),a + pop hl + pop af + ret ; -; We have been called with SP pointing into la-la land. That means -; something bad has happened to our process (or the kernel) +; 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, (_udata + U_DATA__U_INSYS) - or a - jr nz, badbadstack - ld a, (_udata + U_DATA__U_ININTERRUPT) - or a - jr nz, badbadstack - ; - ; Ok we are in user mode, this is less bad. - ; Fake a sigkill - ; + ld a, (_udata + 6) + or a + jr nz, badbadstack + ld a, (_udata + 16) + 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 + 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" + .ascii "ZombAp" + .byte 0 badbadstack: - ld hl,#badbadstack_msg - push hl - call _panic + ld hl,#badbadstack_msg + push hl + call _panic badstackifu: - ld a, (_udata + U_DATA__U_INSYS) - or a - jr nz, do_mmu_kernel - ld a, (_udata + U_DATA__U_ININTERRUPT) - or a - jr nz, do_mmu_kernel - jr badstack_do + ld a, (_udata + 6) + or a + jr nz, do_mmu_kernel + ld a, (_udata + 16) + 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). +; 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 + 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, (_udata + U_DATA__U_INSYS) - or a - ld a, (_udata + U_DATA__U_ININTERRUPT) - or a + in a,(23) + ld l,a + xor a + out (23),a + ld a,l + ld (mmusave),a + jp mmu_irq_ret + + ld a, (_udata + 6) + or a + ld a, (_udata + 16) + or a badstackirq: - ld a, (_udata + U_DATA__U_INSYS) - or a - jr nz, badbadstack_irq - ld a, (_udata + U_DATA__U_ININTERRUPT) - or a - jr nz, badbadstack_irq + ld a, (_udata + 6) + or a + jr nz, badbadstack_irq + ld a, (_udata + 16) + 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_kernel - ld hl,#9 - push hl - ld hl,(_udata + 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 + ; + ; 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_kernel + ld hl,9 + push hl + ld hl,(_udata + 0) + 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, (_udata + U_DATA__U_INSYS) - or a - jr nz, do_mmu_kernel_irq - ld a, (_udata + U_DATA__U_ININTERRUPT) - or a - jr nz, do_mmu_kernel_irq - jr badstack_doirq + ld a, (_udata + 6) + or a + jr nz, do_mmu_kernel_irq + ld a, (_udata + 16) + or a + jr nz, do_mmu_kernel_irq + jr badstack_doirq badbadstack_irq: - ld hl,#badbadstackirq_msg - push hl - call _panic + ld hl,#badbadstackirq_msg + push hl + call _panic badbadstackirq_msg: - .ascii 'IRQ:' + .ascii 'IRQ:' badbadstack_msg: - .asciz 'MMU trap/bad stack' + .ascii 'MMU trap/bad stack' + .byte 0 ; -; This side is easy. We are coming from a sane context (hopefully). -; MMU on, clear flag. +; 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 + ld a,(mmusave) + and 0x01 + out (23),a + ret mmu_user: - ld a,#1 - out (23),a - ret + ld a,1 + out (23),a + ret mmusave: - .byte 0 + .byte 0