[U-Boot] [PATCH v5 0/8] x86: qemu: add fw_cfg interface support for qemu-x86 targets

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

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 \

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

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

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@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@0 { device_type = "cpu"; - compatible = "cpu-x86"; + compatible = "cpu-qemu"; reg = <0>; intel,apic-id = <0>; };
cpu@1 { device_type = "cpu"; - compatible = "cpu-x86"; + compatible = "cpu-qemu"; reg = <1>; intel,apic-id = <1>; };

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;

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;

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

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?

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

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

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@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@1 { - device_type = "cpu"; - compatible = "cpu-qemu"; - reg = <1>; - intel,apic-id = <1>; - }; };
tsc-timer {

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

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

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 -------------
participants (3)
-
Bin Meng
-
Miao Yan
-
Simon Glass