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 /