[comp.os.cpm] UZI, part 1 of 5

dbraun@cadavr.intel.com (Doug Braun ~) (11/29/88)

This and the next four postings contain a shell archive of UZI,
the Z-80 U**x Implementation.  Do the usual concatenation stuff.
I have no idea what happeden to the copy I mailed to comp.sources.misc.
I was going to upload this to the Royal Oak RCP/M, but it was apparently
down last weekend.  I will also soon post the UZI Utilities, which are
a collection of programs that will let you debug your device drivers
and build and manage UZI filesystems under CP/M.


UZI, part 1 of 5

#!/bin/sh
#
#Run this file through sh to get:
#    intro
#    filelist
#    config.h
#    unix.h
#    extern.h
#    data.c
#    dispatch.c
#    extras.c
#    machdep.c
#    makeunix.sub
#    loadunix.sub
echo -n 'Extracting intro ... '
sed 's/^X//' > intro << 'EOF_intro'
X		UZI: UNIX Z-80 IMPLEMENTATION
X
X		  Written by Douglas Braun
X
X
XIntroduction:
X
XUZI is an implementation of the Unix kernel written for a Z-80 based
Xcomputer.  It implementts almost all of the functionality of the
X7th Edition Unix kernel.  UZI was written to run on one specific
Xcollection of custom-built hardware, but since it can easily have device
Xdrivers added to it, and it does not use any memory management hardware,
Xit should be possible to port it to numerous computers that current use
Xthe CP/M operating system.  The source code is written mostly in C,
Xand was compiled with The Code Works' Q/C compiler.  UZI's code was
Xwritten from scratch, and contains no AT&T code, so it is not subject
Xto any of AT&T's copyright or licensing restrictions.  Numerous 7th
XEdition programs have been ported to UZI with little or no difficulty,
Xincluding the complete Bourne shell, ed, sed, dc, cpp, etc.
X
X
XHow it works:
X
XSince there is no standard memory management hardware on 8080-family
Xcomputers, UZI uses "total swapping" to achieve multiprocessing.
XThis has two implications:  First, UZI requires a reasonably fast
Xhard disk.  Second, there is no point in running a different process
Xwhile a process is waiting for disk I/O.  This simplifies the design
Xof the block device drivers, since they do not have to be interrupt-based.
X
XUZI itself occupies the upper 32K of memory, and the currently running
Xprocess occupies the lower 32K.   Since UZI currently barely fits in 32K,
Xa full 64K of RAM is necessary.
X
XUZI does need some additional hardware support.  First, there must be
Xsome sort of clock or timer that can provide a periodic interrupt.
XAlso, the current implementation uses an additional real-time clock
Xto get the time for file timestamps, etc.  The current TTY driver assumes
Xan interrupt-driven keyboard, which should exist on most systems.
XThe distribution contains code for hard and floppy disk drivers, but
Xsince these were written for custom hardware, they are provided only
Xas templates to write new ones.
X
X
XHow UZI is different than real Unix:
X
XUZI implements almost all of the 7th Edition functionality.
XAll file I/O, directories, mountable file systems, user and group IDs,
Xpipes, and applicable device I/O are supported.  Process control
X(fork(), execve(), signal(), kill(), pause(), alarm(), and wait()) are fully
Xsupported.  The number of processes is limited only by the swap space
Xavailable.  As mentioned above,  UZI implements Unix well enough to
Xrun the Bourne shell in its full functionality.  The only changes made
Xto the shell's source code were to satisfy the limitations of the C compiler.
X
XHere is a (possibly incomplete) list of missing features and limitations:
X
X    The debugger- and profiler-related system calls do not exist.
X
X    The old 6th edition seek() was implemented, instead of lseek().
X
X    The supplied TTY driver is bare-bones.  It supports only one port,
X    and most IOCTLs are not supported.
X
X    Inode numbers are only 16-bit, so filesystems are 32 Meg or less.
X
X    File dates are not in the standard format.  Instead they look like
X    those used by MS-DOS.
X
X    The 4.2BSD execve() was implemented.  Additional flavors of exec()
X    are supported by the library.
X
X    The format of the device driver switch table is unlike that of
X    the 7th Edition.
X
X    The necessary semaphores and locking mechanisms to implement 
X    reentrant disk I/O are not there.  This would make it harder to
X    implement interrupt-driven disk I/O without busy-waiting.
X
X
XA Description of this Release:
X
XHere is a list of the files supplied, and a brief description of each:
X
X
Xintro:		What you are reading
X
Xconfig.h:	Setup parameters, such as table sizes, and the device
X		driver switch table.
X
Xunix.h:		All strcuture declarations, typedefs and defines.
X		(Includes things like errno.h).
X
Xextern.h:	Declarations of all global variables and tables.
X
Xdata.c:		Dummy to source extern.h and devine globals.
X
Xdispatch.c:	System call dispatch table.
X
Xscall1.c:	System calls, mostly file-related.
X
Xscall2.c:	Rest of system calls.
X
Xfilesys.c:	Routines for managing file system.
X
Xprocess.c:	Routines for process management and context switching.
X		Somewhat machine-dependent.
X
Xdevio.c:	Generic I/O routines, including queue routines.
X
Xdevtty.c:	Simple TTY driver, slightly-machine dependent.
X
Xdevwd.c:	Hard disk driver.  Very machine-dependent.
X
Xdevflop.c:	Floppy disk driver.  Very machine-dependent.
X
Xdevmisc.c:	Simple device drivers, such as /dev/mem.
X
Xmachdep.c:	Machine-dependent code, especially real-time-clock and
X		interrupt handling code.
X
Xextras.c:	Procedures missing from the Q/C compiler's library.
X
Xfiller.mac:	Dummy to make linker load UZI at correct address.
X
Xmakeunix.sub:	CP/M SUBMIT file to compile everything.
X
Xloadunix.sub:	CP/M SUBMIT file to load everything.
X
X
XMiscellaneous Notes:
X
XUZI was compiled with the Code Works Q/C C compiler and the Microsoft
XM80 assembler under the CP/M operating system, on the same hardware
Xit runs on.  Also used was a version of cpp ported to CP/M, since
Xthe Q/C compiler does not handle macros with arguments.  However, there
Xare only a couple of these in the code, and they could easily be removed.
X
XBecause UZI occupies the upper 32K of memory, the standard L80 linker
Xcould not be used to link it.  Instead, a homebrew L80 replacement linker
Xwas used.  This generated a 64K-byte CP/M .COM file, which has the lower 
X32K pruned by the CP/M PIP utility.  This is the reason for appearance
Xof the string "MOMBASSA" in filler.mac and loadunix.sub.
X
XTo boot UZI, a short CP/M program was run that reads in the UZI image,
Xcopies it to the upper 32K of memory, and jumps to its start address.
XOther CP/M programs were written to build, inspect, and check UZI filesystems
Xunder CP/M.  These made it possible to have a root file system made before
Xstarting up UZI.  If the demand exists, these programs can be included
Xin another release.
X
X
XRunning programs under UZI:
X
XA number of 7th Edition, System V, and 4.2BSD programs were ported to
XUZI.  Most notably, the Bourne shell and ed run fine under UZI.
XIn addition the 4.2BSD stdio library was also ported.  This, along
Xwith the Code Works Q/C library and miscellaneous System V library 
Xfunctions, was used when porting programs.
X
XDue to obvious legal reasons, the source or executables for most of these
Xprograms cannot be released.  However, some kernel-dependent programs
Xsuch as ps and fsck were written from scratch and can be included in future
Xreleases.  Also, a package was created that can be linked to CP/M .COM
Xfiles that will allow them to run under UZI.  This was used to get
Xthe M80 assembler and L80 linker to run under UZI.  Cpp was also
Xported to UZI.  However, it was not possible to fit the Q/C compiler
Xinto 32K, so all programs (and UZI itself) were cross-compiled under CP/M.
X
XThe Minix operating system, written for PCs by Andrew Tanenbaum et al,
Xcontains many programs that should compile and run under UZI.  Since
XMinix is much less encumbered by licensing provisions than real Unix,
Xit would make sense to port Minix programs to UZI.  In fact, UZI itself
Xcould be ported to the PC, and used as a replacement for the Minix kernel.
EOF_intro
echo 'Done'

echo -n 'Extracting filelist ... '
sed 's/^X//' > filelist << 'EOF_filelist'
Xintro
Xfilelist
Xconfig.h
Xunix.h
Xextern.h
Xdata.c
Xdispatch.c
Xmachdep.c
Xscall1.c
Xscall2.c
Xfilesys.c
Xprocess.c
Xdevio.c
Xdevtty.c
Xdevwd.c
Xdevflop.c
Xdevmisc.c
Xextras.c
Xfiller.mac
Xmakeunix.sub
Xloadunix.sub
EOF_filelist
echo 'Done'

echo -n 'Extracting config.h ... '
sed 's/^X//' > config.h << 'EOF_config.h'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  config.h
X***************************************************/
X
X
X/* Remake devio.c when this is changed */
X#ifdef DEVIO
X
Xextern wd_open(), wd_read(),wd_write();
Xextern fd_open(), fd_read(),fd_write();
Xextern tty_open(), tty_close(), tty_read(),tty_write();
Xextern lpr_open(), lpr_close(), lpr_write();
Xextern mem_read(),mem_write();
Xextern mt_read(), mt_write(), mt_open(), mt_close();
Xextern null_write();
X
X
Xstatic struct devsw dev_tab[] =  /* The device driver switch table */
X{
X    { 0x2b38, wd_open, ok,       wd_read, wd_write, nogood },
X    { 0, fd_open, ok,       fd_read, fd_write, nogood },        /* floppy */
X    { 0x3844, wd_open, ok,       wd_read, wd_write, nogood },
X    { 0x252b, wd_open, ok,       wd_read, wd_write, nogood },   /* Swap */
X    { 0, lpr_open, lpr_close, nogood, lpr_write, nogood},     /* printer */
X    { 0, tty_open, tty_close, tty_read, tty_write, ok },      /* tty */
X    { 0, ok, ok, ok, null_write, nogood },                      /* /dev/null */
X    { 0, ok, ok, mem_read, mem_write, nogood },              /* /dev/mem */
X    { 0, mt_open, mt_close, mt_read, mt_write, nogood }
X};
X
X#endif
X
X#define NDEVS   3    /* Devices 0..NDEVS-1 are capable of being mounted */
X#define TTYDEV  5    /* Device used by kernel for messages, panics */
X#define SWAPDEV  3   /* Device for swapping. */
X#define NBUFS  4     /* Number of block buffers */
X
EOF_config.h
echo 'Done'

