Jolix
/joh'liks/ n.,adj. 386BSD

PORTING UNIX TO THE 386: A PRACTICAL APPROACH


William & Lynne Jolitz


First thing the kernel does is open its root filesystem - so we need a way to write a filesystem onto the hard disk, adjacent to the DOS filesystem, which is what this utility does.

William & Lynne:
"Disk storage code, both drivers and partition labels came from the Symmetric Computer Systems 375 and its ST506 controller board.

Somehow, the attribution here vanished, as did goodwill."



The Second PC Utility: cpfs.exe

The Second PC Utility: cpfs.exe

In addition to being able to run 32-bit protected-mode programs, we need to load a preliminary root filesystem for our BSD UNIX kernel to access as it initializes itself during the late phase of boot-up. Like MS-DOS, UNIX needs a dedicated region of the hard disk drive to store the data structures and data blocks that support its filesystem scheme. As we do not have a drive dedicated to BSD, we must instead secure a second partition on the sole disk drive to contain the BSD root filesystem.

Listing 5: Copy File System (file: cpfs.c)
/* Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
 * Written by William Jolitz 7/89
 * Redistribution and use in source and binary forms are freely permitted
 * provided that the above copyright notice and attribution and date of work
 * and this paragraph are duplicated in all such forms.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 * This program copies a BSD filesystem out of an MSDOS file and
 * places it on an pre-reserved disk partition. Note that both the
 * geometry of the particular disk, and the particulars of the
 * BSD partition need to be adjusted to suit the drive on which this will
 * be used. Normally, this would be a very rude requirement, but
 * we tolerate this because this program is a throw-away used to get
 * us started, and we have better schemes to deal with configuration
 * a little further down the pike.
 * Currently works with TURBO C 1.5 .
 */

#include <bios.h>
#include <io.h>
#include <fcntl.h>

#include <sys\stat.h>
#include "diskl.h"

/* Disk geometry (here, a NEC DS5146). Adjust parameters to suit drive. */
#define   NCYL   615
#define   NTRACK   8
#define   NSECT   17

#define   BSIZE   512   /* Disk block size */

/* Location & size of root partition. Adjust for drive partition layout. */
#define   OFF_CYL   290   /* Cylinder offset of start of BSD root partition */
#define   ROOTSZ   50   /* size of root partition, in units of cylinders */

char trkbuf[NSECT*BSIZE];

struct label_blk {
   char bufr[LABELOFFSET];
   struct disklabel dl;
} lbl;

main (argc, argv) char *argv[]; {
   int fi, rem, cyl, head, sector, tfrcnt;
   if (argc != 2) {
      printf ("usage: cpfs <rootfs>\n");
      exit (1);
   }
   fi = open (argv[1],O_BINARY);
   if (fi < 0) {
      printf ("Cannot open \"%s\" file to read filesystem\n",
         argv[1]);
      exit (1);
   }
   cyl = OFF_CYL;
   tfrcnt = head = 0;

#ifndef FIRST
   /* check for presence of disklabel */
   biosdisk (2, 0x80, 0, OFF_CYL, LABELSECTOR, 1, &lbl);
   if (lbl.dl.dk_magic != DISKMAGIC) {
      printf ("BSD Disk partition does not have a label!\n");
      exit (1);
   }

   /* Treat first track of data special; use disk label in first block of
         * file to validate that the file to be loaded and disk drive
         * partition are appropriate for each other. */
   read (fi, trkbuf, BSIZE);
   if (strncmp (trkbuf, &lbl, BSIZE) != 0) {
      printf ("BSD root partition and filesystem mismatch!\n");
      exit (1);
   }

   /* reset filesystem file to beginning */
   lseek (fi, 0, SEEK_SET);
#endif

   printf ("WARNING! About to overwrite disk (will loose previous\n");
   printf ("contents). Are you certain of your use of this program?");
   if (getche () != 'y') exit (1);
   printf("\n");

   /* Transfer file to absolute disk section, a track at a time,
         because we're impatient. */
   while ((rem = read (fi, trkbuf, NSECT*BSIZE)) == NSECT*BSIZE) {
      biosdisk (3, 0x80, head, cyl, 1, NSECT, trkbuf);
      if (++head == NTRACK) {
         head = 0;
         if (++cyl > NCYL || cyl > OFF_CYL+ROOTSZ ) {
            printf ("Overran root partition!\n");
            exit (1);
         }
      }
      tfrcnt += NSECT;
      printf ("Amount transferred %5dK bytes\r",
         tfrcnt*BSIZE/1024);
   }

   /* Transfer any remainder leftover in track buffer. */
   if (rem > BSIZE-1) {
      biosdisk (3, 0x80, head, cyl, 1, rem/BSIZE, trkbuf);
      tfrcnt += rem/BSIZE;
      printf ("Amount transferred %5dK bytes\n",
         tfrcnt*BSIZE/1024);
   }

   exit (0);
}

