Exemple #1
0
static int
read_minix_subp(struct biosdisk *d, struct disklabel* dflt_lbl,
			int this_ext, daddr_t sector)
{
	struct mbr_partition mbr[MBR_PART_COUNT];
	int i;
	int typ;
	struct partition *p;

	if (readsects(&d->ll, sector, 1, d->buf, 0)) {
#ifdef DISK_DEBUG
		printf("Error reading MFS sector %"PRId64"\n", sector);
#endif
		return EIO;
	}
	if ((uint8_t)d->buf[510] != 0x55 || (uint8_t)d->buf[511] != 0xAA) {
		return -1;
	}
	memcpy(&mbr, MBR_PARTS(d->buf), sizeof(mbr));
	for (i = 0; i < MBR_PART_COUNT; i++) {
		typ = mbr[i].mbrp_type;
		if (typ == 0)
			continue;
		sector = this_ext + mbr[i].mbrp_start;
		if (dflt_lbl->d_npartitions >= MAXPARTITIONS)
			continue;
		p = &dflt_lbl->d_partitions[dflt_lbl->d_npartitions++];
		p->p_offset = sector;
		p->p_size = mbr[i].mbrp_size;
		p->p_fstype = xlat_mbr_fstype(typ);
	}
	return 0;
}
Exemple #2
0
int
biosdisk_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
		  void *buf, size_t *rsize)
{
	struct biosdisk *d;
	int blks, frag;

	if (flag != F_READ)
		return EROFS;

	d = (struct biosdisk *) devdata;

	if (d->ll.type == BIOSDISK_TYPE_CD)
		dblk = dblk * DEV_BSIZE / ISO_DEFAULT_BLOCK_SIZE;

	dblk += d->boff;

	blks = size / d->ll.secsize;
	if (blks && readsects(&d->ll, dblk, blks, buf, 0)) {
		if (rsize)
			*rsize = 0;
		return EIO;
	}

	/* needed for CD */
	frag = size % d->ll.secsize;
	if (frag) {
		if (readsects(&d->ll, dblk + blks, 1, d->buf, 0)) {
			if (rsize)
				*rsize = blks * d->ll.secsize;
			return EIO;
		}
		memcpy(buf + blks * d->ll.secsize, d->buf, frag);
	}

	if (rsize)
		*rsize = size;
	return 0;
}
Exemple #3
0
int
blkdevstrategy(void *devdata, int flag, daddr32_t dblk, size_t size, void *buf, size_t *rsize)
{

	if (flag != F_READ)
		return EROFS;

	if (size & (DEV_BSIZE - 1))
		return EINVAL;

	if (rsize)
		*rsize = size;

	if (size != 0 && readsects(0x40, bios_sector + dblk, buf,
				   size / DEV_BSIZE) != 0)
		return EIO;

	return 0;
}
Exemple #4
0
int
blkdevstrategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize)
{
	if (flag != F_READ)
		return EROFS;

	if (size & (BIOSDISK_DEFAULT_SECSIZE - 1))
		return EINVAL;

	if (rsize)
		*rsize = size;

	if (size != 0 && readsects(&d, bios_sector + dblk,
				   size / BIOSDISK_DEFAULT_SECSIZE,
				   buf, 1) != 0)
		return EIO;

	return 0;
}
Exemple #5
0
static int
check_label(struct biosdisk *d, daddr_t sector)
{
	struct disklabel *lp;

	/* find partition in NetBSD disklabel */
	if (readsects(&d->ll, sector + LABELSECTOR, 1, d->buf, 0)) {
#ifdef DISK_DEBUG
		printf("Error reading disklabel\n");
#endif
		return EIO;
	}
	lp = (struct disklabel *) (d->buf + LABELOFFSET);
	if (lp->d_magic != DISKMAGIC || dkcksum(lp)) {
#ifdef DISK_DEBUG
		printf("warning: no disklabel in sector %"PRId64"\n", sector);
#endif
		return -1;
	}

	ingest_label(d, lp);

#ifdef _STANDALONE
	bi_disk.labelsector = sector + LABELSECTOR;
	bi_disk.label.type = lp->d_type;
	memcpy(bi_disk.label.packname, lp->d_packname, 16);
	bi_disk.label.checksum = lp->d_checksum;

	bi_wedge.matchblk = sector + LABELSECTOR;
	bi_wedge.matchnblks = 1;

	md5(bi_wedge.matchhash, d->buf, d->ll.secsize);
#endif

	return 0;
}
Exemple #6
0
void bi_getbiosgeom()
{
	struct btinfo_biosgeom *bibg;
	int i, j, nvalid;
	unsigned char nhd;
	unsigned int cksum;

	pvbcopy((void *)(0x400 + 0x75), &nhd, 1);
#ifdef GEOM_DEBUG
	printf("nhd %d\n", (int)nhd);
#endif

	bibg = alloc(sizeof(struct btinfo_biosgeom)
		     + (nhd - 1) * sizeof(struct bi_biosgeom_entry));
	if (!bibg)
		return;

	for (i = nvalid = 0; i < MAX_BIOSDISKS && nvalid < (int)nhd; i++) {
		struct biosdisk_ll d;
		struct biosdisk_ext13info ed;
		char buf[BIOSDISK_SECSIZE];

		d.dev = 0x80 + i;

		if (set_geometry(&d, &ed))
			continue;
		bzero(&bibg->disk[nvalid], sizeof(bibg->disk[nvalid]));

		bibg->disk[nvalid].sec = d.sec;
		bibg->disk[nvalid].head = d.head;
		bibg->disk[nvalid].cyl = d.cyl;
		bibg->disk[nvalid].dev = d.dev;

		if (readsects(&d, 0, 1, buf, 0)) {
			bibg->disk[nvalid].flags |= BI_GEOM_INVALID;
			nvalid++;
			continue;
		}

#ifdef GEOM_DEBUG
		printf("#%d: %x: C %d H %d S %d\n", nvalid,
		    d.dev, d.cyl, d.head, d.sec);
#endif

		if (d.flags & BIOSDISK_EXT13) {
			if (ed.flags & EXT13_GEOM_VALID)
				bibg->disk[nvalid].totsec = ed.totsec;
			else
				bibg->disk[nvalid].totsec = 0;
			bibg->disk[nvalid].flags |= BI_GEOM_EXTINT13;
		}
		for (j = 0, cksum = 0; j < BIOSDISK_SECSIZE; j++)
			cksum += buf[j];
		bibg->disk[nvalid].cksum = cksum;
		bcopy(&buf[MBR_PARTOFF], bibg->disk[nvalid].dosparts,
		      sizeof(bibg->disk[nvalid].dosparts));
		nvalid++;
	}

	bibg->num = nvalid;

	BI_ADD(bibg, BTINFO_BIOSGEOM, sizeof(struct btinfo_biosgeom)
	       + nvalid * sizeof(struct bi_biosgeom_entry));
}
Exemple #7
0
static int
read_label(struct biosdisk *d)
{
	struct disklabel dflt_lbl;
	struct mbr_partition mbr[MBR_PART_COUNT];
	struct partition *p;
	uint32_t sector;
	int i;
	int error;
	int typ;
	uint32_t ext_base, this_ext, next_ext;
#ifdef COMPAT_386BSD_MBRPART
	int sector_386bsd = -1;
#endif

	memset(&dflt_lbl, 0, sizeof(dflt_lbl));
	dflt_lbl.d_npartitions = 8;

	d->boff = 0;

	if (d->ll.type != BIOSDISK_TYPE_HD)
		/* No label on floppy and CD */
		return -1;

	/*
	 * find NetBSD Partition in DOS partition table
	 * XXX check magic???
	 */
	ext_base = 0;
	next_ext = 0;
	for (;;) {
		this_ext = ext_base + next_ext;
		next_ext = 0;
		if (readsects(&d->ll, this_ext, 1, d->buf, 0)) {
#ifdef DISK_DEBUG
			printf("error reading MBR sector %u\n", this_ext);
#endif
			return EIO;
		}
		memcpy(&mbr, MBR_PARTS(d->buf), sizeof(mbr));
		/* Look for NetBSD partition ID */
		for (i = 0; i < MBR_PART_COUNT; i++) {
			typ = mbr[i].mbrp_type;
			if (typ == 0)
				continue;
			sector = this_ext + mbr[i].mbrp_start;
#ifdef DISK_DEBUG
			printf("ptn type %d in sector %u\n", typ, sector);
#endif
                        if (typ == MBR_PTYPE_MINIX_14B) {
				if (!read_minix_subp(d, &dflt_lbl,
						   this_ext, sector)) {
					/* Don't add "container" partition */
					continue;
				}
			}
			if (typ == MBR_PTYPE_NETBSD) {
				error = check_label(d, sector);
				if (error >= 0)
					return error;
			}
			if (MBR_IS_EXTENDED(typ)) {
				next_ext = mbr[i].mbrp_start;
				continue;
			}
#ifdef COMPAT_386BSD_MBRPART
			if (this_ext == 0 && typ == MBR_PTYPE_386BSD)
				sector_386bsd = sector;
#endif
			if (this_ext != 0) {
				if (dflt_lbl.d_npartitions >= MAXPARTITIONS)
					continue;
				p = &dflt_lbl.d_partitions[dflt_lbl.d_npartitions++];
			} else
				p = &dflt_lbl.d_partitions[i];
			p->p_offset = sector;
			p->p_size = mbr[i].mbrp_size;
			p->p_fstype = xlat_mbr_fstype(typ);
		}
		if (next_ext == 0)
			break;
		if (ext_base == 0) {
			ext_base = next_ext;
			next_ext = 0;
		}
	}

	sector = 0;
#ifdef COMPAT_386BSD_MBRPART
	if (sector_386bsd != -1) {
		printf("old BSD partition ID!\n");
		sector = sector_386bsd;
	}
#endif

	/*
	 * One of two things:
	 * 	1. no MBR
	 *	2. no NetBSD partition in MBR
	 *
	 * We simply default to "start of disk" in this case and
	 * press on.
	 */
	error = check_label(d, sector);
	if (error >= 0)
		return error;

	/*
	 * Nothing at start of disk, return info from mbr partitions.
	 */
	/* XXX fill it to make checksum match kernel one */
	dflt_lbl.d_checksum = dkcksum(&dflt_lbl);
	ingest_label(d, &dflt_lbl);
	return 0;
}
Exemple #8
0
static bool
guid_is_nil(const struct uuid *u)
{
	static const struct uuid nil = { .time_low = 0 };
	return (memcmp(u, &nil, sizeof(*u)) == 0 ? true : false);
}

