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
next 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.