From 92e80988ca52517dfec53e56e68a854368de7037 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 4 Feb 2017 23:29:46 +0000 Subject: [PATCH] v68-softmmu: commit WIP code --- Kernel/platform-v68-softmmu/Makefile | 43 +++++ Kernel/platform-v68-softmmu/README | 5 + Kernel/platform-v68-softmmu/config.h | 33 ++++ Kernel/platform-v68-softmmu/crt0.S | 37 ++++ Kernel/platform-v68-softmmu/device.h | 6 + Kernel/platform-v68-softmmu/devices.c | 42 +++++ Kernel/platform-v68-softmmu/devtty.c | 65 +++++++ Kernel/platform-v68-softmmu/devtty.h | 10 ++ Kernel/platform-v68-softmmu/kernel.def | 1 + Kernel/platform-v68-softmmu/libc.c | 40 +++++ Kernel/platform-v68-softmmu/main.c | 143 +++++++++++++++ Kernel/platform-v68-softmmu/p68000.S | 191 +++++++++++++++++++++ Kernel/platform-v68-softmmu/platform_ide.h | 18 ++ Kernel/platform-v68-softmmu/target.mk | 1 + Kernel/platform-v68-softmmu/tricks.S | 140 +++++++++++++++ 15 files changed, 775 insertions(+) create mode 100644 Kernel/platform-v68-softmmu/Makefile create mode 100644 Kernel/platform-v68-softmmu/README create mode 100644 Kernel/platform-v68-softmmu/config.h create mode 100644 Kernel/platform-v68-softmmu/crt0.S create mode 100644 Kernel/platform-v68-softmmu/device.h create mode 100644 Kernel/platform-v68-softmmu/devices.c create mode 100644 Kernel/platform-v68-softmmu/devtty.c create mode 100644 Kernel/platform-v68-softmmu/devtty.h create mode 100644 Kernel/platform-v68-softmmu/kernel.def create mode 100644 Kernel/platform-v68-softmmu/libc.c create mode 100644 Kernel/platform-v68-softmmu/main.c create mode 100644 Kernel/platform-v68-softmmu/p68000.S create mode 100644 Kernel/platform-v68-softmmu/platform_ide.h create mode 100644 Kernel/platform-v68-softmmu/target.mk create mode 100644 Kernel/platform-v68-softmmu/tricks.S diff --git a/Kernel/platform-v68-softmmu/Makefile b/Kernel/platform-v68-softmmu/Makefile new file mode 100644 index 00000000..739a064b --- /dev/null +++ b/Kernel/platform-v68-softmmu/Makefile @@ -0,0 +1,43 @@ + +CSRCS = devtty.c +CSRCS += devices.c main.c libc.c + +ASRCS = p68000.S crt0.S +ASRCS += tricks.S + +DSRCS = ../dev/devide.c ../dev/mbr.c ../dev/blkdev.c ../dev/devide_discard.c +DOBJS = $(patsubst ../dev/%.c,%.o, $(DSRCS)) + +COBJS = $(CSRCS:.c=$(BINEXT)) +AOBJS = $(ASRCS:.S=.o) +OBJS = $(COBJS) $(AOBJS) $(DOBJS) + +CROSS_CCOPTS += -I../dev/ + +JUNK = $(CSRCS:.c=.o) $(ASRCS:.S=.o) + +all: $(OBJS) + +$(COBJS): %.o: %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(AOBJS): %.o: %.S + $(CROSS_AS) $(ASOPTS) $< -o $*.o + +$(DOBJS): %.o: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +clean: + rm -f $(OBJS) $(JUNK) core *~ + +image: + $(CROSS_LD) -M -o fuzix.elf -T fuzix.ld \ + crt0.o \ + p68000.o ../start.o ../version.o ../lowlevel-68000.o \ + tricks.o ../bankfixed.o main.o ../timer.o ../kdata.o devices.o \ + ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \ + ../syscall_proc.o ../syscall_other.o ../mm.o ../flat_mem.o \ + ../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o \ + ../syscall_fs3.o ../syscall_exec32.o blkdev.o devide.o devide_discard.o mbr.o \ + ../usermem_std-68000.o devtty.o libc.o ../malloc.o > ../fuzix.map + m68k-linux-gnu-objcopy fuzix.elf -O binary ../fuzix.bin diff --git a/Kernel/platform-v68-softmmu/README b/Kernel/platform-v68-softmmu/README new file mode 100644 index 00000000..2886d9de --- /dev/null +++ b/Kernel/platform-v68-softmmu/README @@ -0,0 +1,5 @@ +See platform-v68 + +This is a test tree for a configuration developing the software MMU mode. It's +not yet functional and will crash when fork() is hit. + diff --git a/Kernel/platform-v68-softmmu/config.h b/Kernel/platform-v68-softmmu/config.h new file mode 100644 index 00000000..040f8069 --- /dev/null +++ b/Kernel/platform-v68-softmmu/config.h @@ -0,0 +1,33 @@ +/* Enable to make ^Z dump the inode table for debug */ +#define CONFIG_IDUMP +/* Enable to make ^A drop back into the monitor */ +#undef CONFIG_MONITOR +/* Profil syscall support (not yet complete) */ +#undef CONFIG_PROFIL + +#define CONFIG_32BIT +#define CONFIG_MULTI +#define CONFIG_USERMEM_DIRECT +#define CONFIG_VMMU + +#define MMU_BLKSIZE 8192 + +#define CONFIG_BANKS 1 + +#define TICKSPERSEC 100 /* Ticks per second */ + +#define BOOT_TTY (512 + 1) /* Set this to default device for stdio, stderr */ + /* In this case, the default is the first TTY device */ + /* Temp FIXME set to serial port for debug ease */ + +/* We need a tidier way to do this from the loader */ +#define CMDLINE NULL /* Location of root dev name */ + +/* Device parameters */ +#define NUM_DEV_TTY 1 +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define NBUFS 10 /* Number of block buffers */ +#define NMOUNTS 4 /* Number of mounts at a time */ + +#define MAX_BLKDEV 4 + diff --git a/Kernel/platform-v68-softmmu/crt0.S b/Kernel/platform-v68-softmmu/crt0.S new file mode 100644 index 00000000..95594de0 --- /dev/null +++ b/Kernel/platform-v68-softmmu/crt0.S @@ -0,0 +1,37 @@ +/* + * Need to wipe BSS etc once we figure out our preferred boot method + * + * On entry we are loaded at $2000 with the loader and the loaders + * supervisor stack below us. We are in supervisor mode and the rest + * is our problem. + */ + .globl __end + .globl __bss_start + +.mri 1 + byte $15 + byte $05 + byte $C0 + byte $DE +start: + or #$0700,sr + move.l #__bss_start,a0 + move.l #__end,d0 + sub.l a0,d0 + lsr.l #2,d0 +wipebss: + clr.l (a0)+ + dbra d0,wipebss + + /* FIXME: hard coded ugly */ + move.l #udata_block+1016,a7 + /* udata global */ + move.l #udata_block,a5 + /* ensure we have bank 0 mapped */ + clr.b $00F05000 + /* Launch the OS */ + bsr init_early + bsr init_hardware + bsr fuzix_main + or #$0700,sr +stop: bra stop diff --git a/Kernel/platform-v68-softmmu/device.h b/Kernel/platform-v68-softmmu/device.h new file mode 100644 index 00000000..6f4c1e26 --- /dev/null +++ b/Kernel/platform-v68-softmmu/device.h @@ -0,0 +1,6 @@ +#ifndef __DEVICE_DOT_H__ +#define __DEVICE_DOT_H__ + +extern void mod_control(uint8_t set, uint8_t clr); + +#endif /* __DEVICE_DOT_H__ */ diff --git a/Kernel/platform-v68-softmmu/devices.c b/Kernel/platform-v68-softmmu/devices.c new file mode 100644 index 00000000..5c797330 --- /dev/null +++ b/Kernel/platform-v68-softmmu/devices.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ +// minor open close read write ioctl +// ----------------------------------------------------------------- + /* 0: /dev/hd Disc block devices */ + { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl }, + /* 1: /dev/fd Hard disc block devices (absent) */ + { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 2: /dev/tty TTY devices */ + { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, + /* 3: /dev/lpr Printer devices */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 4: /dev/mem etc System devices (one offs) */ + { no_open, no_close, sys_read, sys_write, sys_ioctl }, + /* Pack to 7 with nxio if adding private devices and start at 8 */ +}; + +bool validdev(uint16_t dev) +{ + /* This is a bit uglier than needed but the right hand side is + a constant this way */ + if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255) + return false; + else + return true; +} + +void device_init(void) +{ + int i; + + devide_init(); +} diff --git a/Kernel/platform-v68-softmmu/devtty.c b/Kernel/platform-v68-softmmu/devtty.c new file mode 100644 index 00000000..3954fa8c --- /dev/null +++ b/Kernel/platform-v68-softmmu/devtty.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include + +volatile uint8_t *uart_data = (volatile uint8_t *)0xF03000; /* UART data */ +volatile uint8_t *uart_status = (volatile uint8_t *)0xF03010; /* UART status */ + +unsigned char tbuf1[TTYSIZ]; + +struct s_queue ttyinq[NUM_DEV_TTY + 1] = { /* ttyinq[0] is never used */ + {NULL, NULL, NULL, 0, 0, 0}, + {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2}, +}; + +/* Output for the system console (kprintf etc) */ +void kputchar(char c) +{ + if (c == '\n') + tty_putc(1, '\r'); + tty_putc(1, c); +} + +ttyready_t tty_writeready(uint8_t minor) +{ + uint8_t c = *uart_status; + return (c & 2) ? TTY_READY_NOW : TTY_READY_SOON; /* TX DATA empty */ +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + *uart_data = c; /* Data */ +} + +void tty_setup(uint8_t minor) +{ +} + +int tty_carrier(uint8_t minor) +{ + return 1; +} + +void tty_sleeping(uint8_t minor) +{ +} + +/* Currently run off the timer */ +void tty_interrupt(void) +{ + uint8_t r = *uart_status; + if (r & 1) { + r = *uart_data; + tty_inproc(1,r); + } +} + +void platform_interrupt(void) +{ + timer_interrupt(); + tty_interrupt(); +} diff --git a/Kernel/platform-v68-softmmu/devtty.h b/Kernel/platform-v68-softmmu/devtty.h new file mode 100644 index 00000000..14c28c31 --- /dev/null +++ b/Kernel/platform-v68-softmmu/devtty.h @@ -0,0 +1,10 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ + +#define KEY_ROWS 8 +#define KEY_COLS 7 +extern uint8_t keymap[8]; +extern uint8_t keyboard[8][7]; +extern uint8_t shiftkeyboard[8][7]; + +#endif diff --git a/Kernel/platform-v68-softmmu/kernel.def b/Kernel/platform-v68-softmmu/kernel.def new file mode 100644 index 00000000..4e3a29f8 --- /dev/null +++ b/Kernel/platform-v68-softmmu/kernel.def @@ -0,0 +1 @@ +#define UDATA_STASH $02FFFC00 \ No newline at end of file diff --git a/Kernel/platform-v68-softmmu/libc.c b/Kernel/platform-v68-softmmu/libc.c new file mode 100644 index 00000000..e718087e --- /dev/null +++ b/Kernel/platform-v68-softmmu/libc.c @@ -0,0 +1,40 @@ +#include "cpu.h" + +void *memcpy(void *d, const void *s, size_t sz) +{ + unsigned char *dp = d; + const unsigned char *sp = s; + while(sz--) + *dp++=*sp++; + return d; +} + +void *memset(void *d, int c, size_t sz) +{ + unsigned char *p = d; + while(sz--) + *p++ = c; + return d; +} + +size_t strlen(const char *p) +{ + const char *e = p; + while(*e++); + return e-p-1; +} + +int memcmp(const void *a, const void *b, size_t n) +{ + const uint8_t *ap = a; + const uint8_t *bp = b; + while(n--) { + if (*ap < *bp) + return -1; + if (*ap != *bp) + return 1; + ap++; + bp++; + } + return 0; +} diff --git a/Kernel/platform-v68-softmmu/main.c b/Kernel/platform-v68-softmmu/main.c new file mode 100644 index 00000000..d4cfec13 --- /dev/null +++ b/Kernel/platform-v68-softmmu/main.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include + +/* FIXME don't hard code! */ +uint8_t *memtop = (uint8_t *)0x100000; +uint8_t *membase = (uint8_t *)0x018000; + +void platform_idle(void) +{ + /* FIXME: disable IRQ, run tty interrupt, re-enable ? */ +} + +void do_beep(void) +{ +} + +/* + * MMU initialize + */ + +void map_init(void) +{ +} + +void pagemap_init(void) +{ + vmmu_init(); +} + +uaddr_t ramtop; +uint8_t need_resched; + +uint8_t platform_param(char *p) +{ + return 0; +} + +void platform_discard(void) +{ +} + +void platform_mmu_setup(struct mmu_context *m) +{ + /* Allocate an initial space for the init task that will hold + the execve arguments and be freed when init loads */ + m->base = vmmu_alloc(&m->mmu, MMU_BLKSIZE, 0, 0, 1); + if (m->base == NULL) + panic("initmmu"); + kprintf("init boot at %p\n", m->base); +} + +void fast_zero_block(void *p) +{ + memset(p, 0, MMU_BLKSIZE); +} + +void fast_swap_block(void *ap, void *bp) +{ + /* TODO */ + uint32_t *a = ap, *b = bp; + int n = 0; + while(n++ < MMU_BLKSIZE/4) { + uint32_t t = *a; + *a++ = *b; + *b++ = t; + } +} + +void fast_copy_block(void *a, void *b) +{ + /* TODO */ + memcpy(a, b, MMU_BLKSIZE); +} + +void fast_op_complete(void) +{ +} + + +/* Live udata and kernel stack for each process */ +/* FIXME: we need to find a way to make these smaller or bank them out but + that has a material cost */ + +u_block udata_block[PTABSIZE]; +uint16_t irqstack[128]; + +/* This will belong in the core 68K code once finalized */ + +void install_vdso(void) +{ + extern uint8_t vdso[]; + /* Should be uput etc */ + memcpy((void *)udata.u_codebase, &vdso, 0x40); +} + +extern void *get_usp(void); +extern void set_usp(void *p); + +void signal_frame(uint8_t *trapframe, uint32_t d0, uint32_t d1, uint32_t a0, + uint32_t a1) +{ + extern void *udata_shadow; + uint8_t *usp = get_usp(); + udata_ptr = udata_shadow; + uint16_t ccr = *(uint16_t *)trapframe; + uint32_t addr = *(uint32_t *)(trapframe + 2); + int err = 0; + + /* Build the user stack frame */ + + /* FIXME: eventually we should put the trap frame details and trap + info into the frame */ + usp -= 4; + err |= uputl(addr, usp); + usp -= 4; + err |= uputw(ccr, usp); + usp -= 2; + err |=uputl(a1, usp); + usp -= 4; + err |= uputl(a0, usp); + usp -= 4; + err |= uputl(d1, usp); + usp -= 4; + err |= uputl(d0, usp); + usp -= 4; + err |= uputl(udata.u_codebase + 4, usp); + set_usp(usp); + + if (err) { + kprintf("%d: stack fault\n", udata.u_ptab->p_pid); + doexit(dump_core(SIGKILL)); + } + /* Now patch up the kernel frame */ + *(uint16_t *)trapframe = 0; + *(uint32_t *)(trapframe + 2) = (uint32_t)udata.u_sigvec[udata.u_cursig]; + udata.u_sigvec[udata.u_cursig] = SIG_DFL; + udata.u_cursig = 0; +} + diff --git a/Kernel/platform-v68-softmmu/p68000.S b/Kernel/platform-v68-softmmu/p68000.S new file mode 100644 index 00000000..9a8d6fd5 --- /dev/null +++ b/Kernel/platform-v68-softmmu/p68000.S @@ -0,0 +1,191 @@ + +#include "../kernel-68000.def" +/* + * Lots left to fill in + */ + + .globl trap_reboot + .globl init_early + .globl init_hardware + .globl program_vectors + .globl outchar + .globl trap_monitor + .globl udata_block + .globl devide_read_data + .globl devide_write_data + .globl vdso +.mri 1 +trap_reboot: +trap_monitor: + or #0700,sr + bra trap_monitor + +init_early: + lea.l udata_block,a5 ; udata ptr + move.l a5,udata_shadow ; shadow copy for entry/exit + rts + +; +; FIXME: could be in discard if we wanted +; +init_hardware: + ; set system RAM size(hadcode hacks for now) + move.w #512,d0 + move.w d0,ramsize + sub.w #64,d0 ; Guess for kernel + move.w d0,procmem ; guesses for now + + move.l #0,a0 + move.w #256,d0 + move.l #unexpected,d1 +init_trap_loop: + move.l d1,(a0)+ + dbra d0,init_trap_loop + ; + ; Now set the vectors we care about + ; + move.w #8,a0 + move.l #bus_error,(a0)+ + move.l #addr_error,(a0)+ + move.l #illegal,(a0)+ + move.l #divzero,(a0)+ + move.l #chk,(a0)+ + move.l #trapv,(a0)+ + move.l #priv,(a0)+ + move.l #trace,(a0)+ + move.l #unimpa,(a0)+ ; A and F line traps + move.l #unimpf,(a0)+ + move.w #$80,a0 + move.w #13,d0 +trapset: + move.l #misctrap,(a0)+ + dbra d0,trapset + move.l #trap14,(a0)+ + move.l #trap15,(a0)+ + move.w #$0,a0 + move.l #uninit,$3c(a0) + move.l #spurious,$60(a0) + move.l #timer_irq,$78(a0) + move.l #mmu_fault,$7C(a0) + + moveq #1,d0 ; + move.b d0,$00F04000 + rts + +timer_irq: + ; C will save and restore a2+/d2+ + movem.l a0-a1/a5/d0-d1,-(sp) + move.l udata_shadow,a5 ; set up the register global + move.b #1,U_DATA__U_ININTERRUPT(a5) + jsr platform_interrupt + clr.b U_DATA__U_ININTERRUPT(a5) + move.b $00F04000,d0 ; Re-enable + + ; DEBUG FIXME + bra no_signal + + tst.b U_DATA__U_INSYS(a5) + bne no_preempt + tst.b need_resched + bne no_preempt + ; + ; Vanish into the scheduler. Some other task will pop back out + ; and eventually we'll re-appear here and continue. + ; + ; FIXME: check IRQ masking + ; + move.l U_DATA__U_PTAB(a5),a0 + move.b #P_READY,P_TAB__P_STATUS_OFFSET(a0) + bsr switchout +no_preempt: + tst.b U_DATA__U_CURSIG(a5) + beq no_signal + bra trap_via_signal ; a0/a1/d0/d1 already stacked + +no_signal: + movem.l (sp)+,a0-a1/a5/d0-d1 + rte + +mmu_fault: + tst.w $00F02020 ; clear the MMU flag + move.l d0,-(sp) + move.b #'M',d0 + jsr outchar + move.l (sp)+,d0 + bra addr_error ; treat as an address error + +; +; Nothing to do in 68000 - all set up once at boot +; +program_vectors: + rts + +; +; TODO +; +map_process_always: +map_process: +map_kernel: +map_restore: +map_save: + rts + +; outchar: Wait for UART TX idle, then print the char in d0 + +outchar: + move.w d0,-(sp) +outcharw: + move.b $00F03010,d0 + btst #1,d0 + beq outcharw + move.w (sp)+,d0 + move.b d0,$00F03000 + rts + +; +; IDE +; +devide_read_data: + move.l blk_op,a0 + move.b 4(a0),d0 + move.b $00F05000,d1 + cmp.b #2,d0 + bne notswap + move.b 5(a0),$00F05000 +notswap: + move.w #255,d0 +devide_read_l: + move.w $00F01000,(a0)+ + dbra d0,devide_read_l + move.b d1,$00F05000 + rts + +devide_write_data: + move.l blk_op,a0 + move.b 4(a0),d0 + move.b $00F05000,d1 + cmp.b #2,d0 + bne notswapw + move.b 5(a0),$00F05000 +notswapw: + move.w #255,d0 +devide_write_l: + move.w (a0)+,$00F01000 + dbra d0,devide_write_l + move.b d1,$00F05000 + rts + +; +; 'VDSO' +; +vdso: trap #14 ; syscall entry + rts + ; signal unwind + movem.l (sp)+,a0/a1/d0/d1 + move.w (sp)+,ccr + rts + ; rest is spare for now + +.section data + +kernel_flag: byte 1 diff --git a/Kernel/platform-v68-softmmu/platform_ide.h b/Kernel/platform-v68-softmmu/platform_ide.h new file mode 100644 index 00000000..6e9d56c8 --- /dev/null +++ b/Kernel/platform-v68-softmmu/platform_ide.h @@ -0,0 +1,18 @@ +#define IDE_IS_MMIO 1 /* MMIO IDE */ + +#define IDE_REG_DATA 0x00F01000 +#define IDE_REG_ERROR 0x00F01002 +#define IDE_REG_FEATURES 0x00F01002 +#define IDE_REG_SEC_COUNT 0x00F01004 +#define IDE_REG_LBA_0 0x00F01006 +#define IDE_REG_LBA_1 0x00F01008 +#define IDE_REG_LBA_2 0x00F0100A +#define IDE_REG_LBA_3 0x00F0100C +#define IDE_REG_DEVHEAD 0x00F0100C +#define IDE_REG_STATUS 0x00F0100E +#define IDE_REG_COMMAND 0x00F0100E +#define IDE_REG_ALTSTATUS 0x00F01010 +#define IDE_REG_CONTROL 0x00F01010 + +#define ide_select(x) +#define ide_deselect() diff --git a/Kernel/platform-v68-softmmu/target.mk b/Kernel/platform-v68-softmmu/target.mk new file mode 100644 index 00000000..df1c235f --- /dev/null +++ b/Kernel/platform-v68-softmmu/target.mk @@ -0,0 +1 @@ +export CPU = 68000 diff --git a/Kernel/platform-v68-softmmu/tricks.S b/Kernel/platform-v68-softmmu/tricks.S new file mode 100644 index 00000000..0175d60c --- /dev/null +++ b/Kernel/platform-v68-softmmu/tricks.S @@ -0,0 +1,140 @@ +#include "../kernel-68000.def" +#include "kernel.def" + + +.globl switchout,switchin,dofork,udata_shadow + +.mri 1 + +; 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(). +switchout: + or #$0700,sr + bsr chksigs + ; save machine state + + clr.w -(sp) ; 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: + move.l usp,a0 + movem.l a0/a2-a4/a6/d2-d7,-(sp) + move.l sp,U_DATA__U_SP(a5) ; this is where the SP is restored in switchin + + ; find another process to run (may select this one again) + bsr getproc + + move.l d0,-(sp) + bsr switchin + + ; we should never get here + bra trap_monitor + +switchin: + or #$0700,sr + move.l 4(sp),a0 ; task to switch to + + ; + ; Now switch task context + ; + move.l P_TAB__P_UDATA_OFFSET(a0),a5 + move.l a5,udata_shadow + + ; Swap support needs to go here once we have the software + ; MMU stable ? + + move.l P_TAB__P_UDATA_OFFSET(a0),a5 + move.l a0,-(sp) + move.l a0,-(sp) + jsr pagemap_switch + addq #4,sp + move.l (sp)+,a0 + + move.l P_TAB__P_UDATA_OFFSET(a0),a5 + ; check u_data->u_ptab matches what we wanted + cmp.l U_DATA__U_PTAB(a5),a0 + bne switchinfail + + move.b #P_RUNNING,P_TAB__P_STATUS_OFFSET(a0) + move.w P_TAB__P_PAGE_OFFSET(a0),U_DATA__U_PAGE(a5) + + ; runticks = 0 + clr.w runticks + + ; restore machine state + move.l U_DATA__U_SP(a5),sp + movem.l (sp)+,a0/a2-a4/a6/d2-d7 + move.l a0,usp + move.w (sp)+,d0 ; FIXME: can we merge ? + + tst.b U_DATA__U_ININTERRUPT(a5) + bne keepoff ; in ISR, leave interrupts off + and #$F8FF,sr +keepoff: + rts ; return with interrupts on + +switchinfail: + bsr outa0hex + lea badswitchmsg,a0 + bsr outstring + ; something went wrong and we didn't switch in what we asked for + bra trap_monitor + + ; + ; this gets exciting on the 68000 because our udata is not in a + ; fixed location except for swap only platforms. That means any + ; udata relative pointers on the stack when we duplicate the kernel + ; stack point to the parent. For the simple case we have a single + ; swapped udata and stack so all is fairly easy. For the other + ; cases we have to return as the parent but set up a fake stack + ; frame for the child to exit the syscall. Simply being careful + ; about pointers doesn't work - the compiler will internally + ; use link/unlk and other stuff. + ; + ; Entry: + ; A5 = u_data pointer for parent + ; 4(sp) = child process table entry + ; + ; Exit: + ; We are running as the child, A5 = u_data pointer of child, on + ; child stack and leap directly back to user mode + ; +dofork: + moveq #-1,d0 + rts + ; + ; We need the child to return off its own stack so this is very + ; different to other platforms. + ; + move.l 4(sp),a0 ; child p_tab + ; + ; in the simple case we only have one udata. In the complex cases + ; we would have to compute the new one and load it into a5 and + ; offset + + ; + ; Set up a switchin frame for the parent process + ; + move.w P_TAB__P_PID_OFFSET(a0),-(sp) ; child pid (parent return) + move.l usp,a0 + movem.l a0/a2-a4/a6/d2-d7,-(sp) ; save state + move.l sp,U_DATA__U_SP(a5) ; save pointer + + move.l a0,-(sp) ; argument to newproc + move.w P_TAB__P_PAGE_OFFSET(a0),d0 ; page + +; jsr bankfork ; copy the memory + + move.l (sp),a0 + + jsr newproc ; Called with the child udata + add.w #54,sp ; toss the stack frames + + clr.w runticks + moveq #0,d0 ; child + rts + +badswitchmsg: ascii "_switchin: FAIL" + byte 13,10,0 +.even -- 2.34.1