UZI180 is a unix-like operating system for Z180-based machines. Derived from UZI (a Unix Edition 7 lookalike system for Z80 machines), UZI180 further benefits from Z180-specific features like 1Mb addressing capabilities, internal timer-counter, etc. The original version of UZI180 from H. Bower was available from the TCJ web site (now gone). Mr Bower has also written an excellent introduction to UZI180, I have a copy online here.
The original UZI180, as posted on the TCJ, was a snapshot version of a work in progress. As such, it was far from stable and many features did not work properly. Since then, I've done several corrections and bug fixes to the sources that increased the overall stability of the system (it used to crash quite often with a "Trap @ 0xXXXX" message). The changes are summarized below:
For a full and detailed list of the changes, see the ChangeLog file included in the distribution. Sources and binaries for the kernel, utilities and libraries can be found in the downloads page.
Under CP/M, you can just use a batch file similar to this one. In case you prefer to do the whole thing manually, here are step-by-step instructions:
Assuming you have a two 3.5"-floppy drive system, insert a CP/M disk with the UZI utilities on A: and a newly formatted floppy on B: (UZI's device 1), then follow these steps (user entered commands are shown in boldface):
First, we create the UZI filesystem with the mkfs (make filesystem) command:
A>mkfs 1 50 2880
Here, '1' tells mkfs to create the filesystem on device number 1 (our 'fd1', see dev_tab in config.h), '50' is the size of the system area (boot block + superblock + inode table), and '2880' is the size of the disk in blocks (one block is 512 bytes). Why 50? Well, that gives us 48 blocks for the inode table, and since an inode takes 64 bytes, we'll have a total of 384 inodes. Inodes are much like the data part of the CP/M directory entries, there is just one inode per file or directory, but unlike CP/M directory entries, a large file does not take several inodes. With 384 inodes you can have a maximum of 384 files and/or directories, which seems to be enough for a 1.44Mb floppy.
As before, '1' refers to the device number 1. Once finished, assuming that no errors were found, we can start the interactive ucp utility to create the directory structure and to import files:
A>ucp 1 ucp:
Here 'ucp:' is, as you probably have guessed, ucp's prompt. For a list of available commands you can enter 'help' or just '?'. You'll probably notice that the command syntax closely resembles unix commands. We begin by creating some directories, like the ones usually found in standard unix systems:
ucp: mkdir dev ucp: mkdir bin ucp: mkdir etc ucp: mkdir lib ucp: mkdir usr ucp: mkdir usr/bin ucp: mkdir root ucp: mkdir home ucp: mkdir tmp
Next, we go to the /dev directory and create entries for our devices:
ucp: mknod fd0 60644 0 ucp: mknod fd1 60644 1 ucp: mknod tty1 20666 12 ucp: mknod tty2 20666 13 ucp: mknod null 20622 14 ucp: mknod kmem 20622 16
Here, the first argument represents the device name (fd0 and fd1 for the floppy drives, tty1 and tty2 for the two terminals, null for the null devive, and kmem for a special "kernel memory" device). The second argument is the device modes and permission, in octal, 20666 meaning "character device" (20000) and readable and writable by anybody (00666); see the unix.h file included with the kernel sources for more details about mode bits. The third argument is the device number, that should correspond to the numbers defined in dev_tab in config.h.
Now we proceed to copy some files. First we need to put the init program in the root directory:
ucp: cd / ucp: bget init ucp: chmod init 755
The second argument to the chmod command is the file permissions. In this case we are making the file executable and readable by anyone (00755). Similary, we populate the /bin directory with utilities:
ucp: cd /bin ucp: bget ssh ucp: chmod ssh 775 ucp: bget ls ucp: chmod ls 755 ucp: bget cp ucp: chmod bget 755 ... etc ...
Which and how many utilities you put in the /bin directory is entirely up to you. However, it is recommended to have a minimum set of standard utilities in order to have a comfortable working environment. You should always have at least a shell (in our case ssh - the simple shell). Other utilities include ls, pwd, cp, mv, rm, chmod, mkdir, rmdir, mknod, cat, mount and umount. Some shells already have builtin versions of these most used commands, but unfortunatelly not our tiny ssh. If you have enough disk space you can also add df, dd, ed, chown, chgrp, date, echo, kill, ps, sync, touch, more, grep, etc... It is recommended to place the system utilities in /bin and application programs in /usr/bin.
Don't forget to put a suitable passwd file in the /etc directory, otherwise you will not be able to login. Initially the passwd file would contain just a single line:
The init utility supplied understands the standard unix passwd file format, and supports encrypted passwords. Likewise, you'll want to have a group file as well. The passwd and group files are used by some other utilities, like ls, in order to display user and group names instead of numeric values. A minimalist group file would contain just a single line:
Once you're finished copying files and making/removing directories you might want to boot your UZI system. Just quit from the ucp program,
ucp: quit A>
optionally check the disk again using fsck as explained above and, keeping the UZI disk in B:, start the kernel. At the boot prompt answer '1' (device number 1, B: in CP/M terms):
A>uzi UZI180 version 1.5.2 built Sat Dec 7 19:25:31 CET 2002 Copyright (c) 1998-2002 by H.F.Bower, D.Braun, S.Nitschke, H.Peraza 1024kB total RAM, 960kB available to processes (15 processes max) boot: 1 Mounting root fs: ok init version 0.8 Welcome to UZI180 on /dev/tty1 (Z180) login:
If everything went OK (i.e., your disk contained no filesystem errors, and the /init and /bin/ssh programs were present), then you will get the login prompt. Login as root, hit enter at the password prompt, and you are at the shell command prompt:
login: root Password: ssh #
You can now run some programs, try let's say 'ls' or 'ls -al', 'date', etc...
These same steps can be used to prepare an UZI partition on a hard disk. You'll need to change the device number 1 in the mkfs and fsck commands to the appropriate device number for the particular hard disk partition. For the mkfs command, you'll need in addition to increase the number of inodes, and to specify the correct number of partition blocks.
Too complicated? Well, there is an easier way: get a ready UZI180 disk image for a 3.5", 1.44Mb floppy. You can use the rawrite.exe program under MS-DOS or the dd command under Unix to transfer the image to a floppy. For best performance format first the disk under CP/M, so the sectors will have the optimum interleave value for the P112 hardware. The floppy is bootable with a suitable kernel, so you should not need CP/M at all. Just insert the floppy into drive A, reset the P112 and at the UZI's login prompt enter root and password root. Note that this time the kernel will not ask for a device to boot. The kernel was compiled for a board with a 16MHz CPU, so if you use a different clock frequency you'll end up with different timings.
One of the most attractive features of the UZI180 operating system is that it contains a built-in CP/M 2.2 emulator. It allows you to run existing CP/M programs like compilers, assemblers and editors directly from the shell command prompt.
Before executing a program, the kernel first tries to determine whether it is a native UZI application or a CP/M program by reading the first few bytes. UZI programs have an embedded signature, while CP/M programs usually begin with a JMP command (0C3h opcode). If that is not the case, then file must be patched. Here is the source for an utility to patch CP/M files that puts a JMP command at the beginning (UZI binary here). This utility could be compiled as well under CP/M (or MS-DOS, or Unix) with minor modifications.
The block 0 on the UZI filesystem is the boot block, and is reserved for the bootloader code. However, existing UZI implementations rely on CP/M in order to boot the system: the kernel is started as a normal CP/M application and then it takes control over the system. It would be more desirable, however, to have standalone bootable disks.
Here is a simple UZI boot loader for the P112. It consists of the following: the boot program code and a boot installer.
How to use it: once you compiled your kernel, copy the kernel binary file to your UZI floppy disk (the location and name is not important), and then copy both the boot installer and the boot loader (the insboot and loader files respectively) to some directory, both of them must reside in the same directory. Make sure insboot has execute permissions (chmod 0755 insboot). Start UZI if you're not already running it, then invoke insboot specifying the name of the device to be made bootable and the full path to the kernel binary file.
For example, suppose your kernel is named vmuzi and is located in the root directory, and the boot utilities reside in the /boot directory; the command sequence will be the following:
ssh# cd /boot ssh# ./insboot /dev/fd0 /vmuzi 0 insboot: boot sector installed ssh#
The last parameter in the example above is optional, and specifies the drive number from which the root filesystem should be mounted (i.e. the value you would usually type in response to the kernel's "boot:" prompt). When that parameter is specified, the kernel does not prompt for the filesystem to boot.
Here is how the loader works: the boot installer program first reads the block allocation map of the kernel file, then writes to the boot block of the specified device the boot code from the 'loader' binary file and appends the block allocation map. When the system is booted, the loader uses the block allocation map to figure out where the kernel resides, then proceeds to load it block by block into memory starting from address 100h, and finally passes the control to it.
With this scheme it does not matter where the kernel is physically located or whether it is fragmented over the disk or not. You should, however, be aware that the insboot program must be run again every time the location or size of the kernel file changes, for example:
In the other hand, insboot does not need to be re-run:
Note that this simple boot loader will work only under the P112 machine, since it makes use of the ROM monitor disk services. However, the whole idea can be applied to any other system as well, you'll just have to write a suitable loader program and to modify the installer appropriately. In those cases where the boot code is so large that the kernel allocation map would not fit, you can use the following workaround: save the kernel allocation map into a separate file (that file will occupy just a single block), and pass that block number to the bootloader. During boot, the bootloader must first fetch the block containing the kernel allocation map, and then use it to load the kernel.
Last modified 10-Sep-2007