*BSD News Article 1626


Return to BSD News archive

Newsgroups: comp.unix.bsd
Path: sserve!manuel!munnari.oz.au!mips!decwrl!csus.edu!netcomsv!mork!jagane
From: jagane@netcom.com (Jagane D Sundar)
Subject: Hack for DOS co-existence(386bsd)
Message-ID: <cgnl=fk.jagane@netcom.com>
Date: Sun, 21 Jun 92 04:14:00 GMT
Organization: Netcom - Online Communication Services  (408 241-9760 guest) 
Keywords: 386bsd DOS co-existence





	Here's a hack for DOS co-existence. It works by allowing DOS to 
	build a filesystem on one a 386bsd partition and fakes fdisk entries
	to make DOS utilities happy.

	ADVANTAGES OF THIS APPROACH:

	1) 	It takes the appropriate condescending attitude towards 
		DOS, ie. DOS is allowed to build its filesystem on a 386bsd 
		partition, but 386bsd is THE OS THAT RULES THE DISK.
		
	2)	Allows tools like mtools to access the DOS partition and
		read the DOS filesystem without any modifications to the 
		device driver code.

	3)	Changes in only one source file( boot.c) that becomes part of
		the secondary boot block( bootas, bootwd).

	4)	It solved my problem very quickly.

	IMPORTANT NOTES:

	1) 	It assumes that 386bsd is the first OS to be installed on the
		hard disk. ie. All previous contents are wiped out.

	2)	It allows just one DOS partition.

	3)	I have tested it with the Pace SCSI Driver but it should work
		fine with the wd driver too.

	INSTRUCTIONS TO USE IT:

	1) Follow normal installation procedure to install 386bsd on the hard
	   disk but MAKE SURE TO INCLUDE A PARTITION (say d) when you make the
	   entry in disklabel. This is the partition that will become the DOS
	   partition.

	2) Copy boot.c included in this message to /sys/i386/stand and make
	   the secondary boot block for the type of your disk(bootas or bootwd).

	3) Copy bootxx to /usr/mdec and write disklabel on the disk using 
	   disklabel.

	4) Compile fdisk.c included to make fdisk utility. Use fdisk to 
	   initialize the partition that you had set aside for DOS. For 
	   example if you had set aside the partition d on disk as0 for
	   DOS, you would say "fdisk -i as0 d".

	5) Use fdisk henceforth to switch to DOS partition.
	   eg. "fdisk -d as0".

	6) Boot DOS from floppy and do a fdisk( the DOS utility). You should 
	   see two partitions, a DOS partition and a dummy partition. DO
	   NOT ATTEMPT TO EVER CAHNGE THINGS IN THE PARTITION TABLE if you 
	   value the sanity of 386bsd partitions.


	INCLUDED:

		boot.c
		fdisk.c

	ACKNOWLEDGEMENTS:

	To BILL JOLITZ for bringing a state of art OS in source form to
	wannabe kernel hackers like me.:

	To Pace Willisson for the SCSI Driver, so I could get my SCSI system
	up.






	Have fun,

		Jagane D Sundar


____________________Cut here for boot.c_______________________________________
/*-
 * Copyright (c) 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * William Jolitz.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifdef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
 All rights reserved.\n";
#endif /* not lint */

#ifdef lint
static char sccsid[] = "from:@(#)boot.c	7.3 (Berkeley) 5/4/91";
#endif /* not lint */

#include "param.h"
#include "reboot.h"
#include <a.out.h>
#include "saio.h"
#include "disklabel.h"
#include "dinode.h"

/*
 * Boot program, loaded by boot block from remaing 7.5K of boot area.
 * Sifts through disklabel and attempts to load an program image of
 * a standalone program off the disk. If keyboard is hit during load,
 * or if an error is encounter, try alternate files.
 */

char *files[] = { "386bsd", "386bsd.alt", "386bsd.old", "boot" , "vmunix", 0};
int	retry = 0;
extern struct disklabel disklabel;
extern	int bootdev, cyloffset;

