summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@FreeBSD.org>2017-05-04 05:26:37 +0000
committerToomas Soome <tsoome@FreeBSD.org>2017-05-04 05:26:37 +0000
commitf6bd3d520f078d20e0ed562aaaece3bc89c2058c (patch)
tree593eaebe2f38a7b5a7980fb39cd4d713ce9f7874
parent8066a14a3c412e1a7d9e3816fa3500cc51fa5937 (diff)
Notes
-rw-r--r--sys/boot/i386/zfsboot/zfsboot.c56
1 files changed, 54 insertions, 2 deletions
diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c
index e76e58fc80e7..88b5231efe45 100644
--- a/sys/boot/i386/zfsboot/zfsboot.c
+++ b/sys/boot/i386/zfsboot/zfsboot.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include "lib.h"
#include "rbx.h"
#include "drv.h"
+#include "edd.h"
#include "util.h"
#include "cons.h"
#include "bootargs.h"
@@ -125,6 +126,7 @@ static int parse_cmd(void);
static void bios_getmem(void);
void *malloc(size_t n);
void free(void *ptr);
+int main(void);
void *
malloc(size_t n)
@@ -469,6 +471,56 @@ copy_dsk(struct dsk *dsk)
}
/*
+ * Get disk size from eax=0x800 and 0x4800. We need to probe both
+ * because 0x4800 may not be available and we would like to get more
+ * or less correct disk size - if it is possible at all.
+ * Note we do not really want to touch drv.c because that code is shared
+ * with boot2 and we can not afford to grow that code.
+ */
+static uint64_t
+drvsize_ext(struct dsk *dskp)
+{
+ uint64_t size, tmp;
+ int cyl, hds, sec;
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x800;
+ v86.edx = dskp->drive;
+ v86int();
+
+ /* Don't error out if we get bad sector number, try EDD as well */
+ if (V86_CY(v86.efl) || /* carry set */
+ (v86.edx & 0xff) <= (unsigned)(dskp->drive & 0x7f)) /* unit # bad */
+ return (0);
+
+ cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
+ /* Convert max head # -> # of heads */
+ hds = ((v86.edx & 0xff00) >> 8) + 1;
+ sec = v86.ecx & 0x3f;
+
+ size = (uint64_t)cyl * hds * sec;
+
+ /* Determine if we can use EDD with this device. */
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x4100;
+ v86.edx = dskp->drive;
+ v86.ebx = 0x55aa;
+ v86int();
+ if (V86_CY(v86.efl) || /* carry set */
+ (v86.ebx & 0xffff) != 0xaa55 || /* signature */
+ (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
+ return (size);
+
+ tmp = drvsize(dskp);
+ if (tmp > size)
+ size = tmp;
+
+ return (size);
+}
+
+/*
* The "layered" ioctl to read disk/partition size. Unfortunately
* the zfsboot case is hardest, because we do not have full software
* stack available, so we need to do some manual work here.
@@ -480,7 +532,7 @@ ldi_get_size(void *priv)
uint64_t size = dskp->size;
if (dskp->start == 0)
- size = drvsize(dskp);
+ size = drvsize_ext(dskp);
return (size * DEV_BSIZE);
}
@@ -515,7 +567,7 @@ probe_drive(struct dsk *dsk)
* out the partition table and probe each slice/partition
* in turn for a vdev or GELI encrypted vdev.
*/
- elba = drvsize(dsk);
+ elba = drvsize_ext(dsk);
if (elba > 0) {
elba--;
}