All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets
@ 2016-01-04  8:00 Miao Yan
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 1/8] x86: adjust ramdisk load address Miao Yan
                   ` (7 more replies)
  0 siblings, 8 replies; 15+ messages in thread
From: Miao Yan @ 2016-01-04  8:00 UTC (permalink / raw)
  To: u-boot

The fw_cfg interface provided by QEMU allow guests to retrieve various information
about the system, e.g. cpu number, variaous firmware data, kernel setup, etc. The
fw_cfg interface can be accessed through 3 IO ports (on x86), using x86 in/out
instructions.

  - 0x510: select configuration items to access
  - 0x511: reading this port will return data selected in 0x510 
  - 0x514: this can be used to detect if DMA interface is available

If fw_cfg DMA interface is available, it can be used to accelerate
accesses.

This patchset adds the following supports for qemu-x86 targets: 

  + the fw_cfg driver itself

  + add a U-Boot command 'fw' to support direct accessing kernel informtion
    from fw_cfg interface, this saves the time of loading them from hard disk or
    network again, through emulated devices.

  + use fw_cfg to get cpu number at runtime, so smp boot no longer relies on
    the cpu node hard-coded in dts files.

Changes in v5:
  + change 'fw' to 'qfw'
  + dynamically bind cpu device instead of fixing device tree blob
  + various cleanups

Miao Yan (8):
  x86: adjust ramdisk load address
  x86: qemu: add fw_cfg support
  x86: qemu: add a cpu uclass driver for qemu target
  x86: fix a typo in function name
  x86: use actual CPU number for allocating memory
  x86: qemu: fix cpu device in smp boot
  x86: qemu: remove cpu node in device tree
  x86: qemu: add documentaion for the fw_cfg interface

 arch/x86/cpu/mp_init.c           |  85 +++++++++++-
 arch/x86/cpu/qemu/Makefile       |   2 +-
 arch/x86/cpu/qemu/cpu.c          |  52 +++++++
 arch/x86/cpu/qemu/fw_cfg.c       | 286 +++++++++++++++++++++++++++++++++++++++
 arch/x86/cpu/qemu/qemu.c         |   3 +
 arch/x86/dts/qemu-x86_i440fx.dts |   9 +-
 arch/x86/dts/qemu-x86_q35.dts    |   9 +-
 arch/x86/include/asm/fw_cfg.h    |  95 +++++++++++++
 doc/README.x86                   |  34 ++++-
 include/configs/x86-common.h     |   3 +-
 10 files changed, 551 insertions(+), 27 deletions(-)
 create mode 100644 arch/x86/cpu/qemu/cpu.c
 create mode 100644 arch/x86/cpu/qemu/fw_cfg.c
 create mode 100644 arch/x86/include/asm/fw_cfg.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot]  [PATCH v5 1/8] x86: adjust ramdisk load address
  2016-01-04  8:00 [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets Miao Yan
@ 2016-01-04  8:00 ` Miao Yan
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 2/8] x86: qemu: add fw_cfg support Miao Yan
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Miao Yan @ 2016-01-04  8:00 UTC (permalink / raw)
  To: u-boot

By default, ramdisk load address is defined to 02000000 in env string.
When loading bzImage to 01000000 (default address), there's a chance that
the ramdisk header would be overwritten by the kernel. Thus increase the
gap and make ramdisk load at 04000000 by default and also this patch
introduces a new configuration item CONFIG_RAMDISK_ADDR for this purpose

Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
Changes in v5:
  - move this change to x86-common.h
  - reorder it to be the first patch

 include/configs/x86-common.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h
index 70ec103..4182a3b 100644
--- a/include/configs/x86-common.h
+++ b/include/configs/x86-common.h
@@ -208,6 +208,7 @@
 #define CONFIG_HOSTNAME		x86
 #define CONFIG_BOOTFILE		"bzImage"
 #define CONFIG_LOADADDR		0x1000000
+#define CONFIG_RAMDISK_ADDR		0x4000000
 
 #define CONFIG_EXTRA_ENV_SETTINGS			\
 	CONFIG_STD_DEVICES_SETTINGS			\
@@ -215,7 +216,7 @@
 	"netdev=eth0\0"					\
 	"consoledev=ttyS0\0"				\
 	"othbootargs=acpi=off\0"			\
-	"ramdiskaddr=0x2000000\0"			\
+	"ramdiskaddr=0x4000000\0"			\
 	"ramdiskfile=initramfs.gz\0"
 
 #define CONFIG_RAMBOOTCOMMAND				\
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot]  [PATCH v5 2/8] x86: qemu: add fw_cfg support
  2016-01-04  8:00 [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets Miao Yan
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 1/8] x86: adjust ramdisk load address Miao Yan
@ 2016-01-04  8:00 ` Miao Yan
  2016-01-07  7:05   ` Bin Meng
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 3/8] x86: qemu: add a cpu uclass driver for qemu target Miao Yan
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Miao Yan @ 2016-01-04  8:00 UTC (permalink / raw)
  To: u-boot

The QEMU fw_cfg interface allows the guest to retrieve various data
information from QEMU. For example, APCI/SMBios tables, number of online
cpus, kernel data and command line, etc.

This patch adds support for QEMU fw_cfg interface.

Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---
Changes in v5:
  - change 'fw' to 'qfw'
  - move fw_cfg.h to include/asm
  - cleanups

 arch/x86/cpu/qemu/Makefile    |   2 +-
 arch/x86/cpu/qemu/fw_cfg.c    | 286 ++++++++++++++++++++++++++++++++++++++++++
 arch/x86/cpu/qemu/qemu.c      |   3 +
 arch/x86/include/asm/fw_cfg.h |  95 ++++++++++++++
 4 files changed, 385 insertions(+), 1 deletion(-)
 create mode 100644 arch/x86/cpu/qemu/fw_cfg.c
 create mode 100644 arch/x86/include/asm/fw_cfg.h

diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile
index 3f3958a..d613798 100644
--- a/arch/x86/cpu/qemu/Makefile
+++ b/arch/x86/cpu/qemu/Makefile
@@ -7,5 +7,5 @@
 ifndef CONFIG_EFI_STUB
 obj-y += car.o dram.o
 endif
-obj-y += qemu.o
+obj-y += fw_cfg.o qemu.o
 obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o