#define	SCSI

#pragma	pack(1)
struct fdisktab {
	unsigned char	active;
	unsigned char	beghead;
	unsigned char	begsect;
	unsigned char	begcyl;
	unsigned char	id;
	unsigned char	endhead;
	unsigned char	endsect;
	unsigned char	endcyl;
	long		startsect;
	long		numsects;
};

/*
 * Boot program... loads /boot out of filesystem indicated by arguements.
 * We assume an autoboot unless we detect a misconfiguration.
 */

main(dev, unit, off)
{
	register struct disklabel *lp;
	register int io;
	register char **bootfile = files;
	int howto = 0;
	struct fdisktab		*fdtab;

	fdtab = (struct fdisktab *) 0x7dbe;
	if(fdtab->active == 0x80)
		Heigh_ho_back_to_dos_we_go(dev, fdtab);

	printf("dev %x unit %x off %d\n", dev, unit, off);
	{ int i = 10000; while(--i) inb(0x84); }
unit = off = 0;
dev = 4;

	/* are we a disk, if so look at disklabel and do things */
	lp = &disklabel;
	if (lp->d_magic == DISKMAGIC) {
	    /*
	     * Synthesize bootdev from dev, unit, type and partition
	     * information from the block 0 bootstrap.
	     * It's dirty work, but someone's got to do it.
	     * This will be used by the filesystem primatives, and
	     * drivers. Ultimately, opendev will be created corresponding
	     * to which drive to pass to top level bootstrap.
	     */
	    for (io = 0; io < lp->d_npartitions; io++) {
#ifdef SCSI
		if (lp->d_type == DTYPE_SCSI) {
			if (lp->d_partitions[io].p_offset == off)
				break;
		} else
#endif
		if (lp->d_partitions[io].p_size == 0)
			continue;
		if (lp->d_partitions[io].p_offset == off*lp->d_secpercyl)
			break;
	    }

	    if (io == 8) goto screwed;
            cyloffset = off;
	} else {
screwed:
		/* probably a bad or non-existant disklabel */
		printf("DIDNT GET DISKLABEL\n");
		io = 0 ;
		howto |= RB_SINGLE|RB_ASKNAME ;
	}

	/* construct bootdev */
	/* currently, PC has no way of booting off alternate controllers */
	bootdev = MAKEBOOTDEV(/*i_dev*/ dev, /*i_adapt*/0, /*i_ctlr*/0,
	    unit, /*i_part*/io);

	for (;;) {

/*printf("namei %s", *bootfile);*/
		io = namei(*bootfile);
		if (io > 2) {
			copyunix(io, howto);
		} else
			printf("File not found");

		printf(" - didn't load %s, ",*bootfile);
		if(*++bootfile == 0) bootfile = files;
		printf("will try %s\n", *bootfile);

		wait(1<<((retry++) + 10));
	}
}

/*ARGSUSED*/
copyunix(io, howto)
	register io;
{
	struct exec x;
	int i;
	char *addr,c;
	struct dinode fil;
	int off;

	fetchi(io, &fil);
/*printf("mode %o ", fil.di_mode);*/
	i = iread(&fil, 0,  (char *)&x, sizeof x);
	off = sizeof x;
	if (i != sizeof x || x.a_magic != 0413) {
		printf("Not an executable format");
		return;
	}

	off = 4096;
	if (iread(&fil, off, (char *)0, x.a_text) != x.a_text)
		goto shread;
	off += x.a_text;

	addr = (char *)x.a_text;
	while ((int)addr & CLOFSET)
		*addr++ = 0;
	
	if (iread(&fil, off, addr, x.a_data) != x.a_data)
		goto shread;

	addr += x.a_data;
	bzero(addr, x.a_bss);

	/* mask high order bits corresponding to relocated system base */
	x.a_entry &= ~0xfff00000;

	/*if (scankbd()) {
		printf("Operator abort");
		kbdreset();
		return;
	}*/

	/* howto, bootdev, cyl */
	i = (*((int (*)()) x.a_entry))(3, bootdev, 0);

	if (i) printf("Program exits with %d", i) ; 
	return;
shread:
	printf("Read of file is incomplete");
	return;
}

