@samitouri / QOSamiQemu / commits / ba4a996631

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>

Denis V. Lunev committed Aug 4, 2026 at 18:34 UTC ba4a996631cd3882246e0892e805d398a63e9b09
1 file changed +27
hw/ide/core.c
+27
@@ -2879,6 +2879,13 @@ static int ide_drive_post_load(void *opaque, int version_id)
2879 {
2880 IDEState *s = opaque;
2881
2882 + /* Only a disk has a translation; an empty slot and ATAPI keep these zero */
2883 + if (s->blk && s->drive_kind != IDE_CD &&
2884 + (s->heads < 1 || s->heads > 16 ||
2885 + s->sectors < 1 || s->sectors > 255)) {
2886 + return -EINVAL;
2887 + }
2888 +
2889 if (s->blk && s->identify_set) {
2890 blk_set_enable_write_cache(s->blk, !!(s->identify_data[85] & (1 << 5)));
2891 }
@@ -2962,6 +2969,25 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = {
2969 }
2970 };
2971
2972 +static bool ide_chs_translation_needed(void *opaque)
2973 +{
2974 + IDEState *s = opaque;
2975 +
2976 + return s->heads != s->drive_heads || s->sectors != s->drive_sectors;
2977 +}
2978 +
2979 +static const VMStateDescription vmstate_ide_drive_chs_translation = {
2980 + .name = "ide_drive/chs_translation",
2981 + .version_id = 1,
2982 + .minimum_version_id = 1,
2983 + .needed = ide_chs_translation_needed,
2984 + .fields = (const VMStateField[]) {
2985 + VMSTATE_INT32(heads, IDEState),
2986 + VMSTATE_INT32(sectors, IDEState),
2987 + VMSTATE_END_OF_LIST()
2988 + }
2989 +};
2990 +
2991 static const VMStateDescription vmstate_ide_tray_state = {
2992 .name = "ide_drive/tray_state",
2993 .version_id = 1,
@@ -3025,6 +3051,7 @@ const VMStateDescription vmstate_ide_drive = {
3051 },
3052 .subsections = (const VMStateDescription * const []) {
3053 &vmstate_ide_drive_pio_state,
3054 + &vmstate_ide_drive_chs_translation,
3055 &vmstate_ide_tray_state,
3056 &vmstate_ide_atapi_gesn_state,
3057 NULL