xref: /kvmtool/arm/fdt.c (revision ba27ff463191d23bae3cf5eb1a46f60dbf58fd52)
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 
28*ba27ff46SWill Deacon static void dump_fdt(const char *dtb_file, void *fdt)
297c0e8b0cSWill Deacon {
307c0e8b0cSWill Deacon 	int count, fd;
317c0e8b0cSWill Deacon 
32*ba27ff46SWill Deacon 	fd = open(dtb_file, O_CREAT | O_TRUNC | O_RDWR, 0666);
337c0e8b0cSWill Deacon 	if (fd < 0)
34*ba27ff46SWill 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 
40*ba27ff46SWill Deacon 	pr_info("Wrote %d bytes to dtb %s\n", count, dtb_file);
417c0e8b0cSWill Deacon 	close(fd);
427c0e8b0cSWill Deacon }
437c0e8b0cSWill Deacon 
447c0e8b0cSWill Deacon #define DEVICE_NAME_MAX_LEN 32
457c0e8b0cSWill Deacon static void generate_virtio_mmio_node(void *fdt, struct virtio_mmio *vmmio)
467c0e8b0cSWill Deacon {
477c0e8b0cSWill Deacon 	char dev_name[DEVICE_NAME_MAX_LEN];
487c0e8b0cSWill Deacon 	u64 addr = vmmio->addr;
497c0e8b0cSWill Deacon 	u64 reg_prop[] = {
507c0e8b0cSWill Deacon 		cpu_to_fdt64(addr),
517c0e8b0cSWill Deacon 		cpu_to_fdt64(VIRTIO_MMIO_IO_SIZE)
527c0e8b0cSWill Deacon 	};
537c0e8b0cSWill Deacon 	u32 irq_prop[] = {
547c0e8b0cSWill Deacon 		cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI),
557c0e8b0cSWill Deacon 		cpu_to_fdt32(vmmio->irq - GIC_SPI_IRQ_BASE),
567c0e8b0cSWill Deacon 		cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
577c0e8b0cSWill Deacon 	};
587c0e8b0cSWill Deacon 
597c0e8b0cSWill Deacon 	snprintf(dev_name, DEVICE_NAME_MAX_LEN, "virtio@%llx", addr);
607c0e8b0cSWill Deacon 
617c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, dev_name));
627c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "virtio,mmio"));
637c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
647c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop)));
657c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
667c0e8b0cSWill Deacon }
677c0e8b0cSWill Deacon 
687c0e8b0cSWill Deacon static int setup_fdt(struct kvm *kvm)
697c0e8b0cSWill Deacon {
707c0e8b0cSWill Deacon 	struct device_header *dev_hdr;
717c0e8b0cSWill Deacon 	u8 staging_fdt[FDT_MAX_SIZE];
727c0e8b0cSWill Deacon 	u32 gic_phandle		= fdt__alloc_phandle();
737c0e8b0cSWill Deacon 	u64 mem_reg_prop[]	= {
747c0e8b0cSWill Deacon 		cpu_to_fdt64(kvm->arch.memory_guest_start),
757c0e8b0cSWill Deacon 		cpu_to_fdt64(kvm->ram_size),
767c0e8b0cSWill Deacon 	};
777c0e8b0cSWill Deacon 	void *fdt		= staging_fdt;
787c0e8b0cSWill Deacon 	void *fdt_dest		= guest_flat_to_host(kvm,
797c0e8b0cSWill Deacon 						     kvm->arch.dtb_guest_start);
807c0e8b0cSWill Deacon 	void (*generate_cpu_nodes)(void *, struct kvm *, u32)
817c0e8b0cSWill Deacon 				= kvm->cpus[0]->generate_fdt_nodes;
827c0e8b0cSWill Deacon 
837c0e8b0cSWill Deacon 	/* Create new tree without a reserve map */
847c0e8b0cSWill Deacon 	_FDT(fdt_create(fdt, FDT_MAX_SIZE));
857c0e8b0cSWill Deacon 	if (kvm->nrcpus > 1)
867c0e8b0cSWill Deacon 		_FDT(fdt_add_reservemap_entry(fdt,
877c0e8b0cSWill Deacon 					      kvm->arch.smp_pen_guest_start,
887c0e8b0cSWill Deacon 					      ARM_SMP_PEN_SIZE));
897c0e8b0cSWill Deacon 	_FDT(fdt_finish_reservemap(fdt));
907c0e8b0cSWill Deacon 
917c0e8b0cSWill Deacon 	/* Header */
927c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, ""));
937c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "interrupt-parent", gic_phandle));
947c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt"));
957c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
967c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
977c0e8b0cSWill Deacon 
987c0e8b0cSWill Deacon 	/* /chosen */
997c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "chosen"));
1007c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "bootargs", kern_cmdline));
1017c0e8b0cSWill Deacon 
1027c0e8b0cSWill Deacon 	/* Initrd */
1037c0e8b0cSWill Deacon 	if (kvm->arch.initrd_size != 0) {
1047c0e8b0cSWill Deacon 		u32 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start);
1057c0e8b0cSWill Deacon 		u32 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start +
1067c0e8b0cSWill Deacon 					       kvm->arch.initrd_size);
1077c0e8b0cSWill Deacon 
1087c0e8b0cSWill Deacon 		_FDT(fdt_property(fdt, "linux,initrd-start",
1097c0e8b0cSWill Deacon 				   &ird_st_prop, sizeof(ird_st_prop)));
1107c0e8b0cSWill Deacon 		_FDT(fdt_property(fdt, "linux,initrd-end",
1117c0e8b0cSWill Deacon 				   &ird_end_prop, sizeof(ird_end_prop)));
1127c0e8b0cSWill Deacon 	}
1137c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
1147c0e8b0cSWill Deacon 
1157c0e8b0cSWill Deacon 	/* Memory */
1167c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "memory"));
1177c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "device_type", "memory"));
1187c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop)));
1197c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
1207c0e8b0cSWill Deacon 
1217c0e8b0cSWill Deacon 	/* CPU and peripherals (interrupt controller, timers, etc) */
1227c0e8b0cSWill Deacon 	if (generate_cpu_nodes)
1237c0e8b0cSWill Deacon 		generate_cpu_nodes(fdt, kvm, gic_phandle);
1247c0e8b0cSWill Deacon 
1257c0e8b0cSWill Deacon 	/* Virtio MMIO devices */
1267c0e8b0cSWill Deacon 	dev_hdr = device__first_dev(DEVICE_BUS_MMIO);
1277c0e8b0cSWill Deacon 	while (dev_hdr) {
1287c0e8b0cSWill Deacon 		generate_virtio_mmio_node(fdt, dev_hdr->data);
1297c0e8b0cSWill Deacon 		dev_hdr = device__next_dev(dev_hdr);
1307c0e8b0cSWill Deacon 	}
1317c0e8b0cSWill Deacon 
1327c0e8b0cSWill Deacon 	/* Finalise. */
1337c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
1347c0e8b0cSWill Deacon 	_FDT(fdt_finish(fdt));
1357c0e8b0cSWill Deacon 
1367c0e8b0cSWill Deacon 	_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
1377c0e8b0cSWill Deacon 	_FDT(fdt_pack(fdt_dest));
1387c0e8b0cSWill Deacon 
139*ba27ff46SWill Deacon 	if (kvm->cfg.arch.dump_dtb_filename)
140*ba27ff46SWill Deacon 		dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest);
1417c0e8b0cSWill Deacon 	return 0;
1427c0e8b0cSWill Deacon }
1437c0e8b0cSWill Deacon late_init(setup_fdt);
1447c0e8b0cSWill Deacon 
1457c0e8b0cSWill Deacon static int read_image(int fd, void **pos, void *limit)
1467c0e8b0cSWill Deacon {
1477c0e8b0cSWill Deacon 	int count;
1487c0e8b0cSWill Deacon 
1497c0e8b0cSWill Deacon 	while (((count = xread(fd, *pos, SZ_64K)) > 0) && *pos <= limit)
1507c0e8b0cSWill Deacon 		*pos += count;
1517c0e8b0cSWill Deacon 
1527c0e8b0cSWill Deacon 	if (pos < 0)
1537c0e8b0cSWill Deacon 		die_perror("xread");
1547c0e8b0cSWill Deacon 
1557c0e8b0cSWill Deacon 	return *pos < limit ? 0 : -ENOMEM;
1567c0e8b0cSWill Deacon }
1577c0e8b0cSWill Deacon 
1587c0e8b0cSWill Deacon #define FDT_ALIGN	SZ_2M
1597c0e8b0cSWill Deacon #define INITRD_ALIGN	4
1607c0e8b0cSWill Deacon #define SMP_PEN_ALIGN	PAGE_SIZE
1617c0e8b0cSWill Deacon int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd,
1627c0e8b0cSWill Deacon 		     const char *kernel_cmdline)
1637c0e8b0cSWill Deacon {
1647c0e8b0cSWill Deacon 	void *pos, *kernel_end, *limit;
1657c0e8b0cSWill Deacon 	unsigned long guest_addr;
1667c0e8b0cSWill Deacon 
1677c0e8b0cSWill Deacon 	if (lseek(fd_kernel, 0, SEEK_SET) < 0)
1687c0e8b0cSWill Deacon 		die_perror("lseek");
1697c0e8b0cSWill Deacon 
1707c0e8b0cSWill Deacon 	/*
1717c0e8b0cSWill Deacon 	 * Linux requires the initrd, pen and dtb to be mapped inside
1727c0e8b0cSWill Deacon 	 * lowmem, so we can't just place them at the top of memory.
1737c0e8b0cSWill Deacon 	 */
1747c0e8b0cSWill Deacon 	limit = kvm->ram_start + min(kvm->ram_size, (u64)SZ_256M) - 1;
1757c0e8b0cSWill Deacon 
1767c0e8b0cSWill Deacon 	pos = kvm->ram_start + ARM_KERN_OFFSET;
1777c0e8b0cSWill Deacon 	kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos);
1787c0e8b0cSWill Deacon 	if (read_image(fd_kernel, &pos, limit) == -ENOMEM)
1797c0e8b0cSWill Deacon 		die("kernel image too big to contain in guest memory.");
1807c0e8b0cSWill Deacon 
1817c0e8b0cSWill Deacon 	kernel_end = pos;
1827c0e8b0cSWill Deacon 	pr_info("Loaded kernel to 0x%llx (%llu bytes)",
1837c0e8b0cSWill Deacon 		kvm->arch.kern_guest_start,
1847c0e8b0cSWill Deacon 		host_to_guest_flat(kvm, pos) - kvm->arch.kern_guest_start);
1857c0e8b0cSWill Deacon 
1867c0e8b0cSWill Deacon 	/*
1877c0e8b0cSWill Deacon 	 * Now load backwards from the end of memory so the kernel
1887c0e8b0cSWill Deacon 	 * decompressor has plenty of space to work with. First up is
1897c0e8b0cSWill Deacon 	 * the SMP pen if we have more than one virtual CPU...
1907c0e8b0cSWill Deacon 	 */
1917c0e8b0cSWill Deacon 	pos = limit;
1927c0e8b0cSWill Deacon 	if (kvm->cfg.nrcpus > 1) {
1937c0e8b0cSWill Deacon 		pos -= (ARM_SMP_PEN_SIZE + SMP_PEN_ALIGN);
1947c0e8b0cSWill Deacon 		guest_addr = ALIGN(host_to_guest_flat(kvm, pos), SMP_PEN_ALIGN);
1957c0e8b0cSWill Deacon 		pos = guest_flat_to_host(kvm, guest_addr);
1967c0e8b0cSWill Deacon 		if (pos < kernel_end)
1977c0e8b0cSWill Deacon 			die("SMP pen overlaps with kernel image.");
1987c0e8b0cSWill Deacon 
1997c0e8b0cSWill Deacon 		kvm->arch.smp_pen_guest_start = guest_addr;
2007c0e8b0cSWill Deacon 		pr_info("Placing SMP pen at 0x%llx - 0x%llx",
2017c0e8b0cSWill Deacon 			kvm->arch.smp_pen_guest_start,
2027c0e8b0cSWill Deacon 			host_to_guest_flat(kvm, limit));
2037c0e8b0cSWill Deacon 		limit = pos;
2047c0e8b0cSWill Deacon 	}
2057c0e8b0cSWill Deacon 
2067c0e8b0cSWill Deacon 	/* ...now the device tree blob... */
2077c0e8b0cSWill Deacon 	pos -= (FDT_MAX_SIZE + FDT_ALIGN);
2087c0e8b0cSWill Deacon 	guest_addr = ALIGN(host_to_guest_flat(kvm, pos), FDT_ALIGN);
2097c0e8b0cSWill Deacon 	pos = guest_flat_to_host(kvm, guest_addr);
2107c0e8b0cSWill Deacon 	if (pos < kernel_end)
2117c0e8b0cSWill Deacon 		die("fdt overlaps with kernel image.");
2127c0e8b0cSWill Deacon 
2137c0e8b0cSWill Deacon 	kvm->arch.dtb_guest_start = guest_addr;
2147c0e8b0cSWill Deacon 	pr_info("Placing fdt at 0x%llx - 0x%llx",
2157c0e8b0cSWill Deacon 		kvm->arch.dtb_guest_start,
2167c0e8b0cSWill Deacon 		host_to_guest_flat(kvm, limit));
2177c0e8b0cSWill Deacon 	limit = pos;
2187c0e8b0cSWill Deacon 
2197c0e8b0cSWill Deacon 	/* ... and finally the initrd, if we have one. */
2207c0e8b0cSWill Deacon 	if (fd_initrd != -1) {
2217c0e8b0cSWill Deacon 		struct stat sb;
2227c0e8b0cSWill Deacon 		unsigned long initrd_start;
2237c0e8b0cSWill Deacon 
2247c0e8b0cSWill Deacon 		if (lseek(fd_initrd, 0, SEEK_SET) < 0)
2257c0e8b0cSWill Deacon 			die_perror("lseek");
2267c0e8b0cSWill Deacon 
2277c0e8b0cSWill Deacon 		if (fstat(fd_initrd, &sb))
2287c0e8b0cSWill Deacon 			die_perror("fstat");
2297c0e8b0cSWill Deacon 
2307c0e8b0cSWill Deacon 		pos -= (sb.st_size + INITRD_ALIGN);
2317c0e8b0cSWill Deacon 		guest_addr = ALIGN(host_to_guest_flat(kvm, pos), INITRD_ALIGN);
2327c0e8b0cSWill Deacon 		pos = guest_flat_to_host(kvm, guest_addr);
2337c0e8b0cSWill Deacon 		if (pos < kernel_end)
2347c0e8b0cSWill Deacon 			die("initrd overlaps with kernel image.");
2357c0e8b0cSWill Deacon 
2367c0e8b0cSWill Deacon 		initrd_start = guest_addr;
2377c0e8b0cSWill Deacon 		if (read_image(fd_initrd, &pos, limit) == -ENOMEM)
2387c0e8b0cSWill Deacon 			die("initrd too big to contain in guest memory.");
2397c0e8b0cSWill Deacon 
2407c0e8b0cSWill Deacon 		kvm->arch.initrd_guest_start = initrd_start;
2417c0e8b0cSWill Deacon 		kvm->arch.initrd_size = host_to_guest_flat(kvm, pos) - initrd_start;
2427c0e8b0cSWill Deacon 		pr_info("Loaded initrd to 0x%llx (%llu bytes)",
2437c0e8b0cSWill Deacon 			kvm->arch.initrd_guest_start,
2447c0e8b0cSWill Deacon 			kvm->arch.initrd_size);
2457c0e8b0cSWill Deacon 	} else {
2467c0e8b0cSWill Deacon 		kvm->arch.initrd_size = 0;
2477c0e8b0cSWill Deacon 	}
2487c0e8b0cSWill Deacon 
2497c0e8b0cSWill Deacon 	strncpy(kern_cmdline, kernel_cmdline, COMMAND_LINE_SIZE);
2507c0e8b0cSWill Deacon 	kern_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
2517c0e8b0cSWill Deacon 
2527c0e8b0cSWill Deacon 	return true;
2537c0e8b0cSWill Deacon }
2547c0e8b0cSWill Deacon 
255ff7ba6faSWill Deacon bool load_bzimage(struct kvm *kvm, int fd_kernel, int fd_initrd,
256ff7ba6faSWill Deacon 		  const char *kernel_cmdline)
2577c0e8b0cSWill Deacon {
2587c0e8b0cSWill Deacon 	/* To b or not to b? That is the zImage. */
2597c0e8b0cSWill Deacon 	return false;
2607c0e8b0cSWill Deacon }
261