static bool
guid_is_equal(const struct uuid *a, const struct uuid *b)
{
	return (memcmp(a, b, sizeof(*a)) == 0 ? true : false);
}

static int
check_gpt(struct biosdisk *d, daddr_t sector)
{
	struct gpt_hdr gpth;
	const struct gpt_ent *ep;
	const struct uuid *u;
	daddr_t entblk;
	size_t size;
	uint32_t crc;
	int sectors;
	int entries;
	int entry;
	int i, j;

	/* read in gpt_hdr sector */
	if (readsects(&d->ll, sector, 1, d->buf, 1)) {
#ifdef DISK_DEBUG
		printf("Error reading GPT header at %"PRId64"\n", sector);
#endif
		return EIO;
	}

	memcpy(&gpth, d->buf, sizeof(gpth));

	if (memcmp(GPT_HDR_SIG, gpth.hdr_sig, sizeof(gpth.hdr_sig)))
		return -1;

	crc = gpth.hdr_crc_self;
	gpth.hdr_crc_self = 0;
	gpth.hdr_crc_self = crc32(0, (const void *)&gpth, GPT_HDR_SIZE);
	if (gpth.hdr_crc_self != crc) {
		return -1;
	}

	if (gpth.hdr_lba_self != sector)
		return -1;

#ifdef _STANDALONE
	bi_wedge.matchblk = sector;
	bi_wedge.matchnblks = 1;

	md5(bi_wedge.matchhash, d->buf, d->ll.secsize);
#endif

	sectors = sizeof(d->buf)/d->ll.secsize; /* sectors per buffer */
	entries = sizeof(d->buf)/gpth.hdr_entsz; /* entries per buffer */
	entblk = gpth.hdr_lba_table;
	crc = crc32(0, NULL, 0);

	j = 0;
	ep = (const struct gpt_ent *)d->buf;

	for (entry = 0; entry < gpth.hdr_entries; entry += entries) {
		size = MIN(sizeof(d->buf),
		    (gpth.hdr_entries - entry) * gpth.hdr_entsz);
		entries = size / gpth.hdr_entsz;
		sectors = roundup(size, d->ll.secsize) / d->ll.secsize;
		if (readsects(&d->ll, entblk, sectors, d->buf, 1))
			return -1;
		entblk += sectors;
		crc = crc32(crc, (const void *)d->buf, size);

		for (i = 0; j < BIOSDISKNPART && i < entries; i++, j++) {
			u = (const struct uuid *)ep[i].ent_type;
			if (!guid_is_nil(u)) {
				d->part[j].offset = ep[i].ent_lba_start;
				d->part[j].size = ep[i].ent_lba_end -
				    ep[i].ent_lba_start + 1;
				if (guid_is_equal(u, &GET_nbsd_ffs))
					d->part[j].fstype = FS_BSDFFS;
				else if (guid_is_equal(u, &GET_nbsd_lfs))
					d->part[j].fstype = FS_BSDLFS;
				else if (guid_is_equal(u, &GET_nbsd_raid))
					d->part[j].fstype = FS_RAID;
				else if (guid_is_equal(u, &GET_nbsd_swap))
					d->part[j].fstype = FS_SWAP;
				else
					d->part[j].fstype = FS_OTHER;
			}
		}

	}

	if (crc != gpth.hdr_crc_table) {
#ifdef DISK_DEBUG	
		printf("GPT table CRC invalid\n");
#endif
		return -1;
	}

	return 0;
}

