diff mbox

[U-Boot,v2] x86: qemu: Move qfw command over to cmd and add Kconfig entry

Message ID 1462545622-22349-1-git-send-email-trini@konsulko.com
State Accepted
Delegated to: Bin Meng
Headers show

Commit Message

Tom Rini May 6, 2016, 2:40 p.m. UTC
- Move the command portion of arch/x86/cpu/qemu/fw_cfg.c into
  cmd/qemu_fw_cfg.c
- Move arch/x86/include/asm/fw_cfg.h to include/qemu_fw_cfg.h
- Rename ACPI table portion to arch/x86/cpu/qemu/acpi_table.c

Signed-off-by: Tom Rini <trini@konsulko.com>
---
Changes in v2:
- Depend on X86 (per Miao Yan)
---
 arch/x86/cpu/mp_init.c         |   2 +-
 arch/x86/cpu/qemu/Makefile     |   3 +-
 arch/x86/cpu/qemu/acpi_table.c | 243 ++++++++++++++++++
 arch/x86/cpu/qemu/cpu.c        |   2 +-
 arch/x86/cpu/qemu/fw_cfg.c     | 570 -----------------------------------------
 arch/x86/cpu/qemu/qemu.c       |   2 +-
 arch/x86/include/asm/fw_cfg.h  | 157 ------------
 arch/x86/lib/acpi_table.c      |   2 +-
 cmd/Kconfig                    |   7 +
 cmd/Makefile                   |   1 +
 cmd/qemu_fw_cfg.c              | 343 +++++++++++++++++++++++++
 configs/qemu-x86_defconfig     |   1 +
 include/qemu_fw_cfg.h          | 162 ++++++++++++
 13 files changed, 763 insertions(+), 732 deletions(-)
 create mode 100644 arch/x86/cpu/qemu/acpi_table.c
 delete mode 100644 arch/x86/cpu/qemu/fw_cfg.c
 delete mode 100644 arch/x86/include/asm/fw_cfg.h
 create mode 100644 cmd/qemu_fw_cfg.c
 create mode 100644 include/qemu_fw_cfg.h

Comments

Bin Meng May 10, 2016, 1:20 a.m. UTC | #1
On Fri, May 6, 2016 at 10:40 PM, Tom Rini <trini@konsulko.com> wrote:
> - Move the command portion of arch/x86/cpu/qemu/fw_cfg.c into
>   cmd/qemu_fw_cfg.c
> - Move arch/x86/include/asm/fw_cfg.h to include/qemu_fw_cfg.h
> - Rename ACPI table portion to arch/x86/cpu/qemu/acpi_table.c
>
> Signed-off-by: Tom Rini <trini@konsulko.com>
> ---
> Changes in v2:
> - Depend on X86 (per Miao Yan)
> ---
>  arch/x86/cpu/mp_init.c         |   2 +-
>  arch/x86/cpu/qemu/Makefile     |   3 +-
>  arch/x86/cpu/qemu/acpi_table.c | 243 ++++++++++++++++++
>  arch/x86/cpu/qemu/cpu.c        |   2 +-
>  arch/x86/cpu/qemu/fw_cfg.c     | 570 -----------------------------------------
>  arch/x86/cpu/qemu/qemu.c       |   2 +-
>  arch/x86/include/asm/fw_cfg.h  | 157 ------------
>  arch/x86/lib/acpi_table.c      |   2 +-
>  cmd/Kconfig                    |   7 +
>  cmd/Makefile                   |   1 +
>  cmd/qemu_fw_cfg.c              | 343 +++++++++++++++++++++++++
>  configs/qemu-x86_defconfig     |   1 +
>  include/qemu_fw_cfg.h          | 162 ++++++++++++
>  13 files changed, 763 insertions(+), 732 deletions(-)
>  create mode 100644 arch/x86/cpu/qemu/acpi_table.c
>  delete mode 100644 arch/x86/cpu/qemu/fw_cfg.c
>  delete mode 100644 arch/x86/include/asm/fw_cfg.h
>  create mode 100644 cmd/qemu_fw_cfg.c
>  create mode 100644 include/qemu_fw_cfg.h
>

Looks good.

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

Tom, will you pick this for this release, or next release?

Miao has a patch [1] to remove CONFIG_QEMU_ACPI_TABLE. If your patch
comes first, Miao needs to rebase his and submit v2.

[1] http://patchwork.ozlabs.org/patch/619748/

Regards,
Bin
Tom Rini May 10, 2016, 2:17 a.m. UTC | #2
On Tue, May 10, 2016 at 09:20:45AM +0800, Bin Meng wrote:
> On Fri, May 6, 2016 at 10:40 PM, Tom Rini <trini@konsulko.com> wrote:
> > - Move the command portion of arch/x86/cpu/qemu/fw_cfg.c into
> >   cmd/qemu_fw_cfg.c
> > - Move arch/x86/include/asm/fw_cfg.h to include/qemu_fw_cfg.h
> > - Rename ACPI table portion to arch/x86/cpu/qemu/acpi_table.c
> >
> > Signed-off-by: Tom Rini <trini@konsulko.com>
> > ---
> > Changes in v2:
> > - Depend on X86 (per Miao Yan)
> > ---
> >  arch/x86/cpu/mp_init.c         |   2 +-
> >  arch/x86/cpu/qemu/Makefile     |   3 +-
> >  arch/x86/cpu/qemu/acpi_table.c | 243 ++++++++++++++++++
> >  arch/x86/cpu/qemu/cpu.c        |   2 +-
> >  arch/x86/cpu/qemu/fw_cfg.c     | 570 -----------------------------------------
> >  arch/x86/cpu/qemu/qemu.c       |   2 +-
> >  arch/x86/include/asm/fw_cfg.h  | 157 ------------
> >  arch/x86/lib/acpi_table.c      |   2 +-
> >  cmd/Kconfig                    |   7 +
> >  cmd/Makefile                   |   1 +
> >  cmd/qemu_fw_cfg.c              | 343 +++++++++++++++++++++++++
> >  configs/qemu-x86_defconfig     |   1 +
> >  include/qemu_fw_cfg.h          | 162 ++++++++++++
> >  13 files changed, 763 insertions(+), 732 deletions(-)
> >  create mode 100644 arch/x86/cpu/qemu/acpi_table.c
> >  delete mode 100644 arch/x86/cpu/qemu/fw_cfg.c
> >  delete mode 100644 arch/x86/include/asm/fw_cfg.h
> >  create mode 100644 cmd/qemu_fw_cfg.c
> >  create mode 100644 include/qemu_fw_cfg.h
> >
> 
> Looks good.
> 
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> 
> Tom, will you pick this for this release, or next release?
> 
> Miao has a patch [1] to remove CONFIG_QEMU_ACPI_TABLE. If your patch
> comes first, Miao needs to rebase his and submit v2.

For the next release, and I'll leave it to you to pull in.  Thanks!
Bin Meng May 10, 2016, 3:08 a.m. UTC | #3
On Tue, May 10, 2016 at 10:17 AM, Tom Rini <trini@konsulko.com> wrote:
> On Tue, May 10, 2016 at 09:20:45AM +0800, Bin Meng wrote:
>> On Fri, May 6, 2016 at 10:40 PM, Tom Rini <trini@konsulko.com> wrote:
>> > - Move the command portion of arch/x86/cpu/qemu/fw_cfg.c into
>> >   cmd/qemu_fw_cfg.c
>> > - Move arch/x86/include/asm/fw_cfg.h to include/qemu_fw_cfg.h
>> > - Rename ACPI table portion to arch/x86/cpu/qemu/acpi_table.c
>> >
>> > Signed-off-by: Tom Rini <trini@konsulko.com>
>> > ---
>> > Changes in v2:
>> > - Depend on X86 (per Miao Yan)
>> > ---
>> >  arch/x86/cpu/mp_init.c         |   2 +-
>> >  arch/x86/cpu/qemu/Makefile     |   3 +-
>> >  arch/x86/cpu/qemu/acpi_table.c | 243 ++++++++++++++++++
>> >  arch/x86/cpu/qemu/cpu.c        |   2 +-
>> >  arch/x86/cpu/qemu/fw_cfg.c     | 570 -----------------------------------------
>> >  arch/x86/cpu/qemu/qemu.c       |   2 +-
>> >  arch/x86/include/asm/fw_cfg.h  | 157 ------------
>> >  arch/x86/lib/acpi_table.c      |   2 +-
>> >  cmd/Kconfig                    |   7 +
>> >  cmd/Makefile                   |   1 +
>> >  cmd/qemu_fw_cfg.c              | 343 +++++++++++++++++++++++++
>> >  configs/qemu-x86_defconfig     |   1 +
>> >  include/qemu_fw_cfg.h          | 162 ++++++++++++
>> >  13 files changed, 763 insertions(+), 732 deletions(-)
>> >  create mode 100644 arch/x86/cpu/qemu/acpi_table.c
>> >  delete mode 100644 arch/x86/cpu/qemu/fw_cfg.c
>> >  delete mode 100644 arch/x86/include/asm/fw_cfg.h
>> >  create mode 100644 cmd/qemu_fw_cfg.c
>> >  create mode 100644 include/qemu_fw_cfg.h
>> >
>>
>> Looks good.
>>
>> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
>>
>> Tom, will you pick this for this release, or next release?
>>
>> Miao has a patch [1] to remove CONFIG_QEMU_ACPI_TABLE. If your patch
>> comes first, Miao needs to rebase his and submit v2.
>
> For the next release, and I'll leave it to you to pull in.  Thanks!

applied to u-boot-x86/next, thanks!
Miao Yan May 10, 2016, 4:35 a.m. UTC | #4
2016-05-10 11:08 GMT+08:00 Bin Meng <bmeng.cn@gmail.com>:
> On Tue, May 10, 2016 at 10:17 AM, Tom Rini <trini@konsulko.com> wrote:
>> On Tue, May 10, 2016 at 09:20:45AM +0800, Bin Meng wrote:
>>> On Fri, May 6, 2016 at 10:40 PM, Tom Rini <trini@konsulko.com> wrote:
>>> > - Move the command portion of arch/x86/cpu/qemu/fw_cfg.c into
>>> >   cmd/qemu_fw_cfg.c
>>> > - Move arch/x86/include/asm/fw_cfg.h to include/qemu_fw_cfg.h
>>> > - Rename ACPI table portion to arch/x86/cpu/qemu/acpi_table.c
>>> >
>>> > Signed-off-by: Tom Rini <trini@konsulko.com>
>>> > ---
>>> > Changes in v2:
>>> > - Depend on X86 (per Miao Yan)
>>> > ---
>>> >  arch/x86/cpu/mp_init.c         |   2 +-
>>> >  arch/x86/cpu/qemu/Makefile     |   3 +-
>>> >  arch/x86/cpu/qemu/acpi_table.c | 243 ++++++++++++++++++
>>> >  arch/x86/cpu/qemu/cpu.c        |   2 +-
>>> >  arch/x86/cpu/qemu/fw_cfg.c     | 570 -----------------------------------------
>>> >  arch/x86/cpu/qemu/qemu.c       |   2 +-
>>> >  arch/x86/include/asm/fw_cfg.h  | 157 ------------
>>> >  arch/x86/lib/acpi_table.c      |   2 +-
>>> >  cmd/Kconfig                    |   7 +
>>> >  cmd/Makefile                   |   1 +
>>> >  cmd/qemu_fw_cfg.c              | 343 +++++++++++++++++++++++++
>>> >  configs/qemu-x86_defconfig     |   1 +
>>> >  include/qemu_fw_cfg.h          | 162 ++++++++++++
>>> >  13 files changed, 763 insertions(+), 732 deletions(-)
>>> >  create mode 100644 arch/x86/cpu/qemu/acpi_table.c
>>> >  delete mode 100644 arch/x86/cpu/qemu/fw_cfg.c
>>> >  delete mode 100644 arch/x86/include/asm/fw_cfg.h
>>> >  create mode 100644 cmd/qemu_fw_cfg.c
>>> >  create mode 100644 include/qemu_fw_cfg.h
>>> >
>>>
>>> Looks good.
>>>
>>> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
>>>
>>> Tom, will you pick this for this release, or next release?
>>>
>>> Miao has a patch [1] to remove CONFIG_QEMU_ACPI_TABLE. If your patch
>>> comes first, Miao needs to rebase his and submit v2.
>>
>> For the next release, and I'll leave it to you to pull in.  Thanks!
>
> applied to u-boot-x86/next, thanks!


