[U-Boot] [PATCH 00/12] cleanup QEMU fw_cfg code

This patchset cleans the QEMU fw_cfg code:
*) split qfw core and qfw command interface *) split x86 specific operations from qfw core *) move x86 ACPI generation code into qfw core as this can also be used by others like ARM64 *) various cleanups
Miao Yan (12): x86: qemu: fix ACPI Kconfig options cmd: qfw: add API to iterate firmware list cmd: qfw: remove qemu_fwcfg_free_files() cmd: qfw: make fwcfg_present and fwcfg_dma_present public x86: qemu: split qfw command interface and qfw core x86: qemu: move x86 specific operations out of qfw core x86: qemu: add comment about qfw register endianness cmd: qfw: rename qemu_fw_cfg.[c|h] to qfw.[c|h] cmd: qfw: workaround qfw build issue cmd: qfw: do not depend on x86 cmd: qfw: bring ACPI generation code into qfw core x86: qemu: rename qemu/acpi_table.c
arch/x86/Kconfig | 10 +- arch/x86/cpu/mp_init.c | 8 +- arch/x86/cpu/qemu/Makefile | 4 +- arch/x86/cpu/qemu/acpi_table.c | 243 -------------------------- arch/x86/cpu/qemu/cpu.c | 2 +- arch/x86/cpu/qemu/e820.c | 43 +++++ arch/x86/cpu/qemu/qemu.c | 52 +++++- arch/x86/lib/Makefile | 2 +- cmd/Kconfig | 2 +- cmd/Makefile | 2 +- cmd/cmd_qfw.c | 195 +++++++++++++++++++++ cmd/qemu_fw_cfg.c | 343 ------------------------------------ common/Kconfig | 1 + drivers/misc/Kconfig | 6 + drivers/misc/Makefile | 1 + drivers/misc/qfw.c | 387 +++++++++++++++++++++++++++++++++++++++++ include/qemu_fw_cfg.h | 162 ----------------- include/qfw.h | 176 +++++++++++++++++++ 18 files changed, 871 insertions(+), 768 deletions(-) delete mode 100644 arch/x86/cpu/qemu/acpi_table.c create mode 100644 arch/x86/cpu/qemu/e820.c create mode 100644 cmd/cmd_qfw.c delete mode 100644 cmd/qemu_fw_cfg.c create mode 100644 drivers/misc/qfw.c delete mode 100644 include/qemu_fw_cfg.h create mode 100644 include/qfw.h

CONFIG_GENENRATE_ACPI_TABLE controls the generation of ACPI table which uses U-Boot's built-in methods and CONFIG_QEMU_ACPI_TABLE controls whether to load ACPI table from QEMU's fw_cfg interface.
But with commit "697ec431469ce0a4c2fc2c02d8685d907491af84 x86: qemu: Drop our own ACPI implementation", there is only one way to support ACPI table for QEMU targets which is the fw_cfg interface. Having two Kconfig options for this purpose is not necessary any more, so this patch consolidates the two.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- arch/x86/Kconfig | 10 +--------- arch/x86/cpu/qemu/Makefile | 2 +- arch/x86/lib/Makefile | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4ef27dc..a60e0da 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -436,21 +436,13 @@ config GENERATE_MP_TABLE config GENERATE_ACPI_TABLE bool "Generate an ACPI (Advanced Configuration and Power Interface) table" default n + select QEMU_FW_CFG if QEMU help The Advanced Configuration and Power Interface (ACPI) specification provides an open standard for device configuration and management by the operating system. It defines platform-independent interfaces for configuration and power management monitoring.
-config QEMU_ACPI_TABLE - bool "Load ACPI table from QEMU fw_cfg interface" - depends on GENERATE_ACPI_TABLE && QEMU - default y - help - By default, U-Boot generates its own ACPI tables. This option, if - enabled, disables U-Boot's version and loads ACPI tables generated - by QEMU. - config GENERATE_SMBIOS_TABLE bool "Generate an SMBIOS (System Management BIOS) table" default y diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 97b965c..43ee4bd 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,4 +8,4 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += cpu.o qemu.o -obj-$(CONFIG_QEMU_ACPI_TABLE) += acpi_table.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index dc90df2..ce5eb82 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sfi.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += smbios.o obj-y += string.o -ifndef CONFIG_QEMU_ACPI_TABLE +ifndef CONFIG_QEMU obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o endif obj-y += tables.o

Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
CONFIG_GENENRATE_ACPI_TABLE controls the generation of ACPI table which uses U-Boot's built-in methods and CONFIG_QEMU_ACPI_TABLE controls whether to load ACPI table from QEMU's fw_cfg interface.
But with commit "697ec431469ce0a4c2fc2c02d8685d907491af84 x86: qemu: Drop our own ACPI implementation", there is only one way to support ACPI table for QEMU targets which is the fw_cfg interface. Having two Kconfig options for this purpose is not necessary any more, so this patch consolidates the two.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/Kconfig | 10 +--------- arch/x86/cpu/qemu/Makefile | 2 +- arch/x86/lib/Makefile | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4ef27dc..a60e0da 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -436,21 +436,13 @@ config GENERATE_MP_TABLE config GENERATE_ACPI_TABLE bool "Generate an ACPI (Advanced Configuration and Power Interface) table" default n
select QEMU_FW_CFG if QEMU
I think this should be CMD_QEMU_FW_CFG
help The Advanced Configuration and Power Interface (ACPI) specification provides an open standard for device configuration and management by the operating system. It defines platform-independent interfaces for configuration and power management monitoring.
-config QEMU_ACPI_TABLE
bool "Load ACPI table from QEMU fw_cfg interface"
depends on GENERATE_ACPI_TABLE && QEMU
default y
help
By default, U-Boot generates its own ACPI tables. This option, if
enabled, disables U-Boot's version and loads ACPI tables generated
by QEMU.
config GENERATE_SMBIOS_TABLE bool "Generate an SMBIOS (System Management BIOS) table" default y diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 97b965c..43ee4bd 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,4 +8,4 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += cpu.o qemu.o -obj-$(CONFIG_QEMU_ACPI_TABLE) += acpi_table.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index dc90df2..ce5eb82 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sfi.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += smbios.o obj-y += string.o -ifndef CONFIG_QEMU_ACPI_TABLE +ifndef CONFIG_QEMU obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o endif obj-y += tables.o --
Regards, Bin

Hi Bin,
2016-05-13 21:59 GMT+08:00 Bin Meng bmeng.cn@gmail.com:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
CONFIG_GENENRATE_ACPI_TABLE controls the generation of ACPI table which uses U-Boot's built-in methods and CONFIG_QEMU_ACPI_TABLE controls whether to load ACPI table from QEMU's fw_cfg interface.
But with commit "697ec431469ce0a4c2fc2c02d8685d907491af84 x86: qemu: Drop our own ACPI implementation", there is only one way to support ACPI table for QEMU targets which is the fw_cfg interface. Having two Kconfig options for this purpose is not necessary any more, so this patch consolidates the two.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/Kconfig | 10 +--------- arch/x86/cpu/qemu/Makefile | 2 +- arch/x86/lib/Makefile | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4ef27dc..a60e0da 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -436,21 +436,13 @@ config GENERATE_MP_TABLE config GENERATE_ACPI_TABLE bool "Generate an ACPI (Advanced Configuration and Power Interface) table" default n
select QEMU_FW_CFG if QEMU
I think this should be CMD_QEMU_FW_CFG
Yes, will fix this. Thanks.
Miao
help The Advanced Configuration and Power Interface (ACPI) specification provides an open standard for device configuration and management by the operating system. It defines platform-independent interfaces for configuration and power management monitoring.
-config QEMU_ACPI_TABLE
bool "Load ACPI table from QEMU fw_cfg interface"
depends on GENERATE_ACPI_TABLE && QEMU
default y
help
By default, U-Boot generates its own ACPI tables. This option, if
enabled, disables U-Boot's version and loads ACPI tables generated
by QEMU.
config GENERATE_SMBIOS_TABLE bool "Generate an SMBIOS (System Management BIOS) table" default y diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 97b965c..43ee4bd 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,4 +8,4 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += cpu.o qemu.o -obj-$(CONFIG_QEMU_ACPI_TABLE) += acpi_table.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index dc90df2..ce5eb82 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sfi.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += smbios.o obj-y += string.o -ifndef CONFIG_QEMU_ACPI_TABLE +ifndef CONFIG_QEMU obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o endif obj-y += tables.o --
Regards, Bin

This patch is part of the refactor work of qfw. It adds 3 APIs to qfw core to iterate firmware list.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- cmd/qemu_fw_cfg.c | 25 ++++++++++++++++++++++--- include/qemu_fw_cfg.h | 9 +++++++++ 2 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/cmd/qemu_fw_cfg.c b/cmd/qemu_fw_cfg.c index 48ae476..192b7d1 100644 --- a/cmd/qemu_fw_cfg.c +++ b/cmd/qemu_fw_cfg.c @@ -229,10 +229,27 @@ void qemu_fwcfg_free_files(void) } }
+struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) +{ + iter->entry = fw_list.next; + return list_entry(iter->entry, struct fw_file, list); +} + +struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) +{ + iter->entry = iter->entry->next; + return list_entry(iter->entry, struct fw_file, list); +} + +bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) +{ + return iter->entry == &fw_list; +} + static int qemu_fwcfg_list_firmware(void) { int ret; - struct list_head *entry; + struct fw_cfg_file_iter iter; struct fw_file *file;
/* make sure fw_list is loaded */ @@ -240,8 +257,10 @@ static int qemu_fwcfg_list_firmware(void) if (ret) return ret;
- list_for_each(entry, &fw_list) { - file = list_entry(entry, struct fw_file, list); + + for (file = qemu_fwcfg_file_iter_init(&iter); + !qemu_fwcfg_file_iter_end(&iter); + file = qemu_fwcfg_file_iter_next(&iter)) { printf("%-56s\n", file->cfg.name); }
diff --git a/include/qemu_fw_cfg.h b/include/qemu_fw_cfg.h index e21f150..19d0ba0 100644 --- a/include/qemu_fw_cfg.h +++ b/include/qemu_fw_cfg.h @@ -87,6 +87,10 @@ struct fw_file { struct list_head list; /* list node to link to fw_list */ };
+struct fw_cfg_file_iter { + struct list_head *entry; /* structure to iterate file list */ +}; + struct fw_cfg_dma_access { __be32 control; __be32 length; @@ -159,4 +163,9 @@ void qemu_fwcfg_free_files(void); */ int qemu_fwcfg_online_cpus(void);
+/* helper functions to iterate firmware file list */ +struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter); +struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter); +bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter); + #endif

