Hi, Any thoughts?
Thanks. On Sun, Nov 30, 2014 at 6:16 PM, João Henrique Ferreira de Freitas <joa...@gmail.com> 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 (joaohf@azedo) (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