diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2011-03-14 22:14:41 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2011-03-14 22:14:41 +0000 |
commit | 69b33539c4420ab485161d9744ad57280e229fa7 (patch) | |
tree | b5502d3403d4ba32abc4a364e1499192a6ec4d5b /sys/arch/amd64 | |
parent | 26cdeae19d2eaec023adb36e2b08a132e413779b (diff) |
Clamp BIOS io attempts to < 2 ^28 - 1 sectors (a.k.a. 128GB for
512-byte sectors) as some BIOSen get confused when we ask for sectors
higher up.
Uss u_int throughout the boot code to calculate sector addresses,
since 32 bits is enough to do 28 ^ 1 - 1 arithmetic. Add checks
for wraparound.
I can now install and boot from the 7th extended partition below
128GB.
Much feedback & guidance from deraadt@. Also from weingart@ on
BIOS io.
ok deraadt@ (less a couple of minor tweaks found in testing)
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r-- | sys/arch/amd64/include/biosvar.h | 3 | ||||
-rw-r--r-- | sys/arch/amd64/stand/installboot/installboot.c | 50 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/biosdev.c | 52 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/biosdev.h | 4 |
4 files changed, 61 insertions, 48 deletions
diff --git a/sys/arch/amd64/include/biosvar.h b/sys/arch/amd64/include/biosvar.h index ba13e9fafa5..0abc8c2b4f8 100644 --- a/sys/arch/amd64/include/biosvar.h +++ b/sys/arch/amd64/include/biosvar.h @@ -1,5 +1,5 @@ /* XXX - DSR */ -/* $OpenBSD: biosvar.h,v 1.11 2010/11/22 21:07:18 miod Exp $ */ +/* $OpenBSD: biosvar.h,v 1.12 2011/03/14 22:14:40 krw Exp $ */ /* * Copyright (c) 1997-1999 Michael Shalayeff @@ -36,6 +36,7 @@ #define BOOTARG_OFF (NBPG*2) #define BOOTARG_LEN (NBPG*1) #define BOOTBIOS_ADDR (0x7c00) +#define BOOTBIOS_MAXSEC ((1 << 28) - 1) /* BIOS configure flags */ #define BIOSF_BIOS32 0x0001 diff --git a/sys/arch/amd64/stand/installboot/installboot.c b/sys/arch/amd64/stand/installboot/installboot.c index 75142e8bd90..0f736b85d37 100644 --- a/sys/arch/amd64/stand/installboot/installboot.c +++ b/sys/arch/amd64/stand/installboot/installboot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: installboot.c,v 1.15 2011/03/13 00:13:52 deraadt Exp $ */ +/* $OpenBSD: installboot.c,v 1.16 2011/03/14 22:14:40 krw Exp $ */ /* $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */ /* @@ -107,14 +107,14 @@ static void devread(int, void *, daddr64_t, size_t, char *); static void sym_set_value(struct sym_data *, char *, u_int32_t); static void pbr_set_symbols(char *, char *, struct sym_data *); static void usage(void); -static daddr64_t findopenbsd(int, struct disklabel *, daddr64_t, int *); +static u_int findopenbsd(int, struct disklabel *, u_int, int *); static void write_bootblocks(int devfd, struct disklabel *); static int sr_volume(int, int *, int *); static void sr_installboot(int); static void sr_installpbr(int, int, int); -static daddr64_t mbr_eoff; /* Offset of the MBR extended partition. */ +static u_int mbr_eoff; /* Offset of the MBR extended partition. */ static void usage(void) @@ -217,7 +217,7 @@ void write_bootblocks(int devfd, struct disklabel *dl) { struct stat sb; - daddr64_t start = 0; + u_int start = 0; int n = 8; /* Write patched proto bootblock(s) into the superblock. */ @@ -238,15 +238,14 @@ write_bootblocks(int devfd, struct disklabel *dl) if (dl->d_type != 0 && dl->d_type != DTYPE_FLOPPY && dl->d_type != DTYPE_VND) { /* Find OpenBSD partition. */ - mbr_eoff = 0; /* Offset of MBR extended partition. */ - start = findopenbsd(devfd, dl, (daddr64_t)DOSBBSECTOR, &n); - if (start == -1) + mbr_eoff = DOSBBSECTOR; /* Offset of MBR extended partition. */ + start = findopenbsd(devfd, dl, DOSBBSECTOR, &n); + if (start == (u_int)-1) errx(1, "no OpenBSD partition"); } if (verbose) - fprintf(stderr, "/boot will be written at sector %lld\n", - (long long)start); + fprintf(stderr, "/boot will be written at sector %u\n", start); if (!nowrite) { if (lseek(devfd, (off_t)start * dl->d_secsize, SEEK_SET) < 0 || @@ -255,12 +254,12 @@ write_bootblocks(int devfd, struct disklabel *dl) } } -daddr64_t -findopenbsd(int devfd, struct disklabel *dl, daddr64_t mbroff, int *n) +u_int +findopenbsd(int devfd, struct disklabel *dl, u_int mbroff, int *n) { struct dos_mbr mbr; struct dos_partition *dp; - daddr64_t start = -1; + u_int start = (u_int)-1; int i; /* Limit the number of recursions */ @@ -268,18 +267,17 @@ findopenbsd(int devfd, struct disklabel *dl, daddr64_t mbroff, int *n) return (-1); if (verbose) - fprintf(stderr, "%s boot record (%cBR) at sector %lld\n", - (mbroff == (off_t)DOSBBSECTOR) ? "master" : "extended", - (mbroff == (off_t)DOSBBSECTOR) ? 'M' : 'E', - (long long)mbroff); + fprintf(stderr, "%s boot record (%cBR) at sector %u\n", + (mbroff == DOSBBSECTOR) ? "master" : "extended", + (mbroff == DOSBBSECTOR) ? 'M' : 'E', mbroff); if (lseek(devfd, (off_t)mbroff * dl->d_secsize, SEEK_SET) < 0 || read(devfd, &mbr, sizeof(mbr)) != sizeof(mbr)) err(4, "can't read boot record"); if (mbr.dmbr_sign != DOSMBR_SIGNATURE) - errx(1, "invalid boot record signature (0x%04X)", - mbr.dmbr_sign); + errx(1, "invalid boot record signature (0x%04X) @ sector %u", + mbr.dmbr_sign, mbroff); for (i = 0; i < NDOSPART; i++) { dp = &mbr.dmbr_parts[i]; @@ -288,21 +286,25 @@ findopenbsd(int devfd, struct disklabel *dl, daddr64_t mbroff, int *n) if (verbose) fprintf(stderr, - "\tpartition %d: type 0x%02X offset %d size %d\n", + "\tpartition %d: type 0x%02X offset %u size %u\n", i, dp->dp_typ, dp->dp_start, dp->dp_size); if (dp->dp_typ == DOSPTYP_OPENBSD) { - start = (daddr64_t)dp->dp_start + mbroff; + if (dp->dp_start > (dp->dp_start + mbroff)) + continue; + start = dp->dp_start + mbroff; break; } if (dp->dp_typ == DOSPTYP_EXTEND || dp->dp_typ == DOSPTYP_EXTENDL) { - mbroff = (daddr64_t)dp->dp_start + mbr_eoff; - if (!mbr_eoff) - mbr_eoff = (daddr64_t)dp->dp_start; + mbroff = dp->dp_start + mbr_eoff; + if (mbr_eoff == DOSBBSECTOR) + mbr_eoff = dp->dp_start; + if (mbroff < dp->dp_start) + continue; start = findopenbsd(devfd, dl, mbroff, n); - if (start != -1) + if (start != (u_int)-1) break; } } diff --git a/sys/arch/amd64/stand/libsa/biosdev.c b/sys/arch/amd64/stand/libsa/biosdev.c index c44c84da20b..b389d1adc69 100644 --- a/sys/arch/amd64/stand/libsa/biosdev.c +++ b/sys/arch/amd64/stand/libsa/biosdev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: biosdev.c,v 1.12 2011/03/13 00:13:52 deraadt Exp $ */ +/* $OpenBSD: biosdev.c,v 1.13 2011/03/14 22:14:40 krw Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -43,15 +43,14 @@ static const char *biosdisk_err(u_int); static int biosdisk_errno(u_int); int CHS_rw (int, int, int, int, int, int, void *); -static int EDD_rw (int, int, u_int64_t, u_int32_t, void *); +static int EDD_rw (int, int, u_int32_t, u_int32_t, void *); -static daddr64_t findopenbsd(bios_diskinfo_t *, daddr64_t, const char **, - int *); +static u_int findopenbsd(bios_diskinfo_t *, u_int, const char **, int *); extern int debug; int bios_bootdev; int bios_cddev = -1; /* Set by srt0 if coming from CD */ -daddr64_t mbr_eoff; /* Offset of the MBR extended partition. */ +u_int mbr_eoff; /* Offset of MBR extended partition. */ #if 0 struct biosdisk { @@ -211,11 +210,15 @@ CHS_rw(int rw, int dev, int cyl, int head, int sect, int nsect, void *buf) } static __inline int -EDD_rw(int rw, int dev, u_int64_t daddr, u_int32_t nblk, void *buf) +EDD_rw(int rw, int dev, u_int32_t daddr, u_int32_t nblk, void *buf) { int rv; volatile static struct EDD_CB cb; + /* Some (most?) BIOSen get confused by i/o above 2 ^ 28 - 1 sector. */ + if ((daddr + nblk) > BOOTBIOS_MAXSEC) + return (1); /* Invalid function/parameter. */ + /* Zero out reserved stuff */ cb.edd_res1 = 0; cb.edd_res2 = 0; @@ -243,7 +246,7 @@ EDD_rw(int rw, int dev, u_int64_t daddr, u_int32_t nblk, void *buf) * Read given sector, handling retry/errors/etc. */ int -biosd_io(int rw, bios_diskinfo_t *bd, daddr32_t off, int nsect, void *buf) +biosd_io(int rw, bios_diskinfo_t *bd, u_int off, int nsect, void *buf) { int dev = bd->bios_number; int j, error; @@ -343,12 +346,12 @@ biosd_io(int rw, bios_diskinfo_t *bd, daddr32_t off, int nsect, void *buf) /* * Try to read the bsd label on the given BIOS device */ -static daddr64_t -findopenbsd(bios_diskinfo_t *bd, daddr64_t mbroff, const char **err, int *n) +static u_int +findopenbsd(bios_diskinfo_t *bd, u_int mbroff, const char **err, int *n) { struct dos_mbr mbr; struct dos_partition *dp; - daddr64_t start = -1; + u_int start = (u_int)-1; int error, i; /* Limit the number of recursions */ @@ -385,17 +388,21 @@ findopenbsd(bios_diskinfo_t *bd, daddr64_t mbroff, const char **err, int *n) dp->dp_start, dp->dp_start); #endif if (dp->dp_typ == DOSPTYP_OPENBSD) { - start = (daddr64_t)dp->dp_start + mbroff; + if (dp->dp_start > (dp->dp_start + mbroff)) + continue; + start = dp->dp_start + mbroff; break; } if (dp->dp_typ == DOSPTYP_EXTEND || dp->dp_typ == DOSPTYP_EXTENDL) { - mbroff = (daddr64_t)dp->dp_start + mbr_eoff; - if (!mbr_eoff) - mbr_eoff = (daddr64_t)dp->dp_start; + mbroff = dp->dp_start + mbr_eoff; + if (mbr_eoff == DOSBBSECTOR) + mbr_eoff = dp->dp_start; + if (mbroff < dp->dp_start) + continue; start = findopenbsd(bd, mbroff, err, n); - if (start != -1) + if (start != (u_int)-1) break; } } @@ -406,7 +413,7 @@ findopenbsd(bios_diskinfo_t *bd, daddr64_t mbroff, const char **err, int *n) const char * bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label) { - daddr64_t start = 0; + u_int start = 0; char *buf; const char *err = NULL; int error; @@ -419,9 +426,9 @@ bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label) /* MBR is a harddisk thing */ if (bd->bios_number & 0x80) { - mbr_eoff = 0; - start = findopenbsd(bd, (daddr64_t)DOSBBSECTOR, &err, &n); - if (start == -1) { + mbr_eoff = DOSBBSECTOR; + start = findopenbsd(bd, DOSBBSECTOR, &err, &n); + if (start == (u_int)-1) { if (err != NULL) return (err); return "no OpenBSD partition\n"; @@ -436,7 +443,7 @@ bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label) printf("loading disklabel @ %u\n", off); #endif /* read disklabel */ - error = biosd_io(F_READ, bd, (daddr32_t)start, 1, buf); + error = biosd_io(F_READ, bd, start, 1, buf); if(error) return("failed to read disklabel"); @@ -659,7 +666,10 @@ biosstrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf, d_partitions[B_PARTITION(dip->bsddev)].p_offset; /* Read all, sub-functions handle track boundaries */ - error = biosd_io(rw, bd, blk, nsect, buf); + if (blk < 0) + error = EINVAL; + else + error = biosd_io(rw, bd, blk, nsect, buf); #ifdef BIOS_DEBUG if (debug) { diff --git a/sys/arch/amd64/stand/libsa/biosdev.h b/sys/arch/amd64/stand/libsa/biosdev.h index 765ba0d0e59..fc0a0ce69ea 100644 --- a/sys/arch/amd64/stand/libsa/biosdev.h +++ b/sys/arch/amd64/stand/libsa/biosdev.h @@ -1,4 +1,4 @@ -/* $OpenBSD: biosdev.h,v 1.3 2011/03/13 00:13:52 deraadt Exp $ */ +/* $OpenBSD: biosdev.h,v 1.4 2011/03/14 22:14:40 krw Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -49,7 +49,7 @@ int biosopen(struct open_file *, ...); int biosclose(struct open_file *); int biosioctl(struct open_file *, u_long, void *); int bios_getdiskinfo(int, bios_diskinfo_t *); -int biosd_io(int, bios_diskinfo_t *, daddr32_t, int, void *); +int biosd_io(int, bios_diskinfo_t *, u_int, int, void *); const char * bios_getdisklabel(bios_diskinfo_t *, struct disklabel *); /* diskprobe.c */ |