xref: /kvmtool/arm/fdt.c (revision 2454c7dc0d18f1fa18f90733df556cd0ee7f571f)
17c0e8b0cSWill Deacon #include "kvm/devices.h"
27c0e8b0cSWill Deacon #include "kvm/fdt.h"
37c0e8b0cSWill Deacon #include "kvm/kvm.h"
47c0e8b0cSWill Deacon #include "kvm/kvm-cpu.h"
57c0e8b0cSWill Deacon #include "kvm/virtio-mmio.h"
67c0e8b0cSWill Deacon 
77c0e8b0cSWill Deacon #include "arm-common/gic.h"
87c0e8b0cSWill Deacon 
97c0e8b0cSWill Deacon #include <stdbool.h>
107c0e8b0cSWill Deacon 
117c0e8b0cSWill Deacon #include <asm/setup.h>
127c0e8b0cSWill Deacon #include <linux/byteorder.h>
137c0e8b0cSWill Deacon #include <linux/kernel.h>
147c0e8b0cSWill Deacon #include <linux/sizes.h>
157c0e8b0cSWill Deacon 
167c0e8b0cSWill Deacon static char kern_cmdline[COMMAND_LINE_SIZE];
177c0e8b0cSWill Deacon 
187c0e8b0cSWill Deacon bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
197c0e8b0cSWill Deacon {
207c0e8b0cSWill Deacon 	return false;
217c0e8b0cSWill Deacon }
227c0e8b0cSWill Deacon 
237c0e8b0cSWill Deacon int kvm__arch_setup_firmware(struct kvm *kvm)
247c0e8b0cSWill Deacon {
257c0e8b0cSWill Deacon 	return 0;
267c0e8b0cSWill Deacon }
277c0e8b0cSWill Deacon 
28ba27ff46SWill Deacon static void dump_fdt(const char *dtb_file, void *fdt)
297c0e8b0cSWill Deacon {
307c0e8b0cSWill Deacon 	int count, fd;
317c0e8b0cSWill Deacon 
32ba27ff46SWill Deacon 	fd = open(dtb_file, O_CREAT | O_TRUNC | O_RDWR, 0666);
337c0e8b0cSWill Deacon 	if (fd < 0)
34ba27ff46SWill Deacon 		die("Failed to write dtb to %s", dtb_file);
357c0e8b0cSWill Deacon 
367c0e8b0cSWill Deacon 	count = write(fd, fdt, FDT_MAX_SIZE);
377c0e8b0cSWill Deacon 	if (count < 0)
387c0e8b0cSWill Deacon 		die_perror("Failed to dump dtb");
397c0e8b0cSWill Deacon 
40ba27ff46SWill Deacon 	pr_info("Wrote %d bytes to dtb %s\n", count, dtb_file);
417c0e8b0cSWill Deacon 	close(fd);
427c0e8b0cSWill Deacon }
437c0e8b0cSWill Deacon 
44beff7ae0SMarc Zyngier #define CPU_NAME_MAX_LEN 8
45beff7ae0SMarc Zyngier static void generate_cpu_nodes(void *fdt, struct kvm *kvm)
46beff7ae0SMarc Zyngier {
47beff7ae0SMarc Zyngier 	int cpu;
48beff7ae0SMarc Zyngier 
49beff7ae0SMarc Zyngier 	_FDT(fdt_begin_node(fdt, "cpus"));
50beff7ae0SMarc Zyngier 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
51beff7ae0SMarc Zyngier 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
52beff7ae0SMarc Zyngier 
53beff7ae0SMarc Zyngier 	for (cpu = 0; cpu < kvm->nrcpus; ++cpu) {
54beff7ae0SMarc Zyngier 		char cpu_name[CPU_NAME_MAX_LEN];
55beff7ae0SMarc Zyngier 
56beff7ae0SMarc Zyngier 		snprintf(cpu_name, CPU_NAME_MAX_LEN, "cpu@%d", cpu);
57beff7ae0SMarc Zyngier 
58beff7ae0SMarc Zyngier 		_FDT(fdt_begin_node(fdt, cpu_name));
59beff7ae0SMarc Zyngier 		_FDT(fdt_property_string(fdt, "device_type", "cpu"));
60beff7ae0SMarc Zyngier 		_FDT(fdt_property_string(fdt, "compatible", kvm->cpus[cpu]->cpu_compatible));
61beff7ae0SMarc Zyngier 
62beff7ae0SMarc Zyngier 		if (kvm->nrcpus > 1)
63beff7ae0SMarc Zyngier 			_FDT(fdt_property_string(fdt, "enable-method", "psci"));
64beff7ae0SMarc Zyngier 
65beff7ae0SMarc Zyngier 		_FDT(fdt_property_cell(fdt, "reg", cpu));
66beff7ae0SMarc Zyngier 		_FDT(fdt_end_node(fdt));
67beff7ae0SMarc Zyngier 	}
68beff7ae0SMarc Zyngier 
69beff7ae0SMarc Zyngier 	_FDT(fdt_end_node(fdt));
70beff7ae0SMarc Zyngier }
71beff7ae0SMarc Zyngier 
72*2454c7dcSWill Deacon static void generate_irq_prop(void *fdt, u8 irq)
737c0e8b0cSWill Deacon {
747c0e8b0cSWill Deacon 	u32 irq_prop[] = {
757c0e8b0cSWill Deacon 		cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI),
76*2454c7dcSWill Deacon 		cpu_to_fdt32(irq - GIC_SPI_IRQ_BASE),
777c0e8b0cSWill Deacon 		cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
787c0e8b0cSWill Deacon 	};
797c0e8b0cSWill Deacon 
807c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop)));
817c0e8b0cSWill Deacon }
827c0e8b0cSWill Deacon 
837c0e8b0cSWill Deacon static int setup_fdt(struct kvm *kvm)
847c0e8b0cSWill Deacon {
857c0e8b0cSWill Deacon 	struct device_header *dev_hdr;
867c0e8b0cSWill Deacon 	u8 staging_fdt[FDT_MAX_SIZE];
877c0e8b0cSWill Deacon 	u32 gic_phandle		= fdt__alloc_phandle();
887c0e8b0cSWill Deacon 	u64 mem_reg_prop[]	= {
897c0e8b0cSWill Deacon 		cpu_to_fdt64(kvm->arch.memory_guest_start),
907c0e8b0cSWill Deacon 		cpu_to_fdt64(kvm->ram_size),
917c0e8b0cSWill Deacon 	};
927c0e8b0cSWill Deacon 	void *fdt		= staging_fdt;
937c0e8b0cSWill Deacon 	void *fdt_dest		= guest_flat_to_host(kvm,
947c0e8b0cSWill Deacon 						     kvm->arch.dtb_guest_start);
95*2454c7dcSWill Deacon 	void (*generate_mmio_fdt_nodes)(void *, struct device_header *,
96*2454c7dcSWill Deacon 					void (*)(void *, u8));
97*2454c7dcSWill Deacon 	void (*generate_cpu_peripheral_fdt_nodes)(void *, struct kvm *, u32)
987c0e8b0cSWill Deacon 					= kvm->cpus[0]->generate_fdt_nodes;
997c0e8b0cSWill Deacon 
1007c0e8b0cSWill Deacon 	/* Create new tree without a reserve map */
1017c0e8b0cSWill Deacon 	_FDT(fdt_create(fdt, FDT_MAX_SIZE));
1027c0e8b0cSWill Deacon 	_FDT(fdt_finish_reservemap(fdt));
1037c0e8b0cSWill Deacon 
1047c0e8b0cSWill Deacon 	/* Header */
1057c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, ""));
1067c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "interrupt-parent", gic_phandle));
1077c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt"));
1087c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
1097c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
1107c0e8b0cSWill Deacon 
1117c0e8b0cSWill Deacon 	/* /chosen */
1127c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "chosen"));
1137c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "bootargs", kern_cmdline));
1147c0e8b0cSWill Deacon 
1157c0e8b0cSWill Deacon 	/* Initrd */
1167c0e8b0cSWill Deacon 	if (kvm->arch.initrd_size != 0) {
1177c0e8b0cSWill Deacon 		u32 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start);
1187c0e8b0cSWill Deacon 		u32 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start +
1197c0e8b0cSWill Deacon 					       kvm->arch.initrd_size);
1207c0e8b0cSWill Deacon 
1217c0e8b0cSWill Deacon 		_FDT(fdt_property(fdt, "linux,initrd-start",
1227c0e8b0cSWill Deacon 				   &ird_st_prop, sizeof(ird_st_prop)));
1237c0e8b0cSWill Deacon 		_FDT(fdt_property(fdt, "linux,initrd-end",
1247c0e8b0cSWill Deacon 				   &ird_end_prop, sizeof(ird_end_prop)));
1257c0e8b0cSWill Deacon 	}
1267c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
1277c0e8b0cSWill Deacon 
1287c0e8b0cSWill Deacon 	/* Memory */
1297c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "memory"));
1307c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "device_type", "memory"));
1317c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop)));
1327c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
1337c0e8b0cSWill Deacon 
1347c0e8b0cSWill Deacon 	/* CPU and peripherals (interrupt controller, timers, etc) */
135beff7ae0SMarc Zyngier 	generate_cpu_nodes(fdt, kvm);
136*2454c7dcSWill Deacon 	if (generate_cpu_peripheral_fdt_nodes)
137*2454c7dcSWill Deacon 		generate_cpu_peripheral_fdt_nodes(fdt, kvm, gic_phandle);
1387c0e8b0cSWill Deacon 
1397c0e8b0cSWill Deacon 	/* Virtio MMIO devices */
1407c0e8b0cSWill Deacon 	dev_hdr = device__first_dev(DEVICE_BUS_MMIO);
1417c0e8b0cSWill Deacon 	while (dev_hdr) {
142*2454c7dcSWill Deacon 		generate_mmio_fdt_nodes = dev_hdr->data;
143*2454c7dcSWill Deacon 		generate_mmio_fdt_nodes(fdt, dev_hdr, generate_irq_prop);
1447c0e8b0cSWill Deacon 		dev_hdr = device__next_dev(dev_hdr);
1457c0e8b0cSWill Deacon 	}
1467c0e8b0cSWill Deacon 
14761076240SWill Deacon 	/* PSCI firmware */
14861076240SWill Deacon 	_FDT(fdt_begin_node(fdt, "psci"));
14961076240SWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "arm,psci"));
15061076240SWill Deacon 	_FDT(fdt_property_string(fdt, "method", "hvc"));
15161076240SWill Deacon 	_FDT(fdt_property_cell(fdt, "cpu_suspend", KVM_PSCI_FN_CPU_SUSPEND));
15261076240SWill Deacon 	_FDT(fdt_property_cell(fdt, "cpu_off", KVM_PSCI_FN_CPU_OFF));
15361076240SWill Deacon 	_FDT(fdt_property_cell(fdt, "cpu_on", KVM_PSCI_FN_CPU_ON));
15461076240SWill Deacon 	_FDT(fdt_property_cell(fdt, "migrate", KVM_PSCI_FN_MIGRATE));
15561076240SWill Deacon 	_FDT(fdt_end_node(fdt));
15661076240SWill Deacon 
1577c0e8b0cSWill Deacon 	/* Finalise. */
1587c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
1597c0e8b0cSWill Deacon 	_FDT(fdt_finish(fdt));
1607c0e8b0cSWill Deacon 
1617c0e8b0cSWill Deacon 	_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
1627c0e8b0cSWill Deacon 	_FDT(fdt_pack(fdt_dest));
1637c0e8b0cSWill Deacon 
164ba27ff46SWill Deacon 	if (kvm->cfg.arch.dump_dtb_filename)
165ba27ff46SWill Deacon 		dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest);
1667c0e8b0cSWill Deacon 	return 0;
1677c0e8b0cSWill Deacon }
1687c0e8b0cSWill Deacon late_init(setup_fdt);
1697c0e8b0cSWill Deacon 
1707c0e8b0cSWill Deacon static int read_image(int fd, void **pos, void *limit)
1717c0e8b0cSWill Deacon {
1727c0e8b0cSWill Deacon 	int count;
1737c0e8b0cSWill Deacon 
1747c0e8b0cSWill Deacon 	while (((count = xread(fd, *pos, SZ_64K)) > 0) && *pos <= limit)
1757c0e8b0cSWill Deacon 		*pos += count;
1767c0e8b0cSWill Deacon 
1777c0e8b0cSWill Deacon 	if (pos < 0)
1787c0e8b0cSWill Deacon 		die_perror("xread");
1797c0e8b0cSWill Deacon 
1807c0e8b0cSWill Deacon 	return *pos < limit ? 0 : -ENOMEM;
1817c0e8b0cSWill Deacon }
1827c0e8b0cSWill Deacon 
1837c0e8b0cSWill Deacon #define FDT_ALIGN	SZ_2M
1847c0e8b0cSWill Deacon #define INITRD_ALIGN	4
1857c0e8b0cSWill Deacon int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd,
1867c0e8b0cSWill Deacon 		     const char *kernel_cmdline)
1877c0e8b0cSWill Deacon {
1887c0e8b0cSWill Deacon 	void *pos, *kernel_end, *limit;
1897c0e8b0cSWill Deacon 	unsigned long guest_addr;
1907c0e8b0cSWill Deacon 
1917c0e8b0cSWill Deacon 	if (lseek(fd_kernel, 0, SEEK_SET) < 0)
1927c0e8b0cSWill Deacon 		die_perror("lseek");
1937c0e8b0cSWill Deacon 
1947c0e8b0cSWill Deacon 	/*
19561076240SWill Deacon 	 * Linux requires the initrd and dtb to be mapped inside lowmem,
19661076240SWill Deacon 	 * so we can't just place them at the top of memory.
1977c0e8b0cSWill Deacon 	 */
1987c0e8b0cSWill Deacon 	limit = kvm->ram_start + min(kvm->ram_size, (u64)SZ_256M) - 1;
1997c0e8b0cSWill Deacon 
2001e0c135aSWill Deacon 	pos = kvm->ram_start + ARM_KERN_OFFSET(kvm);
2017c0e8b0cSWill Deacon 	kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos);
2027c0e8b0cSWill Deacon 	if (read_image(fd_kernel, &pos, limit) == -ENOMEM)
2037c0e8b0cSWill Deacon 		die("kernel image too big to contain in guest memory.");
2047c0e8b0cSWill Deacon 
2057c0e8b0cSWill Deacon 	kernel_end = pos;
2067c0e8b0cSWill Deacon 	pr_info("Loaded kernel to 0x%llx (%llu bytes)",
2077c0e8b0cSWill Deacon 		kvm->arch.kern_guest_start,
2087c0e8b0cSWill Deacon 		host_to_guest_flat(kvm, pos) - kvm->arch.kern_guest_start);
2097c0e8b0cSWill Deacon 
2107c0e8b0cSWill Deacon 	/*
2117c0e8b0cSWill Deacon 	 * Now load backwards from the end of memory so the kernel
2127c0e8b0cSWill Deacon 	 * decompressor has plenty of space to work with. First up is
21361076240SWill Deacon 	 * the device tree blob...
2147c0e8b0cSWill Deacon 	 */
2157c0e8b0cSWill Deacon 	pos = limit;
2167c0e8b0cSWill Deacon 	pos -= (FDT_MAX_SIZE + FDT_ALIGN);
2177c0e8b0cSWill Deacon 	guest_addr = ALIGN(host_to_guest_flat(kvm, pos), FDT_ALIGN);
2187c0e8b0cSWill Deacon 	pos = guest_flat_to_host(kvm, guest_addr);
2197c0e8b0cSWill Deacon 	if (pos < kernel_end)
2207c0e8b0cSWill Deacon 		die("fdt overlaps with kernel image.");
2217c0e8b0cSWill Deacon 
2227c0e8b0cSWill Deacon 	kvm->arch.dtb_guest_start = guest_addr;
2237c0e8b0cSWill Deacon 	pr_info("Placing fdt at 0x%llx - 0x%llx",
2247c0e8b0cSWill Deacon 		kvm->arch.dtb_guest_start,
2257c0e8b0cSWill Deacon 		host_to_guest_flat(kvm, limit));
2267c0e8b0cSWill Deacon 	limit = pos;
2277c0e8b0cSWill Deacon 
2287c0e8b0cSWill Deacon 	/* ... and finally the initrd, if we have one. */
2297c0e8b0cSWill Deacon 	if (fd_initrd != -1) {
2307c0e8b0cSWill Deacon 		struct stat sb;
2317c0e8b0cSWill Deacon 		unsigned long initrd_start;
2327c0e8b0cSWill Deacon 
2337c0e8b0cSWill Deacon 		if (lseek(fd_initrd, 0, SEEK_SET) < 0)
2347c0e8b0cSWill Deacon 			die_perror("lseek");
2357c0e8b0cSWill Deacon 
2367c0e8b0cSWill Deacon 		if (fstat(fd_initrd, &sb))
2377c0e8b0cSWill Deacon 			die_perror("fstat");
2387c0e8b0cSWill Deacon 
2397c0e8b0cSWill Deacon 		pos -= (sb.st_size + INITRD_ALIGN);
2407c0e8b0cSWill Deacon 		guest_addr = ALIGN(host_to_guest_flat(kvm, pos), INITRD_ALIGN);
2417c0e8b0cSWill Deacon 		pos = guest_flat_to_host(kvm, guest_addr);
2427c0e8b0cSWill Deacon 		if (pos < kernel_end)
2437c0e8b0cSWill Deacon 			die("initrd overlaps with kernel image.");
2447c0e8b0cSWill Deacon 
2457c0e8b0cSWill Deacon 		initrd_start = guest_addr;
2467c0e8b0cSWill Deacon 		if (read_image(fd_initrd, &pos, limit) == -ENOMEM)
2477c0e8b0cSWill Deacon 			die("initrd too big to contain in guest memory.");
2487c0e8b0cSWill Deacon 
2497c0e8b0cSWill Deacon 		kvm->arch.initrd_guest_start = initrd_start;
2507c0e8b0cSWill Deacon 		kvm->arch.initrd_size = host_to_guest_flat(kvm, pos) - initrd_start;
2517c0e8b0cSWill Deacon 		pr_info("Loaded initrd to 0x%llx (%llu bytes)",
2527c0e8b0cSWill Deacon 			kvm->arch.initrd_guest_start,
2537c0e8b0cSWill Deacon 			kvm->arch.initrd_size);
2547c0e8b0cSWill Deacon 	} else {
2557c0e8b0cSWill Deacon 		kvm->arch.initrd_size = 0;
2567c0e8b0cSWill Deacon 	}
2577c0e8b0cSWill Deacon 
2587c0e8b0cSWill Deacon 	strncpy(kern_cmdline, kernel_cmdline, COMMAND_LINE_SIZE);
2597c0e8b0cSWill Deacon 	kern_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
2607c0e8b0cSWill Deacon 
2617c0e8b0cSWill Deacon 	return true;
2627c0e8b0cSWill Deacon }
2637c0e8b0cSWill Deacon 
264ff7ba6faSWill Deacon bool load_bzimage(struct kvm *kvm, int fd_kernel, int fd_initrd,
265ff7ba6faSWill Deacon 		  const char *kernel_cmdline)
2667c0e8b0cSWill Deacon {
2677c0e8b0cSWill Deacon 	/* To b or not to b? That is the zImage. */
2687c0e8b0cSWill Deacon 	return false;
2697c0e8b0cSWill Deacon }
270