static int
read_gpt(struct biosdisk *d)
{
	struct biosdisk_extinfo ed;
	daddr_t gptsector[2];
	int i, error;

	if (d->ll.type != BIOSDISK_TYPE_HD)
		/* No GPT on floppy and CD */
		return -1;

	gptsector[0] = GPT_HDR_BLKNO;
	if (set_geometry(&d->ll, &ed) == 0 && d->ll.flags & BIOSDISK_INT13EXT) {
		gptsector[1] = ed.totsec - 1;
		/* Sanity check values returned from BIOS */
		if (ed.sbytes >= 512 && (ed.sbytes & (ed.sbytes - 1)) == 0)
			d->ll.secsize = ed.sbytes;
	} else {
#ifdef DISK_DEBUG
		printf("Unable to determine extended disk geometry - "
			"using CHS\n");
#endif
		/* at least try some other reasonable values then */
		gptsector[1] = d->ll.chs_sectors - 1;
	}

	/*
	 * Use any valid GPT available, do not require both GPTs to be valid
	 */
	for (i = 0; i < __arraycount(gptsector); i++) {
		error = check_gpt(d, gptsector[i]);
		if (error == 0)
			break;
	}

	if (i >= __arraycount(gptsector)) {
		memset(d->part, 0, sizeof(d->part));
		return -1;
	}

#ifdef DISK_DEBUG
	printf("using %s GPT\n", (i == 0) ? "primary" : "secondary");
#endif
	return 0;
}
#endif	/* !NO_GPT */