diff --git a/arch/x86/cpu/qemu/fw_cfg.c b/arch/x86/cpu/qemu/fw_cfg.c
new file mode 100644
index 0000000..17276c3
--- /dev/null
+++ b/arch/x86/cpu/qemu/fw_cfg.c
@@ -0,0 +1,286 @@
+/*
+ * (C) Copyright 2015 Miao Yan <yanmiaoebst@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/fw_cfg.h>
+
+static bool fwcfg_present;
+static bool fwcfg_dma_present;
+
+/*
+ * Read configuration item using fw_cfg PIO interface
+ */
+
+static void qemu_fwcfg_read_entry_pio(uint16_t entry,
+		uint32_t size, void *address)
+{
+	uint32_t i = 0;
+	uint8_t *data = address;
+
+	/*
+	 * writting FW_CFG_INVALID will cause read operation to resume at
+	 * last offset, otherwise read will start at offset 0
+	 */
+
+	if (entry != FW_CFG_INVALID)
+		outw(entry, FW_CONTROL_PORT);
+	while (size--)
+		data[i++] = inb(FW_DATA_PORT);
+}
+
+/*
+ * Read configuration item using fw_cfg DMA interface
+ */
+
+static void qemu_fwcfg_read_entry_dma(uint16_t entry,
+		uint32_t size, void *address)
+{
+	struct fw_cfg_dma_access dma;
+
+	dma.length = cpu_to_be32(size);
+	dma.address = cpu_to_be64((uintptr_t)address);
+	dma.control = cpu_to_be32(FW_CFG_DMA_READ);
+
+	/*
+	 * writting FW_CFG_INVALID will cause read operation to resume at
+	 * last offset, otherwise read will start at offset 0
+	 */
+
+	if (entry != FW_CFG_INVALID)
+		dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16));
+
+	barrier();
+
+	debug("qemu_fwcfg_dma_read_entry: addr %p, length %u control 0x%x\n",
+	      address, size, be32_to_cpu(dma.control));
+
+	outl(cpu_to_be32((uint32_t)&dma), FW_DMA_PORT_HIGH);
+
+	while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR)
+		__asm__ __volatile__ ("pause");
+}
+
+static bool qemu_fwcfg_present(void)
+{
+	uint32_t qemu;
+
+	qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
+	return be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE;
+}
+
+static bool qemu_fwcfg_dma_present(void)
+{
+	uint8_t dma_enabled;
+
+	qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
+	if (dma_enabled & FW_CFG_DMA_ENABLED)
+		return true;
+
+	return false;
+}
+
+static void qemu_fwcfg_read_entry(uint16_t entry,
+		uint32_t length, void *address)
+{
+	if (fwcfg_dma_present)
+		qemu_fwcfg_read_entry_dma(entry, length, address);
+	else
+		qemu_fwcfg_read_entry_pio(entry, length, address);
+}
+
+int qemu_fwcfg_online_cpus(void)
+{
+	uint16_t nb_cpus;
+
+	if (!fwcfg_present)
+		return -ENODEV;
+
+	qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus);
+
+	return le16_to_cpu(nb_cpus);
+}
+
+/*
+ * This function prepares kernel for zboot. It loads kernel data
+ * to 'load_addr', initrd to 'initrd_addr' and kernel command
+ * line using qemu fw_cfg interface.
+ */
+
+static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr)
+{
+	char *data_addr;
+	uint32_t setup_size, kernel_size, cmdline_size, initrd_size;
+
+	qemu_fwcfg_read_entry(FW_CFG_SETUP_SIZE, 4, &setup_size);
+	qemu_fwcfg_read_entry(FW_CFG_KERNEL_SIZE, 4, &kernel_size);
+
+	if (setup_size == 0 || kernel_size == 0) {
+		printf("warning: no kernel available\n");
+		return -1;
+	}
+
+	data_addr = load_addr;
+	qemu_fwcfg_read_entry(FW_CFG_SETUP_DATA,
+			      le32_to_cpu(setup_size), data_addr);
+	data_addr += le32_to_cpu(setup_size);
+
+	qemu_fwcfg_read_entry(FW_CFG_KERNEL_DATA,
+			      le32_to_cpu(kernel_size), data_addr);
+	data_addr += le32_to_cpu(kernel_size);
+
+	data_addr = initrd_addr;
+	qemu_fwcfg_read_entry(FW_CFG_INITRD_SIZE, 4, &initrd_size);
+	if (initrd_size == 0) {
+		printf("warning: no initrd available\n");
+	} else {
+		qemu_fwcfg_read_entry(FW_CFG_INITRD_DATA,
+				      le32_to_cpu(initrd_size), data_addr);
+		data_addr += le32_to_cpu(initrd_size);
+	}
+
+	qemu_fwcfg_read_entry(FW_CFG_CMDLINE_SIZE, 4, &cmdline_size);
+	if (cmdline_size) {
+		qemu_fwcfg_read_entry(FW_CFG_CMDLINE_DATA,
+				      le32_to_cpu(cmdline_size), data_addr);
+		if (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 i;
+	uint32_t count;
+	struct fw_cfg_files *files;
+
+	qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count);
+	if (!count)
+		return 0;
+
+	count = be32_to_cpu(count);
+	files = malloc(count * sizeof(struct fw_cfg_file));
+	if (!files)
+		return -ENOMEM;
+
+	files->count = count;
+	qemu_fwcfg_read_entry(FW_CFG_INVALID,
+			      count * sizeof(struct fw_cfg_file),
+			      files->files);
+
+	for (i = 0; i < files->count; i++)
+		printf("%-56s\n", files->files[i].name);
+	free(files);
+	return 0;
+}
+
+void qemu_fwcfg_init(void)
+{
+	fwcfg_present = qemu_fwcfg_present();
+	if (fwcfg_present)
+		fwcfg_dma_present = qemu_fwcfg_dma_present();
+}
+
+static int qemu_fwcfg_do_list(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	if (qemu_fwcfg_list_firmware() < 0)
+		return CMD_RET_FAILURE;
+
+	return 0;
+}
+
+static int qemu_fwcfg_do_cpus(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	int ret = qemu_fwcfg_online_cpus();
+	if (ret < 0) {
+		printf("QEMU fw_cfg interface not found\n");
+		return CMD_RET_FAILURE;
+	}
+
+	printf("%d cpu(s) online\n", qemu_fwcfg_online_cpus());
+
+	return 0;
+}
+
+static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	char *env;
+	void *load_addr;
+	void *initrd_addr;
+
+	env = getenv("loadaddr");
+	load_addr = env ?
+		(void *)simple_strtoul(env, NULL, 16) :
+		(void *)CONFIG_LOADADDR;
+
+	env = getenv("ramdiskaddr");
+	initrd_addr = env ?
+		(void *)simple_strtoul(env, NULL, 16) :
+		(void *)CONFIG_RAMDISK_ADDR;
+
+	if (argc == 2) {
+		load_addr = (void *)simple_strtoul(argv[0], NULL, 16);
+		initrd_addr = (void *)simple_strtoul(argv[1], NULL, 16);
+	} else if (argc == 1) {
+		load_addr = (void *)simple_strtoul(argv[0], NULL, 16);
+	}
+
+	return qemu_fwcfg_setup_kernel(load_addr, initrd_addr);
+}
+
+static cmd_tbl_t fwcfg_commands[] = {
+	U_BOOT_CMD_MKENT(list, 0, 1, qemu_fwcfg_do_list, "", ""),
+	U_BOOT_CMD_MKENT(cpus, 0, 1, qemu_fwcfg_do_cpus, "", ""),
+	U_BOOT_CMD_MKENT(load, 2, 1, qemu_fwcfg_do_load, "", ""),
+};
+
+static int do_qemu_fw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int ret;
+	cmd_tbl_t *fwcfg_cmd;
+
+	if (!fwcfg_present) {
+		printf("QEMU fw_cfg interface not found\n");
+		return CMD_RET_USAGE;
+	}
+
+	fwcfg_cmd = find_cmd_tbl(argv[1], fwcfg_commands,
+				 ARRAY_SIZE(fwcfg_commands));
+	argc -= 2;
+	argv += 2;
+	if (!fwcfg_cmd || argc > fwcfg_cmd->maxargs)
+		return CMD_RET_USAGE;
+
+	ret = fwcfg_cmd->cmd(fwcfg_cmd, flag, argc, argv);
+
+	return cmd_process_error(fwcfg_cmd, ret);
+}
+
+U_BOOT_CMD(
+	qfw,	4,	1,	do_qemu_fw,
+	"QEMU firmware interface",
+	"<command>\n"
+	"    - list                             : print firmware(s) currently loaded\n"
+	"    - cpus                             : print online cpu number\n"
+	"    - load <kernel addr> <initrd addr> : load kernel and initrd (if any), and setup for zboot\n"
+)
diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c
index 1f93f72..46111c9 100644
--- a/arch/x86/cpu/qemu/qemu.c
+++ b/arch/x86/cpu/qemu/qemu.c
@@ -11,6 +11,7 @@
 #include <asm/processor.h>
 #include <asm/arch/device.h>
 #include <asm/arch/qemu.h>