const char gdtnew[] = {
	0, 0, 0, 0, 0, 0, 0, 0,		    /* (0x0) */
	0xff, 0xff, 0, 0, 0, 0x9f, 0xcf, 0, /* code segment (0x8) */
	0xff, 0xff, 0, 0, 0, 0x93, 0xcf, 0, /* data segment (0x10) */
	0xff, 0xff, 0, 0, 0, 0x9f, 0x00, 0, /* dummy code segment (0x18) */
	0xff, 0xff, 0, 0, 0, 0x93, 0x00, 0, /* dummy data segment (0x20) */
};

const struct {
	short filler;
	short size;
	const char *gdt;
} loadgdt = { 0, sizeof gdtnew - 1, gdtnew };

Heigh_ho_back_to_dos_we_go(dev, fdtab)
struct fdisktab	*fdtab;
{
	char		*boot0block;
	char		*stub, *stub1, *stub2;

	boot0block = (char *)0x7c00;
	stub = (char *)0x7b00;
	stub1 = (char *)0x7b80;
	stub2 = (char *)0x7ba0;

	bzero(stub, 0x100);
	*stub++ = 0x0f; *stub++ = 0x20; *stub++ = 0xc0;
	*stub++ = 0x25;
	*stub++ = 0xfe; *stub++ = 0xff;
	*stub++ = 0x0f; *stub++ = 0x22; *stub++ = 0xc0;
*stub++ = 0xea; *stub++ = 0x80; *stub++ = 0x7b; *stub++ = 0x00; *stub++ = 0x00;


	*stub1++ = 0x31; *stub1++ = 0xc0;
	*stub1++ = 0x8e; *stub1++ = 0xd8;
	*stub1++ = 0x8e; *stub1++ = 0xc0;
	*stub1++ = 0x8e; *stub1++ = 0xd0;
	*stub1++ = 0x8e; *stub1++ = 0xe0;
	*stub1++ = 0x8e; *stub1++ = 0xe8;
	*stub1++ = 0x2e; *stub1++ = 0x0f; *stub1++ = 0x01; *stub1++ = 0x1e;
	*stub1++ = 0xa0; *stub1++ = 0x7b;

*stub1++ = 0xea; *stub1++ = 0x00; *stub1++ = 0x7c; *stub1++ = 0x00; *stub1++ = 0x00;

	*stub2++ = 0x00; *stub2++ = 0x04;
	*stub2++ = 0x00; *stub2++ = 0x00;

	printf("Heigh_ho_back_to_dos_we_go\n");
	bread(dev, fdtab->startsect, boot0block, 512);