echo -n 'Extracting unix.h ... '
sed 's/^X//' > unix.h << 'EOF_unix.h'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  unix.h
X***************************************************/
X
X
X#ifndef vax
X#define CPM
X#endif
X
X#define UFTSIZE 10    /* Number of user files */
X#define OFTSIZE 15    /* Open file table size */
X#define ITABSIZE 20   /* Inode table size */
X#define PTABSIZE 20   /* Process table size */
X
X#define NSIGS 16        /* Number of signals <= 16 */
X
X#define ROOTINODE 1  /* Inode # of /  for all mounted filesystems. */
X
X#define TICKSPERSEC 10  /*Ticks per second */
X#define MAXTICKS   10   /* Max ticks before swapping out (time slice) */
X
X#define ARGBLK 0        /* Block number on SWAPDEV for arguments */
X#define PROGBASE ((char *)(0x100))
X#define MAXEXEC 0       /* Max no of blks of executable file */
X
X#define EMAGIC 0xc3     /* Header of executable */
X#define CMAGIC 24721    /* Random number for cinode c_magic */
X#define SMOUNTED 12742  /* Magic number to specify mounted filesystem */
X#define NULL 0
X
X
X/* These macros are simply to trick the compiler into generating
X   more compact code. */
X
X#define ifnull(e) if(e){}else
X#define ifnot(e) if(e){}else
X#define ifzero(e) if(e){}else
X
X
X
X#ifdef CPM
X    typedef unsigned uint16;
X    typedef int int16;
X#else
X    typedef unsigned short uint16;
X    typedef short int16;
X#endif
X
X
Xtypedef struct s_queue {
X    char *q_base;   /* Pointer to data */
X    char *q_head;  /* Pointer to addr of next char to read. */
X    char *q_tail;  /* Pointer to where next char to insert goes. */
X    int q_size; /* Max size of queue */
X    int q_count;        /* How many characters presently in queue */
X    int q_wakeup;       /* Threshold for waking up processes waiting on queue */
X} queue_t;
X
X
X
Xtypedef struct time_s {
X    uint16 t_time;
X    uint16 t_date;
X} time_t;
X
X
X/* User's structure for times() system call */
X
Xstruct tms {
X	time_t  tms_utime;
X	time_t  tms_stime;
X	time_t  tms_cutime;
X	time_t  tms_cstime;
X	time_t  tms_etime;      /* Elapsed real time */
X} ;
X
X
X/* Flags for setftime() */
X#define A_TIME 1
X#define M_TIME 2
X#define C_TIME 4
X
X
Xtypedef struct off_t {
X    uint16 o_blkno;  /* Block number */
X    int16 o_offset;     /* Offset within block 0-511 */
X} off_t;
X
X
Xtypedef uint16 blkno_t;  /* Can have 65536 512-byte blocks in filesystem */
X#define NULLBLK ((blkno_t)-1)
X
X
Xtypedef struct blkbuf {
X    char        bf_data[512];    /* This MUST be first ! */
X    char        bf_dev;
X    blkno_t     bf_blk;
X    char        bf_dirty;
X    char        bf_busy;
X    uint16      bf_time;        /* LRU time stamp */
X/*    struct blkbuf *bf_next;    /* LRU free list pointer */
X} blkbuf, *bufptr;
X
X
Xtypedef struct dinode {
X    uint16 i_mode;
X    uint16 i_nlink;
X    uint16 i_uid;
X    uint16 i_gid;
X    off_t    i_size;
X    time_t   i_atime;
X    time_t   i_mtime;
X    time_t   i_ctime;
X    blkno_t  i_addr[20];
X} dinode;               /* Exactly 64 bytes long! */
X
X
Xstruct  stat    /* Really only used by users */
X{
X	int16   st_dev;
X	uint16  st_ino;
X	uint16  st_mode;
X	uint16  st_nlink;
X	uint16  st_uid;
X	uint16  st_gid;
X	uint16  st_rdev;
X	off_t   st_size;
X	time_t  st_atime;
X	time_t  st_mtime;
X	time_t  st_ctime;
X};
X
X/* Bit masks for i_mode and st_mode */
X
X#define OTH_EX  0001
X#define OTH_WR  0002
X#define OTH_RD  0004
X#define GRP_EX  0010
X#define GRP_WR  0020
X#define GRP_RD  0040
X#define OWN_EX  0100
X#define OWN_WR  0200
X#define OWN_RD  0400
X
X#define SAV_TXT 01000
X#define SET_GID 02000
X#define SET_UID 04000
X
X#define MODE_MASK 07777
X
X#define F_REG  0100000
X#define F_DIR   040000
X#define F_PIPE  010000
X#define F_BDEV  060000
X#define F_CDEV  020000
X
X#define F_MASK  0170000
X
X
X
Xtypedef struct cinode {
X    int    c_magic;             /* Used to check for corruption. */
X    int    c_dev;               /* Inode's device */
X    unsigned   c_num;           /* Inode # */
X    dinode   c_node;
X    char     c_refs;            /* In-core reference count */
X    char     c_dirty;           /* Modified flag. */
X} cinode, *inoptr;
X
X#define NULLINODE ((inoptr)NULL)
X#define NULLINOPTR ((inoptr*)NULL)
X
X
Xtypedef struct direct {
X    uint16 d_ino;
X    char     d_name[14];
X} direct;
X
X
X
Xtypedef struct filesys {
X    int16       s_mounted;
X    uint16      s_isize;
X    uint16      s_fsize;
X    int16       s_nfree;
X    blkno_t     s_free[50];
X    int16       s_ninode;
X    uint16      s_inode[50];
X    int16       s_fmod;
X    time_t      s_time;
X    blkno_t     s_tfree;
X    uint16      s_tinode;
X    inoptr      s_mntpt; /* Mount point */
X} filesys, *fsptr;
X
Xtypedef struct oft {
X    off_t       o_ptr;   /* File position point16er */
X    inoptr      o_inode; /* Pointer into in-core inode table */
X    char        o_access; /* O_RDONLY, O_WRONLY, or O_RDWR */
X    char        o_refs;  /* Reference count: depends on # of active children*/
X} oft;
X
X
X/* Process table p_status values */
X
X#define P_EMPTY         0    /* Unused slot */
X#define P_RUNNING       1    /* Currently running process */
X#define P_READY         2    /* Runnable   */
X#define P_SLEEP         3    /* Sleeping; can be awakened by signal */
X#define P_XSLEEP        4    /* Sleeping, don't wake up for signal */
X#define P_PAUSE         5    /* Sleeping for pause(); can wakeup for signal */
X#define P_FORKING       6    /* In process of forking; do not mess with */
X#define P_WAIT          7    /* Executed a wait() */
X#define P_ZOMBIE        8    /* Exited. */
X
X
X#define SIGHUP  1       
X#define SIGINT  2      
X#define SIGQUIT 3     
X#define SIGILL  4    
X#define SIGTRAP 5   
X#define SIGIOT  6  
X#define SIGEMT  7 
X#define SIGFPE  8 
X#define SIGKILL 9
X#define SIGBUS  10
X#define SIGSEGV 11
X#define SIGSYS  12
X#define SIGPIPE 13
X#define SIGALRM 14
X#define SIGTERM 15
X
X#define SIG_DFL         (int (*)())0
X#define SIG_IGN         (int (*)())1
X
X#define sigmask(sig)    (1<<(sig))
X
X/* Process table entry */
X
Xtypedef struct p_tab {
X    char        p_status;       /* Process status */
X    int p_pid;    /* Process ID */
X    int p_uid;
X    struct p_tab *p_pptr;    /* Process parent's table entry */
X    blkno_t     p_swap;   /* Starting block of swap space */
X    unsigned    p_alarm;        /* Seconds until alarm goes off */
X    unsigned    p_exitval;      /* Exit value */
X    /* Everything below here is overlaid by time info at exit */
X    char       *p_wait;         /* Address of thing waited for */
X    int p_priority;     /* Process priority */
X    uint16      p_pending;      /* Pending signals */
X    uint16      p_ignored;      /* Ignored signals */
X} p_tab, *ptptr;
X
X/* Per-process data (Swapped with process) */
X
X#asm 8080
X?OSYS equ 2     ;byte offsets of elements of u_data
X?OCALL equ 3
X?ORET equ 4     ;return location
X?ORVAL equ 6    ;return value
X?OERR equ 8     ;error number
X?OSP equ 10     ;users stack pointer
X?OBC equ 12     ;users frame pointer
X#endasm
X
Xtypedef struct u_data {
X    struct p_tab *u_ptab;       /* Process table pointer */
X    char        u_insys;        /* True if in kernel */
X    char        u_callno;       /* sys call being executed. */
X    char        *u_retloc;     /* Return location from sys call */
X    int         u_retval;       /* Return value from sys call */
X    int         u_error;                /* Last error number */
X    char        *u_sp;          /* Used when a process is swapped. */
X    char        *u_bc;          /* Place to save user's frame pointer */
X    int         u_argn;         /* Last arg */
X    int         u_argn1;        /* This way because args on stack backwards */
X    int         u_argn2;
X    int         u_argn3;        /* args n-3, n-2, n-1, and n */
X
X    char *      u_base;         /* Source or dest for I/O */
X    unsigned    u_count;        /* Amount for I/O */
X    off_t       u_offset;       /* Place in file for I/O */
X    struct blkbuf *u_buf;
X
X    int         u_gid;
X    int         u_euid;
X    int         u_egid;
X    int         u_mask;         /* umask: file creation mode mask */
X    time_t      u_time;         /* Start time */
X    char        u_files[UFTSIZE];       /* Process file table:
X	                        contains indexes into open file table. */
X    inoptr      u_cwd;          /* Index into inode table of cwd. */
X    char        *u_break;        /* Top of data space */
X
X    inoptr      u_ino;  /* Used during execve() */
X    char        *u_isp;  /* Value of initial sp (argv) */
X
X    int         (*u_sigvec[NSIGS])();   /* Array of signal vectors */
X    int         u_cursig;       /* Signal currently being caught */
X    char        u_name[8];      /* Name invoked with */
X    time_t      u_utime;        /* Elapsed ticks in user mode */
X    time_t      u_stime;        /* Ticks in system mode */
X    time_t      u_cutime;       /* Total childrens ticks */
X    time_t      u_cstime;
X
X} u_data;
X
X
X/* Struct to temporarily hold arguments in execve */
Xstruct s_argblk {
X    int a_argc;
X    int a_arglen;
X    int a_envc;
X    char a_buf[512-3*sizeof(int)];
X};
X
X
X/* The device driver switch table */
X
Xtypedef struct devsw {
X    int minor;          /* The minor device number (an argument to below) */
X    int (*dev_open)();  /* The routines for reading, etc */
X    int (*dev_close)(); /* format: op(minor,blkno,offset,count,buf); */
X    int (*dev_read)();  /* offset would be ignored for block devices */
X    int (*dev_write)(); /* blkno and offset ignored for tty, etc. */
X    int (*dev_ioctl)(); /* count is rounded to 512 for block devices */
X} devsw;
X
X
X
X/* Open() parameters. */
X
X#define O_RDONLY        0
X#define O_WRONLY        1
X#define O_RDWR          2
X
X/*
X * Error codes
X */
X
X#define EPERM           1               
X#define ENOENT          2               
X#define ESRCH           3               
X#define EINTR           4               
X#define EIO             5               
X#define ENXIO           6               
X#define E2BIG           7               
X#define ENOEXEC         8               
X#define EBADF           9               
X#define ECHILD          10              
X#define EAGAIN          11              
X#define ENOMEM          12              
X#define EACCES          13              
X#define EFAULT          14              
X#define ENOTBLK         15              
X#define EBUSY           16              
X#define EEXIST          17              
X#define EXDEV           18              
X#define ENODEV          19              
X#define ENOTDIR         20              
X#define EISDIR          21              
X#define EINVAL          22              
X#define ENFILE          23              
X#define EMFILE          24              
X#define ENOTTY          25              
X#define ETXTBSY         26              
X#define EFBIG           27              
X#define ENOSPC          28              
X#define ESPIPE          29              
X#define EROFS           30              
X#define EMLINK          31              
X#define EPIPE           32              
X#define ENAMETOOLONG    63              
X
X#include "config.h"
X
EOF_unix.h
echo 'Done'

echo -n 'Extracting extern.h ... '
sed 's/^X//' > extern.h << 'EOF_extern.h'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  extern.h
X***************************************************/
X
X
X/* These are the global data structures */
X
X#ifdef MAIN
X#define extern  
X#endif
X
X
Xextern struct u_data udata; /* MUST BE FIRST */
Xextern struct p_tab ptab[PTABSIZE];
X
Xextern inoptr root;   /* Address of root dir in inode table */
Xextern int16 ROOTDEV;  /* Device number of root filesystem. */
X
Xextern struct cinode i_tab[ITABSIZE];    /* In-core inode table */
Xextern struct oft of_tab[OFTSIZE]; /* Open File Table */
X
Xextern struct filesys fs_tab[NDEVS];  /* Table entry for each
X                                        device with a filesystem. */
Xextern struct blkbuf bufpool[NBUFS];
X
Xextern ptptr initproc; /* The process table address of the first process. */
Xextern int16 inint;   /* flag is set whenever interrupts are being serviced */
X
Xextern int16 sec;   /* Tick counter for counting off one second */
Xextern int16 runticks;  /* Number of ticks current process has been
X                         swapped in */
X
Xextern time_t tod;      /* Time of day */
Xextern time_t ticks;    /* Cumulative tick counter, in minutes and ticks  */
X
Xextern char *swapbase;          /* Used by device driver for swapping */
Xextern unsigned swapcnt;
Xextern blkno_t swapblk;
X
Xextern char vector[3];  /* Place for interrupt vector */
X
X#ifdef MAIN
X#undef extern
X#endif
X
X
EOF_extern.h
echo 'Done'

echo -n 'Extracting data.c ... '
sed 's/^X//' > data.c << 'EOF_data.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  data.c
X***************************************************/
X
X#include "unix.h"
X#define MAIN
X#asm 8080
XCSEG
X@init?::
X        EXTRN   fs@init?
X        JMP     fs@init?
X#endasm
X#include "extern.h"
X
EOF_data.c
echo 'Done'

echo -n 'Extracting dispatch.c ... '
sed 's/^X//' > dispatch.c << 'EOF_dispatch.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  dispatch.c
X***************************************************/
X
X
X/* Dispatch table for system calls */
Xint     __exit(),
X        _open(),
X        _close(),
X        _creat(),
X        _mknod(),
X        _link(),
X        _unlink(),
X        _read(),
X        _write(),
X        _seek(),
X        _chdir(),
X        _sync(),
X        _access(),
X        _chmod(),
X        _chown(),
X        _stat(),
X        _fstat(),
X        _dup(),
X        _getpid(),
X        _getppid(),
X        _getuid(),
X        _umask(),
X        _getfsys(),
X        _execve(),
X        _wait(),
X        _setuid(),
X        _setgid(),
X        _time(),
X        _stime(),
X        _ioctl(),
X        _brk(),
X        _sbrk(),
X        _fork(),
X        _mount(),
X        _umount(),
X        _signal(),
X        _dup2(),
X        _pause(),
X        _alarm(),
X        _kill(),
X        _pipe(),
X        _getgid(),
X        _times();
X
Xint (*disp_tab[])() =
X{       __exit,
X        _open,
X        _close,
X        _creat,
X        _mknod,
X        _link,
X        _unlink,
X        _read,
X        _write,
X        _seek,
X        _chdir,
X        _sync,
X        _access,
X        _chmod,
X        _chown,
X        _stat,
X        _fstat,
X        _dup,
X        _getpid,
X        _getppid,
X        _getuid,
X        _umask,
X        _getfsys,
X        _execve,
X        _wait,
X        _setuid,
X        _setgid,
X        _time,
X        _stime,
X        _ioctl,
X        _brk,
X        _sbrk,
X        _fork,
X        _mount,
X        _umount,
X        _signal,
X        _dup2,
X        _pause,
X        _alarm,
X        _kill,
X        _pipe,
X        _getgid,
X        _times
X };
X
Xchar dtsize = sizeof(disp_tab) / sizeof(int(*)()) - 1;
X
X
EOF_dispatch.c
echo 'Done'

echo -n 'Extracting extras.c ... '
sed 's/^X//' > extras.c << 'EOF_extras.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  extras.c
X***************************************************/
X
X
Xbcopy()
X{
X#asm 8080
X; BCOPY(SRC,DEST,COUNT)
X;
X        POP     H
X        SHLD    HOLDER
X.Z80
X        LD      (BCHLDR),BC
X.8080   
X        POP     B
X        POP     D
X        POP     H
X        PUSH    H
X        PUSH    H
X        PUSH    H
X.Z80
X        LDIR
X.8080
X        LHLD    HOLDER
X.Z80
X        LD      BC,(BCHLDR)
X.8080
X        PCHL
X#endasm
X}
X
X#asm 
X;
XHOLDER: DS      2
XBCHLDR: DS      2
X;
X;
X#endasm
X
X
Xbzero(ptr,count)
Xchar *ptr;
Xint count;
X{
X    *ptr = 0;
X    bcopy(ptr,ptr+1,count-1);
X}
X
X
Xabort()
X{
X#asm 8080
X        DI
X        JMP     $
X#endasm
X}
X
EOF_extras.c
echo 'Done'