Wait, you applied this already ? Did you include the diff I mentioned
? This patch has build issues. Before the patch, the qfw is built
unconditionally for x86-qemu, after applying this patch, qfw depends
on CONFIG_CMD_QEMU_FW_CFG. This is a change of behavior, so you need
to test:

    1) defconfig build
    2) defconfig with CONFIG_CMD_QEMU_FW_CFG disabled because it's
user visible now

This patch breaks 2):


arch/x86/cpu/built-in.o: In function `cpu_qemu_get_count':
/home/myan/work/u-boot/arch/x86/cpu/qemu/cpu.c:28: undefined reference
to `qemu_fwcfg_online_cpus'
arch/x86/cpu/built-in.o: In function `qemu_chipset_init':
/home/myan/work/u-boot/arch/x86/cpu/qemu/qemu.c:91: undefined
reference to `qemu_fwcfg_init'
arch/x86/cpu/built-in.o: In function `write_acpi_tables':
/home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:187: undefined
reference to `qemu_fwcfg_read_firmware_list'
/home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:193: undefined
reference to `qemu_fwcfg_find_file'
/home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:211: undefined
reference to `qemu_fwcfg_read_entry'
arch/x86/cpu/built-in.o: In function `bios_linker_allocate':
/home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:41: undefined
reference to `qemu_fwcfg_find_file'
/home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:71: undefined
reference to `qemu_fwcfg_read_entry'
arch/x86/cpu/built-in.o: In function `bios_linker_add_pointer':
/home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:96: undefined
reference to `qemu_fwcfg_find_file'
/home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:99: undefined
reference to `qemu_fwcfg_find_file'
arch/x86/cpu/built-in.o: In function `bios_linker_add_checksum':
/home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:129: undefined
reference to `qemu_fwcfg_find_file'
arch/x86/cpu/built-in.o: In function `write_acpi_tables':
/home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:239: undefined
reference to `qemu_fwcfg_free_files'
arch/x86/cpu/built-in.o: In function `qemu_cpu_fixup':
/home/myan/work/u-boot/arch/x86/cpu/mp_init.c:454: undefined reference
to `qemu_fwcfg_online_cpus'
make: *** [u-boot] Error 1


And I still think for this patch, it should depend on x86 && qemu. It
doesn't make sense to build qfw for other non-qemu boards.

Miao
Bin Meng May 10, 2016, 5:12 a.m. UTC | #5
Hi Miao,

On Tue, May 10, 2016 at 12:35 PM, Miao Yan <yanmiaobest@gmail.com> wrote:
> 2016-05-10 11:08 GMT+08:00 Bin Meng <bmeng.cn@gmail.com>:
>> On Tue, May 10, 2016 at 10:17 AM, Tom Rini <trini@konsulko.com> wrote:
>>> On Tue, May 10, 2016 at 09:20:45AM +0800, Bin Meng wrote:
>>>> On Fri, May 6, 2016 at 10:40 PM, Tom Rini <trini@konsulko.com> wrote:
>>>> > - Move the command portion of arch/x86/cpu/qemu/fw_cfg.c into
>>>> >   cmd/qemu_fw_cfg.c
>>>> > - Move arch/x86/include/asm/fw_cfg.h to include/qemu_fw_cfg.h
>>>> > - Rename ACPI table portion to arch/x86/cpu/qemu/acpi_table.c
>>>> >
>>>> > Signed-off-by: Tom Rini <trini@konsulko.com>
>>>> > ---
>>>> > Changes in v2:
>>>> > - Depend on X86 (per Miao Yan)
>>>> > ---
>>>> >  arch/x86/cpu/mp_init.c         |   2 +-
>>>> >  arch/x86/cpu/qemu/Makefile     |   3 +-
>>>> >  arch/x86/cpu/qemu/acpi_table.c | 243 ++++++++++++++++++
>>>> >  arch/x86/cpu/qemu/cpu.c        |   2 +-
>>>> >  arch/x86/cpu/qemu/fw_cfg.c     | 570 -----------------------------------------
>>>> >  arch/x86/cpu/qemu/qemu.c       |   2 +-
>>>> >  arch/x86/include/asm/fw_cfg.h  | 157 ------------
>>>> >  arch/x86/lib/acpi_table.c      |   2 +-
>>>> >  cmd/Kconfig                    |   7 +
>>>> >  cmd/Makefile                   |   1 +
>>>> >  cmd/qemu_fw_cfg.c              | 343 +++++++++++++++++++++++++
>>>> >  configs/qemu-x86_defconfig     |   1 +
>>>> >  include/qemu_fw_cfg.h          | 162 ++++++++++++
>>>> >  13 files changed, 763 insertions(+), 732 deletions(-)
>>>> >  create mode 100644 arch/x86/cpu/qemu/acpi_table.c
>>>> >  delete mode 100644 arch/x86/cpu/qemu/fw_cfg.c
>>>> >  delete mode 100644 arch/x86/include/asm/fw_cfg.h
>>>> >  create mode 100644 cmd/qemu_fw_cfg.c
>>>> >  create mode 100644 include/qemu_fw_cfg.h
>>>> >
>>>>
>>>> Looks good.
>>>>
>>>> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
>>>>
>>>> Tom, will you pick this for this release, or next release?
>>>>
>>>> Miao has a patch [1] to remove CONFIG_QEMU_ACPI_TABLE. If your patch
>>>> comes first, Miao needs to rebase his and submit v2.
>>>
>>> For the next release, and I'll leave it to you to pull in.  Thanks!
>>
>> applied to u-boot-x86/next, thanks!
>
>
> Wait, you applied this already ? Did you include the diff I mentioned

The patch is not in mainline. It's currently in x86 tree and we can
always fix issues before a pull request is sent out.

> ? This patch has build issues. Before the patch, the qfw is built
> unconditionally for x86-qemu, after applying this patch, qfw depends
> on CONFIG_CMD_QEMU_FW_CFG. This is a change of behavior, so you need
> to test:
>
>     1) defconfig build
>     2) defconfig with CONFIG_CMD_QEMU_FW_CFG disabled because it's
> user visible now
>
> This patch breaks 2):
>

I doubt everything can be build error free if we randomly switch
something on or off from the Kconfig GUI. I did buildman testing for
this patch and nothing breaks by default. Having said that, I agree
the build error you reported is something we should fix.

>
> arch/x86/cpu/built-in.o: In function `cpu_qemu_get_count':
> /home/myan/work/u-boot/arch/x86/cpu/qemu/cpu.c:28: undefined reference
> to `qemu_fwcfg_online_cpus'
> arch/x86/cpu/built-in.o: In function `qemu_chipset_init':
> /home/myan/work/u-boot/arch/x86/cpu/qemu/qemu.c:91: undefined
> reference to `qemu_fwcfg_init'
> arch/x86/cpu/built-in.o: In function `write_acpi_tables':
> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:187: undefined
> reference to `qemu_fwcfg_read_firmware_list'
> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:193: undefined
> reference to `qemu_fwcfg_find_file'
> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:211: undefined
> reference to `qemu_fwcfg_read_entry'
> arch/x86/cpu/built-in.o: In function `bios_linker_allocate':
> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:41: undefined
> reference to `qemu_fwcfg_find_file'
> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:71: undefined
> reference to `qemu_fwcfg_read_entry'
> arch/x86/cpu/built-in.o: In function `bios_linker_add_pointer':
> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:96: undefined
> reference to `qemu_fwcfg_find_file'
> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:99: undefined
> reference to `qemu_fwcfg_find_file'
> arch/x86/cpu/built-in.o: In function `bios_linker_add_checksum':
> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:129: undefined
> reference to `qemu_fwcfg_find_file'
> arch/x86/cpu/built-in.o: In function `write_acpi_tables':
> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:239: undefined
> reference to `qemu_fwcfg_free_files'
> arch/x86/cpu/built-in.o: In function `qemu_cpu_fixup':
> /home/myan/work/u-boot/arch/x86/cpu/mp_init.c:454: undefined reference
> to `qemu_fwcfg_online_cpus'
> make: *** [u-boot] Error 1
>
>
> And I still think for this patch, it should depend on x86 && qemu. It
> doesn't make sense to build qfw for other non-qemu boards.
>

Tom has the following statement regarding adding qemu dependency to
the Kconfig option:

"In general, I want to see the least restrictive set of depends used.
This should be "easy" to throw into sandbox for testing there and when
we use normal boards under qemu this should also be easy to enable."

I believe Tom wanted to enable this command build testing for Sanbox,
hence increase our build coverage. I think more refactoring work needs
to done to achieve that. Like you said, now QEMU's ACPI table
generation depends on CONFIG_CMD_QEMU_FW_CFG. This looks to me a
little bit odd. We may further split the qemu_fw_cfg.c to two parts:
one only does the command line handling, and the other one does the
fw_cfg stuff.

Maybe you can send out some patches to address these?

Regards,
Bin
Miao Yan May 10, 2016, 7:17 a.m. UTC | #6
Hi Bin,