+#include <asm/fw_cfg.h>
 
 static bool i440fx;
 
@@ -57,6 +58,8 @@ static void qemu_chipset_init(void)
 		x86_pci_write_config32(PCI_BDF(0, 0, 0), PCIEX_BAR,
 				       CONFIG_PCIE_ECAM_BASE | BAR_EN);
 	}
+
+	qemu_fwcfg_init();
 }
 
 int arch_cpu_init(void)
diff --git a/arch/x86/include/asm/fw_cfg.h b/arch/x86/include/asm/fw_cfg.h
new file mode 100644
index 0000000..18ab3fc
--- /dev/null
+++ b/arch/x86/include/asm/fw_cfg.h
@@ -0,0 +1,95 @@
+/*
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __FW_CFG__
+#define __FW_CFG__
+
+#define FW_CONTROL_PORT	0x510
+#define FW_DATA_PORT		0x511
+#define FW_DMA_PORT_LOW	0x514
+#define FW_DMA_PORT_HIGH	0x518
+
+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,
+};
+
+#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 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_cfg_files {
+	__be32 count;
+	struct fw_cfg_file files[];
+};
+
+struct fw_cfg_dma_access {
+	__be32 control;
+	__be32 length;
+	__be64 address;
+};
+
+/**
+ * Initialize QEMU fw_cfg interface
+ */
+
+void qemu_fwcfg_init(void);
+
+/**
+ * Get system cpu number
+ *
+ * @return:   cpu number in system
+ */
+
+int qemu_fwcfg_online_cpus(void);
+
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 3/8] x86: qemu: add a cpu uclass driver for qemu target
  2016-01-04  8:00 [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets Miao Yan
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 1/8] x86: adjust ramdisk load address Miao Yan
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 2/8] x86: qemu: add fw_cfg support Miao Yan
@ 2016-01-04  8:00 ` Miao Yan
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 4/8] x86: fix a typo in function name Miao Yan
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Miao Yan @ 2016-01-04  8:00 UTC (permalink / raw)
  To: u-boot

Add a cpu uclass driver for qemu. Previously, the qemu target gets cpu
number from board dts files, which are manually created at compile time.
This does not scale when more cpus are assigned to guest as the dts files
must be modified as well.

This patch adds a cpu uclass driver for qemu targets to directly read
online cpu number from firmware.

Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 arch/x86/cpu/qemu/Makefile       |  2 +-
 arch/x86/cpu/qemu/cpu.c          | 57 ++++++++++++++++++++++++++++++++++++++++
 arch/x86/dts/qemu-x86_i440fx.dts |  4 +--
 arch/x86/dts/qemu-x86_q35.dts    |  4 +--
 4 files changed, 62 insertions(+), 5 deletions(-)
 create mode 100644 arch/x86/cpu/qemu/cpu.c

diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile
index d613798..176ea54 100644
--- a/arch/x86/cpu/qemu/Makefile
+++ b/arch/x86/cpu/qemu/Makefile
@@ -7,5 +7,5 @@
 ifndef CONFIG_EFI_STUB
 obj-y += car.o dram.o
 endif
-obj-y += fw_cfg.o qemu.o
+obj-y += cpu.o fw_cfg.o qemu.o
 obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o
diff --git a/arch/x86/cpu/qemu/cpu.c b/arch/x86/cpu/qemu/cpu.c
new file mode 100644
index 0000000..a4bf53d
--- /dev/null
+++ b/arch/x86/cpu/qemu/cpu.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015, Miao Yan <yanmiaobest@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/cpu.h>
+#include <asm/fw_cfg.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cpu_qemu_bind(struct udevice *dev)
+{
+	struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+
+	plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+				      "intel,apic-id", -1);
+
+	return 0;
+}
+
+int cpu_qemu_get_desc(struct udevice *dev, char *buf, int size)
+{
+	if (size < CPU_MAX_NAME_LEN)
+		return -ENOSPC;
+
+	cpu_get_name(buf);
+
+	return 0;
+}
+
+static int cpu_qemu_get_count(struct udevice *dev)
+{
+	return qemu_fwcfg_online_cpus();
+}
+
+static const struct cpu_ops cpu_qemu_ops = {
+	.get_desc	= cpu_qemu_get_desc,
+	.get_count	= cpu_qemu_get_count,
+};
+
+static const struct udevice_id cpu_qemu_ids[] = {
+	{ .compatible = "cpu-qemu" },
+	{ }
+};
+
+U_BOOT_DRIVER(cpu_qemu_drv) = {
+	.name		= "cpu_qemu",
+	.id		= UCLASS_CPU,
+	.of_match	= cpu_qemu_ids,
+	.bind		= cpu_qemu_bind,
+	.ops		= &cpu_qemu_ops,
+};
diff --git a/arch/x86/dts/qemu-x86_i440fx.dts b/arch/x86/dts/qemu-x86_i440fx.dts
index 8a06229..4332204 100644
--- a/arch/x86/dts/qemu-x86_i440fx.dts
+++ b/arch/x86/dts/qemu-x86_i440fx.dts
@@ -32,14 +32,14 @@
 
 		cpu@0 {
 			device_type = "cpu";
-			compatible = "cpu-x86";
+			compatible = "cpu-qemu";
 			reg = <0>;
 			intel,apic-id = <0>;
 		};
 
 		cpu at 1 {
 			device_type = "cpu";
-			compatible = "cpu-x86";
+			compatible = "cpu-qemu";
 			reg = <1>;
 			intel,apic-id = <1>;
 		};
diff --git a/arch/x86/dts/qemu-x86_q35.dts b/arch/x86/dts/qemu-x86_q35.dts
index 0b685c8..3e2cfac 100644
--- a/arch/x86/dts/qemu-x86_q35.dts
+++ b/arch/x86/dts/qemu-x86_q35.dts
@@ -43,14 +43,14 @@
 
 		cpu at 0 {
 			device_type = "cpu";
-			compatible = "cpu-x86";
+			compatible = "cpu-qemu";
 			reg = <0>;
 			intel,apic-id = <0>;
 		};
 
 		cpu at 1 {
 			device_type = "cpu";
-			compatible = "cpu-x86";
+			compatible = "cpu-qemu";
 			reg = <1>;
 			intel,apic-id = <1>;
 		};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot]  [PATCH v5 4/8] x86: fix a typo in function name
  2016-01-04  8:00 [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets Miao Yan
                   ` (2 preceding siblings ...)
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 3/8] x86: qemu: add a cpu uclass driver for qemu target Miao Yan
@ 2016-01-04  8:00 ` Miao Yan
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 5/8] x86: use actual CPU number for allocating memory Miao Yan
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Miao Yan @ 2016-01-04  8:00 UTC (permalink / raw)
  To: u-boot

Rename 'find_cpu_by_apid_id' to 'find_cpu_by_apic_id'. This should be a
typo.

Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---
 arch/x86/cpu/mp_init.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
index 4334f5b..2f34317 100644
--- a/arch/x86/cpu/mp_init.c
+++ b/arch/x86/cpu/mp_init.c
@@ -104,7 +104,7 @@ static void ap_do_flight_plan(struct udevice *cpu)
 	}
 }
 
-static int find_cpu_by_apid_id(int apic_id, struct udevice **devp)
+static int find_cpu_by_apic_id(int apic_id, struct udevice **devp)
 {
 	struct udevice *dev;
 
@@ -137,7 +137,7 @@ static void ap_init(unsigned int cpu_index)
 	enable_lapic();
 
 	apic_id = lapicid();
-	ret = find_cpu_by_apid_id(apic_id, &dev);
+	ret = find_cpu_by_apic_id(apic_id, &dev);
 	if (ret) {
 		debug("Unknown CPU apic_id %x\n", apic_id);
 		goto done;
@@ -432,7 +432,7 @@ static int init_bsp(struct udevice **devp)
 	lapic_setup();
 
 	apic_id = lapicid();
-	ret = find_cpu_by_apid_id(apic_id, devp);
+	ret = find_cpu_by_apic_id(apic_id, devp);
 	if (ret) {
 		printf("Cannot find boot CPU, APIC ID %d\n", apic_id);
 		return ret;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 5/8] x86: use actual CPU number for allocating memory
  2016-01-04  8:00 [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets Miao Yan
                   ` (3 preceding siblings ...)
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 4/8] x86: fix a typo in function name Miao Yan
@ 2016-01-04  8:00 ` Miao Yan
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 6/8] x86: qemu: fix cpu device in smp boot Miao Yan
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Miao Yan @ 2016-01-04  8:00 UTC (permalink / raw)
  To: u-boot

Use actual CPU number, instead of maximum cpu configured, to allocate
stack memory in 'load_sipi_vector'

Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---
 arch/x86/cpu/mp_init.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
index 2f34317..2a3ce48 100644
--- a/arch/x86/cpu/mp_init.c
+++ b/arch/x86/cpu/mp_init.c
@@ -210,7 +210,7 @@ static int save_bsp_msrs(char *start, int size)
 	return msr_count;
 }
 
-static int load_sipi_vector(atomic_t **ap_countp)
+static int load_sipi_vector(atomic_t **ap_countp, int num_cpus)
 {
 	struct sipi_params_16bit *params16;
 	struct sipi_params *params;
@@ -239,7 +239,7 @@ static int load_sipi_vector(atomic_t **ap_countp)
 	params->idt_ptr = (uint32_t)x86_get_idt();
 
 	params->stack_size = CONFIG_AP_STACK_SIZE;
-	size = params->stack_size * CONFIG_MAX_CPUS;
+	size = params->stack_size * num_cpus;
 	stack = memalign(size, 4096);
 	if (!stack)
 		return -ENOMEM;
@@ -483,7 +483,7 @@ int mp_init(struct mp_params *p)
 	mp_info.records = p->flight_plan;
 
 	/* Load the SIPI vector */
-	ret = load_sipi_vector(&ap_count);
+	ret = load_sipi_vector(&ap_count, num_cpus);
 	if (ap_count == NULL)
 		return -1;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot]  [PATCH v5 6/8] x86: qemu: fix cpu device in smp boot
  2016-01-04  8:00 [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets Miao Yan
                   ` (4 preceding siblings ...)
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 5/8] x86: use actual CPU number for allocating memory Miao Yan
@ 2016-01-04  8:00 ` Miao Yan
  2016-01-06  0:25   ` Simon Glass
  2016-01-07  7:36   ` Bin Meng
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 7/8] x86: qemu: remove cpu node in device tree Miao Yan
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 8/8] x86: qemu: add documentaion for the fw_cfg interface Miao Yan
  7 siblings, 2 replies; 15+ messages in thread
From: Miao Yan @ 2016-01-04  8:00 UTC (permalink / raw)
  To: u-boot

Currently, when booting with more that one CPU enabled, U-Boot scans
'cpu' node in device tree and calculates CPU number. This does not scale
well as changing CPU number also requires modifying .dts and re-compiling
U-Boot.

This patch uses fw_cfg interface provided by QEMU to detect online CPU
number at runtime, and dynamically adds 'cpu' device to U-Boot's driver
model.

Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
---
 arch/x86/cpu/mp_init.c  | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
 arch/x86/cpu/qemu/cpu.c |  5 ----
 2 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
index 2a3ce48..d217ff0 100644
--- a/arch/x86/cpu/mp_init.c
+++ b/arch/x86/cpu/mp_init.c
@@ -20,8 +20,11 @@
 #include <asm/mtrr.h>
 #include <asm/processor.h>
 #include <asm/sipi.h>
+#include <asm/fw_cfg.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
 #include <linux/linkage.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -441,6 +444,70 @@ static int init_bsp(struct udevice **devp)
 	return 0;
 }
 
+#ifdef CONFIG_QEMU
+static int qemu_cpu_fixup(void)
+{
+	int ret;
+	int cpu_num;
+	int cpu_online;
+	struct udevice *dev, *pdev;
+	struct cpu_platdata *plat;
+	char *cpu;
+
+	/* first we need to find '/cpus' */
+	for (device_find_first_child(dm_root(), &pdev);
+	     pdev;
+	     device_find_next_child(&pdev)) {
+		if (!strcmp(pdev->name, "cpus"))
+			break;
+	}
+	if (!pdev) {
+		printf("unable to find cpus device\n");
+		return -ENODEV;
+	}
+
+	/* calculate cpus that are already bound */
+	cpu_num = 0;
+	for (uclass_find_first_device(UCLASS_CPU, &dev);
+	     dev;
+	     uclass_find_next_device(&dev)) {
+		cpu_num++;
+	}
+
+	/* get actual cpu number */
+	cpu_online = qemu_fwcfg_online_cpus();
+	if (cpu_online < 0) {
+		printf("unable to get online cpu number: %d\n", cpu_online);
+		return cpu_online;
+	}
+
+	/* bind addtional cpus */
+	dev = NULL;
+	for (; cpu_num < cpu_online; cpu_num++) {
+		/*
+		 * allocate device name here as device_bind_driver() does
+		 * not copy device name, 8 bytes are enough for
+		 * sizeof("cpu@") + 3 digits cpu number + '\0'
+		 */
+		cpu = malloc(8);
+		if (!cpu) {
+			printf("unable to allocate device name\n");
+			return -ENOMEM;
+		}
+		sprintf(cpu, "cpu@%d", cpu_num);
+		cpu[7] = '\0';
+		ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev);
+		if (ret) {
+			printf("binding cpu@%d failed: %d\n", cpu_num, ret);
+			return ret;
+		}
+		plat = dev_get_parent_platdata(dev);
+		plat->cpu_id = cpu_num;
+	}
+	return 0;
+}
+#endif
+
 int mp_init(struct mp_params *p)
 {
 	int num_aps;
@@ -454,6 +521,12 @@ int mp_init(struct mp_params *p)
 	if (ret)
 		return ret;
 
+#ifdef CONFIG_QEMU
+	ret = qemu_cpu_fixup();
+	if (ret)
+		return ret;
+#endif
+
 	ret = init_bsp(&cpu);
 	if (ret) {
 		debug("Cannot init boot CPU: err=%d\n", ret);
diff --git a/arch/x86/cpu/qemu/cpu.c b/arch/x86/cpu/qemu/cpu.c
index a4bf53d..e8f486d 100644
--- a/arch/x86/cpu/qemu/cpu.c
+++ b/arch/x86/cpu/qemu/cpu.c
@@ -15,11 +15,6 @@ DECLARE_GLOBAL_DATA_PTR;
 
 int cpu_qemu_bind(struct udevice *dev)
 {
-	struct cpu_platdata *plat = dev_get_parent_platdata(dev);
-
-	plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
-				      "intel,apic-id", -1);
-
 	return 0;
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 7/8] x86: qemu: remove cpu node in device tree
  2016-01-04  8:00 [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets Miao Yan
                   ` (5 preceding siblings ...)
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 6/8] x86: qemu: fix cpu device in smp boot Miao Yan
@ 2016-01-04  8:00 ` Miao Yan
  2016-01-06  0:25   ` Simon Glass
  2016-01-07  7:12   ` Bin Meng
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 8/8] x86: qemu: add documentaion for the fw_cfg interface Miao Yan
  7 siblings, 2 replies; 15+ messages in thread
From: Miao Yan @ 2016-01-04  8:00 UTC (permalink / raw)
  To: u-boot

Remove 'cpu' node in device tree for QEMU targets, and let U-Boot detect
and fix up those information at runtime.

Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
---
 arch/x86/dts/qemu-x86_i440fx.dts | 7 -------
 arch/x86/dts/qemu-x86_q35.dts    | 7 -------
 2 files changed, 14 deletions(-)

diff --git a/arch/x86/dts/qemu-x86_i440fx.dts b/arch/x86/dts/qemu-x86_i440fx.dts
index 4332204..9086b46 100644
--- a/arch/x86/dts/qemu-x86_i440fx.dts
+++ b/arch/x86/dts/qemu-x86_i440fx.dts
@@ -36,13 +36,6 @@
 			reg = <0>;
 			intel,apic-id = <0>;
 		};
-
-		cpu at 1 {
-			device_type = "cpu";
-			compatible = "cpu-qemu";
-			reg = <1>;
-			intel,apic-id = <1>;
-		};
 	};
 
 	tsc-timer {
diff --git a/arch/x86/dts/qemu-x86_q35.dts b/arch/x86/dts/qemu-x86_q35.dts
index 3e2cfac..145e811 100644
--- a/arch/x86/dts/qemu-x86_q35.dts
+++ b/arch/x86/dts/qemu-x86_q35.dts
@@ -47,13 +47,6 @@
 			reg = <0>;
 			intel,apic-id = <0>;
 		};
-
-		cpu at 1 {
-			device_type = "cpu";
-			compatible = "cpu-qemu";
-			reg = <1>;
-			intel,apic-id = <1>;
-		};
 	};
 
 	tsc-timer {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 8/8] x86: qemu: add documentaion for the fw_cfg interface
  2016-01-04  8:00 [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets Miao Yan
                   ` (6 preceding siblings ...)
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 7/8] x86: qemu: remove cpu node in device tree Miao Yan
@ 2016-01-04  8:00 ` Miao Yan
  7 siblings, 0 replies; 15+ messages in thread
From: Miao Yan @ 2016-01-04  8:00 UTC (permalink / raw)
  To: u-boot

Document the usage of 'qfw' command

Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---
Changes in v5:
  - maximum supported is 255 now which is imposed by QEMU
  - 'fw' to 'qfw'

 doc/README.x86 | 34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/doc/README.x86 b/doc/README.x86
index 1271e5e..36aaef0 100644
--- a/doc/README.x86
+++ b/doc/README.x86
@@ -295,9 +295,37 @@ show QEMU's VGA console window. Note this will disable QEMU's serial output.
 If you want to check both consoles, use '-serial stdio'.
 
 Multicore is also supported by QEMU via '-smp n' where n is the number of cores
-to instantiate. Currently the default U-Boot built for QEMU supports 2 cores.
-In order to support more cores, you need add additional cpu nodes in the device
-tree and change CONFIG_MAX_CPUS accordingly.
+to instantiate. Note, the maximum supported CPU number in QEMU is 255.
+
+The fw_cfg interface in QEMU also provides information about kernel data, initrd,
+command-line arguments and more. U-Boot supports directly accessing these informtion
+from fw_cfg interface, this saves the time of loading them from hard disk or
+network again, through emulated devices. To use it , simply providing them in
+QEMU command line:
+
+$ qemu-system-i386 -nographic -bios path/to/u-boot.rom -m 1024 -kernel /path/to/bzImage
+    -append 'root=/dev/ram console=ttyS0' -initrd /path/to/initrd -smp 8
+
+Note: -initrd and -smp are both optional
+
+Then start QEMU, in U-Boot command line use the following U-Boot command to setup kernel:
+
+ => qfw
+qfw - QEMU firmware interface
+
+Usage:
+qfw <command>
+    - list                             : print firmware(s) currently loaded
+    - cpus                             : print online cpu number
+    - load <kernel addr> <initrd addr> : load kernel and initrd (if any) and setup for zboot
+
+=> qfw load
+loading kernel to address 01000000 size 5d9d30 initrd 04000000 size 1b1ab50
+
+Here the kernel (bzImage) is loaded to 01000000 and initrd is to 04000000. Then, 'zboot'
+can be used to boot the kernel:
+
+=> zboot 02000000 - 04000000 1b1ab50
 
 CPU Microcode
 -------------
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 6/8] x86: qemu: fix cpu device in smp boot
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 6/8] x86: qemu: fix cpu device in smp boot Miao Yan
@ 2016-01-06  0:25   ` Simon Glass
  2016-01-06  7:05     ` Miao Yan
  2016-01-07  7:36   ` Bin Meng
  1 sibling, 1 reply; 15+ messages in thread