#ifndef NO_DISKLABEL
static void
ingest_label(struct biosdisk *d, struct disklabel *lp)
{
	int part;

	memset(d->part, 0, sizeof(d->part));

	for (part = 0; part < lp->d_npartitions; part++) {
		if (lp->d_partitions[part].p_size == 0)
			continue;
		if (lp->d_partitions[part].p_fstype == FS_UNUSED)
			continue;
		d->part[part].fstype = lp->d_partitions[part].p_fstype;
		d->part[part].offset = lp->d_partitions[part].p_offset;
		d->part[part].size = lp->d_partitions[part].p_size;
	}
}
Exemple #9
0
/*
 * Attempt to open the disk described by (dev) for use by (f).
 *
 * Note that the philosophy here is "give them exactly what
 * they ask for".  This is necessary because being too "smart"
 * about what the user might want leads to complications.
 * (eg. given no slice or partition value, with a disk that is
 *  sliced - are they after the first BSD slice, or the DOS
 *  slice before it?)
 */
static int 
bd_open(struct open_file *f, void *vdev)
{
    struct alpha_devdesc	*dev = vdev;
    struct dos_partition	*dptr;
    struct open_disk		*od;
    struct disklabel		*lp;
    int				sector, slice, i;
    int				error;
    int				unit;
    prom_return_t		ret;

    unit = dev->d_kind.srmdisk.unit;
    if (unit >= nbdinfo) {
	D(printf("attempt to open nonexistent disk\n"));
	return(ENXIO);
    }
    
    /* Call the prom to open the disk. */
    ret.bits = prom_open(bdinfo[unit].bd_name, bdinfo[unit].bd_namelen);
    if (ret.u.status == 2)
	return (ENXIO);
    if (ret.u.status == 3)
	return (EIO);

    od = (struct open_disk *) malloc(sizeof(struct open_disk));
    if (!od) {
	D(printf("srmdiskopen: no memory\n"));
	return (ENOMEM);
    }

    /* Look up SRM unit number, intialise open_disk structure */
    od->od_fd = ret.u.retval;
    od->od_unit = dev->d_kind.srmdisk.unit;
    od->od_flags = bdinfo[od->od_unit].bd_flags;
    od->od_boff = 0;
    error = 0;

#if 0
    /* Get geometry for this open (removable device may have changed) */
    if (set_geometry(&od->od_ll)) {
	D(printf("bd_open: can't get geometry\n"));
	error = ENXIO;
	goto out;
    }
#endif

    /*
     * Following calculations attempt to determine the correct value
     * for d->od_boff by looking for the slice and partition specified,
     * or searching for reasonable defaults.
     */

#if 0
    /*
     * Find the slice in the DOS slice table.
     */
    if (readsects(&od->od_ll, 0, 1, od->od_buf, 0)) {
	D(printf("bd_open: error reading MBR\n"));
	error = EIO;
	goto out;
    }

    /* 
     * Check the slice table magic.
     */
    if ((od->od_buf[0x1fe] != 0xff) || (od->od_buf[0x1ff] != 0xaa)) {
	/* If a slice number was explicitly supplied, this is an error */
	if (dev->d_kind.srmdisk.slice > 0) {
	    D(printf("bd_open: no slice table/MBR (no magic)\n"));
	    error = ENOENT;
	    goto out;
	}
	sector = 0;
	goto unsliced;		/* may be a floppy */
    }
    dptr = (struct dos_partition *) & od->od_buf[DOSPARTOFF];

    /* 
     * XXX No support here for 'extended' slices
     */
    if (dev->d_kind.srmdisk.slice <= 0) {
	/*
	 * Search for the first FreeBSD slice; this also works on "unsliced"
	 * disks, as they contain a "historically bogus" MBR.
	 */
	for (i = 0; i < NDOSPART; i++, dptr++)
	    if (dptr->dp_typ == DOSPTYP_386BSD) {
		sector = dptr->dp_start;
		break;
	    }
	/* Did we find something? */
	if (sector == -1) {
	    error = ENOENT;
	    goto out;
	}
    } else {
	/*
	 * Accept the supplied slice number unequivocally (we may be looking
	 * for a DOS partition) if we can handle it.
	 */
	if ((dev->d_kind.srmdisk.slice > NDOSPART) || (dev->d_kind.srmdisk.slice < 1)) {
	    error = ENOENT;
	    goto out;
	}
	dptr += (dev->d_kind.srmdisk.slice - 1);
	sector = dptr->dp_start;
    }
 unsliced:

#else
    sector = 0;
#endif
    /* 
     * Now we have the slice, look for the partition in the disklabel if we have
     * a partition to start with.
     */
    if (dev->d_kind.srmdisk.partition < 0) {
	od->od_boff = sector;		/* no partition, must be after the slice */
    } else {
	if (bd_strategy(od, F_READ, sector + LABELSECTOR, 512, od->od_buf, 0)) {
	    D(printf("bd_open: error reading disklabel\n"));
	    error = EIO;
	    goto out;
	}
	lp = (struct disklabel *) (od->od_buf + LABELOFFSET);
	if (lp->d_magic != DISKMAGIC) {
	    D(printf("bd_open: no disklabel\n"));
	    error = ENOENT;
	    goto out;

	} else if (dev->d_kind.srmdisk.partition >= lp->d_npartitions) {

	    /*
	     * The partition supplied is out of bounds; this is fatal.
	     */
	    D(printf("partition '%c' exceeds partitions in table (a-'%c')\n",
		     'a' + dev->d_kind.srmdisk.partition, 'a' + lp->d_npartitions));
	    error = EPART;
	    goto out;

	} else {

	    /*
	     * Complain if the partition type is wrong and it shouldn't be, but
	     * regardless accept this partition.
	     */
	    D(if ((lp->d_partitions[dev->d_kind.srmdisk.partition].p_fstype == FS_UNUSED) &&
		  !(od->od_flags & BD_FLOPPY))	    /* Floppies often have bogus fstype */
	      printf("bd_open: warning, partition marked as unused\n"););

	    od->od_boff = lp->d_partitions[dev->d_kind.srmdisk.partition].p_offset;
	}
    }