	asm("
		cli
		/* load gdt */
		.byte 0x2e,0x0f,0x01,0x15 /* lgdt %cs:$imm */
		.long _loadgdt + 2

		movl	$0x7a00, %esp
		movl	$0x20, %eax
		movl	%ax, %ds
		movl	%ax, %es
		movl	%ax, %fs
		movl	%ax, %gs
		movl	%ax, %ss
		.byte	0xea
		.long	0x7b00
		.word	0x18
	");
}
____________________End boot.c________________________________________________

____________________Cut here for fdisk.c_______________________________________
#include	<stdio.h>
#include	<sys/types.h>
#include	<sys/fcntl.h>
#include	<sys/disklabel.h>

extern int	errno;

struct fdisktab {
	unsigned char	active;
	unsigned char	beghead;
	unsigned char	begsect;
	unsigned char	begcyl;
	unsigned char	id;
	unsigned char	endhead;
	unsigned char	endsect;
	unsigned char	endcyl;
	long		startsect;
	long		numsects;
};

main(argc, argv)
char	**argv;
{
	int	force = 0;
	int	activate_unix = 1;

	if(argc == 4) {
		if(!strcmp(argv[1], "-I"))
			force = 1;
		else if(!strcmp(argv[1], "-i"))
			force = 0;
		else
			usage();
		argc--;
		argv[1] = argv[2];
		argv[2] = argv[3];
		initialize(argc, argv, force);
	} else if(argc == 3) {
		if(!strcmp(argv[1], "-u"))
			activate_unix = 1;
		else if(!strcmp(argv[1], "-d"))
			activate_unix = 0;
		else
			usage();
		activate(argv[2], activate_unix);
	} else if(argc == 2)
		if(*argv[1] != '-')
			display(argv[1]);
		else
			usage();
	else
		usage();
}

initialize(argc, argv, force)
char	**argv;
{
	char			devname[256];
	int			fd;
	unsigned char		buf[2048];
	struct disklabel	*lbl;
	struct fdisktab		*fdisk;
	int			index, i;

	sprintf(devname, "/dev/r%sc", argv[1]);
	if( (fd = open(devname, O_RDWR)) < 0) {
		printf("Could not open %s. Errno %d.\n", devname, errno);
		exit(-1);
	}
	if(read(fd, buf, 1024) < 1024) {
		printf("Error %d reading disklabel from %s\n", errno, devname);
		exit(-1);
	}
	fdisk = (struct fdisktab *) &buf[446];	/* talk about hardwire... */
	if( !((buf[510] == 0x55) && (buf[511] == 0xaa)) ) {
		printf("Invalid boot 0 block on device %s\n", devname);
		exit(-1);
	}
	printf("Found valid boot 0 block on %s\n", devname);
	lbl = (struct disklabel *) &buf[512];
	if(lbl->d_magic != DISKMAGIC) {
		printf("Invalid disklabel on device %s\n", devname);
		exit(-1);
	}
	printf("Found valid disklabel on %s\n", devname);
	if((*argv[2] >= 'A') && (*argv[2] <= 'Z'))
		*argv[2] -= ('A' - 'a');
#ifdef	DEBUG
	printf("part %c\n", *argv[2]);
#endif
	index = *argv[2] - 'a';
	if(index >= MAXPARTITIONS) {
		printf("Partition %c is out of range in device %s\n", *argv[2],
							devname);
		exit(-1);
	}
#ifdef	DEBUG
	for(i = 0; i < MAXPARTITIONS; i++)
		printf("%d p_fstype %d\n", i, lbl->d_partitions[i].p_fstype);
#endif
	if(force || (lbl->d_partitions[index].p_fstype == FS_UNUSED) ) {
		/* create dos partition. */
		fdisk->startsect = lbl->d_partitions[index].p_offset;
		fdisk->numsects = lbl->d_partitions[index].p_size;
		fdisk->id = (unsigned char)4;
 
		/* create dummy partition so that DOS can activate it */
		fdisk++;
		fdisk->active = 0x80;
		fdisk->startsect = lbl->d_partitions[index].p_offset 
					+ lbl->d_partitions[index].p_size;
		fdisk->numsects = 0;
		fdisk->id = (unsigned char)98;
	} else {
		printf("Partition %c of device %s is not an unused partition.\n"
						,*argv[2], devname);
		printf("\tUse the -I flag if you want to force write.\n");
		exit(-1);
	}
	if(lseek(fd, 0, 0) != 0L) {
		printf("Error seeking back to 0 %s\n", devname);
		exit(-1);
	}
	if(write(fd, buf, 1024) != 1024)
		printf("Error %d writing disklabel on %s.\n", errno, devname);
}

activate(dev, activate_unix)
char	*dev;
int	activate_unix;
{
	char			devname[256];
	int			fd;
	unsigned char		buf[2048];
	struct disklabel	*lbl;
	struct fdisktab		*fdisk1, *fdisk2;
	int			index, i;

	sprintf(devname, "/dev/r%sc", dev);
	if( (fd = open(devname, O_RDWR)) < 0) {
		printf("Could not open %s. Errno %d.\n", devname, errno);
		exit(-1);
	}
	if(read(fd, buf, 512) < 512) {
		printf("Error %d reading disklabel from %s\n", errno, devname);
		exit(-1);
	}
	fdisk1 = (struct fdisktab *) &buf[446];	/* talk about hardwire... */
	fdisk2 = fdisk1 + 1;
	if( !((buf[510] == 0x55) && (buf[511] == 0xaa)) ) {
		printf("Invalid boot 0 block on device %s\n", devname);
		exit(-1);
	}
	printf("Found valid boot 0 block on %s\n", devname);
	if(activate_unix) {
		fdisk1->active = 0x00;
		fdisk2->active = 0x80;
	} else {
		fdisk1->active = 0x80;
		fdisk2->active = 0x00;
	}
	if(lseek(fd, 0, 0) != 0L) {
		printf("Error seeking back to 0 %s\n", devname);
		exit(-1);
	}
	if(write(fd, buf, 512) != 512)
		printf("Error %d writing fdisk entry on %s.\n", errno, devname);
}

display(dev)
char	*dev;
{
	char			devname[256];
	int			fd;
	unsigned char		buf[2048];
	struct disklabel	*lbl;
	struct fdisktab		*fdisk1, *fdisk2;
	int			index, i;

	sprintf(devname, "/dev/r%sc", dev);
	if( (fd = open(devname, O_RDWR)) < 0) {
		printf("Could not open %s. Errno %d.\n", devname, errno);
		exit(-1);
	}
	if(read(fd, buf, 1024) < 1024) {
		printf("Error %d reading disklabel from %s\n", errno, devname);
		exit(-1);
	}
	fdisk1 = (struct fdisktab *) &buf[446];	/* talk about hardwire... */
	fdisk2 = fdisk1 + 1;
	if( !((buf[510] == 0x55) && (buf[511] == 0xaa)) ) {
		printf("Invalid boot 0 block on device %s\n", devname);
		exit(-1);
	}
	printf("Found valid boot 0 block on %s\n", devname);
	lbl = (struct disklabel *) &buf[512];
	if(lbl->d_magic != DISKMAGIC) {
		printf("Invalid disklabel on device %s\n", devname);
		exit(-1);
	}
	printf("Found valid disklabel on %s\n", devname);
	printf("disklabel:\n");
	for(i = 0; i < MAXPARTITIONS; i++)
		printf("%c:\tsize %ld,\toffset %ld,\tfstype %d\n",
		'a'+i, lbl->d_partitions[i].p_size,
		lbl->d_partitions[i].p_offset, lbl->d_partitions[i].p_fstype);
	printf("\n");
	printf("fdisk table:\n");
	printf("Entry 1:\toffset %ld,\tsize %ld,\tfstype %d\t %s\n",
		fdisk1->startsect, fdisk1->numsects, fdisk1->id,
		(fdisk1->active == 0x80 ? "ACTIVE" : "NOT ACTIVE") );
	printf("Entry 2:\toffset %ld,\tsize %ld,\tfstype %d\t %s\n",
		fdisk2->startsect, fdisk2->numsects, fdisk2->id,
		(fdisk2->active == 0x80 ? "ACTIVE" : "NOT ACTIVE") );
}

usage()
{
	printf("Usage : fdisk [-i|-I] <device_name> <partition>\n");
	printf("\t\t-i : initialize <partition> as dos partition.\n");
	printf("\t\t-I : force initialize (disregard current partition state)\n");
	printf("\n");

	printf("Usage : fdisk [-d|-u] <device_name>\n");
	printf("\t\t-d : Activate dos partition.\n");
	printf("\t\t-u : Activate 386bsd.\n");
	printf("\n");
	
	printf("Usage : fdisk <device_name>\n");
	printf("\t\t : Display state of partitions on <device_name>.\n");
	printf("\n");

	printf("device_name = [as|wd], partition = [a-h]\n");
	printf("Run fdisk after disklabel.\n");
	exit(-1);
}
____________________End fdisk.c________________________________________________