2016-05-10 13:12 GMT+08:00 Bin Meng <bmeng.cn@gmail.com>:
> Hi Miao,
>
> On Tue, May 10, 2016 at 12:35 PM, Miao Yan <yanmiaobest@gmail.com> wrote:
>> 2016-05-10 11:08 GMT+08:00 Bin Meng <bmeng.cn@gmail.com>:
>>> On Tue, May 10, 2016 at 10:17 AM, Tom Rini <trini@konsulko.com> wrote:
>>>> On Tue, May 10, 2016 at 09:20:45AM +0800, Bin Meng wrote:
>>>>> On Fri, May 6, 2016 at 10:40 PM, Tom Rini <trini@konsulko.com> wrote:
>>>>> > - Move the command portion of arch/x86/cpu/qemu/fw_cfg.c into
>>>>> >   cmd/qemu_fw_cfg.c
>>>>> > - Move arch/x86/include/asm/fw_cfg.h to include/qemu_fw_cfg.h
>>>>> > - Rename ACPI table portion to arch/x86/cpu/qemu/acpi_table.c
>>>>> >
>>>>> > Signed-off-by: Tom Rini <trini@konsulko.com>
>>>>> > ---
>>>>> > Changes in v2:
>>>>> > - Depend on X86 (per Miao Yan)
>>>>> > ---
>>>>> >  arch/x86/cpu/mp_init.c         |   2 +-
>>>>> >  arch/x86/cpu/qemu/Makefile     |   3 +-
>>>>> >  arch/x86/cpu/qemu/acpi_table.c | 243 ++++++++++++++++++
>>>>> >  arch/x86/cpu/qemu/cpu.c        |   2 +-
>>>>> >  arch/x86/cpu/qemu/fw_cfg.c     | 570 -----------------------------------------
>>>>> >  arch/x86/cpu/qemu/qemu.c       |   2 +-
>>>>> >  arch/x86/include/asm/fw_cfg.h  | 157 ------------
>>>>> >  arch/x86/lib/acpi_table.c      |   2 +-
>>>>> >  cmd/Kconfig                    |   7 +
>>>>> >  cmd/Makefile                   |   1 +
>>>>> >  cmd/qemu_fw_cfg.c              | 343 +++++++++++++++++++++++++
>>>>> >  configs/qemu-x86_defconfig     |   1 +
>>>>> >  include/qemu_fw_cfg.h          | 162 ++++++++++++
>>>>> >  13 files changed, 763 insertions(+), 732 deletions(-)
>>>>> >  create mode 100644 arch/x86/cpu/qemu/acpi_table.c
>>>>> >  delete mode 100644 arch/x86/cpu/qemu/fw_cfg.c
>>>>> >  delete mode 100644 arch/x86/include/asm/fw_cfg.h
>>>>> >  create mode 100644 cmd/qemu_fw_cfg.c
>>>>> >  create mode 100644 include/qemu_fw_cfg.h
>>>>> >
>>>>>
>>>>> Looks good.
>>>>>
>>>>> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
>>>>>
>>>>> Tom, will you pick this for this release, or next release?
>>>>>
>>>>> Miao has a patch [1] to remove CONFIG_QEMU_ACPI_TABLE. If your patch
>>>>> comes first, Miao needs to rebase his and submit v2.
>>>>
>>>> For the next release, and I'll leave it to you to pull in.  Thanks!
>>>
>>> applied to u-boot-x86/next, thanks!
>>
>>
>> Wait, you applied this already ? Did you include the diff I mentioned
>
> The patch is not in mainline. It's currently in x86 tree and we can
> always fix issues before a pull request is sent out.
>
>> ? This patch has build issues. Before the patch, the qfw is built
>> unconditionally for x86-qemu, after applying this patch, qfw depends
>> on CONFIG_CMD_QEMU_FW_CFG. This is a change of behavior, so you need
>> to test:
>>
>>     1) defconfig build
>>     2) defconfig with CONFIG_CMD_QEMU_FW_CFG disabled because it's
>> user visible now
>>
>> This patch breaks 2):
>>
>
> I doubt everything can be build error free if we randomly switch
> something on or off from the Kconfig GUI. I did buildman testing for

Well I don't think it's "random", we have mature tools to deal with
dependencies,
it's not like I was directly modifying random stuff in .config with a
text editor.
Kconfig options should be there for a reason, otherwise why bother.
And if it doesn't work then it's a bug.

> this patch and nothing breaks by default. Having said that, I agree
> the build error you reported is something we should fix.

OK. So can you please apply the diff or ask for v3 if you like ?

>
>>
>> arch/x86/cpu/built-in.o: In function `cpu_qemu_get_count':
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/cpu.c:28: undefined reference
>> to `qemu_fwcfg_online_cpus'
>> arch/x86/cpu/built-in.o: In function `qemu_chipset_init':
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/qemu.c:91: undefined
>> reference to `qemu_fwcfg_init'
>> arch/x86/cpu/built-in.o: In function `write_acpi_tables':
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:187: undefined
>> reference to `qemu_fwcfg_read_firmware_list'
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:193: undefined
>> reference to `qemu_fwcfg_find_file'
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:211: undefined
>> reference to `qemu_fwcfg_read_entry'
>> arch/x86/cpu/built-in.o: In function `bios_linker_allocate':
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:41: undefined
>> reference to `qemu_fwcfg_find_file'
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:71: undefined
>> reference to `qemu_fwcfg_read_entry'
>> arch/x86/cpu/built-in.o: In function `bios_linker_add_pointer':
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:96: undefined
>> reference to `qemu_fwcfg_find_file'
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:99: undefined
>> reference to `qemu_fwcfg_find_file'
>> arch/x86/cpu/built-in.o: In function `bios_linker_add_checksum':
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:129: undefined
>> reference to `qemu_fwcfg_find_file'
>> arch/x86/cpu/built-in.o: In function `write_acpi_tables':
>> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:239: undefined
>> reference to `qemu_fwcfg_free_files'
>> arch/x86/cpu/built-in.o: In function `qemu_cpu_fixup':
>> /home/myan/work/u-boot/arch/x86/cpu/mp_init.c:454: undefined reference
>> to `qemu_fwcfg_online_cpus'
>> make: *** [u-boot] Error 1
>>
>>
>> And I still think for this patch, it should depend on x86 && qemu. It
>> doesn't make sense to build qfw for other non-qemu boards.
>>
>
> Tom has the following statement regarding adding qemu dependency to
> the Kconfig option:
>
> "In general, I want to see the least restrictive set of depends used.
> This should be "easy" to throw into sandbox for testing there and when
> we use normal boards under qemu this should also be easy to enable."
>
> I believe Tom wanted to enable this command build testing for Sanbox,
> hence increase our build coverage. I think more refactoring work needs

Maybe some kind of random/allyes/allno config should be in that build
coverage test.

> to done to achieve that. Like you said, now QEMU's ACPI table
> generation depends on CONFIG_CMD_QEMU_FW_CFG. This looks to me a
> little bit odd. We may further split the qemu_fw_cfg.c to two parts:
> one only does the command line handling, and the other one does the
> fw_cfg stuff.

Agreed. I just thought these will be automatically sorted out when we
extend qfw to other architectures.

>
> Maybe you can send out some patches to address these?

Looks like Tom has plans for this ?

Thanks,
Miao

>
> Regards,
> Bin
Tom Rini May 10, 2016, 2:24 p.m. UTC | #7
On Tue, May 10, 2016 at 03:17:04PM +0800, Miao Yan wrote:
> Hi Bin,
> 
> 2016-05-10 13:12 GMT+08:00 Bin Meng <bmeng.cn@gmail.com>:
> > Hi Miao,
> >
> > On Tue, May 10, 2016 at 12:35 PM, Miao Yan <yanmiaobest@gmail.com> wrote:
> >> 2016-05-10 11:08 GMT+08:00 Bin Meng <bmeng.cn@gmail.com>:
> >>> On Tue, May 10, 2016 at 10:17 AM, Tom Rini <trini@konsulko.com> wrote:
> >>>> On Tue, May 10, 2016 at 09:20:45AM +0800, Bin Meng wrote:
> >>>>> On Fri, May 6, 2016 at 10:40 PM, Tom Rini <trini@konsulko.com> wrote:
> >>>>> > - Move the command portion of arch/x86/cpu/qemu/fw_cfg.c into
> >>>>> >   cmd/qemu_fw_cfg.c
> >>>>> > - Move arch/x86/include/asm/fw_cfg.h to include/qemu_fw_cfg.h
> >>>>> > - Rename ACPI table portion to arch/x86/cpu/qemu/acpi_table.c
> >>>>> >
> >>>>> > Signed-off-by: Tom Rini <trini@konsulko.com>
> >>>>> > ---
> >>>>> > Changes in v2:
> >>>>> > - Depend on X86 (per Miao Yan)
> >>>>> > ---
> >>>>> >  arch/x86/cpu/mp_init.c         |   2 +-
> >>>>> >  arch/x86/cpu/qemu/Makefile     |   3 +-
> >>>>> >  arch/x86/cpu/qemu/acpi_table.c | 243 ++++++++++++++++++
> >>>>> >  arch/x86/cpu/qemu/cpu.c        |   2 +-
> >>>>> >  arch/x86/cpu/qemu/fw_cfg.c     | 570 -----------------------------------------
> >>>>> >  arch/x86/cpu/qemu/qemu.c       |   2 +-
> >>>>> >  arch/x86/include/asm/fw_cfg.h  | 157 ------------
> >>>>> >  arch/x86/lib/acpi_table.c      |   2 +-
> >>>>> >  cmd/Kconfig                    |   7 +
> >>>>> >  cmd/Makefile                   |   1 +
> >>>>> >  cmd/qemu_fw_cfg.c              | 343 +++++++++++++++++++++++++
> >>>>> >  configs/qemu-x86_defconfig     |   1 +
> >>>>> >  include/qemu_fw_cfg.h          | 162 ++++++++++++
> >>>>> >  13 files changed, 763 insertions(+), 732 deletions(-)
> >>>>> >  create mode 100644 arch/x86/cpu/qemu/acpi_table.c
> >>>>> >  delete mode 100644 arch/x86/cpu/qemu/fw_cfg.c
> >>>>> >  delete mode 100644 arch/x86/include/asm/fw_cfg.h
> >>>>> >  create mode 100644 cmd/qemu_fw_cfg.c
> >>>>> >  create mode 100644 include/qemu_fw_cfg.h
> >>>>> >
> >>>>>
> >>>>> Looks good.
> >>>>>
> >>>>> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> >>>>>
> >>>>> Tom, will you pick this for this release, or next release?
> >>>>>
> >>>>> Miao has a patch [1] to remove CONFIG_QEMU_ACPI_TABLE. If your patch
> >>>>> comes first, Miao needs to rebase his and submit v2.
> >>>>
> >>>> For the next release, and I'll leave it to you to pull in.  Thanks!
> >>>
> >>> applied to u-boot-x86/next, thanks!
> >>
> >>
> >> Wait, you applied this already ? Did you include the diff I mentioned
> >
> > The patch is not in mainline. It's currently in x86 tree and we can
> > always fix issues before a pull request is sent out.
> >
> >> ? This patch has build issues. Before the patch, the qfw is built
> >> unconditionally for x86-qemu, after applying this patch, qfw depends
> >> on CONFIG_CMD_QEMU_FW_CFG. This is a change of behavior, so you need
> >> to test:
> >>
> >>     1) defconfig build
> >>     2) defconfig with CONFIG_CMD_QEMU_FW_CFG disabled because it's
> >> user visible now
> >>
> >> This patch breaks 2):
> >>
> >
> > I doubt everything can be build error free if we randomly switch
> > something on or off from the Kconfig GUI. I did buildman testing for
> 
> Well I don't think it's "random", we have mature tools to deal with
> dependencies,
> it's not like I was directly modifying random stuff in .config with a
> text editor.
> Kconfig options should be there for a reason, otherwise why bother.
> And if it doesn't work then it's a bug.