On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch is part of the refactor work of qfw. It adds 3 APIs to qfw core to iterate firmware list.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
cmd/qemu_fw_cfg.c | 25 ++++++++++++++++++++++--- include/qemu_fw_cfg.h | 9 +++++++++ 2 files changed, 31 insertions(+), 3 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

This patch is part of the qfw refactor work.
The qemu_fwcfg_free_files() function is only used in error handling in ACPI table generation, let's not make this a core function and move it to the right place.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- arch/x86/cpu/qemu/acpi_table.c | 13 +++++++++++-- cmd/qemu_fw_cfg.c | 12 ------------ include/qemu_fw_cfg.h | 1 - 3 files changed, 11 insertions(+), 15 deletions(-)
diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c index 49381ac..b17fa03 100644 --- a/arch/x86/cpu/qemu/acpi_table.c +++ b/arch/x86/cpu/qemu/acpi_table.c @@ -235,8 +235,17 @@ u32 write_acpi_tables(u32 addr) }
out: - if (ret) - qemu_fwcfg_free_files(); + if (ret) { + struct fw_cfg_file_iter iter; + for (file = qemu_fwcfg_file_iter_init(&iter); + !qemu_fwcfg_file_iter_end(&iter); + file = qemu_fwcfg_file_iter_next(&iter)) { + if (file->addr) { + free((void *)file->addr); + file->addr = 0; + } + } + }
free(table_loader); return addr; diff --git a/cmd/qemu_fw_cfg.c b/cmd/qemu_fw_cfg.c index 192b7d1..9f03ab6 100644 --- a/cmd/qemu_fw_cfg.c +++ b/cmd/qemu_fw_cfg.c @@ -217,18 +217,6 @@ struct fw_file *qemu_fwcfg_find_file(const char *name) 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); - } -} - struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) { iter->entry = fw_list.next; diff --git a/include/qemu_fw_cfg.h b/include/qemu_fw_cfg.h index 19d0ba0..986f4b2 100644 --- a/include/qemu_fw_cfg.h +++ b/include/qemu_fw_cfg.h @@ -154,7 +154,6 @@ 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

Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch is part of the qfw refactor work.
The qemu_fwcfg_free_files() function is only used in error handling in ACPI table generation, let's not make this a core function and move it to the right place.
But I suspect this API may still be needed in some other scenarioes? eg: for future ARM64 ACPI?
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/cpu/qemu/acpi_table.c | 13 +++++++++++-- cmd/qemu_fw_cfg.c | 12 ------------ include/qemu_fw_cfg.h | 1 - 3 files changed, 11 insertions(+), 15 deletions(-)
diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c index 49381ac..b17fa03 100644 --- a/arch/x86/cpu/qemu/acpi_table.c +++ b/arch/x86/cpu/qemu/acpi_table.c @@ -235,8 +235,17 @@ u32 write_acpi_tables(u32 addr) }
out:
if (ret)
qemu_fwcfg_free_files();
if (ret) {
struct fw_cfg_file_iter iter;
for (file = qemu_fwcfg_file_iter_init(&iter);
!qemu_fwcfg_file_iter_end(&iter);
file = qemu_fwcfg_file_iter_next(&iter)) {
if (file->addr) {
free((void *)file->addr);
file->addr = 0;
}
}
} free(table_loader); return addr;
diff --git a/cmd/qemu_fw_cfg.c b/cmd/qemu_fw_cfg.c index 192b7d1..9f03ab6 100644 --- a/cmd/qemu_fw_cfg.c +++ b/cmd/qemu_fw_cfg.c @@ -217,18 +217,6 @@ struct fw_file *qemu_fwcfg_find_file(const char *name) 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);
}
-}
struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) { iter->entry = fw_list.next; diff --git a/include/qemu_fw_cfg.h b/include/qemu_fw_cfg.h index 19d0ba0..986f4b2 100644 --- a/include/qemu_fw_cfg.h +++ b/include/qemu_fw_cfg.h @@ -154,7 +154,6 @@ 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
--
Regards, Bin

On Fri, May 13, 2016 at 10:00:05PM +0800, Bin Meng wrote:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch is part of the qfw refactor work.
The qemu_fwcfg_free_files() function is only used in error handling in ACPI table generation, let's not make this a core function and move it to the right place.
But I suspect this API may still be needed in some other scenarioes? eg: for future ARM64 ACPI?
Yes, as it stands currently the code looks likely useful for non-x86 QEMU+ACPI.

2016-05-14 4:46 GMT+08:00 Tom Rini trini@konsulko.com:
On Fri, May 13, 2016 at 10:00:05PM +0800, Bin Meng wrote:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch is part of the qfw refactor work.
The qemu_fwcfg_free_files() function is only used in error handling in ACPI table generation, let's not make this a core function and move it to the right place.
But I suspect this API may still be needed in some other scenarioes? eg: for future ARM64 ACPI?
Yes, as it stands currently the code looks likely useful for non-x86 QEMU+ACPI.
ARM64 and x86 should be able to share common ACPI code. As for now, this function is not used anywhere but error handling in only one place. I'd prefer not to make this public.
Thanks, Miao
-- Tom

On Mon, May 16, 2016 at 05:47:43PM +0800, Miao Yan wrote:
2016-05-14 4:46 GMT+08:00 Tom Rini trini@konsulko.com:
On Fri, May 13, 2016 at 10:00:05PM +0800, Bin Meng wrote:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch is part of the qfw refactor work.
The qemu_fwcfg_free_files() function is only used in error handling in ACPI table generation, let's not make this a core function and move it to the right place.
But I suspect this API may still be needed in some other scenarioes? eg: for future ARM64 ACPI?
Yes, as it stands currently the code looks likely useful for non-x86 QEMU+ACPI.
ARM64 and x86 should be able to share common ACPI code. As for now, this function is not used anywhere but error handling in only one place. I'd prefer not to make this public.
Well, OK, I'm not going to argue too too hard here, but if someone duplicates this part of the qemu code since it wasn't in common, it's on you :)

This patch is part of the qfw refactor work. This patch makes qemu_fwcfg_present() and qemu_fwcfg_dma_present() public functions.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- cmd/qemu_fw_cfg.c | 37 ++++++++++++++++++++----------------- include/qemu_fw_cfg.h | 3 +++ 2 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/cmd/qemu_fw_cfg.c b/cmd/qemu_fw_cfg.c index 9f03ab6..aab6b1a 100644 --- a/cmd/qemu_fw_cfg.c +++ b/cmd/qemu_fw_cfg.c @@ -62,23 +62,14 @@ static void qemu_fwcfg_read_entry_dma(uint16_t entry, __asm__ __volatile__ ("pause"); }
-static bool qemu_fwcfg_present(void) +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; + return fwcfg_present; }
-static bool qemu_fwcfg_dma_present(void) +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; + return fwcfg_dma_present; }
void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address) @@ -257,9 +248,21 @@ static int qemu_fwcfg_list_firmware(void)
void qemu_fwcfg_init(void) { - fwcfg_present = qemu_fwcfg_present(); - if (fwcfg_present) - fwcfg_dma_present = qemu_fwcfg_dma_present(); + uint32_t qemu; + uint32_t dma_enabled; + + fwcfg_present = false; + fwcfg_dma_present = false; + + qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); + if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE) + fwcfg_present = true; + + if (fwcfg_present) { + qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled); + if (dma_enabled & FW_CFG_DMA_ENABLED) + fwcfg_dma_present = true; + } }
static int qemu_fwcfg_do_list(cmd_tbl_t *cmdtp, int flag, @@ -323,7 +326,7 @@ 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) { + if (!qemu_fwcfg_present()) { printf("QEMU fw_cfg interface not found\n"); return CMD_RET_USAGE; } diff --git a/include/qemu_fw_cfg.h b/include/qemu_fw_cfg.h index 986f4b2..f718e09 100644 --- a/include/qemu_fw_cfg.h +++ b/include/qemu_fw_cfg.h @@ -167,4 +167,7 @@ struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter); struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter); bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter);
+bool qemu_fwcfg_present(void); +bool qemu_fwcfg_dma_present(void); + #endif

On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch is part of the qfw refactor work. This patch makes qemu_fwcfg_present() and qemu_fwcfg_dma_present() public functions.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
cmd/qemu_fw_cfg.c | 37 ++++++++++++++++++++----------------- include/qemu_fw_cfg.h | 3 +++ 2 files changed, 23 insertions(+), 17 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