echo -n 'Extracting machdep.c ... '
sed 's/^X//' > machdep.c << 'EOF_machdep.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  machdep.c
X***************************************************/
X
X
X#include "unix.h"
X#include "extern.h"
X
X
X/* This is called at the very beginning to initialize everything. */
X/* It is the equivalent of main() */
X
Xfs_init()
X{
X    di();
X    stkreset();
X    /* Initialize the interrupt vector */
X    initvec();
X    inint = 0;
X    udata.u_insys = 1;
X    /* Turn off clock */
X    out(0,0xf1);
X    ei();
X
X    init2();   /* in process.c */
X}
X
X
X/* This checks to see if a user-suppled address is legitimate */
Xvaladr(base,size)
Xchar *base;
Xuint16 size;
X{
X    if (base < PROGBASE || base+size >= (char *)&udata)
X    {
X        udata.u_error = EFAULT;
X        return(0);
X    }
X    return(1);
X}
X
X
X/* This adds two tick counts together.
XThe t_time field holds up to one second of ticks,
Xwhile the t_date field counts minutes */
X
Xaddtick(t1,t2)
Xtime_t *t1, *t2;
X{
X
X    t1->t_time += t2->t_time;
X    t1->t_date += t2->t_date;
X    if (t1->t_time >= 60*TICKSPERSEC)
X    {
X        t1->t_time -= 60*TICKSPERSEC;
X        ++t1->t_date;
X    }
X}
X
Xincrtick(t)
Xtime_t *t;
X{
X    if (++t->t_time == 60*TICKSPERSEC)
X    {
X        t->t_time = 0;
X        ++t->t_date;
X    }
X}
X
X
Xstkreset()
X{
X#asm 8080
X        POP     H
X        LXI     SP,udata?-2
X        PCHL
X#endasm
X}
X
X
Xtempstack()
X{
X#asm 8080
X        POP     H
X        LXI     SP,100H
X        PCHL
X#endasm
X}
X
X
X
Xinitvec()
X{
X#asm 8080
X        LXI     H,vector?
X        INX     H
X        MOV     A,L
X        ANI     0FEH
X        MOV     L,A     ;set hl to first even address in vector[].
X        MOV     A,H
X.Z80
X        LD      I,A     ;SET INTERRUPT REGISTER TO UPPER 8 BITS
X.8080
X        MOV     A,L
X        OUT     076H    ;set external vector register with low order byte
X        LXI     D,service?
X        MOV     M,E
X        INX     H
X        MOV     M,D     ;STORE ADDRESS OF SERVICE ROUTINE IN vector[].
X        RET
X#endasm
X}
X
Xextern int unix();
X
X
Xdoexec()
X{
X#asm 8080
X        POP     H
X        POP     H       ;get argument
X        SPHL            ;set stack pointer to it
X        MVI     A,0C3H  ;jump inst
X        STA     0030H   ;dest of RST6 instruction.
X        LXI     H,unix? ;entry address
X        SHLD    0031H
X        XRA     A
X        STA     udata? + ?OSYS
X        JMP     0100H
X#endasm
X}
X
X
Xstatic int cursig;
Xstatic int (*curvec)();
X
X/* This interrupt device routine calls the service routine of each device
Xthat could have interrupted. */
X
Xservice()
X{
X
X    ;
X#asm 8080
X        PUSH    PSW
X        PUSH    B
X        PUSH    D
X        PUSH    H
X.Z80
X        PUSH    IX
X        PUSH    IY
X.8080
X#endasm
X
X    inint = 1;
X
X    if (tty_int())
X        goto found;
X    if (clk_int())
X        goto found;
X/*  if (  ) ...   */
X
X    warning("Spurious interrupt");
X
Xfound:
X    inint = 0;
X
X    /* Deal with a pending caught signal, if any */
X    if (!udata.u_insys)
X        calltrap();
X    ;
X
X#asm 8080
X.Z80
X        POP     IY
X        POP     IX
X.8080
X        POP     H
X        POP     D
X        POP     B
X        POP     PSW
X        EI
X        RET
X#endasm
X
X}
X
X
X
Xcalltrap()
X{
X    /* Deal with a pending caught signal, if any. */
X        /* udata.u_insys should be false, and interrupts enabled.
X        remember, the user may never return from the trap routine */
X
X    if (udata.u_cursig)
X    {
X        cursig = udata.u_cursig;
X        curvec = udata.u_sigvec[cursig];
X        udata.u_cursig = 0;
X        udata.u_sigvec[cursig] = SIG_DFL;   /* Reset to default */
X        ei();
X        (*curvec)(cursig);
X        di();
X    } 
X}
X
X
X
X/* Port addresses of clock chip registers. */
X
X#define SECS 0xe2
X#define MINS 0xe3
X#define HRS 0xe4
X#define DAY 0xe6
X#define MON 0xe7
X#define YEAR 86
X
Xsttime()
X{
X    panic("Calling sttime");
X}
X
X
Xrdtime(tloc)
Xtime_t *tloc;
X{
X    di();
X    tloc->t_time = tod.t_time;
X    tloc->t_date = tod.t_date;
X    ei();
X}
X
X
X/* Update global time of day */
Xrdtod()
X{
X    tod.t_time = (tread(SECS)>>1) | (tread(MINS)<<5) | (tread(HRS)<<11);
X    tod.t_date = tread(DAY) | (tread(MON)<<5) | (YEAR<<9);
X}
X
X
X/* Read BCD clock register, convert to binary. */
Xtread(port)
Xuint16 port;
X{
X    int n;
X
X    n = in(port);
X    return ( 10*((n>>4)&0x0f) + (n&0x0f) );
X}
X
X
X/* Disable interrupts */
Xdi()
X{
X#asm 8080
X        DI      ;disable interrupts
X#endasm
X}
X
X/* Enable interrupts if we are not in service routine */
Xei()
X{
X    if (inint)
X        return;
X    ;   /* Empty statement necessary to fool compiler */
X
X#asm 8080
X        EI      ;disable interrupts
X#endasm
X}
X
X
X
X/* This shifts an unsigned int right 8 places. */
X
Xshift8()
X{
X#asm 8080
X        POP     D       ;ret addr
X        POP     H
X        MOV     L,H
X        MVI     H,0
X        MOV     A,L
X        ANA     A       ;set Z flag on result
X        PUSH    H
X        PUSH    D       ;restore stack
X#endasm
X}
X
X
X/* This prints an error message and dies. */
X
Xpanic(s)
Xchar *s;
X{
X    di();
X    inint = 1;
X    kprintf("PANIC: %s\n",s);
X    idump();
X    abort();
X}
X
X
Xwarning(s)
Xchar *s;
X{
X    kprintf("WARNING: %s\n",s);
X}
X
X
Xputs(s)
Xchar *s;
X{
X    while (*s)
X        kputchar(*(s++));
X}
X
Xkputchar(c)
Xint c;
X{
X    if (c == '\n')
X        _putc('\r');
X    _putc(c);
X    if (c == '\t')
X        puts("\177\177\177\177\177\177\177\177\177\177");
X}
X
X
X
Xidump()
X{
X    inoptr ip;
X    ptptr pp;
X    extern struct cinode i_tab[];
X
X    kprintf(
X        "\tMAGIC\tDEV\tNUM\tMODE\tNLINK\t(DEV)\tREFS\tDIRTY err %d root %d\n",
X            udata.u_error, root - i_tab);
X
X    for (ip=i_tab; ip < i_tab+ITABSIZE; ++ip)
X    {
X        kprintf("%d\t%d\t%d\t%u\t0%o\t%d\t%d\t%d\t%d\n",
X               ip-i_tab, ip->c_magic,ip->c_dev, ip->c_num,
X               ip->c_node.i_mode,ip->c_node.i_nlink,ip->c_node.i_addr[0],
X               ip->c_refs,ip->c_dirty);
X/*****
X        ifnot (ip->c_magic)     
X            break;
X******/
X    }
X
X    kprintf("\n\tSTAT\tWAIT\tPID\tPPTR\tALARM\tPENDING\tIGNORED\n");
X    for (pp=ptab; pp < ptab+PTABSIZE; ++pp)
X    {
X        kprintf("%d\t%d\t0x%x\t%d\t%d\t%d\t0x%x\t0x%x\n",
X               pp-ptab, pp->p_status, pp->p_wait,  pp->p_pid,
X               pp->p_pptr-ptab, pp->p_alarm, pp->p_pending,
X                pp->p_ignored);
X        ifnot(pp->p_pptr)
X            break;
X    }   
X    
X    bufdump();
X
X    kprintf("\ninsys %d ptab %d call %d cwd %d sp 0x%x\n",
X        udata.u_insys,udata.u_ptab-ptab, udata.u_callno, udata.u_cwd-i_tab,
X       udata.u_sp);
X}
X
X
X
X/* Short version of printf to save space */
Xkprintf(nargs)
X        {
X        register char **arg, *fmt;
X        register c, base;
X        char s[7], *itob();
X
X        arg = (char **)&nargs + nargs;
X        fmt = *arg;
X        while (c = *fmt++) {
X                if (c != '%') {
X                        kputchar(c);
X                        continue;
X                        }
X                switch (c = *fmt++) {
X                case 'c':
X                        kputchar(*--arg);
X                        continue;
X                case 'd':
X                        base = -10;
X                        goto prt;
X                case 'o':
X                        base = 8;
X                        goto prt;
X                case 'u':
X                        base = 10;
X                        goto prt;
X                case 'x':
X                        base = 16;
X                prt:
X                        puts(itob(*--arg, s, base));
X                        continue;
X                case 's':
X                        puts(*--arg);
X                        continue;
X                default:
X                        kputchar(c);
X                        continue;
X                        }
X                }
X        }
X
EOF_machdep.c
echo 'Done'

echo -n 'Extracting makeunix.sub ... '
sed 's/^X//' > makeunix.sub << 'EOF_makeunix.sub'
Xb:submit b:qcc data
Xb:submit b:qcc filesys
Xb:submit b:qcc scall1
Xb:submit b:qcc scall2
Xb:submit b:qcc devio
Xb:submit b:qcc devwd
Xb:submit b:qcc devmisc
Xb:submit b:qcc devtty
Xb:submit b:qcc devflop
Xb:submit b:qcc dispatch
Xb:submit b:qcc machdep
Xb:submit b:qcc process
Xb:submit loadunix
X
EOF_makeunix.sub
echo 'Done'

echo -n 'Extracting loadunix.sub ... '
sed 's/^X//' > loadunix.sub << 'EOF_loadunix.sub'
Xloader $1 -o 500 filler data process machdep dispatch scall1 scall2 filesys devio devtty devwd devflop devmisc extras
Xpip unix.bin=$$$$$$.com[osmombassa^Z]
Xera $$$$$$.com
EOF_loadunix.sub
echo 'Done'

exit 0

Doug Braun				Intel Corp CAD
					408 765-4279

 / decwrl \
 | hplabs |
-| oliveb |- !intelca!mipos3!cadev4!dbraun
 | amd    |
 \ qantel /

dbraun@cadavr.intel.com (Doug Braun ~) (11/29/88)

This and the next four postings contain shell archives of UZI,
the Z-80 U**x Implementation.  Several people have asked me to
post it here.

I have no idea what happened to the copy I mailed to comp.sources.misc.
I was going to upload this to the Royal Oak RCP/M, but it was apparently
down last weekend.  I will also soon post the UZI Utilities, which are
a collection of programs that will let you debug your device drivers
and build and manage UZI filesystems under CP/M.


UZI, part 1 of 5