So yes, I suppose QEMU should select this new option since it is
required there for other non-selectable options, rather than just being
enabled in the defconfigs (which is why this is build clean from my
point of view, qemu-x86_defconfig was updated).

> > this patch and nothing breaks by default. Having said that, I agree
> > the build error you reported is something we should fix.
> 
> OK. So can you please apply the diff or ask for v3 if you like ?
> 
> >
> >>
> >> arch/x86/cpu/built-in.o: In function `cpu_qemu_get_count':
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/cpu.c:28: undefined reference
> >> to `qemu_fwcfg_online_cpus'
> >> arch/x86/cpu/built-in.o: In function `qemu_chipset_init':
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/qemu.c:91: undefined
> >> reference to `qemu_fwcfg_init'
> >> arch/x86/cpu/built-in.o: In function `write_acpi_tables':
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:187: undefined
> >> reference to `qemu_fwcfg_read_firmware_list'
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:193: undefined
> >> reference to `qemu_fwcfg_find_file'
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:211: undefined
> >> reference to `qemu_fwcfg_read_entry'
> >> arch/x86/cpu/built-in.o: In function `bios_linker_allocate':
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:41: undefined
> >> reference to `qemu_fwcfg_find_file'
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:71: undefined
> >> reference to `qemu_fwcfg_read_entry'
> >> arch/x86/cpu/built-in.o: In function `bios_linker_add_pointer':
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:96: undefined
> >> reference to `qemu_fwcfg_find_file'
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:99: undefined
> >> reference to `qemu_fwcfg_find_file'
> >> arch/x86/cpu/built-in.o: In function `bios_linker_add_checksum':
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:129: undefined
> >> reference to `qemu_fwcfg_find_file'
> >> arch/x86/cpu/built-in.o: In function `write_acpi_tables':
> >> /home/myan/work/u-boot/arch/x86/cpu/qemu/acpi_table.c:239: undefined
> >> reference to `qemu_fwcfg_free_files'
> >> arch/x86/cpu/built-in.o: In function `qemu_cpu_fixup':
> >> /home/myan/work/u-boot/arch/x86/cpu/mp_init.c:454: undefined reference
> >> to `qemu_fwcfg_online_cpus'
> >> make: *** [u-boot] Error 1
> >>
> >>
> >> And I still think for this patch, it should depend on x86 && qemu. It
> >> doesn't make sense to build qfw for other non-qemu boards.
> >>
> >
> > Tom has the following statement regarding adding qemu dependency to
> > the Kconfig option:
> >
> > "In general, I want to see the least restrictive set of depends used.
> > This should be "easy" to throw into sandbox for testing there and when
> > we use normal boards under qemu this should also be easy to enable."
> >
> > I believe Tom wanted to enable this command build testing for Sanbox,
> > hence increase our build coverage. I think more refactoring work needs
> 
> Maybe some kind of random/allyes/allno config should be in that build
> coverage test.

Yes, my long term goal is that we can make use of random/allyes/allno
for real, along with making the sandbox config extremely full.  Which is
partly why I want lose depends lines

> > to done to achieve that. Like you said, now QEMU's ACPI table
> > generation depends on CONFIG_CMD_QEMU_FW_CFG. This looks to me a
> > little bit odd. We may further split the qemu_fw_cfg.c to two parts:
> > one only does the command line handling, and the other one does the
> > fw_cfg stuff.
> 
> Agreed. I just thought these will be automatically sorted out when we
> extend qfw to other architectures.

Well, this patch was a first pass at trying to separate out the logic.
My end goal is to be able to use -kernel / -initrd / -dtb to pass in
files "directly" to say vexpress_ca9x4 rather than have to fiddle with
fake networking.  So we need to keep that in mind when splitting the
code into cmd/ common/ and arch/x86/ (I'll set aside ACPI tables on ARM
in QEMU for the moment, but lets also not forget that will be something
someone will talk about in the future).

> > Maybe you can send out some patches to address these?
> 
> Looks like Tom has plans for this ?

Well, what you posted before addresses things well enough to start with,
when I have time to cycle back and make use of this on either ARM or
PowerPC or MIPS (and sandbox) I'll re-tweak the Kconfig logic again as
needed.  So lets fold that in for now, thanks!
Miao Yan May 11, 2016, 8:49 a.m. UTC | #8
Hi Tom,

>
> Well, this patch was a first pass at trying to separate out the logic.
> My end goal is to be able to use -kernel / -initrd / -dtb to pass in
> files "directly" to say vexpress_ca9x4 rather than have to fiddle with
> fake networking.  So we need to keep that in mind when splitting the

Well, about that, the fw_cfg is only exposed on certain QEMU emulated boards.
For ARM, it is only available on arm_virt which supports cortexA15/53/57.
Does U-boot have out-of-box support for that ?

Thanks,
Miao

> code into cmd/ common/ and arch/x86/ (I'll set aside ACPI tables on ARM
> in QEMU for the moment, but lets also not forget that will be something
> someone will talk about in the future).
>
diff mbox

Patch

diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
index 2604a68..13bec7a 100644
--- a/arch/x86/cpu/mp_init.c
+++ b/arch/x86/cpu/mp_init.c
@@ -11,6 +11,7 @@ 
 #include <dm.h>
 #include <errno.h>
 #include <malloc.h>
+#include <qemu_fw_cfg.h>
 #include <asm/atomic.h>
 #include <asm/cpu.h>
 #include <asm/interrupt.h>
@@ -21,7 +22,6 @@ 
 #include <asm/mtrr.h>
 #include <asm/processor.h>
 #include <asm/sipi.h>
-#include <asm/fw_cfg.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
 #include <dm/lists.h>
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile
index 6eeddf1..97b965c 100644
--- a/arch/x86/cpu/qemu/Makefile
+++ b/arch/x86/cpu/qemu/Makefile
@@ -7,4 +7,5 @@ 
 ifndef CONFIG_EFI_STUB
 obj-y += car.o dram.o
 endif
-obj-y += cpu.o fw_cfg.o qemu.o
+obj-y += cpu.o qemu.o
+obj-$(CONFIG_QEMU_ACPI_TABLE) += acpi_table.o
diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c
new file mode 100644
index 0000000..49381ac
--- /dev/null
+++ b/arch/x86/cpu/qemu/acpi_table.c
@@ -0,0 +1,243 @@ 
+/*
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <malloc.h>
+#include <qemu_fw_cfg.h>
+#include <asm/io.h>
+#include <asm/tables.h>
+#include <asm/e820.h>
+#include <linux/list.h>
+#include <memalign.h>
+
+/*
+ * This function allocates memory for ACPI tables
+ *
+ * @entry : BIOS linker command entry which tells where to allocate memory
+ *          (either high memory or low memory)
+ * @addr  : The address that should be used for low memory allcation. If the
+ *          memory allocation request is 'ZONE_HIGH' then this parameter will
+ *          be ignored.
+ * @return: 0 on success, or negative value on failure
+ */
+static int bios_linker_allocate(struct bios_linker_entry *entry, u32 *addr)
+{
+	uint32_t size, align;
+	struct fw_file *file;
+	unsigned long aligned_addr;
+
+	align = le32_to_cpu(entry->alloc.align);
+	/* align must be power of 2 */
+	if (align & (align - 1)) {
+		printf("error: wrong alignment %u\n", align);
+		return -EINVAL;
+	}
+
+	file = qemu_fwcfg_find_file(entry->alloc.file);
+	if (!file) {
+		printf("error: can't find file %s\n", entry->alloc.file);
+		return -ENOENT;
+	}
+
+	size = be32_to_cpu(file->cfg.size);
+
+	/*
+	 * ZONE_HIGH means we need to allocate from high memory, since
+	 * malloc space is already at the end of RAM, so we directly use it.
+	 * If allocation zone is ZONE_FSEG, then we use the 'addr' passed
+	 * in which is low memory
+	 */
+	if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) {
+		aligned_addr = (unsigned long)memalign(align, size);
+		if (!aligned_addr) {
+			printf("error: allocating resource\n");
+			return -ENOMEM;
+		}
+	} else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) {
+		aligned_addr = ALIGN(*addr, align);
+	} else {
+		printf("error: invalid allocation zone\n");
+		return -EINVAL;
+	}
+
+	debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n",
+	      file->cfg.name, size, entry->alloc.zone, align, aligned_addr);
+
+	qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
+			      size, (void *)aligned_addr);
+	file->addr = aligned_addr;
+
+	/* adjust address for low memory allocation */
+	if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG)
+		*addr = (aligned_addr + size);
+
+	return 0;
+}
+
+/*
+ * This function patches ACPI tables previously loaded
+ * by bios_linker_allocate()
+ *
+ * @entry : BIOS linker command entry which tells how to patch
+ *          ACPI tables
+ * @return: 0 on success, or negative value on failure
+ */
+static int bios_linker_add_pointer(struct bios_linker_entry *entry)
+{
+	struct fw_file *dest, *src;
+	uint32_t offset = le32_to_cpu(entry->pointer.offset);
+	uint64_t pointer = 0;
+
+	dest = qemu_fwcfg_find_file(entry->pointer.dest_file);
+	if (!dest || !dest->addr)
+		return -ENOENT;
+	src = qemu_fwcfg_find_file(entry->pointer.src_file);
+	if (!src || !src->addr)
+		return -ENOENT;
+
+	debug("bios_linker_add_pointer: dest->addr 0x%lx, src->addr 0x%lx, offset 0x%x size %u, 0x%llx\n",
+	      dest->addr, src->addr, offset, entry->pointer.size, pointer);
+
+	memcpy(&pointer, (char *)dest->addr + offset, entry->pointer.size);
+	pointer	= le64_to_cpu(pointer);
+	pointer += (unsigned long)src->addr;
+	pointer	= cpu_to_le64(pointer);
+	memcpy((char *)dest->addr + offset, &pointer, entry->pointer.size);
+
+	return 0;
+}
+
+/*
+ * This function updates checksum fields of ACPI tables previously loaded
+ * by bios_linker_allocate()
+ *
+ * @entry : BIOS linker command entry which tells where to update ACPI table
+ *          checksums
+ * @return: 0 on success, or negative value on failure
+ */
+static int bios_linker_add_checksum(struct bios_linker_entry *entry)
+{
+	struct fw_file *file;
+	uint8_t *data, cksum = 0;
+	uint8_t *cksum_start;
+
+	file = qemu_fwcfg_find_file(entry->cksum.file);
+	if (!file || !file->addr)
+		return -ENOENT;
+
+	data = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.offset));
+	cksum_start = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.start));
+	cksum = table_compute_checksum(cksum_start,
+				       le32_to_cpu(entry->cksum.length));
+	*data = cksum;
+
+	return 0;
+}
+
+unsigned install_e820_map(unsigned max_entries, struct e820entry *entries)
+{
+	entries[0].addr = 0;
+	entries[0].size = ISA_START_ADDRESS;
+	entries[0].type = E820_RAM;
+
+	entries[1].addr = ISA_START_ADDRESS;
+	entries[1].size = ISA_END_ADDRESS - ISA_START_ADDRESS;
+	entries[1].type = E820_RESERVED;
+
+	/*
+	 * since we use memalign(malloc) to allocate high memory for
+	 * storing ACPI tables, we need to reserve them in e820 tables,
+	 * otherwise kernel will reclaim them and data will be corrupted
+	 */
+	entries[2].addr = ISA_END_ADDRESS;
+	entries[2].size = gd->relocaddr - TOTAL_MALLOC_LEN - ISA_END_ADDRESS;
+	entries[2].type = E820_RAM;
+
+	/* for simplicity, reserve entire malloc space */
+	entries[3].addr = gd->relocaddr - TOTAL_MALLOC_LEN;
+	entries[3].size = TOTAL_MALLOC_LEN;
+	entries[3].type = E820_RESERVED;
+
+	entries[4].addr = gd->relocaddr;
+	entries[4].size = gd->ram_size - gd->relocaddr;
+	entries[4].type = E820_RESERVED;
+
+	entries[5].addr = CONFIG_PCIE_ECAM_BASE;
+	entries[5].size = CONFIG_PCIE_ECAM_SIZE;
+	entries[5].type = E820_RESERVED;
+
+	return 6;
+}
+
+/* This function loads and patches ACPI tables provided by QEMU */
+u32 write_acpi_tables(u32 addr)
+{
+	int i, ret = 0;
+	struct fw_file *file;
+	struct bios_linker_entry *table_loader;
+	struct bios_linker_entry *entry;
+	uint32_t size;
+
+	/* make sure fw_list is loaded */
+	ret = qemu_fwcfg_read_firmware_list();
+	if (ret) {
+		printf("error: can't read firmware file list\n");
+		return addr;
+	}
+
+	file = qemu_fwcfg_find_file("etc/table-loader");
+	if (!file) {
+		printf("error: can't find etc/table-loader\n");
+		return addr;
+	}
+
+	size = be32_to_cpu(file->cfg.size);
+	if ((size % sizeof(*entry)) != 0) {
+		printf("error: table-loader maybe corrupted\n");
+		return addr;
+	}
+
+	table_loader = malloc(size);
+	if (!table_loader) {
+		printf("error: no memory for table-loader\n");
+		return addr;
+	}
+
+	qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
+			      size, table_loader);
+
+	for (i = 0; i < (size / sizeof(*entry)); i++) {
+		entry = table_loader + i;
+		switch (le32_to_cpu(entry->command)) {
+		case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
+			ret = bios_linker_allocate(entry, &addr);
+			if (ret)
+				goto out;
+			break;
+		case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
+			ret = bios_linker_add_pointer(entry);
+			if (ret)
+				goto out;
+			break;
+		case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
+			ret = bios_linker_add_checksum(entry);
+			if (ret)
+				goto out;
+			break;
+		default:
+			break;
+		}
+	}
+
+out:
+	if (ret)
+		qemu_fwcfg_free_files();
+
+	free(table_loader);
+	return addr;
+}
diff --git a/arch/x86/cpu/qemu/cpu.c b/arch/x86/cpu/qemu/cpu.c
index a1b70c6..4d2989a 100644
--- a/arch/x86/cpu/qemu/cpu.c
+++ b/arch/x86/cpu/qemu/cpu.c
@@ -8,8 +8,8 @@ 
 #include <cpu.h>
 #include <dm.h>
 #include <errno.h>