This patch splits qfw command interface and qfw core function into two files, and introduces a new Kconfig option (CONFIG_QFW). for qfw core.
Now when qfw command interface is enabled, it will automatically select qfw core. This patch also makes the ACPI table generation select CONFIG_QFW.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- arch/x86/Kconfig | 2 +- arch/x86/cpu/mp_init.c | 6 +- arch/x86/cpu/qemu/Makefile | 3 +- arch/x86/cpu/qemu/acpi_table.c | 2 + arch/x86/cpu/qemu/qemu.c | 4 + cmd/Kconfig | 1 + cmd/Makefile | 2 +- cmd/cmd_qfw.c | 182 +++++++++++++++++++++ cmd/qemu_fw_cfg.c | 353 ----------------------------------------- common/Kconfig | 1 + drivers/misc/Kconfig | 6 + drivers/misc/Makefile | 1 + drivers/misc/qemu_fw_cfg.c | 185 +++++++++++++++++++++ 13 files changed, 390 insertions(+), 358 deletions(-) create mode 100644 cmd/cmd_qfw.c delete mode 100644 cmd/qemu_fw_cfg.c create mode 100644 drivers/misc/qemu_fw_cfg.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a60e0da..2f63170 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -436,7 +436,7 @@ config GENERATE_MP_TABLE config GENERATE_ACPI_TABLE bool "Generate an ACPI (Advanced Configuration and Power Interface) table" default n - select QEMU_FW_CFG if QEMU + select QFW if QEMU help The Advanced Configuration and Power Interface (ACPI) specification provides an open standard for device configuration and management diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 13bec7a..109b3d7 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -11,7 +11,9 @@ #include <dm.h> #include <errno.h> #include <malloc.h> +#ifdef CONFIG_QFW #include <qemu_fw_cfg.h> +#endif #include <asm/atomic.h> #include <asm/cpu.h> #include <asm/interrupt.h> @@ -420,7 +422,7 @@ static int init_bsp(struct udevice **devp) return 0; }
-#ifdef CONFIG_QEMU +#ifdef CONFIG_QFW static int qemu_cpu_fixup(void) { int ret; @@ -496,7 +498,7 @@ int mp_init(struct mp_params *p) if (ret) return ret;
-#ifdef CONFIG_QEMU +#ifdef CONFIG_QFW ret = qemu_cpu_fixup(); if (ret) return ret; diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 43ee4bd..7c08c3d 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -7,5 +7,6 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif -obj-y += cpu.o qemu.o +obj-y += qemu.o +obj-$(CONFIG_QFW) += cpu.o obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c index b17fa03..4584fc7 100644 --- a/arch/x86/cpu/qemu/acpi_table.c +++ b/arch/x86/cpu/qemu/acpi_table.c @@ -8,7 +8,9 @@ #include <command.h> #include <errno.h> #include <malloc.h> +#ifdef CONFIG_QFW #include <qemu_fw_cfg.h> +#endif #include <asm/io.h> #include <asm/tables.h> #include <asm/e820.h> diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index b41e4ec..2631e99 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -6,7 +6,9 @@
#include <common.h> #include <pci.h> +#ifdef CONFIG_QFW #include <qemu_fw_cfg.h> +#endif #include <asm/irq.h> #include <asm/post.h> #include <asm/processor.h> @@ -88,7 +90,9 @@ static void qemu_chipset_init(void) enable_pm_ich9(); }
+#ifdef CONFIG_QFW qemu_fwcfg_init(); +#endif }
int arch_cpu_init(void) diff --git a/cmd/Kconfig b/cmd/Kconfig index c0fffe3..08b761f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -596,6 +596,7 @@ config CMD_SOUND config CMD_QEMU_FW_CFG bool "qfw" depends on X86 + select QFW help This provides access to the QEMU firmware interface. The main feature is to allow easy loading of files passed to qemu-system diff --git a/cmd/Makefile b/cmd/Makefile index f99e67d..31e4da7 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -105,7 +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_QEMU_FW_CFG) += cmd_qfw.o obj-$(CONFIG_CMD_READ) += read.o obj-$(CONFIG_CMD_REGINFO) += reginfo.o obj-$(CONFIG_CMD_REISER) += reiser.o diff --git a/cmd/cmd_qfw.c b/cmd/cmd_qfw.c new file mode 100644 index 0000000..eefaf65 --- /dev/null +++ b/cmd/cmd_qfw.c @@ -0,0 +1,182 @@ +/* + * (C) Copyright 2015 Miao Yan yanmiaobest@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <errno.h> +#include <qemu_fw_cfg.h> + +/* + * 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_list_firmware(void) +{ + int ret; + struct fw_cfg_file_iter iter; + struct fw_file *file; + + /* make sure fw_list is loaded */ + ret = qemu_fwcfg_read_firmware_list(); + if (ret) + return ret; + + + for (file = qemu_fwcfg_file_iter_init(&iter); + !qemu_fwcfg_file_iter_end(&iter); + file = qemu_fwcfg_file_iter_next(&iter)) { + printf("%-56s\n", file->cfg.name); + } + + return 0; +} + +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 (!qemu_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/cmd/qemu_fw_cfg.c b/cmd/qemu_fw_cfg.c deleted file mode 100644 index aab6b1a..0000000 --- a/cmd/qemu_fw_cfg.c +++ /dev/null @@ -1,353 +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 <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"); -} - -bool qemu_fwcfg_present(void) -{ - return fwcfg_present; -} - -bool qemu_fwcfg_dma_present(void) -{ - return fwcfg_dma_present; -} - -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; -} - -struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) -{ - iter->entry = fw_list.next; - return list_entry(iter->entry, struct fw_file, list); -} - -struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) -{ - iter->entry = iter->entry->next; - return list_entry(iter->entry, struct fw_file, list); -} - -bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) -{ - return iter->entry == &fw_list; -} - -static int qemu_fwcfg_list_firmware(void) -{ - int ret; - struct fw_cfg_file_iter iter; - struct fw_file *file; - - /* make sure fw_list is loaded */ - ret = qemu_fwcfg_read_firmware_list(); - if (ret) - return ret; - - - for (file = qemu_fwcfg_file_iter_init(&iter); - !qemu_fwcfg_file_iter_end(&iter); - file = qemu_fwcfg_file_iter_next(&iter)) { - printf("%-56s\n", file->cfg.name); - } - - return 0; -} - -void qemu_fwcfg_init(void) -{ - uint32_t qemu; - uint32_t dma_enabled; - - fwcfg_present = false; - fwcfg_dma_present = false; - - qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); - if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE) - fwcfg_present = true; - - if (fwcfg_present) { - qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled); - if (dma_enabled & FW_CFG_DMA_ENABLED) - fwcfg_dma_present = true; - } -} - -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 (!qemu_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/common/Kconfig b/common/Kconfig index 067545d..8ca5a68 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -124,3 +124,4 @@ config CONSOLE_RECORD_IN_SIZE tstc() and getc() will use this in preference to real device input. The buffer is allocated immediately after the malloc() region is ready. + diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index af8667f..fa53700 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -138,4 +138,10 @@ config WINBOND_W83627 legacy UART or other devices in the Winbond Super IO chips on X86 platforms.
+config QFW + bool + help + Hidden option to enable QEMU fw_cfg interface. This will be selected by + either CONFIG_CMD_QEMU_FW_CFG or CONFIG_GENERATE_ACPI_TABLE. + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5969d34..4893086 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_RESET) += reset-uclass.o obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o +obj-$(CONFIG_QFW) += qemu_fw_cfg.o diff --git a/drivers/misc/qemu_fw_cfg.c b/drivers/misc/qemu_fw_cfg.c new file mode 100644 index 0000000..e726059 --- /dev/null +++ b/drivers/misc/qemu_fw_cfg.c @@ -0,0 +1,185 @@ +/* + * (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"); +} + +bool qemu_fwcfg_present(void) +{ + return fwcfg_present; +} + +bool qemu_fwcfg_dma_present(void) +{ + return fwcfg_dma_present; +} + +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); +} + +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; +} + +struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) +{ + iter->entry = fw_list.next; + return list_entry((struct list_head *)iter->entry, + struct fw_file, list); +} + +struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) +{ + iter->entry = ((struct list_head *)iter->entry)->next; + return list_entry((struct list_head *)iter->entry, + struct fw_file, list); +} + +bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) +{ + return iter->entry == &fw_list; +} + +void qemu_fwcfg_init(void) +{ + uint32_t qemu; + uint32_t dma_enabled; + + fwcfg_present = false; + fwcfg_dma_present = false; + + qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); + if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE) + fwcfg_present = true; + + if (fwcfg_present) { + qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled); + if (dma_enabled & FW_CFG_DMA_ENABLED) + fwcfg_dma_present = true; + } +} +

Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch splits qfw command interface and qfw core function into two files, and introduces a new Kconfig option (CONFIG_QFW). for qfw core.
Now when qfw command interface is enabled, it will automatically select qfw core. This patch also makes the ACPI table generation select CONFIG_QFW.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/Kconfig | 2 +- arch/x86/cpu/mp_init.c | 6 +- arch/x86/cpu/qemu/Makefile | 3 +- arch/x86/cpu/qemu/acpi_table.c | 2 + arch/x86/cpu/qemu/qemu.c | 4 + cmd/Kconfig | 1 + cmd/Makefile | 2 +- cmd/cmd_qfw.c | 182 +++++++++++++++++++++ cmd/qemu_fw_cfg.c | 353 ----------------------------------------- common/Kconfig | 1 + drivers/misc/Kconfig | 6 + drivers/misc/Makefile | 1 + drivers/misc/qemu_fw_cfg.c | 185 +++++++++++++++++++++ 13 files changed, 390 insertions(+), 358 deletions(-) create mode 100644 cmd/cmd_qfw.c delete mode 100644 cmd/qemu_fw_cfg.c create mode 100644 drivers/misc/qemu_fw_cfg.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a60e0da..2f63170 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -436,7 +436,7 @@ config GENERATE_MP_TABLE config GENERATE_ACPI_TABLE bool "Generate an ACPI (Advanced Configuration and Power Interface) table" default n
select QEMU_FW_CFG if QEMU
select QFW if QEMU help The Advanced Configuration and Power Interface (ACPI) specification provides an open standard for device configuration and management
diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 13bec7a..109b3d7 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -11,7 +11,9 @@ #include <dm.h> #include <errno.h> #include <malloc.h> +#ifdef CONFIG_QFW #include <qemu_fw_cfg.h> +#endif
There is no need to wrap header file with #ifdef.
#include <asm/atomic.h> #include <asm/cpu.h> #include <asm/interrupt.h> @@ -420,7 +422,7 @@ static int init_bsp(struct udevice **devp) return 0; }
-#ifdef CONFIG_QEMU +#ifdef CONFIG_QFW static int qemu_cpu_fixup(void) { int ret; @@ -496,7 +498,7 @@ int mp_init(struct mp_params *p) if (ret) return ret;
-#ifdef CONFIG_QEMU +#ifdef CONFIG_QFW ret = qemu_cpu_fixup(); if (ret) return ret; diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 43ee4bd..7c08c3d 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -7,5 +7,6 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif -obj-y += cpu.o qemu.o +obj-y += qemu.o +obj-$(CONFIG_QFW) += cpu.o obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c index b17fa03..4584fc7 100644 --- a/arch/x86/cpu/qemu/acpi_table.c +++ b/arch/x86/cpu/qemu/acpi_table.c @@ -8,7 +8,9 @@ #include <command.h> #include <errno.h> #include <malloc.h> +#ifdef CONFIG_QFW #include <qemu_fw_cfg.h> +#endif
ditto.
#include <asm/io.h> #include <asm/tables.h> #include <asm/e820.h> diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index b41e4ec..2631e99 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -6,7 +6,9 @@
#include <common.h> #include <pci.h> +#ifdef CONFIG_QFW #include <qemu_fw_cfg.h> +#endif
ditto.
#include <asm/irq.h> #include <asm/post.h> #include <asm/processor.h> @@ -88,7 +90,9 @@ static void qemu_chipset_init(void) enable_pm_ich9(); }
+#ifdef CONFIG_QFW qemu_fwcfg_init(); +#endif }
int arch_cpu_init(void) diff --git a/cmd/Kconfig b/cmd/Kconfig index c0fffe3..08b761f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -596,6 +596,7 @@ config CMD_SOUND config CMD_QEMU_FW_CFG bool "qfw" depends on X86
select QFW help This provides access to the QEMU firmware interface. The main feature is to allow easy loading of files passed to qemu-system
diff --git a/cmd/Makefile b/cmd/Makefile index f99e67d..31e4da7 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -105,7 +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_QEMU_FW_CFG) += cmd_qfw.o obj-$(CONFIG_CMD_READ) += read.o obj-$(CONFIG_CMD_REGINFO) += reginfo.o obj-$(CONFIG_CMD_REISER) += reiser.o diff --git a/cmd/cmd_qfw.c b/cmd/cmd_qfw.c new file mode 100644 index 0000000..eefaf65 --- /dev/null +++ b/cmd/cmd_qfw.c @@ -0,0 +1,182 @@ +/*
- (C) Copyright 2015 Miao Yan yanmiaobest@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <command.h> +#include <errno.h> +#include <qemu_fw_cfg.h>
+/*
- 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_list_firmware(void) +{
int ret;
struct fw_cfg_file_iter iter;
struct fw_file *file;
/* make sure fw_list is loaded */
ret = qemu_fwcfg_read_firmware_list();
if (ret)
return ret;
for (file = qemu_fwcfg_file_iter_init(&iter);
!qemu_fwcfg_file_iter_end(&iter);
file = qemu_fwcfg_file_iter_next(&iter)) {
printf("%-56s\n", file->cfg.name);
}
return 0;
+}
+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 (!qemu_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/cmd/qemu_fw_cfg.c b/cmd/qemu_fw_cfg.c deleted file mode 100644 index aab6b1a..0000000 --- a/cmd/qemu_fw_cfg.c +++ /dev/null @@ -1,353 +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 <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");
-}
-bool qemu_fwcfg_present(void) -{
return fwcfg_present;
-}
-bool qemu_fwcfg_dma_present(void) -{
return fwcfg_dma_present;
-}
-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;
-}
-struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) -{
iter->entry = fw_list.next;
return list_entry(iter->entry, struct fw_file, list);
-}
-struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) -{
iter->entry = iter->entry->next;
return list_entry(iter->entry, struct fw_file, list);
-}
-bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) -{
return iter->entry == &fw_list;
-}
-static int qemu_fwcfg_list_firmware(void) -{
int ret;
struct fw_cfg_file_iter iter;
struct fw_file *file;
/* make sure fw_list is loaded */
ret = qemu_fwcfg_read_firmware_list();
if (ret)
return ret;
for (file = qemu_fwcfg_file_iter_init(&iter);
!qemu_fwcfg_file_iter_end(&iter);
file = qemu_fwcfg_file_iter_next(&iter)) {
printf("%-56s\n", file->cfg.name);
}
return 0;
-}
-void qemu_fwcfg_init(void) -{
uint32_t qemu;
uint32_t dma_enabled;
fwcfg_present = false;
fwcfg_dma_present = false;
qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE)
fwcfg_present = true;
if (fwcfg_present) {
qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
if (dma_enabled & FW_CFG_DMA_ENABLED)
fwcfg_dma_present = true;
}
-}
-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 (!qemu_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/common/Kconfig b/common/Kconfig index 067545d..8ca5a68 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -124,3 +124,4 @@ config CONSOLE_RECORD_IN_SIZE tstc() and getc() will use this in preference to real device input. The buffer is allocated immediately after the malloc() region is ready.
What is this for?
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index af8667f..fa53700 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -138,4 +138,10 @@ config WINBOND_W83627 legacy UART or other devices in the Winbond Super IO chips on X86 platforms.
+config QFW
bool
help
Hidden option to enable QEMU fw_cfg interface. This will be selected by
either CONFIG_CMD_QEMU_FW_CFG or CONFIG_GENERATE_ACPI_TABLE.
endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5969d34..4893086 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_RESET) += reset-uclass.o obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o +obj-$(CONFIG_QFW) += qemu_fw_cfg.o diff --git a/drivers/misc/qemu_fw_cfg.c b/drivers/misc/qemu_fw_cfg.c new file mode 100644 index 0000000..e726059 --- /dev/null +++ b/drivers/misc/qemu_fw_cfg.c @@ -0,0 +1,185 @@ +/*
- (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");
+}
+bool qemu_fwcfg_present(void) +{
return fwcfg_present;
+}
+bool qemu_fwcfg_dma_present(void) +{
return fwcfg_dma_present;
+}
+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);
+}
+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;
+}
+struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) +{
iter->entry = fw_list.next;
return list_entry((struct list_head *)iter->entry,
struct fw_file, list);
+}
+struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) +{
iter->entry = ((struct list_head *)iter->entry)->next;
return list_entry((struct list_head *)iter->entry,
struct fw_file, list);
+}
+bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) +{
return iter->entry == &fw_list;
+}
+void qemu_fwcfg_init(void) +{
uint32_t qemu;
uint32_t dma_enabled;
fwcfg_present = false;
fwcfg_dma_present = false;
qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE)
fwcfg_present = true;
if (fwcfg_present) {
qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
if (dma_enabled & FW_CFG_DMA_ENABLED)
fwcfg_dma_present = true;
}
+}
--
When applying this patch, I got:
$ git am U-Boot-05-12-x86-qemu-split-qfw-command-interface-and-qfw-core.patch Applying: x86: qemu: split qfw command interface and qfw core /git/u-boot/.git/rebase-apply/patch:327: new blank line at EOF. + /git/u-boot/.git/rebase-apply/patch:695: new blank line at EOF. + /git/u-boot/.git/rebase-apply/patch:910: new blank line at EOF. + warning: 3 lines add whitespace errors.
Can you please fix these?
Regards, Bin

Hi Bin,
2016-05-13 22:00 GMT+08:00 Bin Meng bmeng.cn@gmail.com:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch splits qfw command interface and qfw core function into two files, and introduces a new Kconfig option (CONFIG_QFW). for qfw core.
Now when qfw command interface is enabled, it will automatically select qfw core. This patch also makes the ACPI table generation select CONFIG_QFW.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/Kconfig | 2 +- arch/x86/cpu/mp_init.c | 6 +- arch/x86/cpu/qemu/Makefile | 3 +- arch/x86/cpu/qemu/acpi_table.c | 2 + arch/x86/cpu/qemu/qemu.c | 4 + cmd/Kconfig | 1 + cmd/Makefile | 2 +- cmd/cmd_qfw.c | 182 +++++++++++++++++++++ cmd/qemu_fw_cfg.c | 353 ----------------------------------------- common/Kconfig | 1 + drivers/misc/Kconfig | 6 + drivers/misc/Makefile | 1 + drivers/misc/qemu_fw_cfg.c | 185 +++++++++++++++++++++ 13 files changed, 390 insertions(+), 358 deletions(-) create mode 100644 cmd/cmd_qfw.c delete mode 100644 cmd/qemu_fw_cfg.c create mode 100644 drivers/misc/qemu_fw_cfg.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a60e0da..2f63170 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -436,7 +436,7 @@ config GENERATE_MP_TABLE config GENERATE_ACPI_TABLE bool "Generate an ACPI (Advanced Configuration and Power Interface) table" default n
select QEMU_FW_CFG if QEMU
select QFW if QEMU help The Advanced Configuration and Power Interface (ACPI) specification provides an open standard for device configuration and management
diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 13bec7a..109b3d7 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -11,7 +11,9 @@ #include <dm.h> #include <errno.h> #include <malloc.h> +#ifdef CONFIG_QFW #include <qemu_fw_cfg.h> +#endif
There is no need to wrap header file with #ifdef.
OK. And will fix the reset of them.
#include <asm/atomic.h> #include <asm/cpu.h> #include <asm/interrupt.h> @@ -420,7 +422,7 @@ static int init_bsp(struct udevice **devp) return 0; }
-#ifdef CONFIG_QEMU +#ifdef CONFIG_QFW static int qemu_cpu_fixup(void) { int ret; @@ -496,7 +498,7 @@ int mp_init(struct mp_params *p) if (ret) return ret;
-#ifdef CONFIG_QEMU +#ifdef CONFIG_QFW ret = qemu_cpu_fixup(); if (ret) return ret; diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 43ee4bd..7c08c3d 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -7,5 +7,6 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif -obj-y += cpu.o qemu.o +obj-y += qemu.o +obj-$(CONFIG_QFW) += cpu.o obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c index b17fa03..4584fc7 100644 --- a/arch/x86/cpu/qemu/acpi_table.c +++ b/arch/x86/cpu/qemu/acpi_table.c @@ -8,7 +8,9 @@ #include <command.h> #include <errno.h> #include <malloc.h> +#ifdef CONFIG_QFW #include <qemu_fw_cfg.h> +#endif
ditto.
#include <asm/io.h> #include <asm/tables.h> #include <asm/e820.h> diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index b41e4ec..2631e99 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -6,7 +6,9 @@
#include <common.h> #include <pci.h> +#ifdef CONFIG_QFW #include <qemu_fw_cfg.h> +#endif
ditto.
#include <asm/irq.h> #include <asm/post.h> #include <asm/processor.h> @@ -88,7 +90,9 @@ static void qemu_chipset_init(void) enable_pm_ich9(); }
+#ifdef CONFIG_QFW qemu_fwcfg_init(); +#endif }
int arch_cpu_init(void) diff --git a/cmd/Kconfig b/cmd/Kconfig index c0fffe3..08b761f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -596,6 +596,7 @@ config CMD_SOUND config CMD_QEMU_FW_CFG bool "qfw" depends on X86
select QFW help This provides access to the QEMU firmware interface. The main feature is to allow easy loading of files passed to qemu-system
diff --git a/cmd/Makefile b/cmd/Makefile index f99e67d..31e4da7 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -105,7 +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_QEMU_FW_CFG) += cmd_qfw.o obj-$(CONFIG_CMD_READ) += read.o obj-$(CONFIG_CMD_REGINFO) += reginfo.o obj-$(CONFIG_CMD_REISER) += reiser.o diff --git a/cmd/cmd_qfw.c b/cmd/cmd_qfw.c new file mode 100644 index 0000000..eefaf65 --- /dev/null +++ b/cmd/cmd_qfw.c @@ -0,0 +1,182 @@ +/*
- (C) Copyright 2015 Miao Yan yanmiaobest@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <command.h> +#include <errno.h> +#include <qemu_fw_cfg.h>
+/*
- 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_list_firmware(void) +{
int ret;
struct fw_cfg_file_iter iter;
struct fw_file *file;
/* make sure fw_list is loaded */
ret = qemu_fwcfg_read_firmware_list();
if (ret)
return ret;
for (file = qemu_fwcfg_file_iter_init(&iter);
!qemu_fwcfg_file_iter_end(&iter);
file = qemu_fwcfg_file_iter_next(&iter)) {
printf("%-56s\n", file->cfg.name);
}
return 0;
+}
+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 (!qemu_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/cmd/qemu_fw_cfg.c b/cmd/qemu_fw_cfg.c deleted file mode 100644 index aab6b1a..0000000 --- a/cmd/qemu_fw_cfg.c +++ /dev/null @@ -1,353 +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 <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");
-}
-bool qemu_fwcfg_present(void) -{
return fwcfg_present;
-}
-bool qemu_fwcfg_dma_present(void) -{
return fwcfg_dma_present;
-}
-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;
-}
-struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) -{
iter->entry = fw_list.next;
return list_entry(iter->entry, struct fw_file, list);
-}
-struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) -{
iter->entry = iter->entry->next;
return list_entry(iter->entry, struct fw_file, list);
-}
-bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) -{
return iter->entry == &fw_list;
-}
-static int qemu_fwcfg_list_firmware(void) -{
int ret;
struct fw_cfg_file_iter iter;
struct fw_file *file;
/* make sure fw_list is loaded */
ret = qemu_fwcfg_read_firmware_list();
if (ret)
return ret;
for (file = qemu_fwcfg_file_iter_init(&iter);
!qemu_fwcfg_file_iter_end(&iter);
file = qemu_fwcfg_file_iter_next(&iter)) {
printf("%-56s\n", file->cfg.name);
}
return 0;
-}
-void qemu_fwcfg_init(void) -{
uint32_t qemu;
uint32_t dma_enabled;
fwcfg_present = false;
fwcfg_dma_present = false;
qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE)
fwcfg_present = true;
if (fwcfg_present) {
qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
if (dma_enabled & FW_CFG_DMA_ENABLED)
fwcfg_dma_present = true;
}
-}
-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 (!qemu_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/common/Kconfig b/common/Kconfig index 067545d..8ca5a68 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -124,3 +124,4 @@ config CONSOLE_RECORD_IN_SIZE tstc() and getc() will use this in preference to real device input. The buffer is allocated immediately after the malloc() region is ready.
What is this for?
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index af8667f..fa53700 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -138,4 +138,10 @@ config WINBOND_W83627 legacy UART or other devices in the Winbond Super IO chips on X86 platforms.
+config QFW
bool
help
Hidden option to enable QEMU fw_cfg interface. This will be selected by
either CONFIG_CMD_QEMU_FW_CFG or CONFIG_GENERATE_ACPI_TABLE.
endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5969d34..4893086 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_RESET) += reset-uclass.o obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o +obj-$(CONFIG_QFW) += qemu_fw_cfg.o diff --git a/drivers/misc/qemu_fw_cfg.c b/drivers/misc/qemu_fw_cfg.c new file mode 100644 index 0000000..e726059 --- /dev/null +++ b/drivers/misc/qemu_fw_cfg.c @@ -0,0 +1,185 @@ +/*
- (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");
+}
+bool qemu_fwcfg_present(void) +{
return fwcfg_present;
+}
+bool qemu_fwcfg_dma_present(void) +{
return fwcfg_dma_present;
+}
+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);
+}
+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;
+}
+struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) +{
iter->entry = fw_list.next;
return list_entry((struct list_head *)iter->entry,
struct fw_file, list);
+}
+struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) +{
iter->entry = ((struct list_head *)iter->entry)->next;
return list_entry((struct list_head *)iter->entry,
struct fw_file, list);
+}
+bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) +{
return iter->entry == &fw_list;
+}
+void qemu_fwcfg_init(void) +{
uint32_t qemu;
uint32_t dma_enabled;
fwcfg_present = false;
fwcfg_dma_present = false;
qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE)
fwcfg_present = true;
if (fwcfg_present) {
qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
if (dma_enabled & FW_CFG_DMA_ENABLED)
fwcfg_dma_present = true;
}
+}
--
When applying this patch, I got:
$ git am U-Boot-05-12-x86-qemu-split-qfw-command-interface-and-qfw-core.patch Applying: x86: qemu: split qfw command interface and qfw core /git/u-boot/.git/rebase-apply/patch:327: new blank line at EOF.
/git/u-boot/.git/rebase-apply/patch:695: new blank line at EOF.
/git/u-boot/.git/rebase-apply/patch:910: new blank line at EOF.
warning: 3 lines add whitespace errors.
Can you please fix these?
Sure.
Thanks, Miao
Regards, Bin

Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch splits qfw command interface and qfw core function into two files, and introduces a new Kconfig option (CONFIG_QFW). for qfw core.
Now when qfw command interface is enabled, it will automatically select qfw core. This patch also makes the ACPI table generation select CONFIG_QFW.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/Kconfig | 2 +- arch/x86/cpu/mp_init.c | 6 +- arch/x86/cpu/qemu/Makefile | 3 +- arch/x86/cpu/qemu/acpi_table.c | 2 + arch/x86/cpu/qemu/qemu.c | 4 + cmd/Kconfig | 1 + cmd/Makefile | 2 +- cmd/cmd_qfw.c | 182 +++++++++++++++++++++
The file name should be qfw.c without cmd_
cmd/qemu_fw_cfg.c | 353 -----------------------------------------
And I suspect you can also use "git mv" for cmd/qemu_fw_cfg.c. "git mv cmd/qemu_fw_cfg.c cmd/qfw.c"
common/Kconfig | 1 + drivers/misc/Kconfig | 6 + drivers/misc/Makefile | 1 + drivers/misc/qemu_fw_cfg.c | 185 +++++++++++++++++++++ 13 files changed, 390 insertions(+), 358 deletions(-) create mode 100644 cmd/cmd_qfw.c delete mode 100644 cmd/qemu_fw_cfg.c create mode 100644 drivers/misc/qemu_fw_cfg.c
Regards, Bin

Hi Bin,
2016-05-16 16:47 GMT+08:00 Bin Meng bmeng.cn@gmail.com:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch splits qfw command interface and qfw core function into two files, and introduces a new Kconfig option (CONFIG_QFW). for qfw core.
Now when qfw command interface is enabled, it will automatically select qfw core. This patch also makes the ACPI table generation select CONFIG_QFW.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/Kconfig | 2 +- arch/x86/cpu/mp_init.c | 6 +- arch/x86/cpu/qemu/Makefile | 3 +- arch/x86/cpu/qemu/acpi_table.c | 2 + arch/x86/cpu/qemu/qemu.c | 4 + cmd/Kconfig | 1 + cmd/Makefile | 2 +- cmd/cmd_qfw.c | 182 +++++++++++++++++++++
The file name should be qfw.c without cmd_
cmd/qemu_fw_cfg.c | 353 -----------------------------------------
And I suspect you can also use "git mv" for cmd/qemu_fw_cfg.c. "git mv cmd/qemu_fw_cfg.c cmd/qfw.c"
But there is already a qfw.c under driver/misc/, having two files using the same name seems a bit confusing.
Thanks, Miao
common/Kconfig | 1 + drivers/misc/Kconfig | 6 + drivers/misc/Makefile | 1 + drivers/misc/qemu_fw_cfg.c | 185 +++++++++++++++++++++ 13 files changed, 390 insertions(+), 358 deletions(-) create mode 100644 cmd/cmd_qfw.c delete mode 100644 cmd/qemu_fw_cfg.c create mode 100644 drivers/misc/qemu_fw_cfg.c
Regards, Bin

Hi Miao,
On Mon, May 16, 2016 at 5:50 PM, Miao Yan yanmiaobest@gmail.com wrote:
Hi Bin,
2016-05-16 16:47 GMT+08:00 Bin Meng bmeng.cn@gmail.com:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch splits qfw command interface and qfw core function into two files, and introduces a new Kconfig option (CONFIG_QFW). for qfw core.
Now when qfw command interface is enabled, it will automatically select qfw core. This patch also makes the ACPI table generation select CONFIG_QFW.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/Kconfig | 2 +- arch/x86/cpu/mp_init.c | 6 +- arch/x86/cpu/qemu/Makefile | 3 +- arch/x86/cpu/qemu/acpi_table.c | 2 + arch/x86/cpu/qemu/qemu.c | 4 + cmd/Kconfig | 1 + cmd/Makefile | 2 +- cmd/cmd_qfw.c | 182 +++++++++++++++++++++
The file name should be qfw.c without cmd_
cmd/qemu_fw_cfg.c | 353 -----------------------------------------
And I suspect you can also use "git mv" for cmd/qemu_fw_cfg.c. "git mv cmd/qemu_fw_cfg.c cmd/qfw.c"
But there is already a qfw.c under driver/misc/, having two files using the same name seems a bit confusing.
No problem because they are in different directory, and the command one is in a directory named 'cmd'.
Regards, Bin

The original implementation of qfw includes several x86 specific operations, like directly calling outb/inb and using some inline assembly code which prevents it being ported to other architectures.
This patch adds callback functions and moves those to arch/x86/
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- arch/x86/cpu/qemu/qemu.c | 39 ++++++++++++++++++++++++++++++++++++++- drivers/misc/qemu_fw_cfg.c | 30 +++++++++++++----------------- include/qemu_fw_cfg.h | 15 +++++++++------ 3 files changed, 60 insertions(+), 24 deletions(-)
diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index 2631e99..d964283 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -17,6 +17,43 @@
static bool i440fx;
+#ifdef CONFIG_QFW + +#define FW_CONTROL_PORT 0x510 +#define FW_DATA_PORT 0x511 +#define FW_DMA_PORT_LOW 0x514 +#define FW_DMA_PORT_HIGH 0x518 + +static void qemu_x86_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); +} + +static void qemu_x86_fwcfg_read_entry_dma(struct fw_cfg_dma_access *dma) +{ + 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 struct fw_cfg_arch_ops fwcfg_x86_ops = { + .arch_read_pio = qemu_x86_fwcfg_read_entry_pio, + .arch_read_dma = qemu_x86_fwcfg_read_entry_dma +}; +#endif + static void enable_pm_piix(void) { u8 en; @@ -91,7 +128,7 @@ static void qemu_chipset_init(void) }
#ifdef CONFIG_QFW - qemu_fwcfg_init(); + qemu_fwcfg_init(&fwcfg_x86_ops); #endif }
diff --git a/drivers/misc/qemu_fw_cfg.c b/drivers/misc/qemu_fw_cfg.c index e726059..0700641 100644 --- a/drivers/misc/qemu_fw_cfg.c +++ b/drivers/misc/qemu_fw_cfg.c @@ -14,6 +14,7 @@
static bool fwcfg_present; static bool fwcfg_dma_present; +static struct fw_cfg_arch_ops *fwcfg_arch_ops;
static LIST_HEAD(fw_list);
@@ -21,17 +22,10 @@ static LIST_HEAD(fw_list); static void qemu_fwcfg_read_entry_pio(uint16_t entry, uint32_t size, void *address) { - uint32_t i = 0; - uint8_t *data = address; + debug("qemu_fwcfg_read_entry_pio: entry 0x%x, size %u address %p\n", + entry, size, 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); + return fwcfg_arch_ops->arch_read_pio(entry, size, address); }
/* Read configuration item using fw_cfg DMA interface */ @@ -53,13 +47,10 @@ static void qemu_fwcfg_read_entry_dma(uint16_t entry,
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); + debug("qemu_fwcfg_read_entry_dma: entry 0x%x, size %u address %p, control 0x%x\n", + entry, size, address, be32_to_cpu(dma.control));
- while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR) - __asm__ __volatile__ ("pause"); + fwcfg_arch_ops->arch_read_dma(&dma); }
bool qemu_fwcfg_present(void) @@ -164,13 +155,18 @@ bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) return iter->entry == &fw_list; }
-void qemu_fwcfg_init(void) +void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops) { uint32_t qemu; uint32_t dma_enabled;
fwcfg_present = false; fwcfg_dma_present = false; + fwcfg_arch_ops = NULL; + + if (!ops || !ops->arch_read_pio || !ops->arch_read_dma) + return; + fwcfg_arch_ops = ops;
qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE) diff --git a/include/qemu_fw_cfg.h b/include/qemu_fw_cfg.h index f718e09..b0b3b59 100644 --- a/include/qemu_fw_cfg.h +++ b/include/qemu_fw_cfg.h @@ -7,11 +7,6 @@ #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 { @@ -97,6 +92,12 @@ struct fw_cfg_dma_access { __be64 address; };
+struct fw_cfg_arch_ops { + void (*arch_read_pio)(uint16_t selector, uint32_t size, + void *address); + void (*arch_read_dma)(struct fw_cfg_dma_access *dma); +}; + struct bios_linker_entry { __le32 command; union { @@ -148,8 +149,10 @@ struct bios_linker_entry {
/** * Initialize QEMU fw_cfg interface + * + * @ops: arch specific read operations */ -void qemu_fwcfg_init(void); +void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops);
void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address); int qemu_fwcfg_read_firmware_list(void);

On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
The original implementation of qfw includes several x86 specific operations, like directly calling outb/inb and using some inline assembly code which prevents it being ported to other architectures.
This patch adds callback functions and moves those to arch/x86/
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/cpu/qemu/qemu.c | 39 ++++++++++++++++++++++++++++++++++++++- drivers/misc/qemu_fw_cfg.c | 30 +++++++++++++----------------- include/qemu_fw_cfg.h | 15 +++++++++------ 3 files changed, 60 insertions(+), 24 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

This patch adds some comments about qfw register endianness for clarity.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- arch/x86/cpu/qemu/qemu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index d964283..716a0ac 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -19,6 +19,7 @@ static bool i440fx;
#ifdef CONFIG_QFW
+/* on x86, the qfw registers are all IO ports */ #define FW_CONTROL_PORT 0x510 #define FW_DATA_PORT 0x511 #define FW_DMA_PORT_LOW 0x514 @@ -33,15 +34,21 @@ static void qemu_x86_fwcfg_read_entry_pio(uint16_t entry, /* * writting FW_CFG_INVALID will cause read operation to resume at * last offset, otherwise read will start at offset 0 + * + * Note: on platform where the control register is IO port, the + * endianness is little endian. */ if (entry != FW_CFG_INVALID) - outw(entry, FW_CONTROL_PORT); + outw(cpu_to_le16(entry), FW_CONTROL_PORT); + + /* the endianness of data register is string-preserving */ while (size--) data[i++] = inb(FW_DATA_PORT); }
static void qemu_x86_fwcfg_read_entry_dma(struct fw_cfg_dma_access *dma) { + /* the DMA address register is big endian */ outl(cpu_to_be32((uint32_t)dma), FW_DMA_PORT_HIGH);
while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR)

On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
This patch adds some comments about qfw register endianness for clarity.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/cpu/qemu/qemu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Make file names aligned with CONFIG_QFW
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- arch/x86/cpu/mp_init.c | 2 +- arch/x86/cpu/qemu/acpi_table.c | 2 +- arch/x86/cpu/qemu/cpu.c | 2 +- arch/x86/cpu/qemu/qemu.c | 2 +- cmd/cmd_qfw.c | 2 +- drivers/misc/Makefile | 2 +- drivers/misc/qemu_fw_cfg.c | 181 ----------------------------------------- drivers/misc/qfw.c | 181 +++++++++++++++++++++++++++++++++++++++++ include/qemu_fw_cfg.h | 176 --------------------------------------- include/qfw.h | 176 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 363 insertions(+), 363 deletions(-) delete mode 100644 drivers/misc/qemu_fw_cfg.c create mode 100644 drivers/misc/qfw.c delete mode 100644 include/qemu_fw_cfg.h create mode 100644 include/qfw.h
diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 109b3d7..54285fa 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -12,7 +12,7 @@ #include <errno.h> #include <malloc.h> #ifdef CONFIG_QFW -#include <qemu_fw_cfg.h> +#include <qfw.h> #endif #include <asm/atomic.h> #include <asm/cpu.h> diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c index 4584fc7..0c54b80 100644 --- a/arch/x86/cpu/qemu/acpi_table.c +++ b/arch/x86/cpu/qemu/acpi_table.c @@ -9,7 +9,7 @@ #include <errno.h> #include <malloc.h> #ifdef CONFIG_QFW -#include <qemu_fw_cfg.h> +#include <qfw.h> #endif #include <asm/io.h> #include <asm/tables.h> diff --git a/arch/x86/cpu/qemu/cpu.c b/arch/x86/cpu/qemu/cpu.c index 4d2989a..b1a965e 100644 --- a/arch/x86/cpu/qemu/cpu.c +++ b/arch/x86/cpu/qemu/cpu.c @@ -8,7 +8,7 @@ #include <cpu.h> #include <dm.h> #include <errno.h> -#include <qemu_fw_cfg.h> +#include <qfw.h> #include <asm/cpu.h>
DECLARE_GLOBAL_DATA_PTR; diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index 716a0ac..35cd107 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -7,7 +7,7 @@ #include <common.h> #include <pci.h> #ifdef CONFIG_QFW -#include <qemu_fw_cfg.h> +#include <qfw.h> #endif #include <asm/irq.h> #include <asm/post.h> diff --git a/cmd/cmd_qfw.c b/cmd/cmd_qfw.c index eefaf65..aeb576b 100644 --- a/cmd/cmd_qfw.c +++ b/cmd/cmd_qfw.c @@ -7,7 +7,7 @@ #include <common.h> #include <command.h> #include <errno.h> -#include <qemu_fw_cfg.h> +#include <qfw.h>
/* * This function prepares kernel for zboot. It loads kernel data diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 4893086..98704f2 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -43,4 +43,4 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_RESET) += reset-uclass.o obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o -obj-$(CONFIG_QFW) += qemu_fw_cfg.o +obj-$(CONFIG_QFW) += qfw.o diff --git a/drivers/misc/qemu_fw_cfg.c b/drivers/misc/qemu_fw_cfg.c deleted file mode 100644 index 0700641..0000000 --- a/drivers/misc/qemu_fw_cfg.c +++ /dev/null @@ -1,181 +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 <qemu_fw_cfg.h> -#include <asm/io.h> -#include <linux/list.h> - -static bool fwcfg_present; -static bool fwcfg_dma_present; -static struct fw_cfg_arch_ops *fwcfg_arch_ops; - -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) -{ - debug("qemu_fwcfg_read_entry_pio: entry 0x%x, size %u address %p\n", - entry, size, address); - - return fwcfg_arch_ops->arch_read_pio(entry, size, address); -} - -/* 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_read_entry_dma: entry 0x%x, size %u address %p, control 0x%x\n", - entry, size, address, be32_to_cpu(dma.control)); - - fwcfg_arch_ops->arch_read_dma(&dma); -} - -bool qemu_fwcfg_present(void) -{ - return fwcfg_present; -} - -bool qemu_fwcfg_dma_present(void) -{ - return fwcfg_dma_present; -} - -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); -} - -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; -} - -struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) -{ - iter->entry = fw_list.next; - return list_entry((struct list_head *)iter->entry, - struct fw_file, list); -} - -struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) -{ - iter->entry = ((struct list_head *)iter->entry)->next; - return list_entry((struct list_head *)iter->entry, - struct fw_file, list); -} - -bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) -{ - return iter->entry == &fw_list; -} - -void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops) -{ - uint32_t qemu; - uint32_t dma_enabled; - - fwcfg_present = false; - fwcfg_dma_present = false; - fwcfg_arch_ops = NULL; - - if (!ops || !ops->arch_read_pio || !ops->arch_read_dma) - return; - fwcfg_arch_ops = ops; - - qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); - if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE) - fwcfg_present = true; - - if (fwcfg_present) { - qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled); - if (dma_enabled & FW_CFG_DMA_ENABLED) - fwcfg_dma_present = true; - } -} - diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c new file mode 100644 index 0000000..9f1bb2d --- /dev/null +++ b/drivers/misc/qfw.c @@ -0,0 +1,181 @@ +/* + * (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 <qfw.h> +#include <asm/io.h> +#include <linux/list.h> + +static bool fwcfg_present; +static bool fwcfg_dma_present; +static struct fw_cfg_arch_ops *fwcfg_arch_ops; + +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) +{ + debug("qemu_fwcfg_read_entry_pio: entry 0x%x, size %u address %p\n", + entry, size, address); + + return fwcfg_arch_ops->arch_read_pio(entry, size, address); +} + +/* 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_read_entry_dma: entry 0x%x, size %u address %p, control 0x%x\n", + entry, size, address, be32_to_cpu(dma.control)); + + fwcfg_arch_ops->arch_read_dma(&dma); +} + +bool qemu_fwcfg_present(void) +{ + return fwcfg_present; +} + +bool qemu_fwcfg_dma_present(void) +{ + return fwcfg_dma_present; +} + +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); +} + +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; +} + +struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) +{ + iter->entry = fw_list.next; + return list_entry((struct list_head *)iter->entry, + struct fw_file, list); +} + +struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) +{ + iter->entry = ((struct list_head *)iter->entry)->next; + return list_entry((struct list_head *)iter->entry, + struct fw_file, list); +} + +bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) +{ + return iter->entry == &fw_list; +} + +void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops) +{ + uint32_t qemu; + uint32_t dma_enabled; + + fwcfg_present = false; + fwcfg_dma_present = false; + fwcfg_arch_ops = NULL; + + if (!ops || !ops->arch_read_pio || !ops->arch_read_dma) + return; + fwcfg_arch_ops = ops; + + qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); + if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE) + fwcfg_present = true; + + if (fwcfg_present) { + qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled); + if (dma_enabled & FW_CFG_DMA_ENABLED) + fwcfg_dma_present = true; + } +} + diff --git a/include/qemu_fw_cfg.h b/include/qemu_fw_cfg.h deleted file mode 100644 index b0b3b59..0000000 --- a/include/qemu_fw_cfg.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * (C) Copyright 2015 Miao Yan yanmiaobest@gmail.com - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __FW_CFG__ -#define __FW_CFG__ - -#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_file_iter { - struct list_head *entry; /* structure to iterate file list */ -}; - -struct fw_cfg_dma_access { - __be32 control; - __be32 length; - __be64 address; -}; - -struct fw_cfg_arch_ops { - void (*arch_read_pio)(uint16_t selector, uint32_t size, - void *address); - void (*arch_read_dma)(struct fw_cfg_dma_access *dma); -}; - -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 - * - * @ops: arch specific read operations - */ -void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops); - -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); - -/** - * Get system cpu number - * - * @return: cpu number in system - */ -int qemu_fwcfg_online_cpus(void); - -/* helper functions to iterate firmware file list */ -struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter); -struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter); -bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter); - -bool qemu_fwcfg_present(void); -bool qemu_fwcfg_dma_present(void); - -#endif diff --git a/include/qfw.h b/include/qfw.h new file mode 100644 index 0000000..b0b3b59 --- /dev/null +++ b/include/qfw.h @@ -0,0 +1,176 @@ +/* + * (C) Copyright 2015 Miao Yan yanmiaobest@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FW_CFG__ +#define __FW_CFG__ + +#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_file_iter { + struct list_head *entry; /* structure to iterate file list */ +}; + +struct fw_cfg_dma_access { + __be32 control; + __be32 length; + __be64 address; +}; + +struct fw_cfg_arch_ops { + void (*arch_read_pio)(uint16_t selector, uint32_t size, + void *address); + void (*arch_read_dma)(struct fw_cfg_dma_access *dma); +}; + +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 + * + * @ops: arch specific read operations + */ +void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops); + +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); + +/** + * Get system cpu number + * + * @return: cpu number in system + */ +int qemu_fwcfg_online_cpus(void); + +/* helper functions to iterate firmware file list */ +struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter); +struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter); +bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter); + +bool qemu_fwcfg_present(void); +bool qemu_fwcfg_dma_present(void); + +#endif

Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
Make file names aligned with CONFIG_QFW
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/cpu/mp_init.c | 2 +- arch/x86/cpu/qemu/acpi_table.c | 2 +- arch/x86/cpu/qemu/cpu.c | 2 +- arch/x86/cpu/qemu/qemu.c | 2 +- cmd/cmd_qfw.c | 2 +- drivers/misc/Makefile | 2 +- drivers/misc/qemu_fw_cfg.c | 181 ----------------------------------------- drivers/misc/qfw.c | 181 +++++++++++++++++++++++++++++++++++++++++ include/qemu_fw_cfg.h | 176 --------------------------------------- include/qfw.h | 176 +++++++++++++++++++++++++++++++++++++++
Please use 'git mv' for such operation.
10 files changed, 363 insertions(+), 363 deletions(-) delete mode 100644 drivers/misc/qemu_fw_cfg.c create mode 100644 drivers/misc/qfw.c delete mode 100644 include/qemu_fw_cfg.h create mode 100644 include/qfw.h
Regards, Bin

