--- /dev/null
+
+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
--- /dev/null
+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.
+
--- /dev/null
+/* 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+#ifndef __DEVICE_DOT_H__
+#define __DEVICE_DOT_H__
+
+extern void mod_control(uint8_t set, uint8_t clr);
+
+#endif /* __DEVICE_DOT_H__ */
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devide.h>
+#include <blkdev.h>
+#include <devsys.h>
+#include <tty.h>
+#include <vt.h>
+
+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();
+}
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <device.h>
+#include <tty.h>
+
+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();
+}
--- /dev/null
+#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
--- /dev/null
+#define UDATA_STASH $02FFFC00
\ No newline at end of file
--- /dev/null
+#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;
+}
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <flat_mem.h>
+
+/* 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;
+}
+
--- /dev/null
+
+#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
--- /dev/null
+#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()
--- /dev/null
+export CPU = 68000
--- /dev/null
+#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