From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46921) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XvAv7-00039X-Pv for qemu-devel@nongnu.org; Sun, 30 Nov 2014 15:16:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XvAv3-0007Gv-Aq for qemu-devel@nongnu.org; Sun, 30 Nov 2014 15:16:37 -0500 Received: from mail-qa0-x22a.google.com ([2607:f8b0:400d:c00::22a]:34470) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XvAv3-0007GW-5d for qemu-devel@nongnu.org; Sun, 30 Nov 2014 15:16:33 -0500 Received: by mail-qa0-f42.google.com with SMTP id j7so6492822qaq.29 for ; Sun, 30 Nov 2014 12:16:31 -0800 (PST) Received: from [192.168.0.12] ([201.53.206.66]) by mx.google.com with ESMTPSA id w7sm15375645qge.17.2014.11.30.12.16.29 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 30 Nov 2014 12:16:30 -0800 (PST) Message-ID: <547B7B1B.20100@gmail.com> Date: Sun, 30 Nov 2014 18:16:27 -0200 From: =?windows-1252?Q?Jo=E3o_Henrique_Ferreira_de_Freitas?= MIME-Version: 1.0 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 8bit Subject: [Qemu-devel] dtb support on x86 machines List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: "qemu-devel@nongnu.org" 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] [] dump_stack+0x16/0x18 [ 0.687715] [] warn_slowpath_common+0x5e/0x80 [ 0.687804] [] ? __ioremap_check_ram+0x85/0x90 [ 0.687880] [] ? __ioremap_check_ram+0x85/0x90 [ 0.688044] [] warn_slowpath_fmt+0x33/0x40 [ 0.688115] [] __ioremap_check_ram+0x85/0x90 [ 0.688187] [] walk_system_ram_range+0xe0/0x100 [ 0.688267] [] __ioremap_caller+0x6f/0x280 [ 0.688335] [] ? ioremap_prot+0x20/0x20 [ 0.688403] [] ? pci_bus_read_config_word+0x74/0x80 [ 0.688477] [] ? __pci_bus_find_cap_start+0x1e/0x50 [ 0.688550] [] ioremap_nocache+0x1b/0x20 [ 0.688618] [] ? pcibios_add_device+0x3a/0xb0 [ 0.688687] [] pcibios_add_device+0x3a/0xb0 [ 0.688756] [] pci_device_add+0xd0/0x120 [ 0.688826] [] pci_scan_single_device+0x81/0xa0 [ 0.688897] [] pci_scan_slot+0x48/0x140 [ 0.689042] [] pci_scan_child_bus+0x24/0xa0 [ 0.689114] [] pci_acpi_scan_root+0x2e1/0x420 [ 0.689188] [] acpi_pci_root_add+0x185/0x392 [ 0.689260] [] ? acpi_scan_match_handler+0x32/0x57 [ 0.689332] [] acpi_bus_device_attach+0x6c/0xb3 [ 0.689405] [] acpi_ns_walk_namespace+0xb9/0x16b [ 0.689479] [] acpi_walk_namespace+0x79/0xa0 [ 0.689548] [] ? acpi_bus_type_and_status+0x88/0x88 [ 0.689622] [] acpi_bus_scan+0x95/0xa5 [ 0.689688] [] ? acpi_bus_type_and_status+0x88/0x88 [ 0.689762] [] acpi_scan_init+0x47/0x13a [ 0.689830] [] acpi_init+0x233/0x276 [ 0.689900] [] ? acpi_sleep_init+0xd2/0xd2 [ 0.690041] [] do_one_initcall+0xda/0x130 [ 0.690117] [] ? buffer_init+0x46/0x46 [ 0.690187] [] kernel_init_freeable+0x130/0x1f7 [ 0.690258] [] ? do_early_param+0x78/0x78 [ 0.690329] [] ? _raw_spin_unlock_irq+0xd/0x40 [ 0.690399] [] ? _raw_spin_unlock_irq+0x1b/0x40 [ 0.690470] [] ? finish_task_switch+0x45/0xa0 [ 0.690541] [] kernel_init+0x10/0x140 [ 0.690610] [] ret_from_kernel_thread+0x1b/0x28 [ 0.690680] [] ? 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