diff options
author | 1997-08-08 22:01:08 +0000 | |
---|---|---|
committer | 1997-08-08 22:01:08 +0000 | |
commit | 937e549cc6980356521796ed5c3e39ca747a331c (patch) | |
tree | 3aebc5c4a764dde9b42624f567d2197dc1858a83 | |
parent | typo (diff) | |
download | wireguard-openbsd-937e549cc6980356521796ed5c3e39ca747a331c.tar.xz wireguard-openbsd-937e549cc6980356521796ed5c3e39ca747a331c.zip |
Use the new bounds_check_with_label API. Add generic support for reading
both little and big endian BSD disklabels. Add a specific hook to read such
a big-endian disklabel as it is found on amiga (normally, however, amiga
uses the native RDB format, which still is not supported).
-rw-r--r-- | sys/arch/alpha/alpha/disksubr.c | 209 | ||||
-rw-r--r-- | sys/arch/alpha/include/disklabel.h | 195 |
2 files changed, 358 insertions, 46 deletions
diff --git a/sys/arch/alpha/alpha/disksubr.c b/sys/arch/alpha/alpha/disksubr.c index fa233b98587..36c7c417b16 100644 --- a/sys/arch/alpha/alpha/disksubr.c +++ b/sys/arch/alpha/alpha/disksubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: disksubr.c,v 1.10 1997/07/30 11:39:36 niklas Exp $ */ +/* $OpenBSD: disksubr.c,v 1.11 1997/08/08 22:01:08 niklas Exp $ */ /* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */ /* @@ -38,6 +38,17 @@ * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 */ +/* + * This disksubr.c module started to take it's present form on OpenBSD/alpha + * but it was always thought it should be made completely MI and not need to + * be in that alpha-specific tree at all. + * + * XXX The DOS partitioning code is not endian-independent, only native + * endian DOS partition tables can be parsed yet. + * + * XXX Amiga RDB partitioning is not understood yet. + */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/buf.h> @@ -47,25 +58,29 @@ #include <sys/disk.h> /* The native defaults... */ -#ifdef __alpha__ +#if defined(alpha) && !defined(DISKLABEL_ALPHA) #define DISKLABEL_ALPHA -#elif defined(__i386__) || defined(__arc__) +#elif (defined(i386) || defined(arc))) && !defined(DISKLABEL_I386) #define DISKLABEL_I386 +#elif defined(amiga)) && !defined(DISKLABEL_AMIGA) +#define DISKLABEL_AMIGA #endif #define b_cylin b_resid -#define BOOT_MAGIC 0xAA55 -#define BOOT_MAGIC_OFF (DOSPARTOFF + NDOSPART * sizeof (struct dos_partition)) - -#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALPHA) || defined(DISKLABEL_ALL) +#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALPHA) || defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) +void swapdisklabel __P((struct disklabel *d)); char *readbsdlabel __P((struct buf *, void (*) __P((struct buf *)), int, int, - int, struct disklabel *)); + int, int, struct disklabel *)); #endif #if defined(DISKLABEL_I386) || defined(DISKLABEL_ALL) char *readdoslabel __P((struct buf *, void (*) __P((struct buf *)), struct disklabel *, struct cpu_disklabel *)); #endif +#if defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) +char *readamigalabel __P((struct buf *, void (*) __P((struct buf *)), + struct disklabel *, struct cpu_disklabel *)); +#endif static enum disklabel_tag probe_order[] = { LABELPROBES, -1 }; @@ -76,19 +91,80 @@ dk_establish(dk, dev) { } -#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALPHA) || defined(DISKLABEL_ALL) +#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALPHA) || defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) +/* XXX should we not provide generic swapXX functions? */ +#if BYTE_ORDER == BIG_ENDIAN +#define swap32(x) ((x) = htole32(x)) +#define swap16(x) ((x) = htole16(x)) +#else +#define swap32(x) ((x) = htobe32(x)) +#define swap16(x) ((x) = htobe16(x)) +#endif + +/* + * Byteswap all the fields that might be swapped. + */ +void +swapdisklabel(dlp) + struct disklabel *dlp; +{ + int i; + struct partition *pp; + + swap32(dlp->d_magic); + swap16(dlp->d_type); + swap16(dlp->d_subtype); + swap32(dlp->d_secsize); + swap32(dlp->d_nsectors); + swap32(dlp->d_ntracks); + swap32(dlp->d_ncylinders); + swap32(dlp->d_secpercyl); + swap32(dlp->d_secperunit); + swap16(dlp->d_sparespertrack); + swap16(dlp->d_sparespercyl); + swap32(dlp->d_acylinders); + swap16(dlp->d_rpm); + swap16(dlp->d_interleave); + swap16(dlp->d_trackskew); + swap16(dlp->d_cylskew); + swap32(dlp->d_headswitch); + swap32(dlp->d_trkseek); + swap32(dlp->d_flags); + for (i = 0; i < NDDATA; i++) + swap32(dlp->d_drivedata[i]); + for (i = 0; i < NSPARE; i++) + swap32(dlp->d_spare[i]); + swap32(dlp->d_magic2); + swap16(dlp->d_checksum); + swap16(dlp->d_npartitions); + swap32(dlp->d_bbsize); + swap32(dlp->d_sbsize); + for (i = 0; i < MAXPARTITIONS; i++) { + pp = &dlp->d_partitions[i]; + swap32(pp->p_size); + swap32(pp->p_offset); + swap32(pp->p_fsize); + swap16(pp->p_cpg); + } +} + /* * Try to read a standard BSD disklabel at a certain sector. */ char * -readbsdlabel(bp, strat, cyl, sec, off, lp) +readbsdlabel(bp, strat, cyl, sec, off, endian, lp) struct buf *bp; void (*strat) __P((struct buf *)); - int cyl, sec, off; + int cyl, sec, off, endian; struct disklabel *lp; { struct disklabel *dlp; char *msg = NULL; + u_int16_t cksum; + u_int32_t magic; + + if (endian != LITTLE_ENDIAN && endian != BIG_ENDIAN) + panic("readbsdlabel: unsupported byteorder %d", endian); bp->b_blkno = sec; bp->b_cylin = cyl; @@ -103,6 +179,8 @@ readbsdlabel(bp, strat, cyl, sec, off, lp) return (msg); } + magic = endian == BIG_ENDIAN ? htobe32(DISKMAGIC) : htole32(DISKMAGIC); + /* * If off is negative, search until the end of the sector for * the label, otherwise, just look at the specific location @@ -110,16 +188,29 @@ readbsdlabel(bp, strat, cyl, sec, off, lp) */ dlp = (struct disklabel *)(bp->b_data + (off >= 0 ? off : 0)); do { - if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { + if (dlp->d_magic != magic || dlp->d_magic2 != magic) { if (msg == NULL) msg = "no disk label"; - } else if (dlp->d_npartitions > MAXPARTITIONS || - dkcksum(dlp) != 0) - msg = "disk label corrupted"; - else { - *lp = *dlp; - msg = NULL; - break; + } else { + cksum = dkcksum(dlp); + if (endian != BYTE_ORDER) + swapdisklabel(dlp); + if (dlp->d_npartitions > MAXPARTITIONS || cksum != 0) { + msg = "disk label corrupted"; + /* swap back if necessary. */ + if (off < 0 && endian != BYTE_ORDER) + swapdisklabel(dlp); + } else { + *lp = *dlp; + /* Recalc magic on foreign labels */ + if (endian != BYTE_ORDER) { + lp->d_checksum = 0; + lp->d_checksum = dkcksum(lp); + } + msg = NULL; + break; + } + } if (off >= 0) break; @@ -177,23 +268,25 @@ readdisklabel(dev, strat, lp, osdep) case DLT_ALPHA: #if defined(DISKLABEL_ALPHA) || defined(DISKLABEL_ALL) msg = readbsdlabel(bp, strat, 0, ALPHA_LABELSECTOR, - ALPHA_LABELOFFSET, lp); - if (msg == NULL) - lp->d_spare[4] = ALPHA_LABELSECTOR; /* XXX */ + ALPHA_LABELOFFSET, LITTLE_ENDIAN, lp); #endif break; case DLT_I386: #if defined(DISKLABEL_I386) || defined(DISKLABEL_ALL) msg = readdoslabel(bp, strat, lp, osdep); - if (msg == NULL) - lp->d_spare[4] = bp->b_blkno; /* XXX */ - else + if (msg) /* Fallback alternative */ fallbacklabel = *lp; #endif break; + case DLT_AMIGA: +#if defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) + msg = readamigalabel(bp, strat, lp, osdep); +#endif + break; + default: panic("unrecognized disklabel tag %d", *tp); } @@ -201,6 +294,12 @@ readdisklabel(dev, strat, lp, osdep) *lp = minilabel; } + /* Record metainformation about the disklabel. */ + if (msg == NULL) { + osdep->labelsector = bp->b_blkno; + osdep->labeltag = *tp; + } + #if defined(CD9660) if (msg && iso_disklabelspoof(dev, strat, lp) == 0) msg = NULL; @@ -233,8 +332,8 @@ readdoslabel(bp, strat, lp, osdep) struct disklabel *lp; struct cpu_disklabel *osdep; { - struct dos_partition *dp = osdep->dosparts, *dp2; - struct dkbad *db, *bdp = &osdep->bad; + struct dos_partition *dp = osdep->u._i386.dosparts, *dp2; + struct dkbad *db, *bdp = &DKBAD(osdep); char *msg = NULL, *cp; int dospartoff, cyl, i, ourpart = -1; dev_t dev; @@ -368,7 +467,7 @@ donot: /* next, dig out disk label */ msg = readbsdlabel(bp, strat, cyl, dospartoff + I386_LABELSECTOR, -1, - lp); + LITTLE_ENDIAN, lp); if (msg) return (msg); @@ -420,6 +519,25 @@ donot: } #endif +#if defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) +/* + * XXX RDB parsing is missing still. + */ +char * +readamigalabel(bp, strat, lp, osdep) + struct buf *bp; + void (*strat) __P((struct buf *)); + struct disklabel *lp; + struct cpu_disklabel *osdep; +{ + char *msg; + + msg = readbsdlabel(bp, strat, 0, AMIGA_LABELSECTOR, AMIGA_LABELOFFSET, + BIG_ENDIAN, lp); + return (msg); +} +#endif + /* * Check new disk label for sensibility * before setting it. @@ -487,7 +605,6 @@ setdisklabel(olp, nlp, openmask, osdep) /* * Write disk label back to device after modification. - * XXX cannot handle OpenBSD partitions in extended partitions! */ int writedisklabel(dev, strat, lp, osdep) @@ -503,21 +620,28 @@ writedisklabel(dev, strat, lp, osdep) #if defined(DISKLABEL_I386) || defined(DISKLABEL_ALL) struct cpu_disklabel cdl; #endif - int labeloffset, error, i; + int labeloffset, error, i, endian; u_int64_t csum, *p; /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; + /* + * I once played with the thought of using osdep->label{tag,sector} + * as a cache for knowing where (and what) to write. However, now I + * think it might be useful to reprobe if someone has written + * a newer disklabel of another type with disklabel(8) and -r. + */ for (tp = probe_order; msg && *tp != -1; tp++) { dl = *lp; switch (*tp) { case DLT_ALPHA: #if defined(DISKLABEL_ALPHA) || defined(DISKLABEL_ALL) msg = readbsdlabel(bp, strat, 0, ALPHA_LABELSECTOR, - ALPHA_LABELOFFSET, &dl); + ALPHA_LABELOFFSET, LITTLE_ENDIAN, &dl); labeloffset = ALPHA_LABELOFFSET; + endian = LITTLE_ENDIAN; #endif break; @@ -525,6 +649,15 @@ writedisklabel(dev, strat, lp, osdep) #if defined(DISKLABEL_I386) || defined(DISKLABEL_ALL) msg = readdoslabel(bp, strat, &dl, &cdl); labeloffset = I386_LABELOFFSET; + endian = LITTLE_ENDIAN; +#endif + break; + + case DLT_AMIGA: +#if defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) + msg = readamigalabel(bp, strat, &dl, &cdl); + labeloffset = AMIGA_LABELOFFSET; + endian = BIG_ENDIAN; #endif break; @@ -538,6 +671,13 @@ writedisklabel(dev, strat, lp, osdep) goto done; } + if (endian != BYTE_ORDER) { + swapdisklabel(lp); + /* recalc checksum */ + lp->d_checksum = 0; + lp->d_checksum = dkcksum(lp); + } + *(struct disklabel *)(bp->b_data + labeloffset) = *lp; /* Alpha bootblocks are checksummed. */ @@ -563,15 +703,16 @@ done: * if needed, and signal errors or early completion. */ int -bounds_check_with_label(bp, lp, wlabel) +bounds_check_with_label(bp, lp, osdep, wlabel) struct buf *bp; struct disklabel *lp; + struct cpu_disklabel *osdep; int wlabel; { #define blockpersec(count, lp) ((count) * (((lp)->d_secsize) / DEV_BSIZE)) struct partition *p = lp->d_partitions + DISKPART(bp->b_dev); - int labelsector = blockpersec(lp->d_partitions[RAW_PART].p_offset, lp) + - lp->d_spare[4]; /* XXX */ + int labelsector = blockpersec(lp->d_partitions[RAW_PART].p_offset, + lp) + osdep->labelsector; int sz = howmany(bp->b_bcount, DEV_BSIZE); if (bp->b_blkno + sz > blockpersec(p->p_size, lp)) { diff --git a/sys/arch/alpha/include/disklabel.h b/sys/arch/alpha/include/disklabel.h index c34a28db2a1..64037920c19 100644 --- a/sys/arch/alpha/include/disklabel.h +++ b/sys/arch/alpha/include/disklabel.h @@ -1,4 +1,4 @@ -/* $OpenBSD: disklabel.h,v 1.5 1997/06/30 11:50:58 niklas Exp $ */ +/* $OpenBSD: disklabel.h,v 1.6 1997/08/08 22:01:09 niklas Exp $ */ /* $NetBSD: disklabel.h,v 1.1 1995/02/13 23:07:34 cgd Exp $ */ /* @@ -34,19 +34,21 @@ #ifndef _MACHINE_DISKLABEL_H_ #define _MACHINE_DISKLABEL_H_ -enum disklabel_tag { DLT_ALPHA, DLT_I386 }; +enum disklabel_tag { DLT_ALPHA, DLT_I386, DLT_AMIGA }; /* * What disklabels are we probing for, and in which order? */ #ifndef LABELPROBES -#define LABELPROBES DLT_ALPHA, DLT_I386 +#define LABELPROBES DLT_ALPHA, DLT_I386, DLT_AMIGA #endif #define ALPHA_LABELSECTOR 0 /* sector containing label */ #define ALPHA_LABELOFFSET 64 /* offset of label in sector */ #define I386_LABELSECTOR 1 /* sector containing label */ #define I386_LABELOFFSET 0 /* offset of label in sector */ +#define AMIGA_LABELSECTOR 0 /* sector containing label */ +#define AMIGA_LABELOFFSET 64 /* offset of label in sector */ #define LABELSECTOR ALPHA_LABELSECTOR #define LABELOFFSET ALPHA_LABELOFFSET @@ -85,19 +87,188 @@ struct dos_partition { #define DOSPTYP_NETBSD DOSPTYP_386BSD /* NetBSD partition type (XXX) */ #define DOSPTYP_OPENBSD 0xa6 /* OpenBSD partition type */ -#include <sys/dkbad.h> -struct cpu_disklabel { - struct dos_partition dosparts[NDOSPART]; - struct dkbad bad; -}; - /* Isolate the relevant bits to get sector and cylinder. */ #define DPSECT(s) ((s) & 0x3f) #define DPCYL(c, s) ((c) + (((s) & 0xc0) << 2)) -#ifdef _KERNEL -struct disklabel; -int bounds_check_with_label __P((struct buf *, struct disklabel *, int)); +/* + * describes ados Rigid Disk Blocks + * which are used to partition a drive + */ +#define RDBNULL ((u_int32_t)0xffffffff) + +/* + * you will find rdblock somewhere in [0, RDBMAXBLOCKS) + */ +#define RDB_MAXBLOCKS 16 + +struct rdblock { + u_int32_t id; /* 'RDSK' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t nbytes; /* size of disk blocks */ + u_int32_t flags; + u_int32_t badbhead; /* linked list of badblocks */ + u_int32_t partbhead; /* linked list of partblocks */ + u_int32_t fsbhead; /* " " of fsblocks */ + u_int32_t driveinit; + u_int32_t resv1[6]; /* RDBNULL */ + u_int32_t ncylinders; /* number of cylinders on drive */ + u_int32_t nsectors; /* number of sectors per track */ + u_int32_t nheads; /* number of tracks per cylinder */ + u_int32_t interleave; + u_int32_t park; /* only used with st506 i.e. not */ + u_int32_t resv2[3]; + u_int32_t wprecomp; /* start cyl for write precomp */ + u_int32_t reducedwrite; /* start cyl for reduced write current */ + u_int32_t steprate; /* driver step rate in ?s */ + u_int32_t resv3[5]; + u_int32_t rdblowb; /* lowblock of range for rdb's */ + u_int32_t rdbhighb; /* high block of range for rdb's */ + u_int32_t lowcyl; /* low cylinder of partition area */ + u_int32_t highcyl; /* upper cylinder of partition area */ + u_int32_t secpercyl; /* number of sectors per cylinder */ + u_int32_t parkseconds; /* zero if no park needed */ + u_int32_t resv4[2]; + char diskvendor[8]; /* inquiry stuff */ + char diskproduct[16]; /* inquiry stuff */ + char diskrevision[4]; /* inquiry stuff */ + char contvendor[8]; /* inquiry stuff */ + char contproduct[16]; /* inquiry stuff */ + char contrevision[4]; /* inquiry stuff */ +#if never_use_secsize + u_int32_t resv5[0]; +#endif +}; + + +#define RDBF_LAST 0x1 /* last drive available */ +#define RDBF_LASTLUN 0x2 /* last LUN available */ +#define RDBF_LASTUNIT 0x4 /* last target available */ +#define RDBF_NORESELECT 0x8 /* do not use reselect */ +#define RDBF_DISKID 0x10 /* disk id is valid ?? */ +#define RDBF_CTRLID 0x20 /* ctrl id is valid ?? */ +#define RDBF_SYNC 0x40 /* drive supports SCSI synchronous mode */ + +struct ados_environ { + u_int32_t tabsize; /* 0: environ table size */ + u_int32_t sizeblock; /* 1: n long words in a block */ + u_int32_t secorg; /* 2: not used must be zero */ + u_int32_t numheads; /* 3: number of surfaces */ + u_int32_t secperblk; /* 4: must be 1 */ + u_int32_t secpertrk; /* 5: blocks per track */ + u_int32_t resvblocks; /* 6: reserved blocks at start */ + u_int32_t prefac; /* 7: must be 0 */ + u_int32_t interleave; /* 8: normally 1 */ + u_int32_t lowcyl; /* 9: low cylinder of partition */ + u_int32_t highcyl; /* 10: upper cylinder of partition */ + u_int32_t numbufs; /* 11: ados: number of buffers */ + u_int32_t membuftype; /* 12: ados: type of bufmem */ + u_int32_t maxtrans; /* 13: maxtrans the ctrlr supports */ + u_int32_t mask; /* 14: mask for valid address */ + u_int32_t bootpri; /* 15: boot priority for autoboot */ + u_int32_t dostype; /* 16: filesystem type */ + u_int32_t baud; /* 17: serial handler baud rate */ + u_int32_t control; /* 18: control word for fs */ + u_int32_t bootblocks; /* 19: blocks containing boot code */ + u_int32_t fsize; /* 20: file system block size */ + u_int32_t frag; /* 21: allowable frags per block */ + u_int32_t cpg; /* 22: cylinders per group */ +}; + +struct partblock { + u_int32_t id; /* 'PART' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t next; /* next in chain */ + u_int32_t flags; /* see below */ + u_int32_t resv1[3]; + u_char partname[32]; /* (BCPL) part name (may not be unique) */ + u_int32_t resv2[15]; + struct ados_environ e; +#if never_use_secsize + u_int32_t extra[9]; /* 8 for extra added to environ */ #endif +}; + +#define PBF_BOOTABLE 0x1 /* partition is bootable */ +#define PBF_NOMOUNT 0x2 /* partition should be mounted */ + +struct badblock { + u_int32_t id; /* 'BADB' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t next; /* next in chain */ + u_int32_t resv; + struct badblockent { + u_int32_t badblock; + u_int32_t goodblock; + } badtab[0]; /* 61 for secsize == 512 */ +}; + +struct fsblock { + u_int32_t id; /* 'FSHD' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t next; /* next in chain */ + u_int32_t flags; + u_int32_t resv1[2]; + u_int32_t dostype; /* this is a file system for this type */ + u_int32_t version; /* version of this fs */ + u_int32_t patchflags; /* describes which functions to replace */ + u_int32_t type; /* zero */ + u_int32_t task; /* zero */ + u_int32_t lock; /* zero */ + u_int32_t handler; /* zero */ + u_int32_t stacksize; /* to use when loading handler */ + u_int32_t priority; /* to run the fs at. */ + u_int32_t startup; /* zero */ + u_int32_t lsegblocks; /* linked list of lsegblocks of fs code */ + u_int32_t globalvec; /* bcpl vector not used mostly */ +#if never_use_secsize + u_int32_t resv2[44]; +#endif +}; + +struct lsegblock { + u_int32_t id; /* 'LSEG' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t next; /* next in chain */ + u_int32_t loaddata[0]; /* load segment data, 123 for secsize == 512 */ +}; + +#define RDBLOCK_ID 0x5244534b /* 'RDSK' */ +#define PARTBLOCK_ID 0x50415254 /* 'PART' */ +#define BADBLOCK_ID 0x42414442 /* 'BADB' */ +#define FSBLOCK_ID 0x46534844 /* 'FSHD' */ +#define LSEGBLOCK_ID 0x4c534547 /* 'LSEG' */ + +#include <sys/dkbad.h> +struct cpu_disklabel { + enum disklabel_tag labeltag; + int labelsector; + union { + struct { + } _alpha; + struct { + struct dos_partition dosparts[NDOSPART]; + struct dkbad bad; + } _i386; + struct { + u_int32_t rdblock; /* RDBNULL -> inval. */ + u_int32_t pblist[MAXPARTITIONS];/* pblock number */ + int pbindex[MAXPARTITIONS]; /* index of pblock */ + int valid; /* valid? */ + } _amiga; + } u; +}; + +#define DKBAD(x) ((x)->u._i386.bad) #endif /* _MACHINE_DISKLABEL_H_ */ |