qemu-devel
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]