--- /dev/null
+
+CSRCS = devtty.c
+CSRCS += devices.c main.c libc.c biosdisk.c
+
+ASRCS = ibmpc.S crt0.S
+ASRCS += tricks.S
+
+COBJS = $(CSRCS:.c=$(BINEXT))
+AOBJS = $(ASRCS:.S=.o)
+OBJS = $(COBJS) $(AOBJS) $(DOBJS)
+
+JUNK = $(CSRCS:.c=.o) $(ASRCS:.S=.o)
+
+all: $(OBJS)
+
+$(COBJS): %.o: %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.o: %.S
+ $(CROSS_AS) $(ASOPTS) -c $<
+
+clean:
+ rm -f $(OBJS) $(JUNK) core *~
+
+image:
+ $(CROSS_LD) -M -o fuzix.elf -T fuzix.ld \
+ crt0.o \
+ ../start.o ../version.o ../lowlevel-8086.o \
+ main.o ../swap.o ../timer.o ../simple.o ../kdata.o devices.o \
+ ../tty.o ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
+ ibmpc.o ../syscall_proc.o ../syscall_other.o ../mm.o \
+ ../devsys.o ../usermem.o ../syscall_exec16.o ../syscall_fs2.o \
+ tricks.o ../syscall_fs3.o biosdisk.o \
+ ../usermem_std-8086.o devtty.o libc.o > ../fuzix.map
--- /dev/null
+At the moment this is just build testing the core code and totally incomplete
+(no usable drivers, no loader, no task switching, no __ashldi/rdi stubs and
+tons more)
+
--- /dev/null
+
+extern uint8_t biosdata_read(uint16_t offset);
+
+extern uint16_t bioshd_reset(uint16_t drive);
+extern uint32_t bioshd_param(uint16_t drive);
+extern uint32_t bioshd_read(uint16_t cylsec, uint8_t dev, uint8_t head,
+ uint16_t page, uint16_t dptr, uint16_t len);
+extern uint32_t bioshd_write(uint16_t cylsec, uint8_t dev, uint8_t head,
+ uint16_t page, uint16_t dptr, uint16_t len);
+
+extern uint16_t kernel_ds;
+extern uint16_t equipment_word;
--- /dev/null
+/*
+ * PC BIOS disk driver
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devhd.h>
+#include <bios.h>
+
+#define MAX_HD 4
+
+struct disk_geom {
+ uint8_t secs;
+ uint8_t heads;
+ uint16_t cyls;
+ uint8_t max;
+ uint8_t dev;
+};
+
+static uint8_t floppies;
+static uint8_t nfloppy;
+static uint8_t nhd;
+
+static struct disk_geom floppy[4];
+static struct disk_geom harddisk[MAX_HD];
+
+static int bios_transfer(bool is_read, uint8_t rawflag,
+ struct disk_geom *g);
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;
+ return bios_transfer(true, rawflag, &floppy[minor]);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;
+ return bios_transfer(false, rawflag, &floppy[minor]);
+}
+
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;
+ return bios_transfer(true, rawflag, &harddisk[minor]);
+}
+
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;
+ return bios_transfer(false, rawflag, &harddisk[minor]);
+}
+
+static int bios_transfer(bool is_read, uint8_t rawflag, struct disk_geom *g)
+{
+ uint16_t dptr;
+ uint16_t ct = 0;
+ uint32_t st;
+ int map = 0;
+ uint16_t page = kernel_ds;
+ uint16_t left;
+ uint16_t cylsec;
+ uint8_t tries;
+
+ /* Sort the actual request out */
+ if(rawflag == 1) {
+ if (d_blkoff(9))
+ return -1;
+ map = 1;
+ page = udata.u_page;
+#ifdef SWAPDEV
+ } else if (rawflag == 2) { /* Swap device special */
+ page = swappage; /* Acting on this page */
+ map = 1;
+#endif
+ }
+
+ dptr = (uint16_t)udata.u_dptr;
+ left = udata.u_nblock;
+
+ /* Try and read as much as we can in one go */
+ while (ct < udata.u_nblock) {
+ uint16_t n = left;
+ uint8_t sec = udata.u_block % g->secs + 1;
+ uint16_t cyl = udata.u_block / g->secs;
+ uint8_t head = cyl / g->cyls;
+ cyl %= g->cyls;
+ cylsec = (cyl << 8) | sec;
+ cylsec |= (cyl & 0x300) >> 10;
+
+ if (n > g->max)
+ n = g->max;
+
+ /* Try the I/O multiple times if it fails */
+ for (tries = 0; tries < 3; tries ++) {
+ if (is_read)
+ st = bioshd_read(cylsec, g->dev, head, page, dptr, n);
+ else
+ st = bioshd_write(cylsec, g->dev, head, page, dptr, n);
+ /* st will be 00:secs, or 00:random, depending upon the BIOS
+ if we succeeded. If CF is set and it's unknown we'll return
+ 0xFFxxxx */
+ if (st <= 0xFF)
+ break;
+ /* Try and do partial writes, also try and deal with any crap
+ BIOS that can't handle multi-track */
+ if (tries == 2) {
+ bioshd_reset(g->dev);
+ n = 1;
+ }
+ }
+ if (tries == 3) {
+ kprintf("bios disk %d: block %d, error %d\n", g->dev, udata.u_block, st);
+ break;
+ }
+ /* Adjust all our status */
+ udata.u_block += n;
+ ct += n;
+ left -= n;
+ dptr += n << 9;
+ }
+ return ct << 9;
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+ if (!(floppies & (1 << minor))) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ return 0;
+}
+
+int hd_open(uint8_t minor, uint16_t flag)
+{
+ if (minor >= nhd) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ return 0;
+}
+
+void biosdisk_init(void)
+{
+ struct disk_geom *p = harddisk;
+ uint32_t bits;
+ uint16_t dx,cx;
+ int i;
+
+ /* How many disks do we have and what sort ? */
+ nfloppy = equipment_word & 0x01;
+ if (nfloppy)
+ nfloppy = 1 + (equipment_word >> 6) & 3;
+ for (i = 0; i < nfloppy; i++) {
+ bits = bioshd_param(i);
+ if (bits == 0xFFFF)
+ continue;
+ dx = bits >> 16;
+ cx = bits;
+ floppy[i].heads = dx >> 8;
+ floppy[i].cyls = cx >> 8;
+ floppy[i].secs = cx & 0x3F;
+ floppy[i].cyls |= ((cx & 0xC0) << 2);
+ floppy[i].dev = i;
+ /* Keep to sectors/track or less */
+ floppy[i].max = cx & 0x3F;
+ }
+ /* Now the hard disks.. This is so much more fun. We need to be careful
+ not to read further once we have all the disks we should as the BIOS
+ may make up imaginary drives! */
+ nhd = biosdata_read(0x75); /* Because we can't trust anything else */
+ for (i = 0; i < 0x7f && nhd; i++) {
+ bits = bioshd_param(0x80 + i);
+ if (bits == 0xFFFF)
+ continue;
+ nhd--;
+ p->heads = dx >> 8;
+ p->cyls = cx >> 8;
+ p->secs = cx & 0x3F;
+ p->cyls |= ((cx & 0xC0) << 2);
+ /* Assume the BIOS can multitrack.. we may want to be cautious about
+ this for old 8086 boxes */
+ p->max = 255;
+ p->dev = 0x80 + i;
+ p++;
+ }
+ nhd = i;
+}
--- /dev/null
+/* Enable to make ^Z dump the inode table for debug */
+#undef 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_MULTI
+#define CONFIG_SWAP_ONLY
+#define CONFIG_USERMEM_DIRECT
+#define CONFIG_BANKS 1
+#define PROC_SIZE 128 /* 64K, 128 * 512 */
+
+#define CONFIG_SPLIT_UDATA
+#define UDATA_SIZE 512
+#define UDATA_BLKS 1
+
+#define PROGBASE 0x8000UL
+#define PROGLOAD PROGBASE
+#define PROGTOP 0xE000UL
+#define SWAP_SIZE (130 + 2) /* 2 for the udata */
+#define SWAPBASE PROGBASE
+#define SWAPTOP 0xE000UL
+#define MAX_SWAPS PTABSIZE /* Mandatory for swap only */
+#define swap_map(x) ((uint8_t *)(x))
+
+#define SWAPDEV (1)
+
+#define TICKSPERSEC 50 /* 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 6 /* Number of block buffers */
+#define NMOUNTS 2 /* Number of mounts at a time */
--- /dev/null
+ .arch i8086,jumps
+ .code16
+ .att_syntax prefix
+
+ .text
+
+ .global kstack_top
+ .global init_early
+ .global init_hardware
+ .global fuzix_main
+ .global __bss_start
+ .global __end
+
+start:
+ movw $kstack_top,%sp /* Set the stack */
+ movw $__bss_start,%si /* Wipe the BSS */
+ movw $__bss_start+1,%di
+ movw $__end,%cx
+ subw $__bss_start+1,%cx
+ movb $0,(%si)
+ rep
+ movsb
+
+ call init_early
+ call init_hardware
+ call fuzix_main
+1:
+ jmp 1b
+
--- /dev/null
+extern int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+extern int fd_open(uint8_t minor, uint16_t flag);
+extern int hd_open(uint8_t minor, uint16_t flag);
--- /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 <devsys.h>
+#include <tty.h>
+#include <vt.h>
+#include <devhd.h>
+
+struct devsw dev_tab[] = /* The device driver switch table */
+{
+// minor open close read write ioctl
+// -----------------------------------------------------------------
+ /* 0: /dev/hd Disc block devices */
+ { hd_open, no_close, hd_read, hd_write, no_ioctl },
+ /* 1: /dev/fd Hard disc block devices (absent) */
+ { fd_open, no_close, fd_read, fd_write, 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) - 1)
+ return false;
+ else
+ return true;
+}
+
+void device_init(void)
+{
+ int i;
+
+ for (i = 1; i <= MAX_SWAPS; i++)
+ swapmap_init(i);
+}
--- /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
+STARTUP(crt0.o)
+OUTPUT_ARCH(i8086)
+
+
+SEARCH_DIR(.)
+
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x1000, LENGTH = 0xE000
+}
+
+/*
+ * stick everything in ram (of course)
+ */
+SECTIONS
+{
+ .text :
+ {
+ CREATE_OBJECT_SYMBOLS
+ *(.text .text.*)
+
+ . = ALIGN(0x4);
+ /* These are for running static constructors and destructors under ELF. */
+
+ *(.rodata .rodata.*)
+
+ . = ALIGN(0x4);
+ *(.gcc_except_table)
+
+ . = ALIGN(0x4);
+ *(.eh_frame)
+
+ . = ALIGN(0x4);
+ _etext = .;
+ *(.lit)
+ } > ram
+
+ .data :
+ {
+ *(.got.plt) *(.got)
+ *(.shdata)
+ *(.data .data.*)
+ _edata = .;
+ } > ram
+
+ .bss :
+ {
+ . = ALIGN(0x4);
+ __bss_start = . ;
+ *(.shbss)
+ *(.bss .bss.*)
+ *(COMMON)
+ _end = ALIGN (0x8);
+ __end = _end;
+ } > ram
+
+ .stab 0 (NOLOAD) :
+ {
+ *(.stab)
+ }
+
+ .stabstr 0 (NOLOAD) :
+ {
+ *(.stabstr)
+ }
+}
--- /dev/null
+ .arch i8086,jumps
+ .code16
+ .att_syntax prefix
+ .data
+
+ .global udata
+ .global kstack_top
+ .global istack_top
+
+udata:
+ .bss 512
+kstack_top:
+ .bss 256
+istack_top:
+
+ .text
+
+ .global init_early
+ .global init_hardware
+ .global program_vectors
+ .global trap_monitor
+ .global trap_reboot
+ .global kernel_ds
+
+ .global bioshd_param
+ .global bioshd_read
+ .global bioshd_write
+ .global bioshd_reset
+ .global biosdata_read
+ .global equipment_word
+
+
+init_early:
+ /* Dig useful information out of the BIOS */
+ int $11
+ mov %ax,equipment_word
+ int $12
+ mov %ax,ramsize
+ ret
+init_hardware:
+ ret
+program_vectors:
+ ret
+trap_monitor:
+trap_reboot:
+ jmp trap_monitor
+
+/* Returns the BIOS parameter data CX:DX as a long DX:AX to the C code or
+ FFFF if we don't get the right answer
+
+ Things to note this being PC BIOS land
+ - bl return is not reliable for floppies (nor sometimes %cx)
+ - es:di is not reliably set by the BIOS
+ - you must do an int 13 ah=0x01 after this call on PS/2 model 30
+ - some junk leaves interrupts disabled after this call
+ - Leading Edge BIOSes may trash di/si/bp/ds/es !
+ - Some Compaq BIOSes will make stuff up for drive numbers above
+ the last one we use
+
+ long bioshd_param(int drive)
+*/
+bioshd_param:
+ pushw %bp
+ movw %sp,%bp
+ movw $0x0800,%ax /* get drive parameters */
+ movw 4(%bp),%dx
+ pushf
+ stc
+ pushw %di
+ pushw %si
+ pushw %bp
+ pushw %ds
+ int $13
+ popw %ds
+ movw %ds,%ax
+ movw %ax,%es
+ popw %bp
+ popw %si
+ popw %di
+ jc bioshd_fail
+ popf
+ pushw %cx
+ pushw %dx
+ movw 4(%bp),%dx /* drive number */
+ movb $1,%ah
+ int $13
+ popw %dx
+ popw %ax
+ popw %bp
+ ret
+bioshd_fail:
+ popf
+ popw %bp
+ mov $0xFF,%ax
+ mov %ax,%dx
+ ret
+
+bioshd_status:
+ pushw %bp
+ movw %sp,%bp
+ movw 4(%bp),%dx
+ movb $1,%ah
+ int $13
+ popw %bp
+ ret
+
+bioshd_reset:
+ xorb %ah,%ah
+ pushw %bp
+ movw %sp,%bp
+ movw 4(%bp),%dx
+ int $13
+ popw %bp
+ ret
+
+/*
+ * Attempt a block read
+ *
+ * Guess what this is also horribly buggy on lots of systems too
+ * Buffer must be even on some AMI BIOSen (1990/1) so we need to
+ * handle direct I/O with care and also FIXME align buffer cache
+ *
+ * Some bioses destroy dx, and don't always handle carry right so we
+ * must call with stc first
+ *
+ * The original IBM PC-AT BIOS doesn't correctly handle interrupt
+ * disables. For now we just treat that as busted - use a newer BIOS,
+ * you've had 30 years to upgrade it!
+ *
+ * bioshd_read(uint16_t cylsec, uint8_t drive, uint8_t head,
+ * uint16_t seg, uint16_t addr, uint16_t secs)
+ */
+bioshd_read:
+ pushw %bp
+ movw %sp,%bp
+ pushw %es
+ movw 4(%bp),%cx
+ movw 6(%bp),%dx
+ movw 8(%bp),%ax
+ movw %ax,%es
+ movw 10(%bp),%bx
+ movw 12(%bp),%ax
+ movb $2,%ah
+ stc
+ int $13
+ jc read_fail
+ movw $0,%dx
+read_end:
+ popw %es
+ popw %bp
+ ret
+read_fail:
+ movw $0xff,%dx
+ jmp read_end
+
+
+bioshd_write:
+ pushw %bp
+ movw %sp,%bp
+ pushw %es
+ movw 4(%bp),%cx
+ movw 6(%bp),%dx
+ movw 8(%bp),%ax
+ movw %ax,%es
+ movw 10(%bp),%bx
+ movw 12(%bp),%ax
+ movb $3,%ah
+ stc
+ int $13
+ jc read_fail
+ movw $0,%dx
+ popw %es
+ popw %bp
+ ret
+
+biosdata_read:
+ pushw %bp
+ movw %sp,%bp
+ pushw %di
+ movw $0x40,%ax
+ movw %ax,%es
+ movw 4(%bp),%di
+ movb (%di),%al
+ cbw
+ movw %ds,%bx
+ movw %bx,%es
+ popw %di
+ popw %bp
+ ret
+
+kernel_ds:
+ .word 0
+
+ .data
+equipment_word:
+ .word 0
--- /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 <buddy.h>
+
+uint8_t kernel_flag = 1;
+
+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;
+
+uint8_t platform_param(char *p)
+{
+ return 0;
+}
+
+void platform_discard(void)
+{
+}
+
+void memzero(void *p, usize_t len)
+{
+ memset(p, 0, len);
+}
+
+uint16_t irqstack[128]; /* Used for swapping only */
--- /dev/null
+export CPU = 8086
--- /dev/null
+#include "../kernel-8086.def"
+
+ .arch i8086,jumps
+ .code16
+ .att_syntax prefix
+
+ .text
+
+ .globl switchin
+ .globl switchout
+ .globl dofork
+
+switchout:
+ cli
+ call chksigs
+ pushw %ax /* Figure out what we actually need to save */
+ pushw %bx
+ pushw %cx
+ pushw %dx
+ pushw %es
+ pushw %di
+ pushw %bp
+ movw %sp,udata+U_DATA__U_SP
+ call getproc
+ push %ax
+ call switchin
+ jmp trap_monitor
+
+switchin:
+ push %bp
+ mov %sp,%bp
+ cli
+ movw 4(%bp),%si
+ cmpb $0,P_TAB__P_PAGE_OFFSET(%si)
+ /*
+ jne not_swapped
+ TODO */
+ ret
+switchfail:
+/* call outaxhex
+ mov $badswitchmsg,ax
+ calloutstring
+ jmp _trap_monitor */
+
+dofork:
+ /* TODO */
+ movw $-1,%ax
+ ret
+
+ .data
+swapstack:
+ .bss 256