+#include <qemu_fw_cfg.h>
 #include <asm/cpu.h>
-#include <asm/fw_cfg.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
diff --git a/arch/x86/cpu/qemu/fw_cfg.c b/arch/x86/cpu/qemu/fw_cfg.c
deleted file mode 100644
index 2e2794e..0000000
--- a/arch/x86/cpu/qemu/fw_cfg.c
+++ /dev/null
@@ -1,570 +0,0 @@ 
-/*
- * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#include <common.h>
-#include <command.h>
-#include <errno.h>
-#include <malloc.h>
-#include <asm/io.h>
-#include <asm/fw_cfg.h>
-#include <asm/tables.h>
-#include <asm/e820.h>
-#include <linux/list.h>
-#include <memalign.h>
-
-static bool fwcfg_present;
-static bool fwcfg_dma_present;
-
-static LIST_HEAD(fw_list);
-
-/* Read configuration item using fw_cfg PIO interface */
-static void qemu_fwcfg_read_entry_pio(uint16_t entry,
-		uint32_t size, void *address)
-{
-	uint32_t i = 0;
-	uint8_t *data = address;
-
-	/*
-	 * writting FW_CFG_INVALID will cause read operation to resume at
-	 * last offset, otherwise read will start at offset 0
-	 */
-	if (entry != FW_CFG_INVALID)
-		outw(entry, FW_CONTROL_PORT);
-	while (size--)
-		data[i++] = inb(FW_DATA_PORT);
-}
-
-/* Read configuration item using fw_cfg DMA interface */
-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);
-
-	/*
-	 * writting FW_CFG_INVALID will cause read operation to resume at
-	 * last offset, otherwise read will start at offset 0
-	 */
-	if (entry != FW_CFG_INVALID)
-		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)&dma), FW_DMA_PORT_HIGH);
-
-	while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR)
-		__asm__ __volatile__ ("pause");
-}
-
-static bool qemu_fwcfg_present(void)
-{
-	uint32_t qemu;
-
-	qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
-	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, &dma_enabled);
-	if (dma_enabled & FW_CFG_DMA_ENABLED)
-		return true;
-
-	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 -ENODEV;
-
-	qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus);
-
-	return le16_to_cpu(nb_cpus);
-}
-
-/*
- * This function prepares kernel for zboot. It loads kernel data
- * to 'load_addr', initrd to 'initrd_addr' and kernel command
- * line using qemu fw_cfg interface.
- */
-static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr)
-{
-	char *data_addr;
-	uint32_t setup_size, kernel_size, cmdline_size, initrd_size;
-
-	qemu_fwcfg_read_entry(FW_CFG_SETUP_SIZE, 4, &setup_size);
-	qemu_fwcfg_read_entry(FW_CFG_KERNEL_SIZE, 4, &kernel_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);
-
-	data_addr = initrd_addr;
-	qemu_fwcfg_read_entry(FW_CFG_INITRD_SIZE, 4, &initrd_size);
-	if (initrd_size == 0) {
-		printf("warning: no initrd available\n");
-	} else {
-		qemu_fwcfg_read_entry(FW_CFG_INITRD_DATA,
-				      le32_to_cpu(initrd_size), data_addr);
-		data_addr += le32_to_cpu(initrd_size);
-	}
-
-	qemu_fwcfg_read_entry(FW_CFG_CMDLINE_SIZE, 4, &cmdline_size);
-	if (cmdline_size) {
-		qemu_fwcfg_read_entry(FW_CFG_CMDLINE_DATA,
-				      le32_to_cpu(cmdline_size), data_addr);
-		/*
-		 * if kernel cmdline only contains '\0', (e.g. no -append
-		 * when invoking qemu), do not update bootargs
-		 */
-		if (*data_addr != '\0') {
-			if (setenv("bootargs", data_addr) < 0)
-				printf("warning: unable to change bootargs\n");
-		}
-	}
-
-	printf("loading kernel to address %p size %x", load_addr,
-	       le32_to_cpu(kernel_size));
-	if (initrd_size)
-		printf(" initrd %p size %x\n",
-		       initrd_addr,
-		       le32_to_cpu(initrd_size));
-	else
-		printf("\n");
-
-	return 0;
-}
-
-static int qemu_fwcfg_read_firmware_list(void)
-{
-	int i;
-	uint32_t count;
-	struct fw_file *file;
-	struct list_head *entry;
-
-	/* don't read it twice */
-	if (!list_empty(&fw_list))
-		return 0;
-
-	qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count);
-	if (!count)
-		return 0;
-
-	count = be32_to_cpu(count);
-	for (i = 0; i < count; i++) {
-		file = malloc(sizeof(*file));
-		if (!file) {
-			printf("error: allocating resource\n");
-			goto err;
-		}
-		qemu_fwcfg_read_entry(FW_CFG_INVALID,
-				      sizeof(struct fw_cfg_file), &file->cfg);
-		file->addr = 0;
-		list_add_tail(&file->list, &fw_list);
-	}
-
-	return 0;
-
-err:
-	list_for_each(entry, &fw_list) {
-		file = list_entry(entry, struct fw_file, list);
-		free(file);
-	}
-
-	return -ENOMEM;
-}
-
-#ifdef CONFIG_QEMU_ACPI_TABLE
-static struct fw_file *qemu_fwcfg_find_file(const char *name)
-{
-	struct list_head *entry;
-	struct fw_file *file;
-
-	list_for_each(entry, &fw_list) {
-		file = list_entry(entry, struct fw_file, list);
-		if (!strcmp(file->cfg.name, name))
-			return file;
-	}
-
-	return NULL;
-}
-
-/*
- * This function allocates memory for ACPI tables
- *
- * @entry : BIOS linker command entry which tells where to allocate memory
- *          (either high memory or low memory)
- * @addr  : The address that should be used for low memory allcation. If the
- *          memory allocation request is 'ZONE_HIGH' then this parameter will
- *          be ignored.
- * @return: 0 on success, or negative value on failure
- */
-static int bios_linker_allocate(struct bios_linker_entry *entry, u32 *addr)
-{
-	uint32_t size, align;
-	struct fw_file *file;
-	unsigned long aligned_addr;
-
-	align = le32_to_cpu(entry->alloc.align);
-	/* align must be power of 2 */
-	if (align & (align - 1)) {
-		printf("error: wrong alignment %u\n", align);
-		return -EINVAL;
-	}
-
-	file = qemu_fwcfg_find_file(entry->alloc.file);
-	if (!file) {
-		printf("error: can't find file %s\n", entry->alloc.file);
-		return -ENOENT;
-	}
-
-	size = be32_to_cpu(file->cfg.size);
-
-	/*
-	 * ZONE_HIGH means we need to allocate from high memory, since
-	 * malloc space is already at the end of RAM, so we directly use it.
-	 * If allocation zone is ZONE_FSEG, then we use the 'addr' passed
-	 * in which is low memory
-	 */
-	if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) {
-		aligned_addr = (unsigned long)memalign(align, size);
-		if (!aligned_addr) {
-			printf("error: allocating resource\n");
-			return -ENOMEM;
-		}
-	} else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) {
-		aligned_addr = ALIGN(*addr, align);
-	} else {
-		printf("error: invalid allocation zone\n");
-		return -EINVAL;
-	}
-
-	debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n",
-	      file->cfg.name, size, entry->alloc.zone, align, aligned_addr);
-
-	qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
-			      size, (void *)aligned_addr);
-	file->addr = aligned_addr;
-
-	/* adjust address for low memory allocation */
-	if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG)
-		*addr = (aligned_addr + size);
-
-	return 0;
-}
-
-/*
- * This function patches ACPI tables previously loaded
- * by bios_linker_allocate()
- *
- * @entry : BIOS linker command entry which tells how to patch
- *          ACPI tables
- * @return: 0 on success, or negative value on failure
- */
-static int bios_linker_add_pointer(struct bios_linker_entry *entry)
-{
-	struct fw_file *dest, *src;
-	uint32_t offset = le32_to_cpu(entry->pointer.offset);
-	uint64_t pointer = 0;
-
-	dest = qemu_fwcfg_find_file(entry->pointer.dest_file);
-	if (!dest || !dest->addr)
-		return -ENOENT;
-	src = qemu_fwcfg_find_file(entry->pointer.src_file);
-	if (!src || !src->addr)
-		return -ENOENT;
-
-	debug("bios_linker_add_pointer: dest->addr 0x%lx, src->addr 0x%lx, offset 0x%x size %u, 0x%llx\n",
-	      dest->addr, src->addr, offset, entry->pointer.size, pointer);
-
-	memcpy(&pointer, (char *)dest->addr + offset, entry->pointer.size);
-	pointer	= le64_to_cpu(pointer);
-	pointer += (unsigned long)src->addr;
-	pointer	= cpu_to_le64(pointer);
-	memcpy((char *)dest->addr + offset, &pointer, entry->pointer.size);
-
-	return 0;
-}
-
-/*
- * This function updates checksum fields of ACPI tables previously loaded
- * by bios_linker_allocate()
- *
- * @entry : BIOS linker command entry which tells where to update ACPI table
- *          checksums
- * @return: 0 on success, or negative value on failure
- */
-static int bios_linker_add_checksum(struct bios_linker_entry *entry)
-{
-	struct fw_file *file;
-	uint8_t *data, cksum = 0;
-	uint8_t *cksum_start;
-
-	file = qemu_fwcfg_find_file(entry->cksum.file);
-	if (!file || !file->addr)
-		return -ENOENT;
-
-	data = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.offset));
-	cksum_start = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.start));
-	cksum = table_compute_checksum(cksum_start,
-				       le32_to_cpu(entry->cksum.length));
-	*data = cksum;
-
-	return 0;
-}
-
-unsigned install_e820_map(unsigned max_entries, struct e820entry *entries)
-{
-	entries[0].addr = 0;
-	entries[0].size = ISA_START_ADDRESS;
-	entries[0].type = E820_RAM;
-
-	entries[1].addr = ISA_START_ADDRESS;
-	entries[1].size = ISA_END_ADDRESS - ISA_START_ADDRESS;
-	entries[1].type = E820_RESERVED;
-
-	/*
-	 * since we use memalign(malloc) to allocate high memory for
-	 * storing ACPI tables, we need to reserve them in e820 tables,
-	 * otherwise kernel will reclaim them and data will be corrupted
-	 */
-	entries[2].addr = ISA_END_ADDRESS;
-	entries[2].size = gd->relocaddr - TOTAL_MALLOC_LEN - ISA_END_ADDRESS;
-	entries[2].type = E820_RAM;
-
-	/* for simplicity, reserve entire malloc space */
-	entries[3].addr = gd->relocaddr - TOTAL_MALLOC_LEN;
-	entries[3].size = TOTAL_MALLOC_LEN;
-	entries[3].type = E820_RESERVED;
-
-	entries[4].addr = gd->relocaddr;
-	entries[4].size = gd->ram_size - gd->relocaddr;
-	entries[4].type = E820_RESERVED;
-
-	entries[5].addr = CONFIG_PCIE_ECAM_BASE;
-	entries[5].size = CONFIG_PCIE_ECAM_SIZE;
-	entries[5].type = E820_RESERVED;
-
-	return 6;
-}
-
-/* This function loads and patches ACPI tables provided by QEMU */
-u32 write_acpi_tables(u32 addr)
-{
-	int i, ret = 0;
-	struct fw_file *file;
-	struct bios_linker_entry *table_loader;
-	struct bios_linker_entry *entry;
-	uint32_t size;
-	struct list_head *list;
-
-	/* make sure fw_list is loaded */
-	ret = qemu_fwcfg_read_firmware_list();
-	if (ret) {
-		printf("error: can't read firmware file list\n");
-		return addr;
-	}
-
-	file = qemu_fwcfg_find_file("etc/table-loader");
-	if (!file) {
-		printf("error: can't find etc/table-loader\n");
-		return addr;
-	}
-
-	size = be32_to_cpu(file->cfg.size);
-	if ((size % sizeof(*entry)) != 0) {
-		printf("error: table-loader maybe corrupted\n");
-		return addr;
-	}
-
-	table_loader = malloc(size);
-	if (!table_loader) {
-		printf("error: no memory for table-loader\n");
-		return addr;
-	}
-
-	qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
-			      size, table_loader);
-
-	for (i = 0; i < (size / sizeof(*entry)); i++) {
-		entry = table_loader + i;
-		switch (le32_to_cpu(entry->command)) {
-		case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
-			ret = bios_linker_allocate(entry, &addr);
-			if (ret)
-				goto out;
-			break;
-		case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
-			ret = bios_linker_add_pointer(entry);
-			if (ret)
-				goto out;
-			break;
-		case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
-			ret = bios_linker_add_checksum(entry);
-			if (ret)
-				goto out;
-			break;
-		default:
-			break;
-		}
-	}
-
-out:
-	if (ret) {
-		list_for_each(list, &fw_list) {
-			file = list_entry(list, struct fw_file, list);
-			if (file->addr)
-				free((void *)file->addr);
-		}
-	}
-
-	free(table_loader);
-	return addr;
-}
-#endif
-
-static int qemu_fwcfg_list_firmware(void)
-{
-	int ret;
-	struct list_head *entry;
-	struct fw_file *file;
-
-	/* make sure fw_list is loaded */
-	ret = qemu_fwcfg_read_firmware_list();
-	if (ret)
-		return ret;
-
-	list_for_each(entry, &fw_list) {
-		file = list_entry(entry, struct fw_file, list);
-		printf("%-56s\n", file->cfg.name);
-	}
-
-	return 0;
-}
-
-void qemu_fwcfg_init(void)
-{
-	fwcfg_present = qemu_fwcfg_present();
-	if (fwcfg_present)
-		fwcfg_dma_present = qemu_fwcfg_dma_present();
-}
-
-static int qemu_fwcfg_do_list(cmd_tbl_t *cmdtp, int flag,
-		int argc, char * const argv[])
-{
-	if (qemu_fwcfg_list_firmware() < 0)
-		return CMD_RET_FAILURE;
-
-	return 0;
-}
-
-static int qemu_fwcfg_do_cpus(cmd_tbl_t *cmdtp, int flag,
-		int argc, char * const argv[])
-{
-	int ret = qemu_fwcfg_online_cpus();
-	if (ret < 0) {
-		printf("QEMU fw_cfg interface not found\n");
-		return CMD_RET_FAILURE;
-	}
-
-	printf("%d cpu(s) online\n", qemu_fwcfg_online_cpus());
-
-	return 0;
-}
-
-static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag,
-		int argc, char * const argv[])
-{
-	char *env;
-	void *load_addr;
-	void *initrd_addr;
-
-	env = getenv("loadaddr");
-	load_addr = env ?
-		(void *)simple_strtoul(env, NULL, 16) :
-		(void *)CONFIG_LOADADDR;
-
-	env = getenv("ramdiskaddr");
-	initrd_addr = env ?
-		(void *)simple_strtoul(env, NULL, 16) :
-		(void *)CONFIG_RAMDISK_ADDR;
-
-	if (argc == 2) {
-		load_addr = (void *)simple_strtoul(argv[0], NULL, 16);
-		initrd_addr = (void *)simple_strtoul(argv[1], NULL, 16);
-	} else if (argc == 1) {
-		load_addr = (void *)simple_strtoul(argv[0], NULL, 16);
-	}
-
-	return qemu_fwcfg_setup_kernel(load_addr, initrd_addr);
-}
-
-static cmd_tbl_t fwcfg_commands[] = {
-	U_BOOT_CMD_MKENT(list, 0, 1, qemu_fwcfg_do_list, "", ""),
-	U_BOOT_CMD_MKENT(cpus, 0, 1, qemu_fwcfg_do_cpus, "", ""),
-	U_BOOT_CMD_MKENT(load, 2, 1, qemu_fwcfg_do_load, "", ""),
-};
-
-static int do_qemu_fw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-	int ret;
-	cmd_tbl_t *fwcfg_cmd;
-
-	if (!fwcfg_present) {
-		printf("QEMU fw_cfg interface not found\n");
-		return CMD_RET_USAGE;
-	}
-
-	fwcfg_cmd = find_cmd_tbl(argv[1], fwcfg_commands,
-				 ARRAY_SIZE(fwcfg_commands));
-	argc -= 2;
-	argv += 2;
-	if (!fwcfg_cmd || argc > fwcfg_cmd->maxargs)
-		return CMD_RET_USAGE;
-
-	ret = fwcfg_cmd->cmd(fwcfg_cmd, flag, argc, argv);
-
-	return cmd_process_error(fwcfg_cmd, ret);
-}
-
-U_BOOT_CMD(
-	qfw,	4,	1,	do_qemu_fw,
-	"QEMU firmware interface",
-	"<command>\n"
-	"    - list                             : print firmware(s) currently loaded\n"
-	"    - cpus                             : print online cpu number\n"
-	"    - load <kernel addr> <initrd addr> : load kernel and initrd (if any), and setup for zboot\n"
-)
diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c
index 7ad0ee4..b41e4ec 100644
--- a/arch/x86/cpu/qemu/qemu.c
+++ b/arch/x86/cpu/qemu/qemu.c
@@ -6,12 +6,12 @@ 
 
 #include <common.h>
 #include <pci.h>
