Re: [U-Boot] [PATCH v3 1/8] x86: qemu: add fw_cfg support
Hi Bin, 2015-12-30 12:04 GMT+08:00 Bin Meng: > Hi Miao, > > On Tue, Dec 29, 2015 at 6:35 PM, Miao Yan wrote: >> The QEMU fw_cfg interface allows the guest to retrieve various >> data information from QEMU. For example, APCI/SMBios tables, number >> of online cpus, kernel data and command line, etc. >> >> This patch adds support for QEMU fw_cfg interface. >> >> Signed-off-by: Miao Yan >> --- >> Changes in v2: >> - rewrite command handling logic >> - various cleanups >> >> Changes in v3: >> - fix an error in do_qemu_fw() >> >> arch/x86/cpu/qemu/Makefile | 2 +- >> arch/x86/cpu/qemu/fw_cfg.c | 241 >> + >> arch/x86/cpu/qemu/fw_cfg.h | 97 ++ >> arch/x86/cpu/qemu/qemu.c | 3 + >> 4 files changed, 342 insertions(+), 1 deletion(-) >> create mode 100644 arch/x86/cpu/qemu/fw_cfg.c >> create mode 100644 arch/x86/cpu/qemu/fw_cfg.h >> >> diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile >> index 3f3958a..ad424ec 100644 >> --- a/arch/x86/cpu/qemu/Makefile >> +++ b/arch/x86/cpu/qemu/Makefile >> @@ -7,5 +7,5 @@ >> ifndef CONFIG_EFI_STUB >> obj-y += car.o dram.o >> endif >> -obj-y += qemu.o >> +obj-y += qemu.o fw_cfg.o >> obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o >> diff --git a/arch/x86/cpu/qemu/fw_cfg.c b/arch/x86/cpu/qemu/fw_cfg.c >> new file mode 100644 >> index 000..bb6a11e >> --- /dev/null >> +++ b/arch/x86/cpu/qemu/fw_cfg.c >> @@ -0,0 +1,241 @@ >> +/* >> + * (C) Copyright 2015 Miao Yan >> + * >> + * SPDX-License-Identifier:GPL-2.0+ >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include "fw_cfg.h" >> + >> +static bool fwcfg_present; >> +static bool fwcfg_dma_present; >> + >> +static void qemu_fwcfg_read_entry_pio(uint16_t entry, >> + uint32_t size, void *address) >> +{ >> + uint32_t i = 0; >> + uint8_t *data = address; >> + >> + if (entry != FW_CFG_INVALID) > > As we discussed in the v1 thread, can you please put a comment block > here to describe the QEMU internals (ie: what happens if entry == > FW_CFG_INVALID)? > >> + outw(entry, FW_CONTROL_PORT); >> + while (size--) >> + data[i++] = inb(FW_DATA_PORT); >> +} >> + >> +static void qemu_fwcfg_read_entry_dma(uint16_t entry, >> + uint32_t size, void *address) >> +{ >> + struct fw_cfg_dma_access dma; >> + >> + dma.length = cpu_to_be32(size); >> + dma.address = cpu_to_be64((uintptr_t)address); >> + dma.control = cpu_to_be32(FW_CFG_DMA_READ); >> + if (entry != FW_CFG_INVALID) > > ditto. > >> + dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << >> 16)); >> + >> + barrier(); >> + >> + debug("qemu_fwcfg_dma_read_entry: addr %p, length %u control 0x%x\n", >> + address, size, be32_to_cpu(dma.control)); >> + >> + outl(cpu_to_be32((uint32_t)), FW_DMA_PORT_HIGH); >> + >> + while (dma.control & ~FW_CFG_DMA_ERROR) >> + __asm__ __volatile__ ("pause"); > > For some reason, with the v3 patch U-Boot hangs here. I changed to use > pio to read the entry then U-Boot can boot. Can you please check this? Removing some checks in v3 exposed a bug with older qemu versions. I'll fix this. > >> +} >> + >> +static bool qemu_fwcfg_present(void) >> +{ >> + uint32_t qemu; >> + >> + qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, ); >> + return be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE; >> +} >> + >> +static bool qemu_fwcfg_dma_present(void) >> +{ >> + uint8_t dma_enabled; >> + >> + qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, _enabled); >> + if (dma_enabled & FW_CFG_DMA_ENABLED) >> + return 1; > > return true; > >> + >> + return 0; > > return false; > >> +} >> + >> +static void qemu_fwcfg_read_entry(uint16_t entry, >> + uint32_t length, void *address) >> +{ >> + if (fwcfg_dma_present) >> + qemu_fwcfg_read_entry_dma(entry, length, address); >> + else >> + qemu_fwcfg_read_entry_pio(entry, length, address); >> +} >> + >> +int qemu_fwcfg_online_cpus(void) >> +{ >> + uint16_t nb_cpus; >> + >> + if (!fwcfg_present) >> + return 1; >> + >> + qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, _cpus); >> + >> + return le16_to_cpu(nb_cpus); >> +} >> + >> +static int qemu_fwcfg_setup_kernel(void *load_addr) >> +{ >> + char *data_addr; >> + uint32_t setup_size, kernel_size, cmdline_size, initrd_size; >> + >> + qemu_fwcfg_read_entry(FW_CFG_SETUP_SIZE, 4, _size); >> + qemu_fwcfg_read_entry(FW_CFG_KERNEL_SIZE, 4, _size); >> + >> + if (setup_size == 0 || kernel_size == 0) { >> + printf("warning: no kernel available\n"); >> + return -1; >> + } >> + >> + data_addr = load_addr; >> +
Re: [U-Boot] [PATCH v3 1/8] x86: qemu: add fw_cfg support
Hi Miao, On Tue, Dec 29, 2015 at 6:35 PM, Miao Yanwrote: > The QEMU fw_cfg interface allows the guest to retrieve various > data information from QEMU. For example, APCI/SMBios tables, number > of online cpus, kernel data and command line, etc. > > This patch adds support for QEMU fw_cfg interface. > > Signed-off-by: Miao Yan > --- > Changes in v2: > - rewrite command handling logic > - various cleanups > > Changes in v3: > - fix an error in do_qemu_fw() > > arch/x86/cpu/qemu/Makefile | 2 +- > arch/x86/cpu/qemu/fw_cfg.c | 241 > + > arch/x86/cpu/qemu/fw_cfg.h | 97 ++ > arch/x86/cpu/qemu/qemu.c | 3 + > 4 files changed, 342 insertions(+), 1 deletion(-) > create mode 100644 arch/x86/cpu/qemu/fw_cfg.c > create mode 100644 arch/x86/cpu/qemu/fw_cfg.h > > diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile > index 3f3958a..ad424ec 100644 > --- a/arch/x86/cpu/qemu/Makefile > +++ b/arch/x86/cpu/qemu/Makefile > @@ -7,5 +7,5 @@ > ifndef CONFIG_EFI_STUB > obj-y += car.o dram.o > endif > -obj-y += qemu.o > +obj-y += qemu.o fw_cfg.o > obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o > diff --git a/arch/x86/cpu/qemu/fw_cfg.c b/arch/x86/cpu/qemu/fw_cfg.c > new file mode 100644 > index 000..bb6a11e > --- /dev/null > +++ b/arch/x86/cpu/qemu/fw_cfg.c > @@ -0,0 +1,241 @@ > +/* > + * (C) Copyright 2015 Miao Yan > + * > + * SPDX-License-Identifier:GPL-2.0+ > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include "fw_cfg.h" > + > +static bool fwcfg_present; > +static bool fwcfg_dma_present; > + > +static void qemu_fwcfg_read_entry_pio(uint16_t entry, > + uint32_t size, void *address) > +{ > + uint32_t i = 0; > + uint8_t *data = address; > + > + if (entry != FW_CFG_INVALID) As we discussed in the v1 thread, can you please put a comment block here to describe the QEMU internals (ie: what happens if entry == FW_CFG_INVALID)? > + outw(entry, FW_CONTROL_PORT); > + while (size--) > + data[i++] = inb(FW_DATA_PORT); > +} > + > +static void qemu_fwcfg_read_entry_dma(uint16_t entry, > + uint32_t size, void *address) > +{ > + struct fw_cfg_dma_access dma; > + > + dma.length = cpu_to_be32(size); > + dma.address = cpu_to_be64((uintptr_t)address); > + dma.control = cpu_to_be32(FW_CFG_DMA_READ); > + if (entry != FW_CFG_INVALID) ditto. > + dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16)); > + > + barrier(); > + > + debug("qemu_fwcfg_dma_read_entry: addr %p, length %u control 0x%x\n", > + address, size, be32_to_cpu(dma.control)); > + > + outl(cpu_to_be32((uint32_t)), FW_DMA_PORT_HIGH); > + > + while (dma.control & ~FW_CFG_DMA_ERROR) > + __asm__ __volatile__ ("pause"); For some reason, with the v3 patch U-Boot hangs here. I changed to use pio to read the entry then U-Boot can boot. Can you please check this? > +} > + > +static bool qemu_fwcfg_present(void) > +{ > + uint32_t qemu; > + > + qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, ); > + return be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE; > +} > + > +static bool qemu_fwcfg_dma_present(void) > +{ > + uint8_t dma_enabled; > + > + qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, _enabled); > + if (dma_enabled & FW_CFG_DMA_ENABLED) > + return 1; return true; > + > + return 0; return false; > +} > + > +static void qemu_fwcfg_read_entry(uint16_t entry, > + uint32_t length, void *address) > +{ > + if (fwcfg_dma_present) > + qemu_fwcfg_read_entry_dma(entry, length, address); > + else > + qemu_fwcfg_read_entry_pio(entry, length, address); > +} > + > +int qemu_fwcfg_online_cpus(void) > +{ > + uint16_t nb_cpus; > + > + if (!fwcfg_present) > + return 1; > + > + qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, _cpus); > + > + return le16_to_cpu(nb_cpus); > +} > + > +static int qemu_fwcfg_setup_kernel(void *load_addr) > +{ > + char *data_addr; > + uint32_t setup_size, kernel_size, cmdline_size, initrd_size; > + > + qemu_fwcfg_read_entry(FW_CFG_SETUP_SIZE, 4, _size); > + qemu_fwcfg_read_entry(FW_CFG_KERNEL_SIZE, 4, _size); > + > + if (setup_size == 0 || kernel_size == 0) { > + printf("warning: no kernel available\n"); > + return -1; > + } > + > + data_addr = load_addr; > + qemu_fwcfg_read_entry(FW_CFG_SETUP_DATA, > + le32_to_cpu(setup_size), data_addr); > + data_addr += le32_to_cpu(setup_size); > + > + qemu_fwcfg_read_entry(FW_CFG_KERNEL_DATA, > + le32_to_cpu(kernel_size), data_addr); > + data_addr += le32_to_cpu(kernel_size);