From: Simon Glass @ 2016-01-06  0:25 UTC (permalink / raw)
  To: u-boot

On 4 January 2016 at 01:00, Miao Yan <yanmiaobest@gmail.com> wrote:
> Currently, when booting with more that one CPU enabled, U-Boot scans
> 'cpu' node in device tree and calculates CPU number. This does not scale
> well as changing CPU number also requires modifying .dts and re-compiling
> U-Boot.
>
> This patch uses fw_cfg interface provided by QEMU to detect online CPU
> number at runtime, and dynamically adds 'cpu' device to U-Boot's driver
> model.
>
> Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
> ---
>  arch/x86/cpu/mp_init.c  | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
>  arch/x86/cpu/qemu/cpu.c |  5 ----
>  2 files changed, 73 insertions(+), 5 deletions(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

Maybe cpu_qemu_bind() isn't needed now?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 7/8] x86: qemu: remove cpu node in device tree
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 7/8] x86: qemu: remove cpu node in device tree Miao Yan
@ 2016-01-06  0:25   ` Simon Glass
  2016-01-07  7:12   ` Bin Meng
  1 sibling, 0 replies; 15+ messages in thread
From: Simon Glass @ 2016-01-06  0:25 UTC (permalink / raw)
  To: u-boot

On 4 January 2016 at 01:00, Miao Yan <yanmiaobest@gmail.com> wrote:
> Remove 'cpu' node in device tree for QEMU targets, and let U-Boot detect
> and fix up those information at runtime.
>
> Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
> ---
>  arch/x86/dts/qemu-x86_i440fx.dts | 7 -------
>  arch/x86/dts/qemu-x86_q35.dts    | 7 -------
>  2 files changed, 14 deletions(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 6/8] x86: qemu: fix cpu device in smp boot
  2016-01-06  0:25   ` Simon Glass
@ 2016-01-06  7:05     ` Miao Yan
  0 siblings, 0 replies; 15+ messages in thread