+#include <qemu_fw_cfg.h>
 #include <asm/irq.h>
 #include <asm/post.h>
 #include <asm/processor.h>
 #include <asm/arch/device.h>
 #include <asm/arch/qemu.h>
-#include <asm/fw_cfg.h>
 
 static bool i440fx;
 
diff --git a/arch/x86/include/asm/fw_cfg.h b/arch/x86/include/asm/fw_cfg.h
deleted file mode 100644
index e9450c6..0000000
--- a/arch/x86/include/asm/fw_cfg.h
+++ /dev/null
@@ -1,157 +0,0 @@ 
-/*
- * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#ifndef __FW_CFG__
-#define __FW_CFG__
-
-#define FW_CONTROL_PORT	0x510
-#define FW_DATA_PORT		0x511
-#define FW_DMA_PORT_LOW	0x514
-#define FW_DMA_PORT_HIGH	0x518
-
-#include <linux/list.h>
-
-enum qemu_fwcfg_items {
-	FW_CFG_SIGNATURE	= 0x00,
-	FW_CFG_ID		= 0x01,
-	FW_CFG_UUID		= 0x02,
-	FW_CFG_RAM_SIZE		= 0x03,
-	FW_CFG_NOGRAPHIC	= 0x04,
-	FW_CFG_NB_CPUS		= 0x05,
-	FW_CFG_MACHINE_ID	= 0x06,
-	FW_CFG_KERNEL_ADDR	= 0x07,
-	FW_CFG_KERNEL_SIZE	= 0x08,
-	FW_CFG_KERNEL_CMDLINE   = 0x09,
-	FW_CFG_INITRD_ADDR	= 0x0a,
-	FW_CFG_INITRD_SIZE	= 0x0b,
-	FW_CFG_BOOT_DEVICE	= 0x0c,
-	FW_CFG_NUMA		= 0x0d,
-	FW_CFG_BOOT_MENU	= 0x0e,
-	FW_CFG_MAX_CPUS		= 0x0f,
-	FW_CFG_KERNEL_ENTRY	= 0x10,
-	FW_CFG_KERNEL_DATA	= 0x11,
-	FW_CFG_INITRD_DATA	= 0x12,
-	FW_CFG_CMDLINE_ADDR	= 0x13,
-	FW_CFG_CMDLINE_SIZE	= 0x14,
-	FW_CFG_CMDLINE_DATA	= 0x15,
-	FW_CFG_SETUP_ADDR	= 0x16,
-	FW_CFG_SETUP_SIZE	= 0x17,
-	FW_CFG_SETUP_DATA	= 0x18,
-	FW_CFG_FILE_DIR		= 0x19,
-	FW_CFG_FILE_FIRST	= 0x20,
-	FW_CFG_WRITE_CHANNEL	= 0x4000,
-	FW_CFG_ARCH_LOCAL	= 0x8000,
-	FW_CFG_INVALID		= 0xffff,
-};
-
-enum {
-	BIOS_LINKER_LOADER_COMMAND_ALLOCATE	= 0x1,
-	BIOS_LINKER_LOADER_COMMAND_ADD_POINTER  = 0x2,
-	BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
-};
-
-enum {
-	BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1,
-	BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2,
-};
-
-#define FW_CFG_FILE_SLOTS	0x10
-#define FW_CFG_MAX_ENTRY	(FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS)
-#define FW_CFG_ENTRY_MASK	 ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL)
-
-#define FW_CFG_MAX_FILE_PATH	56
-#define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH
-
-#define QEMU_FW_CFG_SIGNATURE	(('Q' << 24) | ('E' << 16) | ('M' << 8) | 'U')
-
-#define FW_CFG_DMA_ERROR	(1 << 0)
-#define FW_CFG_DMA_READ	(1 << 1)
-#define FW_CFG_DMA_SKIP	(1 << 2)
-#define FW_CFG_DMA_SELECT	(1 << 3)
-
-#define FW_CFG_DMA_ENABLED	(1 << 1)
-
-struct fw_cfg_file {
-	__be32 size;
-	__be16 select;
-	__be16 reserved;
-	char name[FW_CFG_MAX_FILE_PATH];
-};
-
-struct fw_file {
-	struct fw_cfg_file cfg; /* firmware file information */
-	unsigned long addr;     /* firmware file in-memory address */
-	struct list_head list;  /* list node to link to fw_list */
-};
-
-struct fw_cfg_dma_access {
-	__be32 control;
-	__be32 length;
-	__be64 address;
-};
-
-struct bios_linker_entry {
-	__le32 command;
-	union {
-		/*
-		 * COMMAND_ALLOCATE - allocate a table from @alloc.file
-		 * subject to @alloc.align alignment (must be power of 2)
-		 * and @alloc.zone (can be HIGH or FSEG) requirements.
-		 *
-		 * Must appear exactly once for each file, and before
-		 * this file is referenced by any other command.
-		 */
-		struct {
-			char file[BIOS_LINKER_LOADER_FILESZ];
-			__le32 align;
-			uint8_t zone;
-		} alloc;
-
-		/*
-		 * COMMAND_ADD_POINTER - patch the table (originating from
-		 * @dest_file) at @pointer.offset, by adding a pointer to the
-		 * table originating from @src_file. 1,2,4 or 8 byte unsigned
-		 * addition is used depending on @pointer.size.
-		 */
-		struct {
-			char dest_file[BIOS_LINKER_LOADER_FILESZ];
-			char src_file[BIOS_LINKER_LOADER_FILESZ];
-			__le32 offset;
-			uint8_t size;
-		} pointer;
-
-		/*
-		 * COMMAND_ADD_CHECKSUM - calculate checksum of the range
-		 * specified by @cksum_start and @cksum_length fields,
-		 * and then add the value at @cksum.offset.
-		 * Checksum simply sums -X for each byte X in the range
-		 * using 8-bit math.
-		 */
-		struct {
-			char file[BIOS_LINKER_LOADER_FILESZ];
-			__le32 offset;
-			__le32 start;
-			__le32 length;
-		} cksum;
-
-		/* padding */
-		char pad[124];
-	};
-} __packed;
-
-/**
- * Initialize QEMU fw_cfg interface
- */
-void qemu_fwcfg_init(void);
-
-/**
- * Get system cpu number
- *
- * @return:   cpu number in system
- */
-int qemu_fwcfg_online_cpus(void);
-
-#endif
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 790f6fb..bb4139a 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -333,7 +333,7 @@  static void acpi_create_ssdt_generator(acpi_header_t *ssdt,
 
 /*
  * QEMU's version of write_acpi_tables is defined in
- * arch/x86/cpu/qemu/fw_cfg.c
+ * arch/x86/cpu/qemu/acpi_table.c
  */
 u32 write_acpi_tables(u32 start)
 {
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 9336752..c0fffe3 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -593,6 +593,13 @@  config CMD_SOUND
 	     sound init   - set up sound system
 	     sound play   - play a sound
 
+config CMD_QEMU_FW_CFG
+	bool "qfw"
+	depends on X86
+	help
+	  This provides access to the QEMU firmware interface.  The main
+	  feature is to allow easy loading of files passed to qemu-system
+	  via -kernel / -initrd
 endmenu
 
 config CMD_BOOTSTAGE
diff --git a/cmd/Makefile b/cmd/Makefile
index f95759e..f99e67d 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -105,6 +105,7 @@  endif
 obj-y += pcmcia.o
 obj-$(CONFIG_CMD_PORTIO) += portio.o
 obj-$(CONFIG_CMD_PXE) += pxe.o
+obj-$(CONFIG_CMD_QEMU_FW_CFG) += qemu_fw_cfg.o
 obj-$(CONFIG_CMD_READ) += read.o
 obj-$(CONFIG_CMD_REGINFO) += reginfo.o
 obj-$(CONFIG_CMD_REISER) += reiser.o
diff --git a/cmd/qemu_fw_cfg.c b/cmd/qemu_fw_cfg.c
new file mode 100644
index 0000000..48ae476
--- /dev/null
+++ b/cmd/qemu_fw_cfg.c
@@ -0,0 +1,343 @@ 
+/*
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <malloc.h>
+#include <qemu_fw_cfg.h>
+#include <asm/io.h>
+#include <linux/list.h>
+
+static bool fwcfg_present;
+static bool fwcfg_dma_present;
+
+static LIST_HEAD(fw_list);
+
+/* Read configuration item using fw_cfg PIO interface */
+static void qemu_fwcfg_read_entry_pio(uint16_t entry,
+		uint32_t size, void *address)
+{
+	uint32_t i = 0;
+	uint8_t *data = address;
+
+	/*
+	 * writting FW_CFG_INVALID will cause read operation to resume at
+	 * last offset, otherwise read will start at offset 0
+	 */
+	if (entry != FW_CFG_INVALID)
+		outw(entry, FW_CONTROL_PORT);
+	while (size--)
+		data[i++] = inb(FW_DATA_PORT);
+}
+
+/* Read configuration item using fw_cfg DMA interface */
+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);
+
+	/*
+	 * writting FW_CFG_INVALID will cause read operation to resume at
+	 * last offset, otherwise read will start at offset 0
+	 */
+	if (entry != FW_CFG_INVALID)
+		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)&dma), FW_DMA_PORT_HIGH);
+
+	while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR)
+		__asm__ __volatile__ ("pause");
+}
+
+static bool qemu_fwcfg_present(void)
+{
+	uint32_t qemu;
+
+	qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
+	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, &dma_enabled);
+	if (dma_enabled & FW_CFG_DMA_ENABLED)
+		return true;
+
+	return false;
+}
+
+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 -ENODEV;
+
+	qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus);
+
+	return le16_to_cpu(nb_cpus);
+}
+
+/*
+ * This function prepares kernel for zboot. It loads kernel data
+ * to 'load_addr', initrd to 'initrd_addr' and kernel command
+ * line using qemu fw_cfg interface.
+ */
+static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr)
+{
+	char *data_addr;
+	uint32_t setup_size, kernel_size, cmdline_size, initrd_size;
+
+	qemu_fwcfg_read_entry(FW_CFG_SETUP_SIZE, 4, &setup_size);
+	qemu_fwcfg_read_entry(FW_CFG_KERNEL_SIZE, 4, &kernel_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);
+
+	data_addr = initrd_addr;
+	qemu_fwcfg_read_entry(FW_CFG_INITRD_SIZE, 4, &initrd_size);
+	if (initrd_size == 0) {
+		printf("warning: no initrd available\n");
+	} else {
+		qemu_fwcfg_read_entry(FW_CFG_INITRD_DATA,
+				      le32_to_cpu(initrd_size), data_addr);
+		data_addr += le32_to_cpu(initrd_size);
+	}
+
+	qemu_fwcfg_read_entry(FW_CFG_CMDLINE_SIZE, 4, &cmdline_size);
+	if (cmdline_size) {
+		qemu_fwcfg_read_entry(FW_CFG_CMDLINE_DATA,
+				      le32_to_cpu(cmdline_size), data_addr);
+		/*
+		 * if kernel cmdline only contains '\0', (e.g. no -append
+		 * when invoking qemu), do not update bootargs
+		 */
+		if (*data_addr != '\0') {
+			if (setenv("bootargs", data_addr) < 0)
+				printf("warning: unable to change bootargs\n");
+		}
+	}
+
+	printf("loading kernel to address %p size %x", load_addr,
+	       le32_to_cpu(kernel_size));
+	if (initrd_size)
+		printf(" initrd %p size %x\n",
+		       initrd_addr,
+		       le32_to_cpu(initrd_size));
+	else
+		printf("\n");
+
+	return 0;
+}
+
+int qemu_fwcfg_read_firmware_list(void)
+{
+	int i;
+	uint32_t count;
+	struct fw_file *file;
+	struct list_head *entry;
+
+	/* don't read it twice */
+	if (!list_empty(&fw_list))
+		return 0;
+
+	qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count);
+	if (!count)
+		return 0;
+
+	count = be32_to_cpu(count);
+	for (i = 0; i < count; i++) {
+		file = malloc(sizeof(*file));
+		if (!file) {
+			printf("error: allocating resource\n");
+			goto err;
+		}
+		qemu_fwcfg_read_entry(FW_CFG_INVALID,
+				      sizeof(struct fw_cfg_file), &file->cfg);
+		file->addr = 0;
+		list_add_tail(&file->list, &fw_list);
+	}
+
+	return 0;
+
+err:
+	list_for_each(entry, &fw_list) {
+		file = list_entry(entry, struct fw_file, list);
+		free(file);
+	}
+
+	return -ENOMEM;
+}
+
+struct fw_file *qemu_fwcfg_find_file(const char *name)
+{
+	struct list_head *entry;
+	struct fw_file *file;
+
+	list_for_each(entry, &fw_list) {
+		file = list_entry(entry, struct fw_file, list);
+		if (!strcmp(file->cfg.name, name))
+			return file;
+	}
+
+	return NULL;
+}
+
+void qemu_fwcfg_free_files(void)
+{
+	struct fw_file *file;
+	struct list_head *list;
+
+	list_for_each(list, &fw_list) {
+		file = list_entry(list, struct fw_file, list);
+		if (file->addr)
+			free((void *)file->addr);
+	}
+}
+
+static int qemu_fwcfg_list_firmware(void)
+{
+	int ret;
+	struct list_head *entry;
+	struct fw_file *file;
+
+	/* make sure fw_list is loaded */
+	ret = qemu_fwcfg_read_firmware_list();
+	if (ret)
+		return ret;
+
+	list_for_each(entry, &fw_list) {
+		file = list_entry(entry, struct fw_file, list);
+		printf("%-56s\n", file->cfg.name);
+	}
+
+	return 0;
+}
+
+void qemu_fwcfg_init(void)
+{
+	fwcfg_present = qemu_fwcfg_present();
+	if (fwcfg_present)
+		fwcfg_dma_present = qemu_fwcfg_dma_present();
+}
+
+static int qemu_fwcfg_do_list(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	if (qemu_fwcfg_list_firmware() < 0)
+		return CMD_RET_FAILURE;
+
+	return 0;
+}
+
+static int qemu_fwcfg_do_cpus(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	int ret = qemu_fwcfg_online_cpus();
+	if (ret < 0) {
+		printf("QEMU fw_cfg interface not found\n");
+		return CMD_RET_FAILURE;
+	}
+
+	printf("%d cpu(s) online\n", qemu_fwcfg_online_cpus());
+
+	return 0;
+}
+
+static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	char *env;
+	void *load_addr;
+	void *initrd_addr;
+
+	env = getenv("loadaddr");
+	load_addr = env ?
+		(void *)simple_strtoul(env, NULL, 16) :
+		(void *)CONFIG_LOADADDR;
+
+	env = getenv("ramdiskaddr");
+	initrd_addr = env ?
+		(void *)simple_strtoul(env, NULL, 16) :
+		(void *)CONFIG_RAMDISK_ADDR;
+
+	if (argc == 2) {
+		load_addr = (void *)simple_strtoul(argv[0], NULL, 16);
+		initrd_addr = (void *)simple_strtoul(argv[1], NULL, 16);
+	} else if (argc == 1) {
+		load_addr = (void *)simple_strtoul(argv[0], NULL, 16);
+	}
+
+	return qemu_fwcfg_setup_kernel(load_addr, initrd_addr);
+}
+
+static cmd_tbl_t fwcfg_commands[] = {
+	U_BOOT_CMD_MKENT(list, 0, 1, qemu_fwcfg_do_list, "", ""),
+	U_BOOT_CMD_MKENT(cpus, 0, 1, qemu_fwcfg_do_cpus, "", ""),
+	U_BOOT_CMD_MKENT(load, 2, 1, qemu_fwcfg_do_load, "", ""),
+};
+
+static int do_qemu_fw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int ret;
+	cmd_tbl_t *fwcfg_cmd;
+
+	if (!fwcfg_present) {
+		printf("QEMU fw_cfg interface not found\n");
+		return CMD_RET_USAGE;
+	}
+
+	fwcfg_cmd = find_cmd_tbl(argv[1], fwcfg_commands,
+				 ARRAY_SIZE(fwcfg_commands));
+	argc -= 2;
+	argv += 2;
+	if (!fwcfg_cmd || argc > fwcfg_cmd->maxargs)
+		return CMD_RET_USAGE;
+
+	ret = fwcfg_cmd->cmd(fwcfg_cmd, flag, argc, argv);
+
+	return cmd_process_error(fwcfg_cmd, ret);
+}
+
+U_BOOT_CMD(
+	qfw,	4,	1,	do_qemu_fw,
+	"QEMU firmware interface",
+	"<command>\n"
+	"    - list                             : print firmware(s) currently loaded\n"
+	"    - cpus                             : print online cpu number\n"
+	"    - load <kernel addr> <initrd addr> : load kernel and initrd (if any), and setup for zboot\n"
+)
diff --git a/configs/qemu-x86_defconfig b/configs/qemu-x86_defconfig
index 53b1ff6..a813e5b 100644
--- a/configs/qemu-x86_defconfig
+++ b/configs/qemu-x86_defconfig
@@ -20,6 +20,7 @@  CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
+CONFIG_CMD_QEMU_FW_CFG=y
 CONFIG_CMD_BOOTSTAGE=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