#!/bin/sh
#
#Run this file through sh to get:
#    intro
#    filelist
#    config.h
#    unix.h
#    extern.h
#    data.c
#    dispatch.c
#    extras.c
#    machdep.c
#    makeunix.sub
#    loadunix.sub
echo -n 'Extracting intro ... '
sed 's/^X//' > intro << 'EOF_intro'
X		UZI: UNIX Z-80 IMPLEMENTATION
X
X		  Written by Douglas Braun
X
X
XIntroduction:
X
XUZI is an implementation of the Unix kernel written for a Z-80 based
Xcomputer.  It implementts almost all of the functionality of the
X7th Edition Unix kernel.  UZI was written to run on one specific
Xcollection of custom-built hardware, but since it can easily have device
Xdrivers added to it, and it does not use any memory management hardware,
Xit should be possible to port it to numerous computers that current use
Xthe CP/M operating system.  The source code is written mostly in C,
Xand was compiled with The Code Works' Q/C compiler.  UZI's code was
Xwritten from scratch, and contains no AT&T code, so it is not subject
Xto any of AT&T's copyright or licensing restrictions.  Numerous 7th
XEdition programs have been ported to UZI with little or no difficulty,
Xincluding the complete Bourne shell, ed, sed, dc, cpp, etc.
X
X
XHow it works:
X
XSince there is no standard memory management hardware on 8080-family
Xcomputers, UZI uses "total swapping" to achieve multiprocessing.
XThis has two implications:  First, UZI requires a reasonably fast
Xhard disk.  Second, there is no point in running a different process
Xwhile a process is waiting for disk I/O.  This simplifies the design
Xof the block device drivers, since they do not have to be interrupt-based.
X
XUZI itself occupies the upper 32K of memory, and the currently running
Xprocess occupies the lower 32K.   Since UZI currently barely fits in 32K,
Xa full 64K of RAM is necessary.
X
XUZI does need some additional hardware support.  First, there must be
Xsome sort of clock or timer that can provide a periodic interrupt.
XAlso, the current implementation uses an additional real-time clock
Xto get the time for file timestamps, etc.  The current TTY driver assumes
Xan interrupt-driven keyboard, which should exist on most systems.
XThe distribution contains code for hard and floppy disk drivers, but
Xsince these were written for custom hardware, they are provided only
Xas templates to write new ones.
X
X
XHow UZI is different than real Unix:
X
XUZI implements almost all of the 7th Edition functionality.
XAll file I/O, directories, mountable file systems, user and group IDs,
Xpipes, and applicable device I/O are supported.  Process control
X(fork(), execve(), signal(), kill(), pause(), alarm(), and wait()) are fully
Xsupported.  The number of processes is limited only by the swap space
Xavailable.  As mentioned above,  UZI implements Unix well enough to
Xrun the Bourne shell in its full functionality.  The only changes made
Xto the shell's source code were to satisfy the limitations of the C compiler.
X
XHere is a (possibly incomplete) list of missing features and limitations:
X
X    The debugger- and profiler-related system calls do not exist.
X
X    The old 6th edition seek() was implemented, instead of lseek().
X
X    The supplied TTY driver is bare-bones.  It supports only one port,
X    and most IOCTLs are not supported.
X
X    Inode numbers are only 16-bit, so filesystems are 32 Meg or less.
X
X    File dates are not in the standard format.  Instead they look like
X    those used by MS-DOS.
X
X    The 4.2BSD execve() was implemented.  Additional flavors of exec()
X    are supported by the library.
X
X    The format of the device driver switch table is unlike that of
X    the 7th Edition.
X
X    The necessary semaphores and locking mechanisms to implement 
X    reentrant disk I/O are not there.  This would make it harder to
X    implement interrupt-driven disk I/O without busy-waiting.
X
X
XA Description of this Release:
X
XHere is a list of the files supplied, and a brief description of each:
X
X
Xintro:		What you are reading
X
Xconfig.h:	Setup parameters, such as table sizes, and the device
X		driver switch table.
X
Xunix.h:		All strcuture declarations, typedefs and defines.
X		(Includes things like errno.h).
X
Xextern.h:	Declarations of all global variables and tables.
X
Xdata.c:		Dummy to source extern.h and devine globals.
X
Xdispatch.c:	System call dispatch table.
X
Xscall1.c:	System calls, mostly file-related.
X
Xscall2.c:	Rest of system calls.
X
Xfilesys.c:	Routines for managing file system.
X
Xprocess.c:	Routines for process management and context switching.
X		Somewhat machine-dependent.
X
Xdevio.c:	Generic I/O routines, including queue routines.
X
Xdevtty.c:	Simple TTY driver, slightly-machine dependent.
X
Xdevwd.c:	Hard disk driver.  Very machine-dependent.
X
Xdevflop.c:	Floppy disk driver.  Very machine-dependent.
X
Xdevmisc.c:	Simple device drivers, such as /dev/mem.
X
Xmachdep.c:	Machine-dependent code, especially real-time-clock and
X		interrupt handling code.
X
Xextras.c:	Procedures missing from the Q/C compiler's library.
X
Xfiller.mac:	Dummy to make linker load UZI at correct address.
X
Xmakeunix.sub:	CP/M SUBMIT file to compile everything.
X
Xloadunix.sub:	CP/M SUBMIT file to load everything.
X
X
XMiscellaneous Notes:
X
XUZI was compiled with the Code Works Q/C C compiler and the Microsoft
XM80 assembler under the CP/M operating system, on the same hardware
Xit runs on.  Also used was a version of cpp ported to CP/M, since
Xthe Q/C compiler does not handle macros with arguments.  However, there
Xare only a couple of these in the code, and they could easily be removed.
X
XBecause UZI occupies the upper 32K of memory, the standard L80 linker
Xcould not be used to link it.  Instead, a homebrew L80 replacement linker
Xwas used.  This generated a 64K-byte CP/M .COM file, which has the lower 
X32K pruned by the CP/M PIP utility.  This is the reason for appearance
Xof the string "MOMBASSA" in filler.mac and loadunix.sub.
X
XTo boot UZI, a short CP/M program was run that reads in the UZI image,
Xcopies it to the upper 32K of memory, and jumps to its start address.
XOther CP/M programs were written to build, inspect, and check UZI filesystems
Xunder CP/M.  These made it possible to have a root file system made before
Xstarting up UZI.  If the demand exists, these programs can be included
Xin another release.
X
X
XRunning programs under UZI:
X
XA number of 7th Edition, System V, and 4.2BSD programs were ported to
XUZI.  Most notably, the Bourne shell and ed run fine under UZI.
XIn addition the 4.2BSD stdio library was also ported.  This, along
Xwith the Code Works Q/C library and miscellaneous System V library 
Xfunctions, was used when porting programs.
X
XDue to obvious legal reasons, the source or executables for most of these
Xprograms cannot be released.  However, some kernel-dependent programs
Xsuch as ps and fsck were written from scratch and can be included in future
Xreleases.  Also, a package was created that can be linked to CP/M .COM
Xfiles that will allow them to run under UZI.  This was used to get
Xthe M80 assembler and L80 linker to run under UZI.  Cpp was also
Xported to UZI.  However, it was not possible to fit the Q/C compiler
Xinto 32K, so all programs (and UZI itself) were cross-compiled under CP/M.
X
XThe Minix operating system, written for PCs by Andrew Tanenbaum et al,
Xcontains many programs that should compile and run under UZI.  Since
XMinix is much less encumbered by licensing provisions than real Unix,
Xit would make sense to port Minix programs to UZI.  In fact, UZI itself
Xcould be ported to the PC, and used as a replacement for the Minix kernel.
EOF_intro
echo 'Done'

echo -n 'Extracting filelist ... '
sed 's/^X//' > filelist << 'EOF_filelist'
Xintro
Xfilelist
Xconfig.h
Xunix.h
Xextern.h
Xdata.c
Xdispatch.c
Xmachdep.c
Xscall1.c
Xscall2.c
Xfilesys.c
Xprocess.c
Xdevio.c
Xdevtty.c
Xdevwd.c
Xdevflop.c
Xdevmisc.c
Xextras.c
Xfiller.mac
Xmakeunix.sub
Xloadunix.sub
EOF_filelist
echo 'Done'

echo -n 'Extracting config.h ... '
sed 's/^X//' > config.h << 'EOF_config.h'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  config.h
X***************************************************/
X
X
X/* Remake devio.c when this is changed */
X#ifdef DEVIO
X
Xextern wd_open(), wd_read(),wd_write();
Xextern fd_open(), fd_read(),fd_write();
Xextern tty_open(), tty_close(), tty_read(),tty_write();
Xextern lpr_open(), lpr_close(), lpr_write();
Xextern mem_read(),mem_write();
Xextern mt_read(), mt_write(), mt_open(), mt_close();
Xextern null_write();
X
X
Xstatic struct devsw dev_tab[] =  /* The device driver switch table */
X{
X    { 0x2b38, wd_open, ok,       wd_read, wd_write, nogood },
X    { 0, fd_open, ok,       fd_read, fd_write, nogood },        /* floppy */
X    { 0x3844, wd_open, ok,       wd_read, wd_write, nogood },
X    { 0x252b, wd_open, ok,       wd_read, wd_write, nogood },   /* Swap */
X    { 0, lpr_open, lpr_close, nogood, lpr_write, nogood},     /* printer */
X    { 0, tty_open, tty_close, tty_read, tty_write, ok },      /* tty */
X    { 0, ok, ok, ok, null_write, nogood },                      /* /dev/null */
X    { 0, ok, ok, mem_read, mem_write, nogood },              /* /dev/mem */
X    { 0, mt_open, mt_close, mt_read, mt_write, nogood }
X};
X
X#endif
X
X#define NDEVS   3    /* Devices 0..NDEVS-1 are capable of being mounted */
X#define TTYDEV  5    /* Device used by kernel for messages, panics */
X#define SWAPDEV  3   /* Device for swapping. */
X#define NBUFS  4     /* Number of block buffers */
X
EOF_config.h
echo 'Done'

echo -n 'Extracting unix.h ... '
sed 's/^X//' > unix.h << 'EOF_unix.h'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  unix.h
X***************************************************/
X
X
X#ifndef vax
X#define CPM
X#endif
X
X#define UFTSIZE 10    /* Number of user files */
X#define OFTSIZE 15    /* Open file table size */
X#define ITABSIZE 20   /* Inode table size */
X#define PTABSIZE 20   /* Process table size */
X
X#define NSIGS 16        /* Number of signals <= 16 */
X
X#define ROOTINODE 1  /* Inode # of /  for all mounted filesystems. */
X
X#define TICKSPERSEC 10  /*Ticks per second */
X#define MAXTICKS   10   /* Max ticks before swapping out (time slice) */
X
X#define ARGBLK 0        /* Block number on SWAPDEV for arguments */
X#define PROGBASE ((char *)(0x100))
X#define MAXEXEC 0       /* Max no of blks of executable file */
X
X#define EMAGIC 0xc3     /* Header of executable */
X#define CMAGIC 24721    /* Random number for cinode c_magic */
X#define SMOUNTED 12742  /* Magic number to specify mounted filesystem */
X#define NULL 0
X
X
X/* These macros are simply to trick the compiler into generating
X   more compact code. */
X
X#define ifnull(e) if(e){}else
X#define ifnot(e) if(e){}else
X#define ifzero(e) if(e){}else
X
X
X
X#ifdef CPM
X    typedef unsigned uint16;
X    typedef int int16;
X#else
X    typedef unsigned short uint16;
X    typedef short int16;
X#endif
X
X
Xtypedef struct s_queue {
X    char *q_base;   /* Pointer to data */
X    char *q_head;  /* Pointer to addr of next char to read. */
X    char *q_tail;  /* Pointer to where next char to insert goes. */
X    int q_size; /* Max size of queue */
X    int q_count;        /* How many characters presently in queue */
X    int q_wakeup;       /* Threshold for waking up processes waiting on queue */
X} queue_t;
X
X
X
Xtypedef struct time_s {
X    uint16 t_time;
X    uint16 t_date;
X} time_t;
X
X
X/* User's structure for times() system call */
X
Xstruct tms {
X	time_t  tms_utime;
X	time_t  tms_stime;
X	time_t  tms_cutime;
X	time_t  tms_cstime;
X	time_t  tms_etime;      /* Elapsed real time */
X} ;
X
X
X/* Flags for setftime() */
X#define A_TIME 1
X#define M_TIME 2
X#define C_TIME 4
X
X
Xtypedef struct off_t {
X    uint16 o_blkno;  /* Block number */
X    int16 o_offset;     /* Offset within block 0-511 */
X} off_t;
X
X
Xtypedef uint16 blkno_t;  /* Can have 65536 512-byte blocks in filesystem */
X#define NULLBLK ((blkno_t)-1)
X
X
Xtypedef struct blkbuf {
X    char        bf_data[512];    /* This MUST be first ! */
X    char        bf_dev;
X    blkno_t     bf_blk;
X    char        bf_dirty;
X    char        bf_busy;
X    uint16      bf_time;        /* LRU time stamp */
X/*    struct blkbuf *bf_next;    /* LRU free list pointer */
X} blkbuf, *bufptr;
X
X
Xtypedef struct dinode {
X    uint16 i_mode;
X    uint16 i_nlink;
X    uint16 i_uid;
X    uint16 i_gid;
X    off_t    i_size;
X    time_t   i_atime;
X    time_t   i_mtime;
X    time_t   i_ctime;
X    blkno_t  i_addr[20];
X} dinode;               /* Exactly 64 bytes long! */
X
X
Xstruct  stat    /* Really only used by users */
X{
X	int16   st_dev;
X	uint16  st_ino;
X	uint16  st_mode;
X	uint16  st_nlink;
X	uint16  st_uid;
X	uint16  st_gid;
X	uint16  st_rdev;
X	off_t   st_size;
X	time_t  st_atime;
X	time_t  st_mtime;
X	time_t  st_ctime;
X};
X
X/* Bit masks for i_mode and st_mode */
X
X#define OTH_EX  0001
X#define OTH_WR  0002
X#define OTH_RD  0004
X#define GRP_EX  0010
X#define GRP_WR  0020
X#define GRP_RD  0040
X#define OWN_EX  0100
X#define OWN_WR  0200
X#define OWN_RD  0400
X
X#define SAV_TXT 01000
X#define SET_GID 02000
X#define SET_UID 04000
X
X#define MODE_MASK 07777
X
X#define F_REG  0100000
X#define F_DIR   040000
X#define F_PIPE  010000
X#define F_BDEV  060000
X#define F_CDEV  020000
X
X#define F_MASK  0170000
X
X
X
Xtypedef struct cinode {
X    int    c_magic;             /* Used to check for corruption. */
X    int    c_dev;               /* Inode's device */
X    unsigned   c_num;           /* Inode # */
X    dinode   c_node;
X    char     c_refs;            /* In-core reference count */
X    char     c_dirty;           /* Modified flag. */
X} cinode, *inoptr;
X
X#define NULLINODE ((inoptr)NULL)
X#define NULLINOPTR ((inoptr*)NULL)
X
X
Xtypedef struct direct {
X    uint16 d_ino;
X    char     d_name[14];
X} direct;
X
X
X
Xtypedef struct filesys {
X    int16       s_mounted;
X    uint16      s_isize;
X    uint16      s_fsize;
X    int16       s_nfree;
X    blkno_t     s_free[50];
X    int16       s_ninode;
X    uint16      s_inode[50];
X    int16       s_fmod;
X    time_t      s_time;
X    blkno_t     s_tfree;
X    uint16      s_tinode;
X    inoptr      s_mntpt; /* Mount point */
X} filesys, *fsptr;
X
Xtypedef struct oft {
X    off_t       o_ptr;   /* File position point16er */
X    inoptr      o_inode; /* Pointer into in-core inode table */
X    char        o_access; /* O_RDONLY, O_WRONLY, or O_RDWR */
X    char        o_refs;  /* Reference count: depends on # of active children*/
X} oft;
X
X
X/* Process table p_status values */
X
X#define P_EMPTY         0    /* Unused slot */
X#define P_RUNNING       1    /* Currently running process */
X#define P_READY         2    /* Runnable   */
X#define P_SLEEP         3    /* Sleeping; can be awakened by signal */
X#define P_XSLEEP        4    /* Sleeping, don't wake up for signal */
X#define P_PAUSE         5    /* Sleeping for pause(); can wakeup for signal */
X#define P_FORKING       6    /* In process of forking; do not mess with */
X#define P_WAIT          7    /* Executed a wait() */
X#define P_ZOMBIE        8    /* Exited. */
X
X
X#define SIGHUP  1       
X#define SIGINT  2      
X#define SIGQUIT 3     
X#define SIGILL  4    
X#define SIGTRAP 5   
X#define SIGIOT  6  
X#define SIGEMT  7 
X#define SIGFPE  8 
X#define SIGKILL 9
X#define SIGBUS  10
X#define SIGSEGV 11
X#define SIGSYS  12
X#define SIGPIPE 13
X#define SIGALRM 14
X#define SIGTERM 15
X
X#define SIG_DFL         (int (*)())0
X#define SIG_IGN         (int (*)())1
X
X#define sigmask(sig)    (1<<(sig))
X
X/* Process table entry */
X
Xtypedef struct p_tab {
X    char        p_status;       /* Process status */
X    int p_pid;    /* Process ID */
X    int p_uid;
X    struct p_tab *p_pptr;    /* Process parent's table entry */
X    blkno_t     p_swap;   /* Starting block of swap space */
X    unsigned    p_alarm;        /* Seconds until alarm goes off */
X    unsigned    p_exitval;      /* Exit value */
X    /* Everything below here is overlaid by time info at exit */
X    char       *p_wait;         /* Address of thing waited for */
X    int p_priority;     /* Process priority */
X    uint16      p_pending;      /* Pending signals */
X    uint16      p_ignored;      /* Ignored signals */
X} p_tab, *ptptr;
X
X/* Per-process data (Swapped with process) */
X
X#asm 8080
X?OSYS equ 2     ;byte offsets of elements of u_data
X?OCALL equ 3
X?ORET equ 4     ;return location
X?ORVAL equ 6    ;return value
X?OERR equ 8     ;error number
X?OSP equ 10     ;users stack pointer
X?OBC equ 12     ;users frame pointer
X#endasm
X
Xtypedef struct u_data {
X    struct p_tab *u_ptab;       /* Process table pointer */
X    char        u_insys;        /* True if in kernel */
X    char        u_callno;       /* sys call being executed. */
X    char        *u_retloc;     /* Return location from sys call */
X    int         u_retval;       /* Return value from sys call */
X    int         u_error;                /* Last error number */
X    char        *u_sp;          /* Used when a process is swapped. */
X    char        *u_bc;          /* Place to save user's frame pointer */
X    int         u_argn;         /* Last arg */
X    int         u_argn1;        /* This way because args on stack backwards */
X    int         u_argn2;
X    int         u_argn3;        /* args n-3, n-2, n-1, and n */
X
X    char *      u_base;         /* Source or dest for I/O */
X    unsigned    u_count;        /* Amount for I/O */
X    off_t       u_offset;       /* Place in file for I/O */
X    struct blkbuf *u_buf;
X
X    int         u_gid;
X    int         u_euid;
X    int         u_egid;
X    int         u_mask;         /* umask: file creation mode mask */
X    time_t      u_time;         /* Start time */
X    char        u_files[UFTSIZE];       /* Process file table:
X	                        contains indexes into open file table. */
X    inoptr      u_cwd;          /* Index into inode table of cwd. */
X    char        *u_break;        /* Top of data space */
X
X    inoptr      u_ino;  /* Used during execve() */
X    char        *u_isp;  /* Value of initial sp (argv) */
X
X    int         (*u_sigvec[NSIGS])();   /* Array of signal vectors */
X    int         u_cursig;       /* Signal currently being caught */
X    char        u_name[8];      /* Name invoked with */
X    time_t      u_utime;        /* Elapsed ticks in user mode */
X    time_t      u_stime;        /* Ticks in system mode */
X    time_t      u_cutime;       /* Total childrens ticks */
X    time_t      u_cstime;
X
X} u_data;
X
X
X/* Struct to temporarily hold arguments in execve */
Xstruct s_argblk {
X    int a_argc;
X    int a_arglen;
X    int a_envc;
X    char a_buf[512-3*sizeof(int)];
X};
X
X
X/* The device driver switch table */
X
Xtypedef struct devsw {
X    int minor;          /* The minor device number (an argument to below) */
X    int (*dev_open)();  /* The routines for reading, etc */
X    int (*dev_close)(); /* format: op(minor,blkno,offset,count,buf); */
X    int (*dev_read)();  /* offset would be ignored for block devices */
X    int (*dev_write)(); /* blkno and offset ignored for tty, etc. */
X    int (*dev_ioctl)(); /* count is rounded to 512 for block devices */
X} devsw;
X
X
X
X/* Open() parameters. */
X
X#define O_RDONLY        0
X#define O_WRONLY        1
X#define O_RDWR          2
X
X/*
X * Error codes
X */
X
X#define EPERM           1               
X#define ENOENT          2               
X#define ESRCH           3               
X#define EINTR           4               
X#define EIO             5               
X#define ENXIO           6               
X#define E2BIG           7               
X#define ENOEXEC         8               
X#define EBADF           9               
X#define ECHILD          10              
X#define EAGAIN          11              
X#define ENOMEM          12              
X#define EACCES          13              
X#define EFAULT          14              
X#define ENOTBLK         15              
X#define EBUSY           16              
X#define EEXIST          17              
X#define EXDEV           18              
X#define ENODEV          19              
X#define ENOTDIR         20              
X#define EISDIR          21              
X#define EINVAL          22              
X#define ENFILE          23              
X#define EMFILE          24              
X#define ENOTTY          25              
X#define ETXTBSY         26              
X#define EFBIG           27              
X#define ENOSPC          28              
X#define ESPIPE          29              
X#define EROFS           30              
X#define EMLINK          31              
X#define EPIPE           32              
X#define ENAMETOOLONG    63              
X
X#include "config.h"
X
EOF_unix.h
echo 'Done'

