The Second PC Utility: cpfs.exeIn 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.
|