cpfs.c (see Listing 5) is a program which loads this filesystem from a previously downloaded MS-DOS file. cpfs.c leverages BIOS disk calls to write appropriately to the absolute disk. If this program were to be commonly used, you might wish to dig out the disk geometry and BSD partition from additional MS-DOS and/or BIOS calls, but for our purposes, this program is sufficient.

The first block of the root (typically, the first sector of the drive) contains the disk label (see Listing 6 for diskl.h). This data structure will eventually be used in the 386BSD port to make the system drive-independent. However, we first need to place the seminal label on the very first filesystem. cpfs.c, which has hard-wired geometry constants, can initially be compiled (by defining "FIRST") to blindly write that first filesystem with this label. In subsequent use (compiled without "FIRST" defined) cpfs.c will use this label to validate a load, hopefully saving a bleary-eyed developer from ultimate disaster.

Listing 6: Unix Disklabel (file: diskl.h)
/* Copyright (c) 1985,1986,1989,1990 Micheal J. Karels for 
 * Symmetric Computer Systems. All rights reserved.
 * Based on a concept by Sam Leffler. Written by Michael J. Karels 4/85
 * Revised by William Jolitz 86-90.
 * Redistribution and use in source and binary forms are freely permitted
 * provided that the above copyright notice and attribution and date of work
 * and this paragraph are duplicated in all such forms.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 * Each disk has a label which includes information about the hardware
 * disk geometry, filesystem partitions, and drive specific information.
 * The label is in block 1, offset from the beginning to leave room
 * for a bootstrap, etc.
 */

#define LABELSECTOR   1      /* sector containing label */
#define LABELOFFSET   (BSIZE-120)   /* offset of label in sector */
#define DISKMAGIC   0xabc      /* The disk magic number */
#define   DTYPE_ST506   1      /* ST506 Winchester */
#define   DTYPE_FLOPPY   2      /* 5-1/4" minifloppy */
#define   DTYPE_SCSI   3      /* SCSI Direct Access Device */

struct disklabel {
   short   dk_magic;      /* the magic number */
   short   dk_type;      /* drive type */
   struct dcon {
      short   dc_secsize;   /* # of bytes per sector */
      short   dc_nsectors;   /* # of sectors per track */
      short   dc_ntracks;   /* # of tracks per cylinder */
      short   dc_ncylinders;   /* # of cylinders per unit */
      long   dc_secpercyl;   /* # of sectors per cylinder */
      long   dc_secperunit;   /* # of sectors per unit */
      long   dc_drivedata[4]; /* drive-type specific information */
   } dc;
   struct dpart {         /* the partition table */
      long   nblocks;   /* number of sectors in partition */
      long   cyloff;      /* starting cylinder for partition */
   } dk_partition[8];
   char   dk_name[16];      /* pack identifier */
};

#define dk_secsize      dc.dc_secsize
#define dk_nsectors      dc.dc_nsectors
#define dk_ntracks      dc.dc_ntracks
#define dk_ncylinders      dc.dc_ncylinders
#define dk_secpercyl      dc.dc_secpercyl
#define dk_secperunit      dc.dc_secperunit

/* Drive data for ST506. */
#define dk_precompcyl   dc.dc_drivedata[0]
#define dk_ecc      dc.dc_drivedata[1]   /* used only when formatting */
#define dk_gap3      dc.dc_drivedata[2]   /* used only when formatting */

/* Drive data for SCSI */
#define dk_blind   dc.dc_drivedata[0]     /* can we work in "blind" i/o */

When using this program with disk drives greater than 1024 cylinders, logical translation by the disk controller to a different geometry is a problem. Some calls used by MS-DOS and applications programs would invoke a 10-bit field for cylinder address in the disk address data structure, reflecting an early limitation of some PC disk controllers (the WD1010 disk controller chip, for example). One clever workaround which doesn't require altering the operating system is to encode disk addresses with a logical mapping scheme so that some of the cylinder address bits would be mapped into more plentiful sector and head address bits. This scheme, while quite acceptable to MS-DOS (which is never picky about sector placement), is not acceptable to BSD (which is extremely picky about sector placement). The BSD Fast Filesystem uses rotational and head placement algorithms to improve filesystem performance by taking disk latency into account. Therefore, running on a logically mapped disk may significantly degrade performance by throwing off this mechanism in the Fast Filesystem. Additional code is required to detect and defeat this condition, because this translation must be maintained while MS-DOS is running.




<<BACK NEXT >>



Copyright 1989, 1990, 2006 TeleMuse Partners, William Jolitz and Lynne Jolitz