The qfw command interface makes use of CONFIG_LOADADDR and CONFIG_RAMDISKADDR to setup kernel. But not all boards have these macro, which causes build problem on those platforms.
This patch fixes this issue.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- cmd/cmd_qfw.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/cmd/cmd_qfw.c b/cmd/cmd_qfw.c index aeb576b..13ad673 100644 --- a/cmd/cmd_qfw.c +++ b/cmd/cmd_qfw.c @@ -126,12 +126,20 @@ static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag, env = getenv("loadaddr"); load_addr = env ? (void *)simple_strtoul(env, NULL, 16) : +#ifdef CONFIG_LOADADDR (void *)CONFIG_LOADADDR; +#else + NULL; +#endif
env = getenv("ramdiskaddr"); initrd_addr = env ? (void *)simple_strtoul(env, NULL, 16) : +#ifdef CONFIG_RAMDISK_ADDR (void *)CONFIG_RAMDISK_ADDR; +#else + NULL; +#endif
if (argc == 2) { load_addr = (void *)simple_strtoul(argv[0], NULL, 16); @@ -140,6 +148,11 @@ static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag, load_addr = (void *)simple_strtoul(argv[0], NULL, 16); }
+ if (!load_addr || !initrd_addr) { + printf("missing load or initrd address\n"); + return CMD_RET_FAILURE; + } + return qemu_fwcfg_setup_kernel(load_addr, initrd_addr); }

Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
The qfw command interface makes use of CONFIG_LOADADDR and CONFIG_RAMDISKADDR to setup kernel. But not all boards have these macro, which causes build problem on those platforms.
This patch fixes this issue.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
Looks good.
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But the commit title "workaround" looks to be a workaround, which does not sound that good.
cmd/cmd_qfw.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/cmd/cmd_qfw.c b/cmd/cmd_qfw.c index aeb576b..13ad673 100644 --- a/cmd/cmd_qfw.c +++ b/cmd/cmd_qfw.c @@ -126,12 +126,20 @@ static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag, env = getenv("loadaddr"); load_addr = env ? (void *)simple_strtoul(env, NULL, 16) : +#ifdef CONFIG_LOADADDR (void *)CONFIG_LOADADDR; +#else
NULL;
+#endif
env = getenv("ramdiskaddr"); initrd_addr = env ? (void *)simple_strtoul(env, NULL, 16) :
+#ifdef CONFIG_RAMDISK_ADDR (void *)CONFIG_RAMDISK_ADDR; +#else
NULL;
+#endif
if (argc == 2) { load_addr = (void *)simple_strtoul(argv[0], NULL, 16);
@@ -140,6 +148,11 @@ static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag, load_addr = (void *)simple_strtoul(argv[0], NULL, 16); }
if (!load_addr || !initrd_addr) {
printf("missing load or initrd address\n");
return CMD_RET_FAILURE;
}
return qemu_fwcfg_setup_kernel(load_addr, initrd_addr);
}
--
Regards, Bin