From: Miao Yan @ 2016-01-06  7:05 UTC (permalink / raw)
  To: u-boot

2016-01-06 8:25 GMT+08:00 Simon Glass <sjg@chromium.org>:
> On 4 January 2016 at 01:00, Miao Yan <yanmiaobest@gmail.com> wrote:
>> Currently, when booting with more that one CPU enabled, U-Boot scans
>> 'cpu' node in device tree and calculates CPU number. This does not scale
>> well as changing CPU number also requires modifying .dts and re-compiling
>> U-Boot.
>>
>> This patch uses fw_cfg interface provided by QEMU to detect online CPU
>> number at runtime, and dynamically adds 'cpu' device to U-Boot's driver
>> model.
>>
>> Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
>> ---
>>  arch/x86/cpu/mp_init.c  | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  arch/x86/cpu/qemu/cpu.c |  5 ----
>>  2 files changed, 73 insertions(+), 5 deletions(-)
>
> Reviewed-by: Simon Glass <sjg@chromium.org>
>
> Maybe cpu_qemu_bind() isn't needed now?

Right, this can be removed.

Hi Bin, do you have any comments on this one ?

Thanks,
Miao

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 2/8] x86: qemu: add fw_cfg support
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 2/8] x86: qemu: add fw_cfg support Miao Yan
@ 2016-01-07  7:05   ` Bin Meng
  0 siblings, 0 replies; 15+ messages in thread
From: Bin Meng @ 2016-01-07  7:05 UTC (permalink / raw)
  To: u-boot

Hi Miao,

On Mon, Jan 4, 2016 at 4:00 PM, Miao Yan <yanmiaobest@gmail.com> wrote:
> The QEMU fw_cfg interface allows the guest to retrieve various data
> information from QEMU. For example, APCI/SMBios tables, number of online
> cpus, kernel data and command line, etc.
>
> This patch adds support for QEMU fw_cfg interface.
>
> Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
> Changes in v5:
>   - change 'fw' to 'qfw'
>   - move fw_cfg.h to include/asm
>   - cleanups
>
>  arch/x86/cpu/qemu/Makefile    |   2 +-
>  arch/x86/cpu/qemu/fw_cfg.c    | 286 ++++++++++++++++++++++++++++++++++++++++++
>  arch/x86/cpu/qemu/qemu.c      |   3 +
>  arch/x86/include/asm/fw_cfg.h |  95 ++++++++++++++
>  4 files changed, 385 insertions(+), 1 deletion(-)
>  create mode 100644 arch/x86/cpu/qemu/fw_cfg.c
>  create mode 100644 arch/x86/include/asm/fw_cfg.h
>
> diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile
> index 3f3958a..d613798 100644
> --- a/arch/x86/cpu/qemu/Makefile
> +++ b/arch/x86/cpu/qemu/Makefile
> @@ -7,5 +7,5 @@
>  ifndef CONFIG_EFI_STUB
>  obj-y += car.o dram.o
>  endif
> -obj-y += qemu.o
> +obj-y += fw_cfg.o qemu.o
>  obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o
> diff --git a/arch/x86/cpu/qemu/fw_cfg.c b/arch/x86/cpu/qemu/fw_cfg.c
> new file mode 100644
> index 0000000..17276c3
> --- /dev/null
> +++ b/arch/x86/cpu/qemu/fw_cfg.c
> @@ -0,0 +1,286 @@
> +/*
> + * (C) Copyright 2015 Miao Yan <yanmiaoebst@gmail.com>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <errno.h>
> +#include <malloc.h>
> +#include <asm/io.h>
> +#include <asm/fw_cfg.h>
> +
> +static bool fwcfg_present;
> +static bool fwcfg_dma_present;
> +
> +/*
> + * Read configuration item using fw_cfg PIO interface
> + */
> +

Please use one-line comment format, as it fits a single line. Also the
blank line here is not needed. Please fix this globally in this file.

> +static void qemu_fwcfg_read_entry_pio(uint16_t entry,
> +               uint32_t size, void *address)
> +{
> +       uint32_t i = 0;
> +       uint8_t *data = address;
> +
> +       /*
> +        * writting FW_CFG_INVALID will cause read operation to resume at
> +        * last offset, otherwise read will start at offset 0
> +        */
> +
> +       if (entry != FW_CFG_INVALID)
> +               outw(entry, FW_CONTROL_PORT);
> +       while (size--)
> +               data[i++] = inb(FW_DATA_PORT);
> +}
> +
> +/*
> + * Read configuration item using fw_cfg DMA interface
> + */
> +
> +static void qemu_fwcfg_read_entry_dma(uint16_t entry,
> +               uint32_t size, void *address)
> +{
> +       struct fw_cfg_dma_access dma;
> +
> +       dma.length = cpu_to_be32(size);
> +       dma.address = cpu_to_be64((uintptr_t)address);
> +       dma.control = cpu_to_be32(FW_CFG_DMA_READ);
> +
> +       /*
> +        * writting FW_CFG_INVALID will cause read operation to resume at
> +        * last offset, otherwise read will start at offset 0
> +        */
> +
> +       if (entry != FW_CFG_INVALID)
> +               dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16));
> +
> +       barrier();
> +
> +       debug("qemu_fwcfg_dma_read_entry: addr %p, length %u control 0x%x\n",
> +             address, size, be32_to_cpu(dma.control));
> +
> +       outl(cpu_to_be32((uint32_t)&dma), FW_DMA_PORT_HIGH);
> +
> +       while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR)
> +               __asm__ __volatile__ ("pause");
> +}
> +
> +static bool qemu_fwcfg_present(void)
> +{
> +       uint32_t qemu;
> +
> +       qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
> +       return be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE;
> +}
> +
> +static bool qemu_fwcfg_dma_present(void)
> +{
> +       uint8_t dma_enabled;
> +
> +       qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
> +       if (dma_enabled & FW_CFG_DMA_ENABLED)
> +               return true;
> +
> +       return false;
> +}
> +
> +static void qemu_fwcfg_read_entry(uint16_t entry,
> +               uint32_t length, void *address)
> +{
> +       if (fwcfg_dma_present)
> +               qemu_fwcfg_read_entry_dma(entry, length, address);
> +       else
> +               qemu_fwcfg_read_entry_pio(entry, length, address);
> +}
> +
> +int qemu_fwcfg_online_cpus(void)
> +{
> +       uint16_t nb_cpus;
> +
> +       if (!fwcfg_present)
> +               return -ENODEV;
> +
> +       qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus);
> +
> +       return le16_to_cpu(nb_cpus);
> +}
> +
> +/*
> + * This function prepares kernel for zboot. It loads kernel data
> + * to 'load_addr', initrd to 'initrd_addr' and kernel command
> + * line using qemu fw_cfg interface.
> + */
> +
> +static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr)
> +{
> +       char *data_addr;
> +       uint32_t setup_size, kernel_size, cmdline_size, initrd_size;
> +
> +       qemu_fwcfg_read_entry(FW_CFG_SETUP_SIZE, 4, &setup_size);
> +       qemu_fwcfg_read_entry(FW_CFG_KERNEL_SIZE, 4, &kernel_size);
> +
> +       if (setup_size == 0 || kernel_size == 0) {
> +               printf("warning: no kernel available\n");
> +               return -1;
> +       }
> +
> +       data_addr = load_addr;
> +       qemu_fwcfg_read_entry(FW_CFG_SETUP_DATA,
> +                             le32_to_cpu(setup_size), data_addr);
> +       data_addr += le32_to_cpu(setup_size);
> +
> +       qemu_fwcfg_read_entry(FW_CFG_KERNEL_DATA,
> +                             le32_to_cpu(kernel_size), data_addr);
> +       data_addr += le32_to_cpu(kernel_size);
> +
> +       data_addr = initrd_addr;
> +       qemu_fwcfg_read_entry(FW_CFG_INITRD_SIZE, 4, &initrd_size);
> +       if (initrd_size == 0) {
> +               printf("warning: no initrd available\n");
> +       } else {
> +               qemu_fwcfg_read_entry(FW_CFG_INITRD_DATA,
> +                                     le32_to_cpu(initrd_size), data_addr);
> +               data_addr += le32_to_cpu(initrd_size);
> +       }
> +
> +       qemu_fwcfg_read_entry(FW_CFG_CMDLINE_SIZE, 4, &cmdline_size);
> +       if (cmdline_size) {

Testing shows that invoking QEMU without '-append' parameter, with
cause cmdline_size here equals to 1. I think this is because QEMU pass
a \000 as the command line to the guest. Please handle this correctly,
and adding a comment block for this as well.

> +               qemu_fwcfg_read_entry(FW_CFG_CMDLINE_DATA,
> +                                     le32_to_cpu(cmdline_size), data_addr);
> +               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 i;
> +       uint32_t count;
> +       struct fw_cfg_files *files;
> +
> +       qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count);
> +       if (!count)
> +               return 0;
> +
> +       count = be32_to_cpu(count);
> +       files = malloc(count * sizeof(struct fw_cfg_file));
> +       if (!files)
> +               return -ENOMEM;
> +
> +       files->count = count;
> +       qemu_fwcfg_read_entry(FW_CFG_INVALID,
> +                             count * sizeof(struct fw_cfg_file),
> +                             files->files);
> +
> +       for (i = 0; i < files->count; i++)
> +               printf("%-56s\n", files->files[i].name);
> +       free(files);
> +       return 0;
> +}
> +
> +void qemu_fwcfg_init(void)
> +{
> +       fwcfg_present = qemu_fwcfg_present();
> +       if (fwcfg_present)
> +               fwcfg_dma_present = qemu_fwcfg_dma_present();
> +}
> +
> +static int qemu_fwcfg_do_list(cmd_tbl_t *cmdtp, int flag,
> +               int argc, char * const argv[])
> +{
> +       if (qemu_fwcfg_list_firmware() < 0)
> +               return CMD_RET_FAILURE;
> +
> +       return 0;
> +}
> +
> +static int qemu_fwcfg_do_cpus(cmd_tbl_t *cmdtp, int flag,
> +               int argc, char * const argv[])
> +{
> +       int ret = qemu_fwcfg_online_cpus();
> +       if (ret < 0) {
> +               printf("QEMU fw_cfg interface not found\n");
> +               return CMD_RET_FAILURE;
> +       }
> +
> +       printf("%d cpu(s) online\n", qemu_fwcfg_online_cpus());
> +
> +       return 0;
> +}
> +
> +static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag,
> +               int argc, char * const argv[])
> +{
> +       char *env;
> +       void *load_addr;
> +       void *initrd_addr;
> +
> +       env = getenv("loadaddr");
> +       load_addr = env ?
> +               (void *)simple_strtoul(env, NULL, 16) :
> +               (void *)CONFIG_LOADADDR;
> +
> +       env = getenv("ramdiskaddr");
> +       initrd_addr = env ?
> +               (void *)simple_strtoul(env, NULL, 16) :
> +               (void *)CONFIG_RAMDISK_ADDR;
> +
> +       if (argc == 2) {
> +               load_addr = (void *)simple_strtoul(argv[0], NULL, 16);
> +               initrd_addr = (void *)simple_strtoul(argv[1], NULL, 16);
> +       } else if (argc == 1) {
> +               load_addr = (void *)simple_strtoul(argv[0], NULL, 16);
> +       }
> +
> +       return qemu_fwcfg_setup_kernel(load_addr, initrd_addr);
> +}
> +
> +static cmd_tbl_t fwcfg_commands[] = {
> +       U_BOOT_CMD_MKENT(list, 0, 1, qemu_fwcfg_do_list, "", ""),
> +       U_BOOT_CMD_MKENT(cpus, 0, 1, qemu_fwcfg_do_cpus, "", ""),
> +       U_BOOT_CMD_MKENT(load, 2, 1, qemu_fwcfg_do_load, "", ""),
> +};
> +
> +static int do_qemu_fw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       int ret;
> +       cmd_tbl_t *fwcfg_cmd;
> +
> +       if (!fwcfg_present) {
> +               printf("QEMU fw_cfg interface not found\n");
> +               return CMD_RET_USAGE;
> +       }
> +
> +       fwcfg_cmd = find_cmd_tbl(argv[1], fwcfg_commands,
> +                                ARRAY_SIZE(fwcfg_commands));
> +       argc -= 2;
> +       argv += 2;
> +       if (!fwcfg_cmd || argc > fwcfg_cmd->maxargs)
> +               return CMD_RET_USAGE;
> +
> +       ret = fwcfg_cmd->cmd(fwcfg_cmd, flag, argc, argv);
> +
> +       return cmd_process_error(fwcfg_cmd, ret);
> +}
> +
> +U_BOOT_CMD(
> +       qfw,    4,      1,      do_qemu_fw,
> +       "QEMU firmware interface",
> +       "<command>\n"
> +       "    - list                             : print firmware(s) currently loaded\n"
> +       "    - cpus                             : print online cpu number\n"
> +       "    - load <kernel addr> <initrd addr> : load kernel and initrd (if any), and setup for zboot\n"
> +)
> diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c
> index 1f93f72..46111c9 100644
> --- a/arch/x86/cpu/qemu/qemu.c
> +++ b/arch/x86/cpu/qemu/qemu.c
> @@ -11,6 +11,7 @@
>  #include <asm/processor.h>
>  #include <asm/arch/device.h>
>  #include <asm/arch/qemu.h>
> +#include <asm/fw_cfg.h>
>
>  static bool i440fx;
>
> @@ -57,6 +58,8 @@ static void qemu_chipset_init(void)
>                 x86_pci_write_config32(PCI_BDF(0, 0, 0), PCIEX_BAR,
>                                        CONFIG_PCIE_ECAM_BASE | BAR_EN);
>         }
> +
> +       qemu_fwcfg_init();
>  }
>
>  int arch_cpu_init(void)
> diff --git a/arch/x86/include/asm/fw_cfg.h b/arch/x86/include/asm/fw_cfg.h
> new file mode 100644
> index 0000000..18ab3fc
> --- /dev/null
> +++ b/arch/x86/include/asm/fw_cfg.h
> @@ -0,0 +1,95 @@
> +/*
> + * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#ifndef __FW_CFG__
> +#define __FW_CFG__
> +
> +#define FW_CONTROL_PORT        0x510
> +#define FW_DATA_PORT           0x511
> +#define FW_DMA_PORT_LOW        0x514
> +#define FW_DMA_PORT_HIGH       0x518
> +
> +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,
> +};
> +
> +#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 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_cfg_files {
> +       __be32 count;
> +       struct fw_cfg_file files[];
> +};
> +
> +struct fw_cfg_dma_access {
> +       __be32 control;
> +       __be32 length;
> +       __be64 address;
> +};
> +
> +/**
> + * Initialize QEMU fw_cfg interface
> + */
> +
> +void qemu_fwcfg_init(void);
> +
> +/**
> + * Get system cpu number
> + *
> + * @return:   cpu number in system
> + */
> +
> +int qemu_fwcfg_online_cpus(void);
> +
> +#endif
> --

Regards,
Bin

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 7/8] x86: qemu: remove cpu node in device tree
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 7/8] x86: qemu: remove cpu node in device tree Miao Yan
  2016-01-06  0:25   ` Simon Glass
