[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] dtb support on x86 machines
From: |
João Henrique Freitas |
Subject: |
Re: [Qemu-devel] dtb support on x86 machines |
Date: |
Mon, 8 Dec 2014 13:30:08 -0200 |
Hi,
Any thoughts?
Thanks.
On Sun, Nov 30, 2014 at 6:16 PM, João Henrique Ferreira de Freitas
<address@hidden> wrote:
> Hi,
>
>
> I would like to share my work-in-progress about device-tree on qemux x86
> machine. The patch is not fully functional but works as a proof of concept.
> It is based on qemu stable-2.1 and when I solve my questions I will do using
> master branch.
>
> Besides that device-tree on x86 machines is not widespread used but works.
> The bootloader syslinux has support to it and I am doing the similar patches
> to kexec too. So I deciced to do the some with qemu. ;)
>
> The patch uses setup_data field of linux boot protocol
> (https://www.kernel.org/doc/Documentation/x86/boot.txt) which is a linked
> list of 'struct setup_data'. Usually setup_data is used to extend boot
> parameters. I am using it to put a loaded dtb there.
>
> Until now you can see the patch at
> https://github.com/joaohf/qemu/commit/941d68e6126b4e0908fdd8a90fa7d3f28098a49f.
> I will send it to qemu-devel list when I solve my biggest question that I am
> going to explain later.
>
> ------ begin ----
>
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index ef9fad8..94467ba 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -51,6 +51,7 @@
> #include "exec/address-spaces.h"
> #include "sysemu/arch_init.h"
> #include "qemu/bitmap.h"
> +#include "sysemu/device_tree.h"
> #include "qemu/config-file.h"
> #include "hw/acpi/acpi.h"
> #include "hw/acpi/cpu_hotplug.h"
> @@ -75,7 +76,7 @@
> /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables
> * (128K) and other BIOS datastructures (less than 4K reported to be used
> at
> * the moment, 32K should be enough for a while). */
> -unsigned acpi_data_size = 0x20000 + 0x8000;
> +unsigned acpi_data_size = 0x20000 + 0x80000;
> void pc_set_legacy_acpi_data_size(void)
> {
> acpi_data_size = 0x10000;
> @@ -741,17 +742,77 @@ static long get_file_size(FILE *f)
> return size;
> }
>
> +static int load_dtb(FWCfgState *fw_cfg,
> + const char *dtb_filename,
> + void **dtb_addr,
> + int *dtb_size)
> +{
> + void *fdt = NULL;
> +
> + fdt = load_device_tree(dtb_filename, dtb_size);
> + if (!fdt) {
> + fprintf(stderr, "Couldn't open dtb file %s\n", dtb_filename);
> + return -1;
> + }
> +
> + qemu_fdt_dumpdtb(fdt, *dtb_size);
> +
> + *dtb_addr = fdt;
> +
> + return 0;
> +}
> +
> +struct setup_data {
> + uint64_t next;
> + uint32_t type;
> +#define SETUP_NONE 0
> +#define SETUP_E820_EXT 1
> +#define SETUP_DTB 2
> +#define SETUP_PCI 3
> +#define SETUP_EFI 4
> + uint32_t len;
> + uint8_t data[0];
> +} __attribute__((packed));
> +
> +static int setup_dtb_data(FWCfgState *fw_cfg,
> + void **setup_data_addr, int *setup_data_size,
> + void *dtb_addr, off_t dtb_size)
> +{
> + struct setup_data *sd;
> + int sdsize;
> +
> + sd = g_malloc(sizeof(struct setup_data) + dtb_size);
> + if (!sd) {
> + return -1;
> + }
> +
> + memset(sd, 0, sizeof(struct setup_data) + dtb_size);
> + sd->next = 0;
> + sd->type = SETUP_DTB;
> + sd->len = dtb_size;
> + memcpy(sd->data, dtb_addr, dtb_size);
> +
> + sdsize = sd->len + sizeof(struct setup_data);
> +
> + *setup_data_addr = (void *) sd;
> + *setup_data_size = sdsize;
> +
> + return 0;
> +}
> +
> static void load_linux(FWCfgState *fw_cfg,
> const char *kernel_filename,
> const char *initrd_filename,
> + const char *dtb_filename,
> const char *kernel_cmdline,
> hwaddr max_ram_size)
> {
> uint16_t protocol;
> - int setup_size, kernel_size, initrd_size = 0, cmdline_size;
> + int setup_size, kernel_size, initrd_size = 0, cmdline_size, dtb_size =
> 0, setup_data_size = 0;;
> uint32_t initrd_max;
> uint8_t header[8192], *setup, *kernel, *initrd_data;
> - hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0;
> + hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0,
> setup_data_addr = 0;
> + void *dtb_addr, *setup_data;
> FILE *f;
> char *vmode;
>
> @@ -891,6 +952,53 @@ static void load_linux(FWCfgState *fw_cfg,
> stl_p(header+0x21c, initrd_size);
> }
>
> + /* load dtb */
> + if (dtb_filename) {
> + int retval;
> + retval = load_dtb(fw_cfg, dtb_filename, &dtb_addr, &dtb_size);
> + if (retval < 0) {
> + fprintf(stderr, "qemu: error loading dtb %s: %s\n",
> + dtb_filename, strerror(errno));
> + exit(1);
> + }
> +
> + retval = setup_dtb_data(fw_cfg, &setup_data, &setup_data_size,
> + dtb_addr, dtb_size);
> + if (retval < 0) {
> + fprintf(stderr, "qemu: error no memory to setup_data\n");
> + exit(1);
> + }
> +
> +// if (!initrd_addr) {
> +// setup_data_addr = (initrd_max-initrd_size-setup_data_size) &
> ~4095;
> +// } else {
> + setup_data_addr =
> QEMU_ALIGN_UP(initrd_max-initrd_size-setup_data_size, 4096);
> +// }
> +
> + stq_p(header+0x250, setup_data_addr);
> +
> + cpu_physical_memory_write(setup_data_addr, setup_data,
> setup_data_size);
> +
>
> ----------
>
> Above you can see how a dtb are loaded and how setup_data is filled. I am
> put setup_data_addr at header[0x250] and tells to qemu to write
> setup_data_addr to guest memory.
>
> This approach works and I can see my device-tree at guest
> '/proc/device-tree'.
>
> ----------
> +#if 1
> + fprintf(stderr,
> + "qemu: initrd_max = %d\n"
> + "qemu: dtb addr = 0x%p\n"
> + "qemu: dtb size = %d\n"
> + "qemu: setup_data size = %d\n"
> + "qemu: setup_data addr = 0x%p\n"
> + "qemu: setup_data_addr = 0x" TARGET_FMT_plx "\n"
> + "qemu: header[0x250] = " TARGET_FMT_plx "\n",
> + initrd_max,
> + dtb_addr,
> + dtb_size,
> + setup_data_size,
> + setup_data,
> + setup_data_addr,
> + ldq_p(header+0x250));
> +#endif
> +
> + }
> +
> /* load kernel and setup */
> setup_size = header[0x1f1];
> if (setup_size == 0) {
> @@ -911,6 +1019,11 @@ static void load_linux(FWCfgState *fw_cfg,
> exit(1);
> }
> fclose(f);
> +
> + fprintf(stderr,
> + "qemu: setup_size = %d\n",
> + setup_size);
> +
> memcpy(setup, header, MIN(sizeof(header), setup_size));
>
> fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
> @@ -1298,7 +1411,7 @@ FWCfgState *pc_memory_init(MachineState *machine,
>
> if (linux_boot) {
> load_linux(fw_cfg, machine->kernel_filename,
> machine->initrd_filename,
> - machine->kernel_cmdline, below_4g_mem_size);
> + machine->dtb_filename, machine->kernel_cmdline,
> below_4g_mem_size);
> }
>
> for (i = 0; i < nb_option_roms; i++) {
>
> ------------ end -------------
>
> So, running a qemu instance gives the following. Pay attention I am using
> the '-dtb' parameter to load device-tree.
>
> Running qemu-system-i386...
> /srv/yocto/build/dizzy/tmp/sysroots/x86_64-linux/usr/bin/qemu-system-i386
> -kernel bzImage
> -net nic,vlan=0 -net tap,vlan=0,ifname=tap0,script=no,downscript=no -cpu
> qemu32 -hda image-lsb-qemux86.ext3
> -show-cursor -usb -usbdevice wacom-tablet -vga vmware -no-reboot -dtb
> device_tree_lc.dtb
> -m 256 --append "vga=0 uvesafb.mode_option=640x480-32 root=/dev/hda rw
> mem=256M
> ip=192.168.7.2::192.168.7.1:255.255.255.0 oprofile.timer=1 "
> qemu: initrd_max = 267780095
> qemu: dtb addr = 0x0x7f0d80beb010
> qemu: dtb size = 134848
> qemu: setup_data size = 134864
> qemu: setup_data addr = 0x0x7f0d80a74010
> qemu: setup_data_addr = 0x000000000ff40000
> qemu: header[0x250] = 000000000ff40000
> qemu: setup_size = 15360
>
>
> [ 0.000000] Initializing cgroup subsys cpuset
> [ 0.000000] Initializing cgroup subsys cpu
> [ 0.000000] Initializing cgroup subsys cpuacct
> [ 0.000000] Linux version 3.10.55-ltsi-yocto-standard (address@hidden) (gcc
> version 4.8.2 (GCC) ) #1 SMP PREEMPT Fri Oct 31 19:23:26 BRST 2014
> [ 0.000000] e820: BIOS-provided physical RAM map:
> [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
> [ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff]
> reserved
> [ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff]
> reserved
> [ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000000ffdffff] usable
> [ 0.000000] BIOS-e820: [mem 0x000000000ffe0000-0x000000000fffffff]
> reserved
> [ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff]
> reserved
> [ 0.000000] e820: update [mem 0x0ff40000-0x0ff60ecf] usable ==> usable
> [ 0.000000] extended physical RAM map:
> [ 0.000000] reserve setup_data: [mem
> 0x0000000000000000-0x000000000009fbff] usable
> [ 0.000000] reserve setup_data: [mem
> 0x000000000009fc00-0x000000000009ffff] reserved
> [ 0.000000] reserve setup_data: [mem
> 0x00000000000f0000-0x00000000000fffff] reserved
> [ 0.000000] reserve setup_data: [mem
> 0x0000000000100000-0x000000000ff3ffff] usable
> [ 0.000000] reserve setup_data: [mem
> 0x000000000ff40000-0x000000000ff60ecf] usable
> [ 0.000000] reserve setup_data: [mem
> 0x000000000ff60ed0-0x000000000ffdffff] usable
> [ 0.000000] reserve setup_data: [mem
> 0x000000000ffe0000-0x000000000fffffff] reserved
> [ 0.000000] reserve setup_data: [mem
> 0x00000000fffc0000-0x00000000ffffffff] reserved
> [ 0.000000] e820: remove [mem 0x10000000-0xfffffffffffffffe] usable
> [ 0.000000] Notice: NX (Execute Disable) protection missing in CPU!
> [ 0.000000] e820: user-defined physical RAM map:
> [ 0.000000] user: [mem 0x0000000000000000-0x000000000009fbff] usable
> [ 0.000000] user: [mem 0x000000000009fc00-0x000000000009ffff] reserved
> [ 0.000000] user: [mem 0x00000000000f0000-0x00000000000fffff] reserved
> [ 0.000000] user: [mem 0x0000000000100000-0x000000000ff3ffff] usable
> [ 0.000000] user: [mem 0x000000000ff40000-0x000000000ff60ecf] usable
> [ 0.000000] user: [mem 0x000000000ff60ed0-0x000000000ffdffff] usable
> [ 0.000000] user: [mem 0x000000000ffe0000-0x000000000fffffff] reserved
> [ 0.000000] user: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
>
>
> Then I conclude that 'setup_data_addr = 0x000000000ff40000' is the guest
> address that qemu put the setup_data (with dtb). In the begin of dmesg we
> can see:
>
> [ 0.000000] reserve setup_data: [mem
> 0x000000000ff40000-0x000000000ff60ecf] usable
> ....
> [ 0.000000] user: [mem 0x000000000ff40000-0x000000000ff60ecf] usable
>
> The size of this memory range is the same of setup_data size (134864).
>
>
> So, the linux claim about 'ioremap on RAM pfn 0xff40'
>
>
> [......]
>
> [ 0.685545] ------------[ cut here ]------------
> [ 0.685758] WARNING: at
> /srv/yocto/build/daisy-padtec-otns/tmp/work/qemux86-padtec-linux/linux-yocto/3.10.55+gitAUTOINC+f79a00265e_8e055f3b66-r0/linux/arch/x86/mm/ioremap.c:63
> __ioremap_check_ram+0x85/0x90()
> [ 0.685912] ioremap on RAM pfn 0xff40
> [ 0.686064] Modules linked in:
> [ 0.686322] CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> 3.10.55-ltsi-yocto-standard #1
> [ 0.686413] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
> rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
> [ 0.686613] cf895c4c cf895c4c cf895c14 c16e3eaa cf895c3c c103650e
> c189f938 cf895c68
> [ 0.686841] 0000003f c102e0e5 c102e0e5 cff3e820 0000ffe0 00000400
> cf895c54 c1036563
> [ 0.687134] 00000009 cf895c4c c189f938 cf895c68 cf895c78 c102e0e5
> c18a9358 0000003f
> [ 0.687349] Call Trace:
> [ 0.687627] [<c16e3eaa>] dump_stack+0x16/0x18
> [ 0.687715] [<c103650e>] warn_slowpath_common+0x5e/0x80
> [ 0.687804] [<c102e0e5>] ? __ioremap_check_ram+0x85/0x90
> [ 0.687880] [<c102e0e5>] ? __ioremap_check_ram+0x85/0x90
> [ 0.688044] [<c1036563>] warn_slowpath_fmt+0x33/0x40
> [ 0.688115] [<c102e0e5>] __ioremap_check_ram+0x85/0x90
> [ 0.688187] [<c103ede0>] walk_system_ram_range+0xe0/0x100
> [ 0.688267] [<c102ddef>] __ioremap_caller+0x6f/0x280
> [ 0.688335] [<c102e060>] ? ioremap_prot+0x20/0x20
> [ 0.688403] [<c134efc4>] ? pci_bus_read_config_word+0x74/0x80
> [ 0.688477] [<c135407e>] ? __pci_bus_find_cap_start+0x1e/0x50
> [ 0.688550] [<c102e01b>] ioremap_nocache+0x1b/0x20
> [ 0.688618] [<c15e2aca>] ? pcibios_add_device+0x3a/0xb0
> [ 0.688687] [<c15e2aca>] pcibios_add_device+0x3a/0xb0
> [ 0.688756] [<c1351900>] pci_device_add+0xd0/0x120
> [ 0.688826] [<c16ddca1>] pci_scan_single_device+0x81/0xa0
> [ 0.688897] [<c1351998>] pci_scan_slot+0x48/0x140
> [ 0.689042] [<c1352584>] pci_scan_child_bus+0x24/0xa0
> [ 0.689114] [<c15e1541>] pci_acpi_scan_root+0x2e1/0x420
> [ 0.689188] [<c1380bba>] acpi_pci_root_add+0x185/0x392
> [ 0.689260] [<c137dcba>] ? acpi_scan_match_handler+0x32/0x57
> [ 0.689332] [<c137de9f>] acpi_bus_device_attach+0x6c/0xb3
> [ 0.689405] [<c1394fdb>] acpi_ns_walk_namespace+0xb9/0x16b
> [ 0.689479] [<c1395433>] acpi_walk_namespace+0x79/0xa0
> [ 0.689548] [<c137de33>] ? acpi_bus_type_and_status+0x88/0x88
> [ 0.689622] [<c137eaca>] acpi_bus_scan+0x95/0xa5
> [ 0.689688] [<c137de33>] ? acpi_bus_type_and_status+0x88/0x88
> [ 0.689762] [<c1a2ea27>] acpi_scan_init+0x47/0x13a
> [ 0.689830] [<c1a2e86a>] acpi_init+0x233/0x276
> [ 0.689900] [<c1a2e637>] ? acpi_sleep_init+0xd2/0xd2
> [ 0.690041] [<c10001ca>] do_one_initcall+0xda/0x130
> [ 0.690117] [<c1a1db6e>] ? buffer_init+0x46/0x46
> [ 0.690187] [<c19fbb70>] kernel_init_freeable+0x130/0x1f7
> [ 0.690258] [<c19fb4d2>] ? do_early_param+0x78/0x78
> [ 0.690329] [<c16e8cad>] ? _raw_spin_unlock_irq+0xd/0x40
> [ 0.690399] [<c16e8cbb>] ? _raw_spin_unlock_irq+0x1b/0x40
> [ 0.690470] [<c1060135>] ? finish_task_switch+0x45/0xa0
> [ 0.690541] [<c16dcea0>] kernel_init+0x10/0x140
> [ 0.690610] [<c16ef537>] ret_from_kernel_thread+0x1b/0x28
> [ 0.690680] [<c16dce90>] ? rest_init+0x80/0x80
> [ 0.692118] ---[ end trace c548593bf4ae83de ]---
>
>
> I can't figure out why linux kernel is claims about:
>
> [ 0.685912] ioremap on RAM pfn 0xff40
>
>
> May I need to map setup_data allocation using a different approach?
>
> How I can reserve the right pointer address and pass it to guest?
>
>
> You can see the full dmesg output at
> https://gist.github.com/joaohf/c4132c767373cf85633c
>
>
> Any help with qemu memory will be lovely.
>
>
> Thanks.
>
> --
> João Henrique Ferreira de Freitas - joaohf_at_gmail.com
> Campinas-SP-Brasil
>
--
João Henrique Ferreira de Freitas - joaohf_at_gmail.com
Campinas-SP-Brasil
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [Qemu-devel] dtb support on x86 machines,
João Henrique Freitas <=