All of lore.kernel.org
 help / color / mirror / Atom feed
From: "João Henrique Ferreira de Freitas" <joaohf@gmail.com>
To: "qemu-devel@nongnu.org" <qemu-devel@nongnu.org>
Subject: [Qemu-devel] dtb support on x86 machines
Date: Sun, 30 Nov 2014 18:16:27 -0200	[thread overview]
Message-ID: <547B7B1B.20100@gmail.com> (raw)

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

             reply	other threads:[~2014-11-30 20:16 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-30 20:16 João Henrique Ferreira de Freitas [this message]
2014-12-08 15:30 ` [Qemu-devel] dtb support on x86 machines João Henrique Freitas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=547B7B1B.20100@gmail.com \
    --to=joaohf@gmail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.