summaryrefslogtreecommitdiff
path: root/sys/arch/amd64
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2011-03-14 22:14:41 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2011-03-14 22:14:41 +0000
commit69b33539c4420ab485161d9744ad57280e229fa7 (patch)
treeb5502d3403d4ba32abc4a364e1499192a6ec4d5b /sys/arch/amd64
parent26cdeae19d2eaec023adb36e2b08a132e413779b (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.h3
-rw-r--r--sys/arch/amd64/stand/installboot/installboot.c50
-rw-r--r--sys/arch/amd64/stand/libsa/biosdev.c52
-rw-r--r--sys/arch/amd64/stand/libsa/biosdev.h4
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 */