b8e4cd2bb3
It boots FreeBSD from a running MS-DOS system. It's compiled using some MS-DOS tools, but there is a binary hidden in the uuencoded file. (Go ahead, flame me if you can come up with a solution for the problem. Just saying "this is bad" doesn't count!) Rod, you were right: one would have to deal with weird interfaces to the memory managers, and it seems that Christian found them all, and made them work. Thanks Christian! Reviewed by: phk Submitted by: DI. Christian Gusenbauer <cg@fimp01.fim.uni-linz.ac.at> Christians README: ------------------ Hi Everybody! This is version 1.5 of "fbsdboot", a program that allows you to boot a kernel from a MS-DOS partition or a FreeBSD partition. This program runs using DOS. It works with various memory managers (like EMM386, 386MAX) under certain circumstances. First, a FreeBSD kernel is always loaded to memory starting at 0x100000. To assure that loading the kernel *does not* overwrite memory used by memory managers, high memory for the kernel is allocated and after loading the kernel it's moved to 0x100000. Second, there are many ways to switch to protected mode which is necessary to start the kernel. Each BIOS gives you the possibility to use INT15H (AH=89H) to do that. But some memory-managers like 386max does not allow you to use this method. An other way to do the switch is to use DPMI services, but they do not guarantee, that the protected mode application is executed with privilege level 0. Therefore this method is *not* used. VCPI services offer another way to switch to protected mode, and VCPI servers are built into "emm386.exe", "386max" and "qemm". That's why, this method is implemented in fbsdboot.exe. Fbsdboot.exe tries to switch to protected mode using VCPI services. If they're not available INT15H is used to do the switch. If that fails, it's not possible for this version of fbsdboot.exe to boot a kernel :-(. You can get commandline options of fbsdboot if you start it with "-?" as option! I don't know, if fbsdboot works with QEMM, as I don't have the possibility to test it. Enjoy and have fun! Christian. cg@fimp01.fim.uni-linz.ac.at PS: Many thanks to Bruce Evans for his assistance!
296 lines
7.3 KiB
C
296 lines
7.3 KiB
C
/*
|
|
* Mach Operating System
|
|
* Copyright (c) 1992, 1991 Carnegie Mellon University
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission to use, copy, modify and distribute this software and its
|
|
* documentation is hereby granted, provided that both the copyright
|
|
* notice and this permission notice appear in all copies of the
|
|
* software, derivative works or modified versions, and any portions
|
|
* thereof, and that both notices appear in supporting documentation.
|
|
*
|
|
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
|
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
|
|
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
|
*
|
|
* Carnegie Mellon requests users of this software to return to
|
|
*
|
|
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
|
* School of Computer Science
|
|
* Carnegie Mellon University
|
|
* Pittsburgh PA 15213-3890
|
|
*
|
|
* any improvements or extensions that they make and grant Carnegie Mellon
|
|
* the rights to redistribute these changes.
|
|
*
|
|
* from: Mach, Revision 2.2 92/04/04 11:35:49 rpd
|
|
* $Id: disk.c,v 1.4 1994/02/22 22:59:40 rgrimes Exp $
|
|
*/
|
|
#include <stdio.h>
|
|
#include <memory.h>
|
|
|
|
#define bcopy(a,b,c) memcpy(b,a,c)
|
|
|
|
#include "boot.h"
|
|
#ifdef DO_BAD144
|
|
#include "dkbad.h"
|
|
#endif
|
|
#include "disklabe.h"
|
|
|
|
#define BIOS_DEV_FLOPPY 0x0
|
|
#define BIOS_DEV_WIN 0x80
|
|
|
|
#define BPS 512
|
|
#define SPT(di) ((di)&0xff)
|
|
#define HEADS(di) ((((di)>>8)&0xff)+1)
|
|
|
|
static char i_buf[BPS];
|
|
#define I_ADDR ((void *) i_buf) /* XXX where all reads go */
|
|
|
|
#ifdef DO_BAD144
|
|
struct dkbad dkb;
|
|
int do_bad144;
|
|
long bsize;
|
|
#endif
|
|
|
|
static int spt, spc;
|
|
|
|
char *iodest;
|
|
struct fs *fs;
|
|
struct inode inode;
|
|
long dosdev, slice, unit, part, maj, boff, poff, bnum, cnt;
|
|
|
|
extern int biosread(int dev, int track, int head, int sector, int cnt, unsigned char far *buffer);
|
|
|
|
/*#define EMBEDDED_DISKLABEL 1*/
|
|
/*extern struct disklabel disklabel;*/
|
|
struct disklabel disklabel;
|
|
|
|
static void Bread(int dosdev, long sector);
|
|
static long badsect(int dosdev, long sector);
|
|
|
|
unsigned long get_diskinfo(int drive)
|
|
{
|
|
char dr = (char) drive;
|
|
unsigned long rt;
|
|
|
|
_asm {
|
|
mov ah,8 ; get diskinfo
|
|
mov dl,dr ; drive
|
|
int 13h
|
|
cmp ah,0
|
|
je ok
|
|
;
|
|
; Failure! We assume it's a floppy!
|
|
;
|
|
sub ax,ax
|
|
mov bh,ah
|
|
mov bl,2
|
|
mov ch,79
|
|
mov cl,15
|
|
mov dh,1
|
|
mov dl,1
|
|
ok:
|
|
mov ah,dh
|
|
mov al,cl
|
|
and al,3fh
|
|
mov word ptr rt,ax
|
|
|
|
xor bx,bx
|
|
mov bl,cl
|
|
and bl,0c0h
|
|
shl bx,2
|
|
mov bl,ch
|
|
mov word ptr rt+2,bx
|
|
}
|
|
return rt;
|
|
}
|
|
|
|
int devopen(void)
|
|
{
|
|
struct dos_partition *dptr;
|
|
struct disklabel *dl;
|
|
int dosdev = (int) inode.i_dev;
|
|
int i;
|
|
long di, sector;
|
|
|
|
di = get_diskinfo(dosdev);
|
|
spc = (spt = (int)SPT(di)) * (int)HEADS(di);
|
|
if (dosdev == 2)
|
|
{
|
|
boff = 0;
|
|
part = (spt == 15 ? 3 : 1);
|
|
}
|
|
else
|
|
{
|
|
#ifdef EMBEDDED_DISKLABEL
|
|
dl = &disklabel;
|
|
#else EMBEDDED_DISKLABEL
|
|
Bread(dosdev, 0);
|
|
dptr = (struct dos_partition *)(((char *)I_ADDR)+DOSPARTOFF);
|
|
sector = LABELSECTOR;
|
|
for (i = 0; i < NDOSPART; i++, dptr++)
|
|
if (dptr->dp_typ == DOSPTYP_386BSD) {
|
|
sector = dptr->dp_start + LABELSECTOR;
|
|
slice = i+1;
|
|
break;
|
|
}
|
|
Bread(dosdev, sector++);
|
|
dl=((struct disklabel *)I_ADDR);
|
|
disklabel = *dl; /* structure copy (maybe useful later)*/
|
|
#endif EMBEDDED_DISKLABEL
|
|
if (dl->d_magic != DISKMAGIC) {
|
|
printf("bad disklabel");
|
|
return 1;
|
|
}
|
|
|
|
if( (maj == 4) || (maj == 0) || (maj == 1)) {
|
|
if (dl->d_type == DTYPE_SCSI)
|
|
maj = 4; /* use scsi as boot dev */
|
|
else
|
|
maj = 0; /* must be ESDI/IDE */
|
|
}
|
|
|
|
boff = dl->d_partitions[part].p_offset;
|
|
#ifdef DO_BAD144
|
|
bsize = dl->d_partitions[part].p_size;
|
|
do_bad144 = 0;
|
|
if (dl->d_flags & D_BADSECT) {
|
|
/* this disk uses bad144 */
|
|
int i;
|
|
long dkbbnum;
|
|
struct dkbad *dkbptr;
|
|
|
|
/* find the first readable bad144 sector */
|
|
/* some of this code is copied from ufs/disk_subr.c */
|
|
/* read a bad sector table */
|
|
dkbbnum = dl->d_secperunit - dl->d_nsectors;
|
|
if (dl->d_secsize > DEV_BSIZE)
|
|
dkbbnum *= dl->d_secsize / DEV_BSIZE;
|
|
else
|
|
dkbbnum /= DEV_BSIZE / dl->d_secsize;
|
|
i = 0;
|
|
do_bad144 = 0;
|
|
do {
|
|
/* XXX: what if the "DOS sector" < 512 bytes ??? */
|
|
Bread(dosdev, dkbbnum + i);
|
|
dkbptr = (struct dkbad *) I_ADDR;
|
|
/* XXX why is this not in <sys/dkbad.h> ??? */
|
|
#define DKBAD_MAGIC 0x4321
|
|
if (dkbptr->bt_mbz == 0 &&
|
|
dkbptr->bt_flag == DKBAD_MAGIC) {
|
|
dkb = *dkbptr; /* structure copy */
|
|
do_bad144 = 1;
|
|
break;
|
|
}
|
|
i += 2;
|
|
} while (i < 10 && (u_long) i < dl->d_nsectors);
|
|
if (!do_bad144)
|
|
printf("Bad badsect table\n");
|
|
else
|
|
printf("Using bad144 bad sector at %ld\n", dkbbnum+i);
|
|
}
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void devread(void)
|
|
{
|
|
long offset, sector = bnum;
|
|
int dosdev = (int) inode.i_dev;
|
|
for (offset = 0; offset < cnt; offset += BPS)
|
|
{
|
|
Bread(dosdev, badsect(dosdev, sector++));
|
|
bcopy(I_ADDR, iodest+offset, BPS);
|
|
}
|
|
}
|
|
|
|
/* Read ahead buffer large enough for one track on a 1440K floppy. For
|
|
* reading from floppies, the bootstrap has to be loaded on a 64K boundary
|
|
* to ensure that this buffer doesn't cross a 64K DMA boundary.
|
|
*/
|
|
#define RA_SECTORS 18
|
|
static char ra_buf[RA_SECTORS * BPS];
|
|
static int ra_dev;
|
|
static long ra_end;
|
|
static long ra_first;
|
|
|
|
static void Bread(int dosdev, long sector)
|
|
{
|
|
if (dosdev != ra_dev || sector < ra_first || sector >= ra_end)
|
|
{
|
|
int cyl, head, sec, nsec;
|
|
|
|
cyl = (int) (sector/(long)spc);
|
|
head = (int) ((sector % (long) spc) / (long) spt);
|
|
sec = (int) (sector % (long) spt);
|
|
nsec = spt - sec;
|
|
if (nsec > RA_SECTORS)
|
|
nsec = RA_SECTORS;
|
|
if (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0)
|
|
{
|
|
nsec = 1;
|
|
while (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0)
|
|
printf("Error: C:%d H:%d S:%d\n", cyl, head, sec);
|
|
}
|
|
ra_dev = dosdev;
|
|
ra_first = sector;
|
|
ra_end = sector + nsec;
|
|
}
|
|
bcopy(ra_buf + (sector - ra_first) * BPS, I_ADDR, BPS);
|
|
}
|
|
|
|
static long badsect(int dosdev, long sector)
|
|
{
|
|
#ifdef DO_BAD144
|
|
int i;
|
|
|
|
if (do_bad144) {
|
|
u_short cyl;
|
|
u_short head;
|
|
u_short sec;
|
|
long newsec;
|
|
struct disklabel *dl = &disklabel;
|
|
|
|
/* XXX */
|
|
/* from wd.c */
|
|
/* bt_cyl = cylinder number in sorted order */
|
|
/* bt_trksec is actually (head << 8) + sec */
|
|
|
|
/* only remap sectors in the partition */
|
|
if (sector < boff || sector >= boff + bsize) {
|
|
goto no_remap;
|
|
}
|
|
|
|
cyl = (u_short) (sector / dl->d_secpercyl);
|
|
head = (u_short) ((sector % dl->d_secpercyl) / dl->d_nsectors);
|
|
sec = (u_short) (sector % dl->d_nsectors);
|
|
sec = (head<<8) + sec;
|
|
|
|
/* now, look in the table for a possible bad sector */
|
|
for (i=0; i<126; i++) {
|
|
if (dkb.bt_bad[i].bt_cyl == cyl) {
|
|
/* found same cylinder */
|
|
if (dkb.bt_bad[i].bt_trksec == sec) {
|
|
/* FOUND! */
|
|
break;
|
|
}
|
|
} else if (dkb.bt_bad[i].bt_cyl > cyl) {
|
|
i = 126;
|
|
break;
|
|
}
|
|
}
|
|
if (i == 126) {
|
|
/* didn't find bad sector */
|
|
goto no_remap;
|
|
}
|
|
/* otherwise find replacement sector */
|
|
newsec = dl->d_secperunit - dl->d_nsectors - i -1;
|
|
return newsec;
|
|
}
|
|
no_remap:
|
|
#endif
|
|
return sector;
|
|
}
|