[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] dtb support on x86 machines
From: |
João Henrique Ferreira de Freitas |
Subject: |
[Qemu-devel] dtb support on x86 machines |
Date: |
Sun, 30 Nov 2014 18:16:27 -0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 |
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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] dtb support on x86 machines,
João Henrique Ferreira de Freitas <=