Read bios geometry for boot devices from fw_cfg.
By receiving LCHS values directly from QEMU through fw_cfg we will be able to support logical geometries which can not be inferred by SeaBIOS itself. (For instance: A 8GB virtio-blk hard drive which was originally created as an IDE and must report LCHS of */32/63 for its operating system to function will always break under SeaBIOS since a LARGE/LBA translation will be used, causing the number of reported logical heads to be > 32.)
The only LCHS paravirtual interface available at the moment is for IDE disks (rtc_read() in get_translation()) and it's limited to a maximum of 4 disks (this code existed in SeaBIOS's translation function before SCSI and VirtIO were even introduced). This is why we create a new interface which allows passing LCHS information per hdd.
Boot device information is serialized in the following way: * device_path lcyls lheads lsecs\n ... * device_path lcyls lheads lsecs\0
Device path is a null terminated string in the "Open Firmware" device path format, the same path as used in bootorder.
Reviewed-by: Karl Heubaum karl.heubaum@oracle.com Reviewed-by: Arbel Moshe arbel.moshe@oracle.com Signed-off-by: Sam Eiderman shmuel.eiderman@oracle.com --- src/boot.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+)
diff --git a/src/boot.c b/src/boot.c index 5acf94fe..a2cb167c 100644 --- a/src/boot.c +++ b/src/boot.c @@ -24,6 +24,79 @@
/**************************************************************** + * Boot device logical geometry + ****************************************************************/ + +typedef struct BootDeviceLCHS { + char *name; + u32 lcyls; + u32 lheads; + u32 lsecs; +} BootDeviceLCHS; + +static BootDeviceLCHS *BiosGeometry VARVERIFY32INIT; +static int BiosGeometryCount; + +static char * +parse_u32(char *cur, u32 *n) +{ + u32 m = 0; + if (cur) { + while ('0' <= *cur && *cur <= '9') { + m = 10 * m + (*cur - '0'); + cur++; + } + if (*cur != '\0') + cur++; + } + *n = m; + return cur; +} + +static void +loadBiosGeometry(void) +{ + char *f = romfile_loadfile("bios-geometry", NULL); + if (!f) + return; + + int i = 0; + BiosGeometryCount = 1; + while (f[i]) { + if (f[i] == '\n') + BiosGeometryCount++; + i++; + } + BiosGeometry = malloc_tmphigh(BiosGeometryCount * sizeof(BootDeviceLCHS)); + if (!BiosGeometry) { + warn_noalloc(); + free(f); + BiosGeometryCount = 0; + return; + } + + dprintf(1, "bios geometry:\n"); + i = 0; + do { + BootDeviceLCHS *d = &BiosGeometry[i]; + d->name = f; + f = strchr(f, '\n'); + if (f) + *(f++) = '\0'; + char *chs_values = strchr(d->name, ' '); + if (chs_values) + *(chs_values++) = '\0'; + chs_values = parse_u32(chs_values, &d->lcyls); + chs_values = parse_u32(chs_values, &d->lheads); + chs_values = parse_u32(chs_values, &d->lsecs); + dprintf(1, "%s: (%u, %u, %u)\n", + d->name, d->lcyls, d->lheads, d->lsecs); + i++; + } while (f); +} + + +/**************************************************************** * Boot priority ordering ****************************************************************/
@@ -288,6 +361,7 @@ boot_init(void) BootRetryTime = romfile_loadint("etc/boot-fail-wait", 60*1000);
loadBootOrder(); + loadBiosGeometry(); }