On Fri, May 13, 2016 at 10:00:37PM +0800, Bin Meng wrote:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
The qfw command interface makes use of CONFIG_LOADADDR and CONFIG_RAMDISKADDR to setup kernel. But not all boards have these macro, which causes build problem on those platforms.
This patch fixes this issue.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
Looks good.
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But the commit title "workaround" looks to be a workaround, which does not sound that good.
Yes, maybe just say that it's no longer requiring default values?

2016-05-14 4:46 GMT+08:00 Tom Rini trini@konsulko.com:
On Fri, May 13, 2016 at 10:00:37PM +0800, Bin Meng wrote:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
The qfw command interface makes use of CONFIG_LOADADDR and CONFIG_RAMDISKADDR to setup kernel. But not all boards have these macro, which causes build problem on those platforms.
This patch fixes this issue.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
Looks good.
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But the commit title "workaround" looks to be a workaround, which does not sound that good.
Yes, maybe just say that it's no longer requiring default values?
OK. Will fix.
Thanks, Miao
-- Tom

The qfw command interface used to depend on X86, this patch removes this restriction so it can be built for sandbox for testing. For normal usage, it can only be used with CONFIG_QEMU.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- cmd/Kconfig | 1 - 1 file changed, 1 deletion(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig index 08b761f..01870cb 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -595,7 +595,6 @@ config CMD_SOUND
config CMD_QEMU_FW_CFG bool "qfw" - depends on X86 select QFW help This provides access to the QEMU firmware interface. The main

Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
The qfw command interface used to depend on X86, this patch removes this restriction so it can be built for sandbox for testing. For normal usage, it can only be used with CONFIG_QEMU.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Would you prepare a patch to enable this on Sandbox?
cmd/Kconfig | 1 - 1 file changed, 1 deletion(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig index 08b761f..01870cb 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -595,7 +595,6 @@ config CMD_SOUND
config CMD_QEMU_FW_CFG bool "qfw"
depends on X86 select QFW help This provides access to the QEMU firmware interface. The main
--
Regards, Bin

Hi Bin,
2016-05-13 22:00 GMT+08:00 Bin Meng bmeng.cn@gmail.com:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
The qfw command interface used to depend on X86, this patch removes this restriction so it can be built for sandbox for testing. For normal usage, it can only be used with CONFIG_QEMU.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Would you prepare a patch to enable this on Sandbox?
I'll give it a try. Do you prefer to do that in this patch-set or submit later ?
Miao
cmd/Kconfig | 1 - 1 file changed, 1 deletion(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig index 08b761f..01870cb 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -595,7 +595,6 @@ config CMD_SOUND
config CMD_QEMU_FW_CFG bool "qfw"
depends on X86 select QFW help This provides access to the QEMU firmware interface. The main
--
Regards, Bin

Hi Miao,
On Mon, May 16, 2016 at 5:44 PM, Miao Yan yanmiaobest@gmail.com wrote:
Hi Bin,
2016-05-13 22:00 GMT+08:00 Bin Meng bmeng.cn@gmail.com:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
The qfw command interface used to depend on X86, this patch removes this restriction so it can be built for sandbox for testing. For normal usage, it can only be used with CONFIG_QEMU.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Would you prepare a patch to enable this on Sandbox?
I'll give it a try. Do you prefer to do that in this patch-set or submit later ?
Please do in this patch-set so that we can test the sandbox build with this qfw command.
Regards, Bin

Loading ACPI table from QEMU's fw_cfg interface is not x86 specific (ARM64 may also make user of it). So move the code common place.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- arch/x86/cpu/qemu/acpi_table.c | 211 ----------------------------------------- drivers/misc/qfw.c | 206 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+), 211 deletions(-)
diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c index 0c54b80..63853e4 100644 --- a/arch/x86/cpu/qemu/acpi_table.c +++ b/arch/x86/cpu/qemu/acpi_table.c @@ -5,141 +5,7 @@ */
#include <common.h> -#include <command.h> -#include <errno.h> -#include <malloc.h> -#ifdef CONFIG_QFW -#include <qfw.h> -#endif -#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) { @@ -175,80 +41,3 @@ unsigned install_e820_map(unsigned max_entries, struct e820entry *entries)
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) { - struct fw_cfg_file_iter iter; - for (file = qemu_fwcfg_file_iter_init(&iter); - !qemu_fwcfg_file_iter_end(&iter); - file = qemu_fwcfg_file_iter_next(&iter)) { - if (file->addr) { - free((void *)file->addr); - file->addr = 0; - } - } - } - - free(table_loader); - return addr; -} diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c index 9f1bb2d..c0aaa61 100644 --- a/drivers/misc/qfw.c +++ b/drivers/misc/qfw.c @@ -10,6 +10,9 @@ #include <malloc.h> #include <qfw.h> #include <asm/io.h> +#ifdef CONFIG_GENERATE_ACPI_TABLE +#include <asm/tables.h> +#endif #include <linux/list.h>
static bool fwcfg_present; @@ -18,6 +21,209 @@ static struct fw_cfg_arch_ops *fwcfg_arch_ops;
static LIST_HEAD(fw_list);
+#ifdef CONFIG_GENERATE_ACPI_TABLE +/* + * 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; +} + +/* 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) { + struct fw_cfg_file_iter iter; + for (file = qemu_fwcfg_file_iter_init(&iter); + !qemu_fwcfg_file_iter_end(&iter); + file = qemu_fwcfg_file_iter_next(&iter)) { + if (file->addr) { + free((void *)file->addr); + file->addr = 0; + } + } + } + + free(table_loader); + return addr; +} +#endif + /* Read configuration item using fw_cfg PIO interface */ static void qemu_fwcfg_read_entry_pio(uint16_t entry, uint32_t size, void *address)

On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
Loading ACPI table from QEMU's fw_cfg interface is not x86 specific (ARM64 may also make user of it). So move the code common place.
typo: use
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/cpu/qemu/acpi_table.c | 211 ----------------------------------------- drivers/misc/qfw.c | 206 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+), 211 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Rename qemu/acpi_table.c to qemu/e820.c, because ACPI stuff is moved to qfw core, this file only contains code for installing e820 table.
Signed-off-by: Miao Yan yanmiaobest@gmail.com --- arch/x86/cpu/qemu/Makefile | 3 +-- arch/x86/cpu/qemu/acpi_table.c | 43 ------------------------------------------ arch/x86/cpu/qemu/e820.c | 43 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 45 deletions(-) delete mode 100644 arch/x86/cpu/qemu/acpi_table.c create mode 100644 arch/x86/cpu/qemu/e820.c
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 7c08c3d..a080c5e 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,5 +8,4 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += qemu.o -obj-$(CONFIG_QFW) += cpu.o -obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o +obj-$(CONFIG_QFW) += cpu.o e820.o diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c deleted file mode 100644 index 63853e4..0000000 --- a/arch/x86/cpu/qemu/acpi_table.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * (C) Copyright 2015 Miao Yan yanmiaobest@gmail.com - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/e820.h> - -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; -} diff --git a/arch/x86/cpu/qemu/e820.c b/arch/x86/cpu/qemu/e820.c new file mode 100644 index 0000000..63853e4 --- /dev/null +++ b/arch/x86/cpu/qemu/e820.c @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2015 Miao Yan yanmiaobest@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/e820.h> + +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; +}

Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
Rename qemu/acpi_table.c to qemu/e820.c, because ACPI stuff is moved to qfw core, this file only contains code for installing e820 table.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/cpu/qemu/Makefile | 3 +-- arch/x86/cpu/qemu/acpi_table.c | 43 ------------------------------------------ arch/x86/cpu/qemu/e820.c | 43 ++++++++++++++++++++++++++++++++++++++++++
Please use "git mv".
3 files changed, 44 insertions(+), 45 deletions(-) delete mode 100644 arch/x86/cpu/qemu/acpi_table.c create mode 100644 arch/x86/cpu/qemu/e820.c
Regards, Bin

