From e1c6f446165406a1667f5308588c4cfd6049b41a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 3 Nov 2016 17:45:46 +0000 Subject: [PATCH] v68: initial pieces for a banked memory version of v68 This is a stepping stone to MMU supporting versions, but also relevant to systems like the N8VEM 68000 board where you have 4MB in 1MB windows, which with the low 64K memory protection is almost ideal for running a Unixlike OS single user. --- Kernel/platform-v68-banked/Makefile | 43 +++++ Kernel/platform-v68-banked/README | 17 ++ Kernel/platform-v68-banked/config.h | 53 ++++++ Kernel/platform-v68-banked/crt0.S | 34 ++++ Kernel/platform-v68-banked/device.h | 6 + Kernel/platform-v68-banked/devices.c | 45 +++++ Kernel/platform-v68-banked/devtty.c | 65 +++++++ Kernel/platform-v68-banked/devtty.h | 10 ++ Kernel/platform-v68-banked/libc.c | 40 +++++ Kernel/platform-v68-banked/main.c | 116 +++++++++++++ Kernel/platform-v68-banked/p68000.S | 191 ++++++++++++++++++++ Kernel/platform-v68-banked/platform_ide.h | 18 ++ Kernel/platform-v68-banked/target.mk | 1 + Kernel/platform-v68-banked/tricks.S | 201 ++++++++++++++++++++++ 14 files changed, 840 insertions(+) create mode 100644 Kernel/platform-v68-banked/Makefile create mode 100644 Kernel/platform-v68-banked/README create mode 100644 Kernel/platform-v68-banked/config.h create mode 100644 Kernel/platform-v68-banked/crt0.S create mode 100644 Kernel/platform-v68-banked/device.h create mode 100644 Kernel/platform-v68-banked/devices.c create mode 100644 Kernel/platform-v68-banked/devtty.c create mode 100644 Kernel/platform-v68-banked/devtty.h create mode 100644 Kernel/platform-v68-banked/libc.c create mode 100644 Kernel/platform-v68-banked/main.c create mode 100644 Kernel/platform-v68-banked/p68000.S create mode 100644 Kernel/platform-v68-banked/platform_ide.h create mode 100644 Kernel/platform-v68-banked/target.mk create mode 100644 Kernel/platform-v68-banked/tricks.S diff --git a/Kernel/platform-v68-banked/Makefile b/Kernel/platform-v68-banked/Makefile new file mode 100644 index 00000000..b6f97c9d --- /dev/null +++ b/Kernel/platform-v68-banked/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 ../simple.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 ../swap.o ../buddy.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-banked/README b/Kernel/platform-v68-banked/README new file mode 100644 index 00000000..a7e2b645 --- /dev/null +++ b/Kernel/platform-v68-banked/README @@ -0,0 +1,17 @@ +See platform-v68 + +This is a test tree for a configuration using banked memory (N8VEM 680x0 +style) + + +TODO +- Make bankfixed support 32bit +- Make bankfixed support only writing out used areas of memory + +Look at bankfixed/bankfixed32 split - put the smarts in bankfixed32 and then +look at a proper swap allocator so we don't waste tons of memory. + +- Write the bank copy routines (copy needed bits zero rest and optimise) +- Write optimised udata copier ? + + diff --git a/Kernel/platform-v68-banked/config.h b/Kernel/platform-v68-banked/config.h new file mode 100644 index 00000000..373c5097 --- /dev/null +++ b/Kernel/platform-v68-banked/config.h @@ -0,0 +1,53 @@ +/* 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 +/* This works for banks as kernel is not banked, but won't work when we go + real MMU */ +#define CONFIG_USERMEM_DIRECT +#define CONFIG_BANK_FIXED +#define MAX_MAPS 4 +#define MAPBASE 0x00200000 +#define MAP_SIZE 0x00100000 + +#define CONFIG_BANKS 1 +#define PROC_SIZE MAP_SIZE /* 1MB */ + +#define CONFIG_SPLIT_UDATA +#define UDATA_SIZE 1024 +#define UDATA_BLKS 2 + +#define PROGBASE MAPBASE +#define PROGTOP (MAPBASE + MAP_SIZE) +#define SWAP_SIZE ((MAP_SIZE/512) + 2) /* 2 for the udata */ +#define SWAPBASE PROGBASE +#define SWAPTOP PROGTOP +#define MAX_SWAPS 3 /* So can reuse the same fs */ + /* Use a bigger swap area for real uses ! */ +#define swap_map(x) ((uint8_t *)(x)) + +#define SWAPDEV (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-banked/crt0.S b/Kernel/platform-v68-banked/crt0.S new file mode 100644 index 00000000..9b7796cb --- /dev/null +++ b/Kernel/platform-v68-banked/crt0.S @@ -0,0 +1,34 @@ +/* + * 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 + bsr init_early + bsr init_hardware + bsr fuzix_main + or #$0700,sr +stop: bra stop diff --git a/Kernel/platform-v68-banked/device.h b/Kernel/platform-v68-banked/device.h new file mode 100644 index 00000000..6f4c1e26 --- /dev/null +++ b/Kernel/platform-v68-banked/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-banked/devices.c b/Kernel/platform-v68-banked/devices.c new file mode 100644 index 00000000..3c1bef54 --- /dev/null +++ b/Kernel/platform-v68-banked/devices.c @@ -0,0 +1,45 @@ +#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(); + + for (i = 1; i <= MAX_SWAPS; i++) + swapmap_add(i); +} diff --git a/Kernel/platform-v68-banked/devtty.c b/Kernel/platform-v68-banked/devtty.c new file mode 100644 index 00000000..3954fa8c --- /dev/null +++ b/Kernel/platform-v68-banked/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-banked/devtty.h b/Kernel/platform-v68-banked/devtty.h new file mode 100644 index 00000000..14c28c31 --- /dev/null +++ b/Kernel/platform-v68-banked/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-banked/libc.c b/Kernel/platform-v68-banked/libc.c new file mode 100644 index 00000000..e718087e --- /dev/null +++ b/Kernel/platform-v68-banked/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-banked/main.c b/Kernel/platform-v68-banked/main.c new file mode 100644 index 00000000..d5f293ee --- /dev/null +++ b/Kernel/platform-v68-banked/main.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include + +void platform_idle(void) +{ + /* FIXME: disable IRQ, run tty interrupt, re-enable ? */ +} + +void do_beep(void) +{ +} + +/* + * MMU initialize + */ + +void map_init(void) +{ +} + +uaddr_t ramtop; +uint8_t need_resched; + +uaddr_t pagemap_base(void) +{ + return 0x20000UL; +} + +uint8_t platform_param(char *p) +{ + return 0; +} + +void platform_discard(void) +{ +} + +void memzero(void *p, usize_t len) +{ + memset(p, 0, len); +} + +arg_t _memalloc(void) +{ + udata.u_error = ENOSYS; + return -1; +} + +arg_t _memfree(void) +{ + udata.u_error = ENOSYS; + return -1; +} + +/* 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]; + +/* 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-banked/p68000.S b/Kernel/platform-v68-banked/p68000.S new file mode 100644 index 00000000..f06ad0b7 --- /dev/null +++ b/Kernel/platform-v68-banked/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 0x00F05000,d1 + cmp.b d0,#2 + bne motswap + move.b 5(a0),0x00F05000 +notswap: + move.w #255,d0 +devide_read_l: + move.w $00F01000,(a0)+ + dbra d0,devide_read_l + move.b d1,0x00F05000 + rts + +devide_write_data: + move.l blk_op,a0 + move.b 4(a0),d0 + move.b 0x00F05000,d1 + cmp.b d0,#2 + bne motswapw + move.b 5(a0),0x00F05000 +notswapw: + move.w #255,d0 +devide_write_l: + move.w (a0)+,$00F01000 + dbra d0,devide_write_l + move.b d1,0x00F05000 + 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-banked/platform_ide.h b/Kernel/platform-v68-banked/platform_ide.h new file mode 100644 index 00000000..6e9d56c8 --- /dev/null +++ b/Kernel/platform-v68-banked/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-banked/target.mk b/Kernel/platform-v68-banked/target.mk new file mode 100644 index 00000000..df1c235f --- /dev/null +++ b/Kernel/platform-v68-banked/target.mk @@ -0,0 +1 @@ +export CPU = 68000 diff --git a/Kernel/platform-v68-banked/tricks.S b/Kernel/platform-v68-banked/tricks.S new file mode 100644 index 00000000..1d82a8a5 --- /dev/null +++ b/Kernel/platform-v68-banked/tricks.S @@ -0,0 +1,201 @@ +#include "../kernel-68000.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 + ; + ; keep a fast path for wakeup of the last executed process + ; + tst.b nready + bne slow_path +idling: + and #$F8FF,sr + jsr platform_idle + or #$0700,sr + move.b nready,d0 + beq idling + cmp.b #1,d0 + bne slow_path + move.l U_DATA__U_PTAB(a5),a0 + cmp.b #P_READY,P_TAB__P_STATUS(a0) + bne slow_path + mov.b #P_RUNNING,P_TAB_P_STATUS(a0) + movem.l (sp)+,a0/a2-a4/a6/d2-d7 + addq #2,sp + and #$F8FF,sr + rts + +slow_path: + lea.l udata_stash,a0 + move.l a5,a1 + move.w #255,d0 + ; FIXME - optimise 1K copy +copyi: move.l (a1)+,(a0)+ + dbra d0,copyi + + ; 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 + + ; + ; We are going to copy over the process stack so use the + ; other stack for this + ; + lea.l #irqstack+256,sp ; switch stack to copy the udata/stack + + ; + ; Now switch task context + ; + move.l P_TAB__P_UDATA_OFFSET(a0),a5 + tst.w P_TAB__P_PAGE_OFFSET(a0) ; swapped or existing process ? + bne not_swapped + +; +; FIXME: sort IRQ enables +; + + move.l a0,-(sp) + move.l a0,-(sp) + jsr swapper + addq #4,sp + move.l (sp)+,a0 + + or #$0700,sr + +not_swapped: + move.w P_TAB__P_PAGE_OFFSET(a0),d0 + ; switch memory bank + move.b d0,$FFF05000 + ; is the cached udata still valid ? + move.l P_TAB__P_UDATA_OFFSET(a0),a5 + cmp.l U_DATA__U_PTAB(a5),a0 + beq skip_copyback + ; + ; Recover the udata block + ; + lea.l udata_stash,a1 + move.w #255,d0 +copyo: + move.l (a1)+,(a5)+ + dbra d0,copyo + +skip_copyback: + 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: + ; + ; 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 + + jsr bankfork ; copy the memory + + move.l a0,-(sp) ; argument to newproc + ; Save the udata + move.l a5,a0 + lea.l udata_stash,a1 + move.w #255,d0 +copyf: move.l (a0)+,(a1)+ + dbra d0,copyf + + ; switch memory bank + move.l (s0),a0 + move.w P_TAB__P_PAGE_OFFSET(a0),d0 + move.b d0,$FFF05000 + + 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