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; }
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; }
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; }
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; }
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; }
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)); }
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; }
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; } }
/* * 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; } }