@ 2016-01-07  7:12   ` Bin Meng
  1 sibling, 0 replies; 15+ messages in thread
From: Bin Meng @ 2016-01-07  7:12 UTC (permalink / raw)
  To: u-boot

On Mon, Jan 4, 2016 at 4:00 PM, Miao Yan <yanmiaobest@gmail.com> wrote:
> Remove 'cpu' node in device tree for QEMU targets, and let U-Boot detect
> and fix up those information at runtime.
>
> Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
> ---
>  arch/x86/dts/qemu-x86_i440fx.dts | 7 -------
>  arch/x86/dts/qemu-x86_q35.dts    | 7 -------
>  2 files changed, 14 deletions(-)
>

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v5 6/8] x86: qemu: fix cpu device in smp boot
  2016-01-04  8:00 ` [U-Boot] [PATCH v5 6/8] x86: qemu: fix cpu device in smp boot Miao Yan
  2016-01-06  0:25   ` Simon Glass
@ 2016-01-07  7:36   ` Bin Meng
  1 sibling, 0 replies; 15+ messages in thread
From: Bin Meng @ 2016-01-07  7:36 UTC (permalink / raw)
  To: u-boot

On Mon, Jan 4, 2016 at 4:00 PM, Miao Yan <yanmiaobest@gmail.com> wrote:
> Currently, when booting with more that one CPU enabled, U-Boot scans
> 'cpu' node in device tree and calculates CPU number. This does not scale
> well as changing CPU number also requires modifying .dts and re-compiling
> U-Boot.
>
> This patch uses fw_cfg interface provided by QEMU to detect online CPU
> number at runtime, and dynamically adds 'cpu' device to U-Boot's driver
> model.
>
> Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
> ---
>  arch/x86/cpu/mp_init.c  | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
>  arch/x86/cpu/qemu/cpu.c |  5 ----
>  2 files changed, 73 insertions(+), 5 deletions(-)
>