diff --git a/include/qemu_fw_cfg.h b/include/qemu_fw_cfg.h
new file mode 100644
index 0000000..e21f150
--- /dev/null
+++ b/include/qemu_fw_cfg.h
@@ -0,0 +1,162 @@ 
+/*
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __FW_CFG__
+#define __FW_CFG__
+
+#define FW_CONTROL_PORT	0x510
+#define FW_DATA_PORT		0x511
+#define FW_DMA_PORT_LOW	0x514
+#define FW_DMA_PORT_HIGH	0x518
+
+#include <linux/list.h>
+
+enum qemu_fwcfg_items {
+	FW_CFG_SIGNATURE	= 0x00,
+	FW_CFG_ID		= 0x01,
+	FW_CFG_UUID		= 0x02,
+	FW_CFG_RAM_SIZE		= 0x03,
+	FW_CFG_NOGRAPHIC	= 0x04,
+	FW_CFG_NB_CPUS		= 0x05,
+	FW_CFG_MACHINE_ID	= 0x06,
+	FW_CFG_KERNEL_ADDR	= 0x07,
+	FW_CFG_KERNEL_SIZE	= 0x08,
+	FW_CFG_KERNEL_CMDLINE   = 0x09,
+	FW_CFG_INITRD_ADDR	= 0x0a,
+	FW_CFG_INITRD_SIZE	= 0x0b,
+	FW_CFG_BOOT_DEVICE	= 0x0c,
+	FW_CFG_NUMA		= 0x0d,
+	FW_CFG_BOOT_MENU	= 0x0e,
+	FW_CFG_MAX_CPUS		= 0x0f,
+	FW_CFG_KERNEL_ENTRY	= 0x10,
+	FW_CFG_KERNEL_DATA	= 0x11,
+	FW_CFG_INITRD_DATA	= 0x12,
+	FW_CFG_CMDLINE_ADDR	= 0x13,
+	FW_CFG_CMDLINE_SIZE	= 0x14,
+	FW_CFG_CMDLINE_DATA	= 0x15,
+	FW_CFG_SETUP_ADDR	= 0x16,
+	FW_CFG_SETUP_SIZE	= 0x17,
+	FW_CFG_SETUP_DATA	= 0x18,
+	FW_CFG_FILE_DIR		= 0x19,
+	FW_CFG_FILE_FIRST	= 0x20,
+	FW_CFG_WRITE_CHANNEL	= 0x4000,
+	FW_CFG_ARCH_LOCAL	= 0x8000,
+	FW_CFG_INVALID		= 0xffff,
+};
+
+enum {
+	BIOS_LINKER_LOADER_COMMAND_ALLOCATE	= 0x1,
+	BIOS_LINKER_LOADER_COMMAND_ADD_POINTER  = 0x2,
+	BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
+};
+
+enum {
+	BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1,
+	BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2,
+};
+
+#define FW_CFG_FILE_SLOTS	0x10
+#define FW_CFG_MAX_ENTRY	(FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS)
+#define FW_CFG_ENTRY_MASK	 ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL)
+
+#define FW_CFG_MAX_FILE_PATH	56
+#define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH
+
+#define QEMU_FW_CFG_SIGNATURE	(('Q' << 24) | ('E' << 16) | ('M' << 8) | 'U')
+
+#define FW_CFG_DMA_ERROR	(1 << 0)
+#define FW_CFG_DMA_READ	(1 << 1)
+#define FW_CFG_DMA_SKIP	(1 << 2)
+#define FW_CFG_DMA_SELECT	(1 << 3)
+
+#define FW_CFG_DMA_ENABLED	(1 << 1)
+
+struct fw_cfg_file {
+	__be32 size;
+	__be16 select;
+	__be16 reserved;
+	char name[FW_CFG_MAX_FILE_PATH];
+};
+
+struct fw_file {
+	struct fw_cfg_file cfg; /* firmware file information */
+	unsigned long addr;     /* firmware file in-memory address */
+	struct list_head list;  /* list node to link to fw_list */
+};
+
+struct fw_cfg_dma_access {
+	__be32 control;
+	__be32 length;
+	__be64 address;
+};
+
+struct bios_linker_entry {
+	__le32 command;
+	union {
+		/*
+		 * COMMAND_ALLOCATE - allocate a table from @alloc.file
+		 * subject to @alloc.align alignment (must be power of 2)
+		 * and @alloc.zone (can be HIGH or FSEG) requirements.
+		 *
+		 * Must appear exactly once for each file, and before
+		 * this file is referenced by any other command.
+		 */
+		struct {
+			char file[BIOS_LINKER_LOADER_FILESZ];
+			__le32 align;
+			uint8_t zone;
+		} alloc;
+
+		/*
+		 * COMMAND_ADD_POINTER - patch the table (originating from
+		 * @dest_file) at @pointer.offset, by adding a pointer to the
+		 * table originating from @src_file. 1,2,4 or 8 byte unsigned
+		 * addition is used depending on @pointer.size.
+		 */
+		struct {
+			char dest_file[BIOS_LINKER_LOADER_FILESZ];
+			char src_file[BIOS_LINKER_LOADER_FILESZ];
+			__le32 offset;
+			uint8_t size;
+		} pointer;
+
+		/*
+		 * COMMAND_ADD_CHECKSUM - calculate checksum of the range
+		 * specified by @cksum_start and @cksum_length fields,
+		 * and then add the value at @cksum.offset.
+		 * Checksum simply sums -X for each byte X in the range
+		 * using 8-bit math.
+		 */
+		struct {
+			char file[BIOS_LINKER_LOADER_FILESZ];
+			__le32 offset;
+			__le32 start;
+			__le32 length;
+		} cksum;
+
+		/* padding */
+		char pad[124];
+	};
+} __packed;
+
+/**
+ * Initialize QEMU fw_cfg interface
+ */
+void qemu_fwcfg_init(void);
+
+void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address);
+int qemu_fwcfg_read_firmware_list(void);
+struct fw_file *qemu_fwcfg_find_file(const char *name);
+void qemu_fwcfg_free_files(void);
+
+/**
+ * Get system cpu number
+ *
+ * @return:   cpu number in system
+ */
+int qemu_fwcfg_online_cpus(void);
+
+#endif