echo -n 'Extracting extern.h ... '
sed 's/^X//' > extern.h << 'EOF_extern.h'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  extern.h
X***************************************************/
X
X
X/* These are the global data structures */
X
X#ifdef MAIN
X#define extern  
X#endif
X
X
Xextern struct u_data udata; /* MUST BE FIRST */
Xextern struct p_tab ptab[PTABSIZE];
X
Xextern inoptr root;   /* Address of root dir in inode table */
Xextern int16 ROOTDEV;  /* Device number of root filesystem. */
X
Xextern struct cinode i_tab[ITABSIZE];    /* In-core inode table */
Xextern struct oft of_tab[OFTSIZE]; /* Open File Table */
X
Xextern struct filesys fs_tab[NDEVS];  /* Table entry for each
X                                        device with a filesystem. */
Xextern struct blkbuf bufpool[NBUFS];
X
Xextern ptptr initproc; /* The process table address of the first process. */
Xextern int16 inint;   /* flag is set whenever interrupts are being serviced */
X
Xextern int16 sec;   /* Tick counter for counting off one second */
Xextern int16 runticks;  /* Number of ticks current process has been
X                         swapped in */
X
Xextern time_t tod;      /* Time of day */
Xextern time_t ticks;    /* Cumulative tick counter, in minutes and ticks  */
X
Xextern char *swapbase;          /* Used by device driver for swapping */
Xextern unsigned swapcnt;
Xextern blkno_t swapblk;
X
Xextern char vector[3];  /* Place for interrupt vector */
X
X#ifdef MAIN
X#undef extern
X#endif
X
X
EOF_extern.h
echo 'Done'

echo -n 'Extracting data.c ... '
sed 's/^X//' > data.c << 'EOF_data.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  data.c
X***************************************************/
X
X#include "unix.h"
X#define MAIN
X#asm 8080
XCSEG
X@init?::
X        EXTRN   fs@init?
X        JMP     fs@init?
X#endasm
X#include "extern.h"
X
EOF_data.c
echo 'Done'

echo -n 'Extracting dispatch.c ... '
sed 's/^X//' > dispatch.c << 'EOF_dispatch.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  dispatch.c
X***************************************************/
X
X
X/* Dispatch table for system calls */
Xint     __exit(),
X        _open(),
X        _close(),
X        _creat(),
X        _mknod(),
X        _link(),
X        _unlink(),
X        _read(),
X        _write(),
X        _seek(),
X        _chdir(),
X        _sync(),
X        _access(),
X        _chmod(),
X        _chown(),
X        _stat(),
X        _fstat(),
X        _dup(),
X        _getpid(),
X        _getppid(),
X        _getuid(),
X        _umask(),
X        _getfsys(),
X        _execve(),
X        _wait(),
X        _setuid(),
X        _setgid(),
X        _time(),
X        _stime(),
X        _ioctl(),
X        _brk(),
X        _sbrk(),
X        _fork(),
X        _mount(),
X        _umount(),
X        _signal(),
X        _dup2(),
X        _pause(),
X        _alarm(),
X        _kill(),
X        _pipe(),
X        _getgid(),
X        _times();
X
Xint (*disp_tab[])() =
X{       __exit,
X        _open,
X        _close,
X        _creat,
X        _mknod,
X        _link,
X        _unlink,
X        _read,
X        _write,
X        _seek,
X        _chdir,
X        _sync,
X        _access,
X        _chmod,
X        _chown,
X        _stat,
X        _fstat,
X        _dup,
X        _getpid,
X        _getppid,
X        _getuid,
X        _umask,
X        _getfsys,
X        _execve,
X        _wait,
X        _setuid,
X        _setgid,
X        _time,
X        _stime,
X        _ioctl,
X        _brk,
X        _sbrk,
X        _fork,
X        _mount,
X        _umount,
X        _signal,
X        _dup2,
X        _pause,
X        _alarm,
X        _kill,
X        _pipe,
X        _getgid,
X        _times
X };
X
Xchar dtsize = sizeof(disp_tab) / sizeof(int(*)()) - 1;
X
X
EOF_dispatch.c
echo 'Done'

echo -n 'Extracting extras.c ... '
sed 's/^X//' > extras.c << 'EOF_extras.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  extras.c
X***************************************************/
X
X
Xbcopy()
X{
X#asm 8080
X; BCOPY(SRC,DEST,COUNT)
X;
X        POP     H
X        SHLD    HOLDER
X.Z80
X        LD      (BCHLDR),BC
X.8080   
X        POP     B
X        POP     D
X        POP     H
X        PUSH    H
X        PUSH    H
X        PUSH    H
X.Z80
X        LDIR
X.8080
X        LHLD    HOLDER
X.Z80
X        LD      BC,(BCHLDR)
X.8080
X        PCHL
X#endasm
X}
X
X#asm 
X;
XHOLDER: DS      2
XBCHLDR: DS      2
X;
X;
X#endasm
X
X
Xbzero(ptr,count)
Xchar *ptr;
Xint count;
X{
X    *ptr = 0;
X    bcopy(ptr,ptr+1,count-1);
X}
X
X
Xabort()
X{
X#asm 8080
X        DI
X        JMP     $
X#endasm
X}
X
EOF_extras.c
echo 'Done'