Hi Bin,
2016-05-13 22:01 GMT+08:00 Bin Meng bmeng.cn@gmail.com:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
Rename qemu/acpi_table.c to qemu/e820.c, because ACPI stuff is moved to qfw core, this file only contains code for installing e820 table.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/cpu/qemu/Makefile | 3 +-- arch/x86/cpu/qemu/acpi_table.c | 43 ------------------------------------------ arch/x86/cpu/qemu/e820.c | 43 ++++++++++++++++++++++++++++++++++++++++++
Please use "git mv".
I did use "git mv". I'll double check.
Miao
3 files changed, 44 insertions(+), 45 deletions(-) delete mode 100644 arch/x86/cpu/qemu/acpi_table.c create mode 100644 arch/x86/cpu/qemu/e820.c
Regards, Bin

On Mon, May 16, 2016 at 05:40:16PM +0800, Miao Yan wrote:
Hi Bin,
2016-05-13 22:01 GMT+08:00 Bin Meng bmeng.cn@gmail.com:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
Rename qemu/acpi_table.c to qemu/e820.c, because ACPI stuff is moved to qfw core, this file only contains code for installing e820 table.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/cpu/qemu/Makefile | 3 +-- arch/x86/cpu/qemu/acpi_table.c | 43 ------------------------------------------ arch/x86/cpu/qemu/e820.c | 43 ++++++++++++++++++++++++++++++++++++++++++
Please use "git mv".
I did use "git mv". I'll double check.
I believe you need to tell git to work harder to detect renames. You'll have to do git format-patch --find-copies-harder ... and git send-email ... rather than just using send-email by itself (or, there's a knob somewhere I've missed that lets you tweak the rename threshold via the config file).

