Commit ba4a996631 for qemu.org
commit ba4a996631cd3882246e0892e805d398a63e9b09
Author: Denis V. Lunev <den@openvz.org>
Date: Tue Aug 4 18:34:44 2026 +0200
hw/ide: migrate the logical CHS translation
INITIALIZE DEVICE PARAMETERS lets a guest replace the logical CHS
translation used to turn the CHS registers into an LBA, but s->heads and
s->sectors were in no VMStateDescription. The destination rebuilt them
from the drive configuration, so a guest that had selected one of its own
kept addressing the disk in it while the device translated with the
default, landing on sectors nobody asked for.
Add a subsection for it, sent only when the guest replaced the default, so
that migration to an older QEMU keeps working for every other guest.
s->cylinders is left out, as no command changes it.
Validate what is loaded in the existing post_load: ide_get_sector()
multiplies by these fields and ide_set_sector() divides by them.
Cc: John Snow <jsnow@redhat.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Fixes: 176e4961bb33 ("hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command")
Signed-off-by: Denis V. Lunev <den@openvz.org>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 28219f5ef8..b074325afa 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -2879,6 +2879,13 @@ static int ide_drive_post_load(void *opaque, int version_id)
{
IDEState *s = opaque;
+ /* Only a disk has a translation; an empty slot and ATAPI keep these zero */
+ if (s->blk && s->drive_kind != IDE_CD &&
+ (s->heads < 1 || s->heads > 16 ||
+ s->sectors < 1 || s->sectors > 255)) {
+ return -EINVAL;
+ }
+
if (s->blk && s->identify_set) {
blk_set_enable_write_cache(s->blk, !!(s->identify_data[85] & (1 << 5)));
}
@@ -2962,6 +2969,25 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = {
}
};
+static bool ide_chs_translation_needed(void *opaque)
+{
+ IDEState *s = opaque;
+
+ return s->heads != s->drive_heads || s->sectors != s->drive_sectors;
+}
+
+static const VMStateDescription vmstate_ide_drive_chs_translation = {
+ .name = "ide_drive/chs_translation",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = ide_chs_translation_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_INT32(heads, IDEState),
+ VMSTATE_INT32(sectors, IDEState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_ide_tray_state = {
.name = "ide_drive/tray_state",
.version_id = 1,
@@ -3025,6 +3051,7 @@ const VMStateDescription vmstate_ide_drive = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_ide_drive_pio_state,
+ &vmstate_ide_drive_chs_translation,
&vmstate_ide_tray_state,
&vmstate_ide_atapi_gesn_state,
NULL