[snip]

>  int cpu_qemu_bind(struct udevice *dev)
>  {
> -       struct cpu_platdata *plat = dev_get_parent_platdata(dev);
> -
> -       plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
> -                                     "intel,apic-id", -1);
> -
>         return 0;
>  }

Yep, this cpu_qemu_bind can be removed.

>

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2016-01-07  7:36 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-04  8:00 [U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets Miao Yan
2016-01-04  8:00 ` [U-Boot] [PATCH v5 1/8] x86: adjust ramdisk load address Miao Yan
2016-01-04  8:00 ` [U-Boot] [PATCH v5 2/8] x86: qemu: add fw_cfg support Miao Yan
2016-01-07  7:05   ` Bin Meng
2016-01-04  8:00 ` [U-Boot] [PATCH v5 3/8] x86: qemu: add a cpu uclass driver for qemu target Miao Yan
2016-01-04  8:00 ` [U-Boot] [PATCH v5 4/8] x86: fix a typo in function name Miao Yan
2016-01-04  8:00 ` [U-Boot] [PATCH v5 5/8] x86: use actual CPU number for allocating memory Miao Yan
2016-01-04  8:00 ` [U-Boot] [PATCH v5 6/8] x86: qemu: fix cpu device in smp boot Miao Yan
2016-01-06  0:25   ` Simon Glass
2016-01-06  7:05     ` Miao Yan
2016-01-07  7:36   ` Bin Meng
2016-01-04  8:00 ` [U-Boot] [PATCH v5 7/8] x86: qemu: remove cpu node in device tree Miao Yan
2016-01-06  0:25   ` Simon Glass
2016-01-07  7:12   ` Bin Meng
2016-01-04  8:00 ` [U-Boot] [PATCH v5 8/8] x86: qemu: add documentaion for the fw_cfg interface Miao Yan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.