2016-05-17 8:42 GMT+08:00 Tom Rini trini@konsulko.com:
On Mon, May 16, 2016 at 05:40:16PM +0800, Miao Yan wrote:
Hi Bin,
2016-05-13 22:01 GMT+08:00 Bin Meng bmeng.cn@gmail.com:
Hi Miao,
On Fri, May 13, 2016 at 2:29 PM, Miao Yan yanmiaobest@gmail.com wrote:
Rename qemu/acpi_table.c to qemu/e820.c, because ACPI stuff is moved to qfw core, this file only contains code for installing e820 table.
Signed-off-by: Miao Yan yanmiaobest@gmail.com
arch/x86/cpu/qemu/Makefile | 3 +-- arch/x86/cpu/qemu/acpi_table.c | 43 ------------------------------------------ arch/x86/cpu/qemu/e820.c | 43 ++++++++++++++++++++++++++++++++++++++++++
Please use "git mv".
I did use "git mv". I'll double check.
I believe you need to tell git to work harder to detect renames. You'll have to do git format-patch --find-copies-harder ... and git send-email ... rather than just using send-email by itself (or, there's a knob somewhere I've missed that lets you tweak the rename threshold via the config file).
Thanks Tom, I'll try that.
Miao
-- Tom
participants (3)
-
Bin Meng
-
Miao Yan
-
Tom Rini