@samitouri / QOSamiQemu / commits / 9943d6244a

hw/nvram/fw_cfg: Enforce standard layout for x86 fw_cfg I/O ports

The fw_cfg_init_io_dma() function allows the caller to specify the base port number of the selector/data register and the base port number of the DMA address register separately. No caller actually uses this: they all pass in base + 4 for the dma_iobase. To reduce the risk of unnecessary variation in what different x86 machine types use as their fw_cfg register layout, remove the dma_iobase argument from fw_cfg_init_io_dma(), and have the function always use the same "DMA port is base port + 4" layout. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@mailo.com> Message-id: 20260529174639.451353-4-peter.maydell@linaro.org Reviewed-by: Michael S. Tsirkin <mst@redhat.com>

Peter Maydell committed May 29, 2026 at 18:46 UTC 9943d6244a9348df5363f1a41c1afb073d477e53
5 files changed +22 -12
hw/i386/fw_cfg.c
+1 -2
@@ -127,8 +127,7 @@ FWCfgState *fw_cfg_arch_create(MachineState *ms,
127 const CPUArchIdList *cpus = mc->possible_cpu_arch_ids(ms);
128 int nb_numa_nodes = ms->numa_state->num_nodes;
129
130 - fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4,
131 - &address_space_memory);
130 + fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, &address_space_memory);
131 fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, boot_cpus);
132
133 /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
hw/i386/microvm.c
+1 -2
@@ -320,8 +320,7 @@ static void microvm_memory_init(MicrovmMachineState *mms)
320 e820_add_entry(0x100000000ULL, x86ms->above_4g_mem_size, E820_RAM);
321 }
322
323 - fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4,
324 - &address_space_memory);
323 + fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, &address_space_memory);
324
325 fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, machine->smp.cpus);
326 fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, machine->smp.max_cpus);
hw/i386/pc.c
+1 -2
@@ -568,8 +568,7 @@ void xen_load_linux(PCMachineState *pcms)
568
569 assert(MACHINE(pcms)->kernel_filename != NULL);
570
571 - fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4,
572 - &address_space_memory);
571 + fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, &address_space_memory);
572 fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
573 rom_set_fw(fw_cfg);
574
hw/nvram/fw_cfg.c
+4 -4
@@ -1019,15 +1019,14 @@ static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
1019 qemu_add_machine_init_done_notifier(&s->machine_ready);
1020 }
1021
1022 -FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
1023 - AddressSpace *dma_as)
1022 +FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, AddressSpace *dma_as)
1023 {
1024 DeviceState *dev;
1025 SysBusDevice *sbd;
1026 FWCfgIoState *ios;
1027 FWCfgState *s;
1028 MemoryRegion *iomem = get_system_io();
1030 - bool dma_requested = dma_iobase && dma_as;
1029 + bool dma_requested = dma_as;
1030
1031 dev = qdev_new(TYPE_FW_CFG_IO);
1032 if (!dma_requested) {
@@ -1048,7 +1047,8 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
1047 /* 64 bits for the address field */
1048 s->dma_as = dma_as;
1049 s->dma_addr = 0;
1051 - memory_region_add_subregion(iomem, dma_iobase, &s->dma_iomem);
1050 + /* DMA register ioport is always at base + 4 */
1051 + memory_region_add_subregion(iomem, iobase + 4, &s->dma_iomem);
1052 }
1053
1054 return s;
include/hw/nvram/fw_cfg.h
+15 -2
@@ -305,8 +305,21 @@ bool fw_cfg_add_file_from_generator(FWCfgState *s,
305 Object *parent, const char *part,
306 const char *filename, Error **errp);
307
308 -FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
309 - AddressSpace *dma_as);
308 +/**
309 + * fw_cfg_init_io_dma:
310 + * @iobase: x86 port number which is the base of the fw_cfg port range
311 + * @dma_as: the device will do DMA to/from this AddressSpace
312 + *
313 + * Create a fw_cfg device and map it into the specified I/O port range.
314 + *
315 + * This creates a device with the x86 PC standard port I/O layout:
316 + * - Selector Register IOport: @iobase
317 + * - Data Register IOport: @iobase + 1
318 + * - DMA Address IOport: @iobase + 4
319 + *
320 + * Returns the device object.
321 + */
322 +FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, AddressSpace *dma_as);
323 FWCfgState *fw_cfg_init_mem_nodma(hwaddr ctl_addr, hwaddr data_addr,
324 unsigned data_width);
325 /**