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 (sz string) * device lchs ... * device path (sz string) * device lchs
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 | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+)
diff --git a/src/boot.c b/src/boot.c index 5acf94fe..b4382041 100644 --- a/src/boot.c +++ b/src/boot.c @@ -24,6 +24,84 @@
/**************************************************************** + * Boot device logical geometry + ****************************************************************/ + +typedef struct BootDeviceLCHSSerialized { + u32 lcyls; + u32 lheads; + u32 lsecs; +} PACKED BootDeviceLCHSSerialized; + +typedef struct BootDeviceLCHS { + char *name; + u32 lcyls; + u32 lheads; + u32 lsecs; +} BootDeviceLCHS; + +static BootDeviceLCHS *BiosGeometry VARVERIFY32INIT; +static int BiosGeometryCount; + +static void +loadBiosGeometry(void) +{ + BiosGeometryCount = 0; + int fsize; + char *f = romfile_loadfile("bios-geometry", &fsize); + if (!f) + return; + + u32 struct_size = sizeof(BootDeviceLCHSSerialized); + + int i; + int str_found = 0; + + for (i = 0; i < fsize; i++) { + if (f[i] != '\0') + str_found = 1; + else if (f[i] == '\0' && str_found) { + str_found = 0; + i++; + if (i + struct_size > fsize) + break; + i += struct_size - 1; + BiosGeometryCount++; + } else + break; + } + + BiosGeometry = malloc_tmphigh(BiosGeometryCount * sizeof(BootDeviceLCHS)); + if (!BiosGeometry) { + warn_noalloc(); + free(f); + BiosGeometryCount = 0; + return; + } + + dprintf(1, "bios geometry:\n"); + + BootDeviceLCHSSerialized *blk; + BootDeviceLCHS *d; + + for (i = 0; i < BiosGeometryCount; i++) { + d = &BiosGeometry[i]; + d->name = f; + f += strlen(f) + 1; + + blk = (BootDeviceLCHSSerialized *)f; + d->lcyls = blk->lcyls; + d->lheads = blk->lheads; + d->lsecs = blk->lsecs; + f += struct_size; + + dprintf(1, "%s: (%u, %u, %u)\n", + d->name, d->lcyls, d->lheads, d->lsecs); + } +} + + +/**************************************************************** * Boot priority ordering ****************************************************************/
@@ -288,6 +366,7 @@ boot_init(void) BootRetryTime = romfile_loadint("etc/boot-fail-wait", 60*1000);
loadBootOrder(); + loadBiosGeometry(); }