Re: [U-Boot] [PATCH v3 1/8] x86: qemu: add fw_cfg support

2015-12-30 Thread Miao Yan
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

2015-12-29 Thread 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?

> +}
> +
> +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);