echo -n 'Extracting machdep.c ... '
sed 's/^X//' > machdep.c << 'EOF_machdep.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  machdep.c
X***************************************************/
X
X
X#include "unix.h"
X#include "extern.h"
X
X
X/* This is called at the very beginning to initialize everything. */
X/* It is the equivalent of main() */
X
Xfs_init()
X{
X    di();
X    stkreset();
X    /* Initialize the interrupt vector */
X    initvec();
X    inint = 0;
X    udata.u_insys = 1;
X    /* Turn off clock */
X    out(0,0xf1);
X    ei();
X
X    init2();   /* in process.c */
X}
X
X
X/* This checks to see if a user-suppled address is legitimate */
Xvaladr(base,size)
Xchar *base;
Xuint16 size;
X{
X    if (base < PROGBASE || base+size >= (char *)&udata)
X    {
X        udata.u_error = EFAULT;
X        return(0);
X    }
X    return(1);
X}
X
X
X/* This adds two tick counts together.
XThe t_time field holds up to one second of ticks,
Xwhile the t_date field counts minutes */
X
Xaddtick(t1,t2)
Xtime_t *t1, *t2;
X{
X
X    t1->t_time += t2->t_time;
X    t1->t_date += t2->t_date;
X    if (t1->t_time >= 60*TICKSPERSEC)
X    {
X        t1->t_time -= 60*TICKSPERSEC;
X        ++t1->t_date;
X    }
X}
X
Xincrtick(t)
Xtime_t *t;
X{
X    if (++t->t_time == 60*TICKSPERSEC)
X    {
X        t->t_time = 0;
X        ++t->t_date;
X    }
X}
X
X
Xstkreset()
X{
X#asm 8080
X        POP     H
X        LXI     SP,udata?-2
X        PCHL
X#endasm
X}
X
X
Xtempstack()
X{
X#asm 8080
X        POP     H
X        LXI     SP,100H
X        PCHL
X#endasm
X}
X
X
X
Xinitvec()
X{
X#asm 8080
X        LXI     H,vector?
X        INX     H
X        MOV     A,L
X        ANI     0FEH
X        MOV     L,A     ;set hl to first even address in vector[].
X        MOV     A,H
X.Z80
X        LD      I,A     ;SET INTERRUPT REGISTER TO UPPER 8 BITS
X.8080
X        MOV     A,L
X        OUT     076H    ;set external vector register with low order byte
X        LXI     D,service?
X        MOV     M,E
X        INX     H
X        MOV     M,D     ;STORE ADDRESS OF SERVICE ROUTINE IN vector[].
X        RET
X#endasm
X}
X
Xextern int unix();
X
X
Xdoexec()
X{
X#asm 8080
X        POP     H
X        POP     H       ;get argument
X        SPHL            ;set stack pointer to it
X        MVI     A,0C3H  ;jump inst
X        STA     0030H   ;dest of RST6 instruction.
X        LXI     H,unix? ;entry address
X        SHLD    0031H
X        XRA     A
X        STA     udata? + ?OSYS
X        JMP     0100H
X#endasm
X}
X
X
Xstatic int cursig;
Xstatic int (*curvec)();
X
X/* This interrupt device routine calls the service routine of each device
Xthat could have interrupted. */
X
Xservice()
X{
X
X    ;
X#asm 8080
X        PUSH    PSW
X        PUSH    B
X        PUSH    D
X        PUSH    H
X.Z80
X        PUSH    IX
X        PUSH    IY
X.8080
X#endasm
X
X    inint = 1;
X
X    if (tty_int())
X        goto found;
X    if (clk_int())
X        goto found;
X/*  if (  ) ...   */
X
X    warning("Spurious interrupt");
X
Xfound:
X    inint = 0;
X
X    /* Deal with a pending caught signal, if any */
X    if (!udata.u_insys)
X        calltrap();
X    ;
X
X#asm 8080
X.Z80
X        POP     IY
X        POP     IX
X.8080
X        POP     H
X        POP     D
X        POP     B
X        POP     PSW
X        EI
X        RET
X#endasm
X
X}
X
X
X
Xcalltrap()
X{
X    /* Deal with a pending caught signal, if any. */
X        /* udata.u_insys should be false, and interrupts enabled.
X        remember, the user may never return from the trap routine */
X
X    if (udata.u_cursig)
X    {
X        cursig = udata.u_cursig;
X        curvec = udata.u_sigvec[cursig];
X        udata.u_cursig = 0;
X        udata.u_sigvec[cursig] = SIG_DFL;   /* Reset to default */
X        ei();
X        (*curvec)(cursig);
X        di();
X    } 
X}
X
X
X
X/* Port addresses of clock chip registers. */
X
X#define SECS 0xe2
X#define MINS 0xe3
X#define HRS 0xe4
X#define DAY 0xe6
X#define MON 0xe7
X#define YEAR 86
X
Xsttime()
X{
X    panic("Calling sttime");
X}
X
X
Xrdtime(tloc)
Xtime_t *tloc;
X{
X    di();
X    tloc->t_time = tod.t_time;
X    tloc->t_date = tod.t_date;
X    ei();
X}
X
X
X/* Update global time of day */
Xrdtod()
X{
X    tod.t_time = (tread(SECS)>>1) | (tread(MINS)<<5) | (tread(HRS)<<11);
X    tod.t_date = tread(DAY) | (tread(MON)<<5) | (YEAR<<9);
X}
X
X
X/* Read BCD clock register, convert to binary. */
Xtread(port)
Xuint16 port;
X{
X    int n;
X
X    n = in(port);
X    return ( 10*((n>>4)&0x0f) + (n&0x0f) );
X}
X
X
X/* Disable interrupts */
Xdi()
X{
X#asm 8080
X        DI      ;disable interrupts
X#endasm
X}
X
X/* Enable interrupts if we are not in service routine */
Xei()
X{
X    if (inint)
X        return;
X    ;   /* Empty statement necessary to fool compiler */
X
X#asm 8080
X        EI      ;disable interrupts
X#endasm
X}
X
X
X
X/* This shifts an unsigned int right 8 places. */
X
Xshift8()
X{
X#asm 8080
X        POP     D       ;ret addr
X        POP     H
X        MOV     L,H
X        MVI     H,0
X        MOV     A,L
X        ANA     A       ;set Z flag on result
X        PUSH    H
X        PUSH    D       ;restore stack
X#endasm
X}
X
X
X/* This prints an error message and dies. */
X
Xpanic(s)
Xchar *s;
X{
X    di();
X    inint = 1;
X    kprintf("PANIC: %s\n",s);
X    idump();
X    abort();
X}
X
X
Xwarning(s)
Xchar *s;
X{
X    kprintf("WARNING: %s\n",s);
X}
X
X
Xputs(s)
Xchar *s;
X{
X    while (*s)
X        kputchar(*(s++));
X}
X
Xkputchar(c)
Xint c;
X{
X    if (c == '\n')
X        _putc('\r');
X    _putc(c);
X    if (c == '\t')
X        puts("\177\177\177\177\177\177\177\177\177\177");
X}
X
X
X
Xidump()
X{
X    inoptr ip;
X    ptptr pp;
X    extern struct cinode i_tab[];
X
X    kprintf(
X        "\tMAGIC\tDEV\tNUM\tMODE\tNLINK\t(DEV)\tREFS\tDIRTY err %d root %d\n",
X            udata.u_error, root - i_tab);
X
X    for (ip=i_tab; ip < i_tab+ITABSIZE; ++ip)
X    {
X        kprintf("%d\t%d\t%d\t%u\t0%o\t%d\t%d\t%d\t%d\n",
X               ip-i_tab, ip->c_magic,ip->c_dev, ip->c_num,
X               ip->c_node.i_mode,ip->c_node.i_nlink,ip->c_node.i_addr[0],
X               ip->c_refs,ip->c_dirty);
X/*****
X        ifnot (ip->c_magic)     
X            break;
X******/
X    }
X
X    kprintf("\n\tSTAT\tWAIT\tPID\tPPTR\tALARM\tPENDING\tIGNORED\n");
X    for (pp=ptab; pp < ptab+PTABSIZE; ++pp)
X    {
X        kprintf("%d\t%d\t0x%x\t%d\t%d\t%d\tNewsgroups: comp.os.cpm
Subject: UZI, part 1 of 5
Expires: 
References: 
Sender: 
Reply-To: dbraun@cadavr.UUCP ()
Followup-To: 
Distribution: 
Organization: Corporate CAD, INTeL Corporation, Santa Clara, CA
Keywords: 


This and the next four postings contain a shell archive of UZI,
the Z-80 U**x Implementation.  Do the usual concatenation stuff.
I have no idea what happeden to the copy I mailed to comp.sources.misc.
I was going to upload this to the Royal Oak RCP/M, but it was apparently
down last weekend.  I will also soon post the UZI Utilities, which are
a collection of programs that will let you debug your device drivers
and build and manage UZI filesystems under CP/M.


UZI, part 1 of 5

#!/bin/sh
#
#Run this file through sh to get:
#    intro
#    filelist
#    config.h
#    unix.h
#    extern.h
#    data.c
#    dispatch.c
#    extras.c
#    machdep.c
#    makeunix.sub
#    loadunix.sub
echo -n 'Extracting intro ... '
sed 's/^X//' > intro << 'EOF_intro'
X		UZI: UNIX Z-80 IMPLEMENTATION
X
X		  Written by Douglas Braun
X
X
XIntroduction:
X
XUZI is an implementation of the Unix kernel written for a Z-80 based
Xcomputer.  It implementts almost all of the functionality of the
X7th Edition Unix kernel.  UZI was written to run on one specific
Xcollection of custom-built hardware, but since it can easily have device
Xdrivers added to it, and it does not use any memory management hardware,
Xit should be possible to port it to numerous computers that current use
Xthe CP/M operating system.  The source code is written mostly in C,
Xand was compiled with The Code Works' Q/C compiler.  UZI's code was
Xwritten from scratch, and contains no AT&T code, so it is not subject
Xto any of AT&T's copyright or licensing restrictions.  Numerous 7th
XEdition programs have been ported to UZI with little or no difficulty,
Xincluding the complete Bourne shell, ed, sed, dc, cpp, etc.
X
X
XHow it works:
X
XSince there is no standard memory management hardware on 8080-family
Xcomputers, UZI uses "total swapping" to achieve multiprocessing.
XThis has two implications:  First, UZI requires a reasonably fast
Xhard disk.  Second, there is no point in running a different process
Xwhile a process is waiting for disk I/O.  This simplifies the design
Xof the block device drivers, since they do not have to be interrupt-based.
X
XUZI itself occupies the upper 32K of memory, and the currently running
Xprocess occupies the lower 32K.   Since UZI currently barely fits in 32K,
Xa full 64K of RAM is necessary.
X
XUZI does need some additional hardware support.  First, there must be
Xsome sort of clock or timer that can provide a periodic interrupt.
XAlso, the current implementation uses an additional real-time clock
Xto get the time for file timestamps, etc.  The current TTY driver assumes
Xan interrupt-driven keyboard, which should exist on most systems.
XThe distribution contains code for hard and floppy disk drivers, but
Xsince these were written for custom hardware, they are provided only
Xas templates to write new ones.
X
X
XHow UZI is different than real Unix:
X
XUZI implements almost all of the 7th Edition functionality.
XAll file I/O, directories, mountable file systems, user and group IDs,
Xpipes, and applicable device I/O are supported.  Process control
X(fork(), execve(), signal(), kill(), pause(), alarm(), and wait()) are fully
Xsupported.  The number of processes is limited only by the swap space
Xavailable.  As mentioned above,  UZI implements Unix well enough to
Xrun the Bourne shell in its full functionality.  The only changes made
Xto the shell's source code were to satisfy the limitations of the C compiler.
X
XHere is a (possibly incomplete) list of missing features and limitations:
X
X    The debugger- and profiler-related system calls do not exist.
X
X    The old 6th edition seek() was implemented, instead of lseek().
X
X    The supplied TTY driver is bare-bones.  It supports only one port,
X    and most IOCTLs are not supported.
X
X    Inode numbers are only 16-bit, so filesystems are 32 Meg or less.
X
X    File dates are not in the standard format.  Instead they look like
X    those used by MS-DOS.
X
X    The 4.2BSD execve() was implemented.  Additional flavors of exec()
X    are supported by the library.
X
X    The format of the device driver switch table is unlike that of
X    the 7th Edition.
X
X    The necessary semaphores and locking mechanisms to implement 
X    reentrant disk I/O are not there.  This would make it harder to
X    implement interrupt-driven disk I/O without busy-waiting.
X
X
XA Description of this Release:
X
XHere is a list of the files supplied, and a brief description of each:
X
X
Xintro:		What you are reading
X
Xconfig.h:	Setup parameters, such as table sizes, and the device
X		driver switch table.
X
Xunix.h:		All strcuture declarations, typedefs and defines.
X		(Includes things like errno.h).
X
Xextern.h:	Declarations of all global variables and tables.
X
Xdata.c:		Dummy to source extern.h and devine globals.
X
Xdispatch.c:	System call dispatch table.
X
Xscall1.c:	System calls, mostly file-related.
X
Xscall2.c:	Rest of system calls.
X
Xfilesys.c:	Routines for managing file system.
X
Xprocess.c:	Routines for process management and context switching.
X		Somewhat machine-dependent.
X
Xdevio.c:	Generic I/O routines, including queue routines.
X
Xdevtty.c:	Simple TTY driver, slightly-machine dependent.
X
Xdevwd.c:	Hard disk driver.  Very machine-dependent.
X
Xdevflop.c:	Floppy disk driver.  Very machine-dependent.
X
Xdevmisc.c:	Simple device drivers, such as /dev/mem.
X
Xmachdep.c:	Machine-dependent code, especially real-time-clock and
X		interrupt handling code.
X
Xextras.c:	Procedures missing from the Q/C compiler's library.
X
Xfiller.mac:	Dummy to make linker load UZI at correct address.
X
Xmakeunix.sub:	CP/M SUBMIT file to compile everything.
X
Xloadunix.sub:	CP/M SUBMIT file to load everything.
X
X
XMiscellaneous Notes:
X
XUZI was compiled with the Code Works Q/C C compiler and the Microsoft
XM80 assembler under the CP/M operating system, on the same hardware
Xit runs on.  Also used was a version of cpp ported to CP/M, since
Xthe Q/C compiler does not handle macros with arguments.  However, there
Xare only a couple of these in the code, and they could easily be removed.
X
XBecause UZI occupies the upper 32K of memory, the standard L80 linker
Xcould not be used to link it.  Instead, a homebrew L80 replacement linker
Xwas used.  This generated a 64K-byte CP/M .COM file, which has the lower 
X32K pruned by the CP/M PIP utility.  This is the reason for appearance
Xof the string "MOMBASSA" in filler.mac and loadunix.sub.
X
XTo boot UZI, a short CP/M program was run that reads in the UZI image,
Xcopies it to the upper 32K of memory, and jumps to its start address.
XOther CP/M programs were written to build, inspect, and check UZI filesystems
Xunder CP/M.  These made it possible to have a root file system made before
Xstarting up UZI.  If the demand exists, these programs can be included
Xin another release.
X
X
XRunning programs under UZI:
X
XA number of 7th Edition, System V, and 4.2BSD programs were ported to
XUZI.  Most notably, the Bourne shell and ed run fine under UZI.
XIn addition the 4.2BSD stdio library was also ported.  This, along
Xwith the Code Works Q/C library and miscellaneous System V library 
Xfunctions, was used when porting programs.
X
XDue to obvious legal reasons, the source or executables for most of these
Xprograms cannot be released.  However, some kernel-dependent programs
Xsuch as ps and fsck were written from scratch and can be included in future
Xreleases.  Also, a package was created that can be linked to CP/M .COM
Xfiles that will allow them to run under UZI.  This was used to get
Xthe M80 assembler and L80 linker to run under UZI.  Cpp was also
Xported to UZI.  However, it was not possible to fit the Q/C compiler
Xinto 32K, so all programs (and UZI itself) were cross-compiled under CP/M.
X
XThe Minix operating system, written for PCs by Andrew Tanenbaum et al,
Xcontains many programs that should compile and run under UZI.  Since
XMinix is much less encumbered by licensing provisions than real Unix,
Xit would make sense to port Minix programs to UZI.  In fact, UZI itself
Xcould be ported to the PC, and used as a replacement for the Minix kernel.
EOF_intro
echo 'Done'

echo -n 'Extracting filelist ... '
sed 's/^X//' > filelist << 'EOF_filelist'
Xintro
Xfilelist
Xconfig.h
Xunix.h
Xextern.h
Xdata.c
Xdispatch.c
Xmachdep.c
Xscall1.c
Xscall2.c
Xfilesys.c
Xprocess.c
Xdevio.c
Xdevtty.c
Xdevwd.c
Xdevflop.c
Xdevmisc.c
Xextras.c
Xfiller.mac
Xmakeunix.sub
Xloadunix.sub
EOF_filelist
echo 'Done'

echo -n 'Extracting config.h ... '
sed 's/^X//' > config.h << 'EOF_config.h'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  config.h
X***************************************************/
X
X
X/* Remake devio.c when this is changed */
X#ifdef DEVIO
X
Xextern wd_open(), wd_read(),wd_write();
Xextern fd_open(), fd_read(),fd_write();
Xextern tty_open(), tty_close(), tty_read(),tty_write();
Xextern lpr_open(), lpr_close(), lpr_write();
Xextern mem_read(),mem_write();
Xextern mt_read(), mt_write(), mt_open(), mt_close();
Xextern null_write();
X
X
Xstatic struct devsw dev_tab[] =  /* The device driver switch table */
X{
X    { 0x2b38, wd_open, ok,       wd_read, wd_write, nogood },
X    { 0, fd_open, ok,       fd_read, fd_write, nogood },        /* floppy */
X    { 0x3844, wd_open, ok,       wd_read, wd_write, nogood },
X    { 0x252b, wd_open, ok,       wd_read, wd_write, nogood },   /* Swap */
X    { 0, lpr_open, lpr_close, nogood, lpr_write, nogood},     /* printer */
X    { 0, tty_open, tty_close, tty_read, tty_write, ok },      /* tty */
X    { 0, ok, ok, ok, null_write, nogood },                      /* /dev/null */
X    { 0, ok, ok, mem_read, mem_write, nogood },              /* /dev/mem */
X    { 0, mt_open, mt_close, mt_read, mt_write, nogood }
X};
X
X#endif
X
X#define NDEVS   3    /* Devices 0..NDEVS-1 are capable of being mounted */
X#define TTYDEV  5    /* Device used by kernel for messages, panics */
X#define SWAPDEV  3   /* Device for swapping. */
X#define NBUFS  4     /* Number of block buffers */
X
EOF_config.h
echo 'Done'

echo -n 'Extracting unix.h ... '
sed 's/^X//' > unix.h << 'EOF_unix.h'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  unix.h
X***************************************************/
X
X
X#ifndef vax
X#define CPM
X#endif
X
X#define UFTSIZE 10    /* Number of user files */
X#define OFTSIZE 15    /* Open file table size */
X#define ITABSIZE 20   /* Inode table size */
X#define PTABSIZE 20   /* Process table size */
X
X#define NSIGS 16        /* Number of signals <= 16 */
X
X#define ROOTINODE 1  /* Inode # of /  for all mounted filesystems. */
X
X#define TICKSPERSEC 10  /*Ticks per second */
X#define MAXTICKS   10   /* Max ticks before swapping out (time slice) */
X
X#define ARGBLK 0        /* Block number on SWAPDEV for arguments */
X#define PROGBASE ((char *)(0x100))
X#define MAXEXEC 0       /* Max no of blks of executable file */
X
X#define EMAGIC 0xc3     /* Header of executable */
X#define CMAGIC 24721    /* Random number for cinode c_magic */
X#define SMOUNTED 12742  /* Magic number to specify mounted filesystem */
X#define NULL 0
X
X
X/* These macros are simply to trick the compiler into generating
X   more compact code. */
X
X#define ifnull(e) if(e){}else
X#define ifnot(e) if(e){}else
X#define ifzero(e) if(e){}else
X
X
X
X#ifdef CPM
X    typedef unsigned uint16;
X    typedef int int16;
X#else
X    typedef unsigned short uint16;
X    typedef short int16;
X#endif
X
X
Xtypedef struct s_queue {
X    char *q_base;   /* Pointer to data */
X    char *q_head;  /* Pointer to addr of next char to read. */
X    char *q_tail;  /* Pointer to where next char to insert goes. */
X    int q_size; /* Max size of queue */
X    int q_count;        /* How many characters presently in queue */
X    int q_wakeup;       /* Threshold for waking up processes waiting on queue */
X} queue_t;
X
X
X
Xtypedef struct time_s {
X    uint16 t_time;
X    uint16 t_date;
X} time_t;
X
X
X/* User's structure for times() system call */
X
Xstruct tms {
X	time_t  tms_utime;
X	time_t  tms_stime;
X	time_t  tms_cutime;
X	time_t  tms_cstime;
X	time_t  tms_etime;      /* Elapsed real time */
X} ;
X
X
X/* Flags for setftime() */
X#define A_TIME 1
X#define M_TIME 2
X#define C_TIME 4
X
X
Xtypedef struct off_t {
X    uint16 o_blkno;  /* Block number */
X    int16 o_offset;     /* Offset within block 0-511 */
X} off_t;
X
X
Xtypedef uint16 blkno_t;  /* Can have 65536 512-byte blocks in filesystem */
X#define NULLBLK ((blkno_t)-1)
X
X
Xtypedef struct blkbuf {
X    char        bf_data[512];    /* This MUST be first ! */
X    char        bf_dev;
X    blkno_t     bf_blk;
X    char        bf_dirty;
X    char        bf_busy;
X    uint16      bf_time;        /* LRU time stamp */
X/*    struct blkbuf *bf_next;    /* LRU free list pointer */
X} blkbuf, *bufptr;
X
X
Xtypedef struct dinode {
X    uint16 i_mode;
X    uint16 i_nlink;
X    uint16 i_uid;
X    uint16 i_gid;
X    off_t    i_size;
X    time_t   i_atime;
X    time_t   i_mtime;
X    time_t   i_ctime;
X    blkno_t  i_addr[20];
X} dinode;               /* Exactly 64 bytes long! */
X
X
Xstruct  stat    /* Really only used by users */
X{
X	int16   st_dev;
X	uint16  st_ino;
X	uint16  st_mode;
X	uint16  st_nlink;
X	uint16  st_uid;
X	uint16  st_gid;
X	uint16  st_rdev;
X	off_t   st_size;
X	time_t  st_atime;
X	time_t  st_mtime;
X	time_t  st_ctime;
X};
X
X/* Bit masks for i_mode and st_mode */
X
X#define OTH_EX  0001
X#define OTH_WR  0002
X#define OTH_RD  0004
X#define GRP_EX  0010
X#define GRP_WR  0020
X#define GRP_RD  0040
X#define OWN_EX  0100
X#define OWN_WR  0200
X#define OWN_RD  0400
X
X#define SAV_TXT 01000
X#define SET_GID 02000
X#define SET_UID 04000
X
X#define MODE_MASK 07777
X
X#define F_REG  0100000
X#define F_DIR   040000
X#define F_PIPE  010000
X#define F_BDEV  060000
X#define F_CDEV  020000
X
X#define F_MASK  0170000
X
X
X
Xtypedef struct cinode {
X    int    c_magic;             /* Used to check for corruption. */
X    int    c_dev;               /* Inode's device */
X    unsigned   c_num;           /* Inode # */
X    dinode   c_node;
X    char     c_refs;            /* In-core reference count */
X    char     c_dirty;           /* Modified flag. */
X} cinode, *inoptr;
X
X#define NULLINODE ((inoptr)NULL)
X#define NULLINOPTR ((inoptr*)NULL)
X
X
Xtypedef struct direct {
X    uint16 d_ino;
X    char     d_name[14];
X} direct;
X
X
X
Xtypedef struct filesys {
X    int16       s_mounted;
X    uint16      s_isize;
X    uint16      s_fsize;
X    int16       s_nfree;
X    blkno_t     s_free[50];
X    int16       s_ninode;
X    uint16      s_inode[50];
X    int16       s_fmod;
X    time_t      s_time;
X    blkno_t     s_tfree;
X    uint16      s_tinode;
X    inoptr      s_mntpt; /* Mount point */
X} filesys, *fsptr;
X
Xtypedef struct oft {
X    off_t       o_ptr;   /* File position point16er */
X    inoptr      o_inode; /* Pointer into in-core inode table */
X    char        o_access; /* O_RDONLY, O_WRONLY, or O_RDWR */
X    char        o_refs;  /* Reference count: depends on # of active children*/
X} oft;
X
X
X/* Process table p_status values */
X
X#define P_EMPTY         0    /* Unused slot */
X#define P_RUNNING       1    /* Currently running process */
X#define P_READY         2    /* Runnable   */
X#define P_SLEEP         3    /* Sleeping; can be awakened by signal */
X#define P_XSLEEP        4    /* Sleeping, don't wake up for signal */
X#define P_PAUSE         5    /* Sleeping for pause(); can wakeup for signal */
X#define P_FORKING       6    /* In process of forking; do not mess with */
X#define P_WAIT          7    /* Executed a wait() */
X#define P_ZOMBIE        8    /* Exited. */
X
X
X#define SIGHUP  1       
X#define SIGINT  2      
X#define SIGQUIT 3     
X#define SIGILL  4    
X#define SIGTRAP 5   
X#define SIGIOT  6  
X#define SIGEMT  7 
X#define SIGFPE  8 
X#define SIGKILL 9
X#define SIGBUS  10
X#define SIGSEGV 11
X#define SIGSYS  12
X#define SIGPIPE 13
X#define SIGALRM 14
X#define SIGTERM 15
X
X#define SIG_DFL         (int (*)())0
X#define SIG_IGN         (int (*)())1
X
X#define sigmask(sig)    (1<<(sig))
X
X/* Process table entry */
X
Xtypedef struct p_tab {
X    char        p_status;       /* Process status */
X    int p_pid;    /* Process ID */
X    int p_uid;
X    struct p_tab *p_pptr;    /* Process parent's table entry */
X    blkno_t     p_swap;   /* Starting block of swap space */
X    unsigned    p_alarm;        /* Seconds until alarm goes off */
X    unsigned    p_exitval;      /* Exit value */
X    /* Everything below here is overlaid by time info at exit */
X    char       *p_wait;         /* Address of thing waited for */
X    int p_priority;     /* Process priority */
X    uint16      p_pending;      /* Pending signals */
X    uint16      p_ignored;      /* Ignored signals */
X} p_tab, *ptptr;
X
X/* Per-process data (Swapped with process) */
X
X#asm 8080
X?OSYS equ 2     ;byte offsets of elements of u_data
X?OCALL equ 3
X?ORET equ 4     ;return location
X?ORVAL equ 6    ;return value
X?OERR equ 8     ;error number
X?OSP equ 10     ;users stack pointer
X?OBC equ 12     ;users frame pointer
X#endasm
X
Xtypedef struct u_data {
X    struct p_tab *u_ptab;       /* Process table pointer */
X    char        u_insys;        /* True if in kernel */
X    char        u_callno;       /* sys call being executed. */
X    char        *u_retloc;     /* Return location from sys call */
X    int         u_retval;       /* Return value from sys call */
X    int         u_error;                /* Last error number */
X    char        *u_sp;          /* Used when a process is swapped. */
X    char        *u_bc;          /* Place to save user's frame pointer */
X    int         u_argn;         /* Last arg */
X    int         u_argn1;        /* This way because args on stack backwards */
X    int         u_argn2;
X    int         u_argn3;        /* args n-3, n-2, n-1, and n */
X
X    char *      u_base;         /* Source or dest for I/O */
X    unsigned    u_count;        /* Amount for I/O */
X    off_t       u_offset;       /* Place in file for I/O */
X    struct blkbuf *u_buf;
X
X    int         u_gid;
X    int         u_euid;
X    int         u_egid;
X    int         u_mask;         /* umask: file creation mode mask */
X    time_t      u_time;         /* Start time */
X    char        u_files[UFTSIZE];       /* Process file table:
X	                        contains indexes into open file table. */
X    inoptr      u_cwd;          /* Index into inode table of cwd. */
X    char        *u_break;        /* Top of data space */
X
X    inoptr      u_ino;  /* Used during execve() */
X    char        *u_isp;  /* Value of initial sp (argv) */
X
X    int         (*u_sigvec[NSIGS])();   /* Array of signal vectors */
X    int         u_cursig;       /* Signal currently being caught */
X    char        u_name[8];      /* Name invoked with */
X    time_t      u_utime;        /* Elapsed ticks in user mode */
X    time_t      u_stime;        /* Ticks in system mode */
X    time_t      u_cutime;       /* Total childrens ticks */
X    time_t      u_cstime;
X
X} u_data;
X
X
X/* Struct to temporarily hold arguments in execve */
Xstruct s_argblk {
X    int a_argc;
X    int a_arglen;
X    int a_envc;
X    char a_buf[512-3*sizeof(int)];
X};
X
X
X/* The device driver switch table */
X
Xtypedef struct devsw {
X    int minor;          /* The minor device number (an argument to below) */
X    int (*dev_open)();  /* The routines for reading, etc */
X    int (*dev_close)(); /* format: op(minor,blkno,offset,count,buf); */
X    int (*dev_read)();  /* offset would be ignored for block devices */
X    int (*dev_write)(); /* blkno and offset ignored for tty, etc. */
X    int (*dev_ioctl)(); /* count is rounded to 512 for block devices */
X} devsw;
X
X
X
X/* Open() parameters. */
X
X#define O_RDONLY        0
X#define O_WRONLY        1
X#define O_RDWR          2
X
X/*
X * Error codes
X */
X
X#define EPERM           1               
X#define ENOENT          2               
X#define ESRCH           3               
X#define EINTR           4               
X#define EIO             5               
X#define ENXIO           6               
X#define E2BIG           7               
X#define ENOEXEC         8               
X#define EBADF           9               
X#define ECHILD          10              
X#define EAGAIN          11              
X#define ENOMEM          12              
X#define EACCES          13              
X#define EFAULT          14              
X#define ENOTBLK         15              
X#define EBUSY           16              
X#define EEXIST          17              
X#define EXDEV           18              
X#define ENODEV          19              
X#define ENOTDIR         20              
X#define EISDIR          21              
X#define EINVAL          22              
X#define ENFILE          23              
X#define EMFILE          24              
X#define ENOTTY          25              
X#define ETXTBSY         26              
X#define EFBIG           27              
X#define ENOSPC          28              
X#define ESPIPE          29              
X#define EROFS           30              
X#define EMLINK          31              
X#define EPIPE           32              
X#define ENAMETOOLONG    63              
X
X#include "config.h"
X
EOF_unix.h
echo 'Done'

echo -n 'Extracting extern.h ... '
sed 's/^X//' > extern.h << 'EOF_extern.h'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  extern.h
X***************************************************/
X
X
X/* These are the global data structures */
X
X#ifdef MAIN
X#define extern  
X#endif
X
X
Xextern struct u_data udata; /* MUST BE FIRST */
Xextern struct p_tab ptab[PTABSIZE];
X
Xextern inoptr root;   /* Address of root dir in inode table */
Xextern int16 ROOTDEV;  /* Device number of root filesystem. */
X
Xextern struct cinode i_tab[ITABSIZE];    /* In-core inode table */
Xextern struct oft of_tab[OFTSIZE]; /* Open File Table */
X
Xextern struct filesys fs_tab[NDEVS];  /* Table entry for each
X                                        device with a filesystem. */
Xextern struct blkbuf bufpool[NBUFS];
X
Xextern ptptr initproc; /* The process table address of the first process. */
Xextern int16 inint;   /* flag is set whenever interrupts are being serviced */
X
Xextern int16 sec;   /* Tick counter for counting off one second */
Xextern int16 runticks;  /* Number of ticks current process has been
X                         swapped in */
X
Xextern time_t tod;      /* Time of day */
Xextern time_t ticks;    /* Cumulative tick counter, in minutes and ticks  */
X
Xextern char *swapbase;          /* Used by device driver for swapping */
Xextern unsigned swapcnt;
Xextern blkno_t swapblk;
X
Xextern char vector[3];  /* Place for interrupt vector */
X
X#ifdef MAIN
X#undef extern
X#endif
X
X
EOF_extern.h
echo 'Done'

echo -n 'Extracting data.c ... '
sed 's/^X//' > data.c << 'EOF_data.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  data.c
X***************************************************/
X
X#include "unix.h"
X#define MAIN
X#asm 8080
XCSEG
X@init?::
X        EXTRN   fs@init?
X        JMP     fs@init?
X#endasm
X#include "extern.h"
X
EOF_data.c
echo 'Done'

echo -n 'Extracting dispatch.c ... '
sed 's/^X//' > dispatch.c << 'EOF_dispatch.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  dispatch.c
X***************************************************/
X
X
X/* Dispatch table for system calls */
Xint     __exit(),
X        _open(),
X        _close(),
X        _creat(),
X        _mknod(),
X        _link(),
X        _unlink(),
X        _read(),
X        _write(),
X        _seek(),
X        _chdir(),
X        _sync(),
X        _access(),
X        _chmod(),
X        _chown(),
X        _stat(),
X        _fstat(),
X        _dup(),
X        _getpid(),
X        _getppid(),
X        _getuid(),
X        _umask(),
X        _getfsys(),
X        _execve(),
X        _wait(),
X        _setuid(),
X        _setgid(),
X        _time(),
X        _stime(),
X        _ioctl(),
X        _brk(),
X        _sbrk(),
X        _fork(),
X        _mount(),
X        _umount(),
X        _signal(),
X        _dup2(),
X        _pause(),
X        _alarm(),
X        _kill(),
X        _pipe(),
X        _getgid(),
X        _times();
X
Xint (*disp_tab[])() =
X{       __exit,
X        _open,
X        _close,
X        _creat,
X        _mknod,
X        _link,
X        _unlink,
X        _read,
X        _write,
X        _seek,
X        _chdir,
X        _sync,
X        _access,
X        _chmod,
X        _chown,
X        _stat,
X        _fstat,
X        _dup,
X        _getpid,
X        _getppid,
X        _getuid,
X        _umask,
X        _getfsys,
X        _execve,
X        _wait,
X        _setuid,
X        _setgid,
X        _time,
X        _stime,
X        _ioctl,
X        _brk,
X        _sbrk,
X        _fork,
X        _mount,
X        _umount,
X        _signal,
X        _dup2,
X        _pause,
X        _alarm,
X        _kill,
X        _pipe,
X        _getgid,
X        _times
X };
X
Xchar dtsize = sizeof(disp_tab) / sizeof(int(*)()) - 1;
X
X
EOF_dispatch.c
echo 'Done'

echo -n 'Extracting extras.c ... '
sed 's/^X//' > extras.c << 'EOF_extras.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  extras.c
X***************************************************/
X
X
Xbcopy()
X{
X#asm 8080
X; BCOPY(SRC,DEST,COUNT)
X;
X        POP     H
X        SHLD    HOLDER
X.Z80
X        LD      (BCHLDR),BC
X.8080   
X        POP     B
X        POP     D
X        POP     H
X        PUSH    H
X        PUSH    H
X        PUSH    H
X.Z80
X        LDIR
X.8080
X        LHLD    HOLDER
X.Z80
X        LD      BC,(BCHLDR)
X.8080
X        PCHL
X#endasm
X}
X
X#asm 
X;
XHOLDER: DS      2
XBCHLDR: DS      2
X;
X;
X#endasm
X
X
Xbzero(ptr,count)
Xchar *ptr;
Xint count;
X{
X    *ptr = 0;
X    bcopy(ptr,ptr+1,count-1);
X}
X
X
Xabort()
X{
X#asm 8080
X        DI
X        JMP     $
X#endasm
X}
X
EOF_extras.c
echo 'Done'

echo -n 'Extracting machdep.c ... '
sed 's/^X//' > machdep.c << 'EOF_machdep.c'
X/**************************************************
XUZI (Unix Z80 Implementation) Kernel:  machdep.c
X***************************************************/
X
X
X#include "unix.h"
X#include "extern.h"
X
X
X/* This is called at the very beginning to initialize everything. */
X/* It is the equivalent of main() */
X
Xfs_init()
X{
X    di();
X    stkreset();
X    /* Initialize the interrupt vector */
X    initvec();
X    inint = 0;
X    udata.u_insys = 1;
X    /* Turn off clock */
X    out(0,0xf1);
X    ei();
X
X    init2();   /* in process.c */
X}
X
X
X/* This checks to see if a user-suppled address is legitimate */
Xvaladr(base,size)
Xchar *base;
Xuint16 size;
X{
X    if (base < PROGBASE || base+size >= (char *)&udata)
X    {
X        udata.u_error = EFAULT;
X        return(0);
X    }
X    return(1);
X}
X
X
X/* This adds two tick counts together.
XThe t_time field holds up to one second of ticks,
Xwhile the t_date field counts minutes */
X
Xaddtick(t1,t2)
Xtime_t *t1, *t2;
X{
X
X    t1->t_time += t2->t_time;
X    t1->t_date += t2->t_date;
X    if (t1->t_time >= 60*TICKSPERSEC)
X    {
X        t1->t_time -= 60*TICKSPERSEC;
X        ++t1->t_date;
X    }
X}
X
Xincrtick(t)
Xtime_t *t;
X{
X    if (++t->t_time == 60*TICKSPERSEC)
X    {
X        t->t_time = 0;
X        ++t->t_date;
X    }
X}
X
X
Xstkreset()
X{
X#asm 8080
X        POP     H
X        LXI     SP,udata?-2
X        PCHL
X#endasm
X}
X
X
Xtempstack()
X{
X#asm 8080
X        POP     H
X        LXI     SP,100H
X        PCHL
X#endasm
X}
X
X
X
Xinitvec()
X{
X#asm 8080
X        LXI     H,vector?
X        INX     H
X        MOV     A,L
X        ANI     0FEH
X        MOV     L,A     ;set hl to first even address in vector[].
X        MOV     A,H
X.Z80
X        LD      I,A     ;SET INTERRUPT REGISTER TO UPPER 8 BITS
X.8080
X        MOV     A,L
X        OUT     076H    ;set external vector register with low order byte
X        LXI     D,service?
X        MOV     M,E
X        INX     H
X        MOV     M,D     ;STORE ADDRESS OF SERVICE ROUTINE IN vector[].
X        RET
X#endasm
X}
X
Xextern int unix();
X
X
Xdoexec()
X{
X#asm 8080
X        POP     H
X        POP     H       ;get argument
X        SPHL            ;set stack pointer to it
X        MVI     A,0C3H  ;jump inst
X        STA     0030H   ;dest of RST6 instruction.
X        LXI     H,unix? ;entry address
X        SHLD    0031H
X        XRA     A
X        STA     udata? + ?OSYS
X        JMP     0100H
X#endasm
X}
X
X
Xstatic int cursig;
Xstatic int (*curvec)();
X
X/* This interrupt device routine calls the service routine of each device
Xthat could have interrupted. */
X
Xservice()
X{
X
X    ;
X#asm 8080
X        PUSH    PSW
X        PUSH    B
X        PUSH    D
X        PUSH    H
X.Z80
X        PUSH    IX
X        PUSH    IY
X.8080
X#endasm
X
X    inint = 1;
X
X    if (tty_int())
X        goto found;
X    if (clk_int())
X        goto found;
X/*  if (  ) ...   */
X
X    warning("Spurious interrupt");
X
Xfound:
X    inint = 0;
X
X    /* Deal with a pending caught signal, if any */
X    if (!udata.u_insys)
X        calltrap();
X    ;
X
X#asm 8080
X.Z80
X        POP     IY
X        POP     IX
X.8080
X        POP     H
X        POP     D
X        POP     B
X        POP     PSW
X        EI
X        RET
X#endasm
X
X}
X
X
X
Xcalltrap()
X{
X    /* Deal with a pending caught signal, if any. */
X        /* udata.u_insys should be false, and interrupts enabled.
X        remember, the user may never return from the trap routine */
X
X    if (udata.u_cursig)
X    {
X        cursig = udata.u_cursig;
X        curvec = udata.u_sigvec[cursig];
X        udata.u_cursig = 0;
X        udata.u_sigvec[cursig] = SIG_DFL;   /* Reset to default */
X        ei();
X        (*curvec)(cursig);
X        di();
X    } 
X}
X
X
X
X/* Port addresses of clock chip registers. */
X
X#define SECS 0xe2
X#define MINS 0xe3
X#define HRS 0xe4
X#define DAY 0xe6
X#define MON 0xe7
X#define YEAR 86
X
Xsttime()
X{
X    panic("Calling sttime");
X}
X
X
Xrdtime(tloc)
Xtime_t *tloc;
X{
X    di();
X    tloc->t_time = tod.t_time;
X    tloc->t_date = tod.t_date;
X    ei();
X}
X
X
X/* Update global time of day */
Xrdtod()
X{
X    tod.t_time = (tread(SECS)>>1) | (tread(MINS)<<5) | (tread(HRS)<<11);
X    tod.t_date = tread(DAY) | (tread(MON)<<5) | (YEAR<<9);
X}
X
X
X/* Read BCD clock register, convert to binary. */
Xtread(port)
Xuint16 port;
X{
X    int n;
X
X    n = in(port);
X    return ( 10*((n>>4)&0x0f) + (n&0x0f) );
X}
X
X
X/* Disable interrupts */
Xdi()
X{
X#asm 8080
X        DI      ;disable interrupts
X#endasm
X}
X
X/* Enable interrupts if we are not in service routine */
Xei()
X{
X    if (inint)
X        return;
X    ;   /* Empty statement necessary to fool compiler */
X
X#asm 8080
X        EI      ;disable interrupts
X#endasm
X}
X
X
X
X/* This shifts an unsigned int right 8 places. */
X
Xshift8()
X{
X#asm 8080
X        POP     D       ;ret addr
X        POP     H
X        MOV     L,H
X        MVI     H,0
X        MOV     A,L
X        ANA     A       ;set Z flag on result
X        PUSH    H
X        PUSH    D       ;restore stack
X#endasm
X}
X
X
X/* This prints an error message and dies. */
X
Xpanic(s)
Xchar *s;
X{
X    di();
X    inint = 1;
X    kprintf("PANIC: %s\n",s);
X    idump();
X    abort();
X}
X
X
Xwarning(s)
Xchar *s;
X{
X    kprintf("WARNING: %s\n",s);
X}
X
X
Xputs(s)
Xchar *s;
X{
X    while (*s)
X        kputchar(*(s++));
X}
X
Xkputchar(c)
Xint c;
X{
X    if (c == '\n')
X        _putc('\r');
X    _putc(c);
X    if (c == '\t')
X        puts("\177\177\177\177\177\177\177\177\177\177");
X}
X
X
X
Xidump()
X{
X    inoptr ip;
X    ptptr pp;
X    extern struct cinode i_tab[];
X
X    kprintf(
X        "\tMAGIC\tDEV\tNUM\tMODE\tNLINK\t(DEV)\tREFS\tDIRTY err %d root %d\n",
X            udata.u_error, root - i_tab);
X
X    for (ip=i_tab; ip < i_tab+ITABSIZE; ++ip)
X    {
X        kprintf("%d\t%d\t%d\t%u\t0%o\t%d\t%d\t%d\t%d\n",
X               ip-i_tab, ip->c_magic,ip->c_dev, ip->c_num,
X               ip->c_node.i_mode,ip->c_node.i_nlink,ip->c_node.i_addr[0],
X               ip->c_refs,ip->c_dirty);
X/*****
X        ifnot (ip->c_magic)     
X            break;
X******/
X    }
X
X    kprintf("\n\tSTAT\tWAIT\tPID\tPPTR\tALARM\tPENDING\tIGNORED\n");
X    for (pp=ptab; pp < ptab+PTABSIZE; ++pp)
X    {
X        kprintf("%d\t%d\t0x%x\t%d\t%d\t%d\t0x%x\t0x%x\n",
X               pp-ptab, pp->p_status, pp->p_wait,  pp->p_pid,
X               pp->p_pptr-ptab, pp->p_alarm, pp->p_pending,
X                pp->p_ignored);
X        ifnot(pp->p_pptr)
X            break;
X    }   
X    
X    bufdump();
X
X    kprintf("\ninsys %d ptab %d call %d cwd %d sp 0x%x\n",
X        udata.u_insys,udata.u_ptab-ptab, udata.u_callno, udata.u_cwd-i_tab,
X       udata.u_sp);
X}
X
X
X
X/* Short version of printf to save space */
Xkprintf(nargs)
X        {
X        register char **arg, *fmt;
X        register c, base;
X        char s[7], *itob();
X
X        arg = (char **)&nargs + nargs;
X        fmt = *arg;
X        while (c = *fmt++) {
X                if (c != '%') {
X                        kputchar(c);
X                        continue;
X                        }
X                switch (c = *fmt++) {
X                case 'c':
X                        kputchar(*--arg);
X                        continue;
X                case 'd':
X                        base = -10;
X                        goto prt;
X                case 'o':
X                        base = 8;
X                        goto prt;
X                case 'u':
X                        base = 10;
X                        goto prt;
X                case 'x':
X                        base = 16;
X                prt:
X                        puts(itob(*--arg, s, base));
X                        continue;
X                case 's':
X                        puts(*--arg);
X                        continue;
X                default:
X                        kputchar(c);
X                        continue;
X                        }
X                }
X        }
X
EOF_machdep.c
echo 'Done'

echo -n 'Extracting makeunix.sub ... '
sed 's/^X//' > makeunix.sub << 'EOF_makeunix.sub'
Xb:submit b:qcc data
Xb:submit b:qcc filesys
Xb:submit b:qcc scall1
Xb:submit b:qcc scall2
Xb:submit b:qcc devio
Xb:submit b:qcc devwd
Xb:submit b:qcc devmisc
Xb:submit b:qcc devtty
Xb:submit b:qcc devflop
Xb:submit b:qcc dispatch
Xb:submit b:qcc machdep
Xb:submit b:qcc process
Xb:submit loadunix
X
EOF_makeunix.sub
echo 'Done'

echo -n 'Extracting loadunix.sub ... '
sed 's/^X//' > loadunix.sub << 'EOF_loadunix.sub'
Xloader $1 -o 500 filler data process machdep dispatch scall1 scall2 filesys devio devtty devwd devflop devmisc extras
Xpip unix.bin=$$$$$$.com[osmombassa^Z]
Xera $$$$$$.com
EOF_loadunix.sub
echo 'Done'

exit 0

Doug Braun				Intel Corp CAD
					408 765-4279

 / decwrl \
 | hplabs |
-| oliveb |- !intelca!mipos3!cadev4!dbraun
 | amd    |
 \ qantel /