xref: /kvmtool/arm/fdt.c (revision 7c0e8b0c5560ce2f500fa4d7ba7865e7360e7991)
1*7c0e8b0cSWill Deacon #include "kvm/devices.h"
2*7c0e8b0cSWill Deacon #include "kvm/fdt.h"
3*7c0e8b0cSWill Deacon #include "kvm/kvm.h"
4*7c0e8b0cSWill Deacon #include "kvm/kvm-cpu.h"
5*7c0e8b0cSWill Deacon #include "kvm/virtio-mmio.h"
6*7c0e8b0cSWill Deacon 
7*7c0e8b0cSWill Deacon #include "arm-common/gic.h"
8*7c0e8b0cSWill Deacon 
9*7c0e8b0cSWill Deacon #include <stdbool.h>
10*7c0e8b0cSWill Deacon 
11*7c0e8b0cSWill Deacon #include <asm/setup.h>
12*7c0e8b0cSWill Deacon #include <linux/byteorder.h>
13*7c0e8b0cSWill Deacon #include <linux/kernel.h>
14*7c0e8b0cSWill Deacon #include <linux/sizes.h>
15*7c0e8b0cSWill Deacon 
16*7c0e8b0cSWill Deacon #define DEBUG			0
17*7c0e8b0cSWill Deacon #define DEBUG_FDT_DUMP_FILE	"/tmp/kvmtool.dtb"
18*7c0e8b0cSWill Deacon 
19*7c0e8b0cSWill Deacon static char kern_cmdline[COMMAND_LINE_SIZE];
20*7c0e8b0cSWill Deacon 
21*7c0e8b0cSWill Deacon bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
22*7c0e8b0cSWill Deacon {
23*7c0e8b0cSWill Deacon 	return false;
24*7c0e8b0cSWill Deacon }
25*7c0e8b0cSWill Deacon 
26*7c0e8b0cSWill Deacon int kvm__arch_setup_firmware(struct kvm *kvm)
27*7c0e8b0cSWill Deacon {
28*7c0e8b0cSWill Deacon 	return 0;
29*7c0e8b0cSWill Deacon }
30*7c0e8b0cSWill Deacon 
31*7c0e8b0cSWill Deacon #if DEBUG
32*7c0e8b0cSWill Deacon static void dump_fdt(void *fdt)
33*7c0e8b0cSWill Deacon {
34*7c0e8b0cSWill Deacon 	int count, fd;
35*7c0e8b0cSWill Deacon 
36*7c0e8b0cSWill Deacon 	fd = open(DEBUG_FDT_DUMP_FILE, O_CREAT | O_TRUNC | O_RDWR, 0666);
37*7c0e8b0cSWill Deacon 	if (fd < 0)
38*7c0e8b0cSWill Deacon 		die("Failed to write dtb to %s", DEBUG_FDT_DUMP_FILE);
39*7c0e8b0cSWill Deacon 
40*7c0e8b0cSWill Deacon 	count = write(fd, fdt, FDT_MAX_SIZE);
41*7c0e8b0cSWill Deacon 	if (count < 0)
42*7c0e8b0cSWill Deacon 		die_perror("Failed to dump dtb");
43*7c0e8b0cSWill Deacon 
44*7c0e8b0cSWill Deacon 	pr_info("Wrote %d bytes to dtb %s\n", count, DEBUG_FDT_DUMP_FILE);
45*7c0e8b0cSWill Deacon 	close(fd);
46*7c0e8b0cSWill Deacon }
47*7c0e8b0cSWill Deacon #else
48*7c0e8b0cSWill Deacon static void dump_fdt(void *fdt) { }
49*7c0e8b0cSWill Deacon #endif
50*7c0e8b0cSWill Deacon 
51*7c0e8b0cSWill Deacon #define DEVICE_NAME_MAX_LEN 32
52*7c0e8b0cSWill Deacon static void generate_virtio_mmio_node(void *fdt, struct virtio_mmio *vmmio)
53*7c0e8b0cSWill Deacon {
54*7c0e8b0cSWill Deacon 	char dev_name[DEVICE_NAME_MAX_LEN];
55*7c0e8b0cSWill Deacon 	u64 addr = vmmio->addr;
56*7c0e8b0cSWill Deacon 	u64 reg_prop[] = {
57*7c0e8b0cSWill Deacon 		cpu_to_fdt64(addr),
58*7c0e8b0cSWill Deacon 		cpu_to_fdt64(VIRTIO_MMIO_IO_SIZE)
59*7c0e8b0cSWill Deacon 	};
60*7c0e8b0cSWill Deacon 	u32 irq_prop[] = {
61*7c0e8b0cSWill Deacon 		cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI),
62*7c0e8b0cSWill Deacon 		cpu_to_fdt32(vmmio->irq - GIC_SPI_IRQ_BASE),
63*7c0e8b0cSWill Deacon 		cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
64*7c0e8b0cSWill Deacon 	};
65*7c0e8b0cSWill Deacon 
66*7c0e8b0cSWill Deacon 	snprintf(dev_name, DEVICE_NAME_MAX_LEN, "virtio@%llx", addr);
67*7c0e8b0cSWill Deacon 
68*7c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, dev_name));
69*7c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "virtio,mmio"));
70*7c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
71*7c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop)));
72*7c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
73*7c0e8b0cSWill Deacon }
74*7c0e8b0cSWill Deacon 
75*7c0e8b0cSWill Deacon static int setup_fdt(struct kvm *kvm)
76*7c0e8b0cSWill Deacon {
77*7c0e8b0cSWill Deacon 	struct device_header *dev_hdr;
78*7c0e8b0cSWill Deacon 	u8 staging_fdt[FDT_MAX_SIZE];
79*7c0e8b0cSWill Deacon 	u32 gic_phandle		= fdt__alloc_phandle();
80*7c0e8b0cSWill Deacon 	u64 mem_reg_prop[]	= {
81*7c0e8b0cSWill Deacon 		cpu_to_fdt64(kvm->arch.memory_guest_start),
82*7c0e8b0cSWill Deacon 		cpu_to_fdt64(kvm->ram_size),
83*7c0e8b0cSWill Deacon 	};
84*7c0e8b0cSWill Deacon 	void *fdt		= staging_fdt;
85*7c0e8b0cSWill Deacon 	void *fdt_dest		= guest_flat_to_host(kvm,
86*7c0e8b0cSWill Deacon 						     kvm->arch.dtb_guest_start);
87*7c0e8b0cSWill Deacon 	void (*generate_cpu_nodes)(void *, struct kvm *, u32)
88*7c0e8b0cSWill Deacon 				= kvm->cpus[0]->generate_fdt_nodes;
89*7c0e8b0cSWill Deacon 
90*7c0e8b0cSWill Deacon 	/* Create new tree without a reserve map */
91*7c0e8b0cSWill Deacon 	_FDT(fdt_create(fdt, FDT_MAX_SIZE));
92*7c0e8b0cSWill Deacon 	if (kvm->nrcpus > 1)
93*7c0e8b0cSWill Deacon 		_FDT(fdt_add_reservemap_entry(fdt,
94*7c0e8b0cSWill Deacon 					      kvm->arch.smp_pen_guest_start,
95*7c0e8b0cSWill Deacon 					      ARM_SMP_PEN_SIZE));
96*7c0e8b0cSWill Deacon 	_FDT(fdt_finish_reservemap(fdt));
97*7c0e8b0cSWill Deacon 
98*7c0e8b0cSWill Deacon 	/* Header */
99*7c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, ""));
100*7c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "interrupt-parent", gic_phandle));
101*7c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt"));
102*7c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
103*7c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
104*7c0e8b0cSWill Deacon 
105*7c0e8b0cSWill Deacon 	/* /chosen */
106*7c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "chosen"));
107*7c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "bootargs", kern_cmdline));
108*7c0e8b0cSWill Deacon 
109*7c0e8b0cSWill Deacon 	/* Initrd */
110*7c0e8b0cSWill Deacon 	if (kvm->arch.initrd_size != 0) {
111*7c0e8b0cSWill Deacon 		u32 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start);
112*7c0e8b0cSWill Deacon 		u32 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start +
113*7c0e8b0cSWill Deacon 					       kvm->arch.initrd_size);
114*7c0e8b0cSWill Deacon 
115*7c0e8b0cSWill Deacon 		_FDT(fdt_property(fdt, "linux,initrd-start",
116*7c0e8b0cSWill Deacon 				   &ird_st_prop, sizeof(ird_st_prop)));
117*7c0e8b0cSWill Deacon 		_FDT(fdt_property(fdt, "linux,initrd-end",
118*7c0e8b0cSWill Deacon 				   &ird_end_prop, sizeof(ird_end_prop)));
119*7c0e8b0cSWill Deacon 	}
120*7c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
121*7c0e8b0cSWill Deacon 
122*7c0e8b0cSWill Deacon 	/* Memory */
123*7c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "memory"));
124*7c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "device_type", "memory"));
125*7c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop)));
126*7c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
127*7c0e8b0cSWill Deacon 
128*7c0e8b0cSWill Deacon 	/* CPU and peripherals (interrupt controller, timers, etc) */
129*7c0e8b0cSWill Deacon 	if (generate_cpu_nodes)
130*7c0e8b0cSWill Deacon 		generate_cpu_nodes(fdt, kvm, gic_phandle);
131*7c0e8b0cSWill Deacon 
132*7c0e8b0cSWill Deacon 	/* Virtio MMIO devices */
133*7c0e8b0cSWill Deacon 	dev_hdr = device__first_dev(DEVICE_BUS_MMIO);
134*7c0e8b0cSWill Deacon 	while (dev_hdr) {
135*7c0e8b0cSWill Deacon 		generate_virtio_mmio_node(fdt, dev_hdr->data);
136*7c0e8b0cSWill Deacon 		dev_hdr = device__next_dev(dev_hdr);
137*7c0e8b0cSWill Deacon 	}
138*7c0e8b0cSWill Deacon 
139*7c0e8b0cSWill Deacon 	/* Finalise. */
140*7c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
141*7c0e8b0cSWill Deacon 	_FDT(fdt_finish(fdt));
142*7c0e8b0cSWill Deacon 
143*7c0e8b0cSWill Deacon 	_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
144*7c0e8b0cSWill Deacon 	_FDT(fdt_pack(fdt_dest));
145*7c0e8b0cSWill Deacon 
146*7c0e8b0cSWill Deacon 	dump_fdt(fdt_dest);
147*7c0e8b0cSWill Deacon 	return 0;
148*7c0e8b0cSWill Deacon }
149*7c0e8b0cSWill Deacon late_init(setup_fdt);
150*7c0e8b0cSWill Deacon 
151*7c0e8b0cSWill Deacon static int read_image(int fd, void **pos, void *limit)
152*7c0e8b0cSWill Deacon {
153*7c0e8b0cSWill Deacon 	int count;
154*7c0e8b0cSWill Deacon 
155*7c0e8b0cSWill Deacon 	while (((count = xread(fd, *pos, SZ_64K)) > 0) && *pos <= limit)
156*7c0e8b0cSWill Deacon 		*pos += count;
157*7c0e8b0cSWill Deacon 
158*7c0e8b0cSWill Deacon 	if (pos < 0)
159*7c0e8b0cSWill Deacon 		die_perror("xread");
160*7c0e8b0cSWill Deacon 
161*7c0e8b0cSWill Deacon 	return *pos < limit ? 0 : -ENOMEM;
162*7c0e8b0cSWill Deacon }
163*7c0e8b0cSWill Deacon 
164*7c0e8b0cSWill Deacon #define FDT_ALIGN	SZ_2M
165*7c0e8b0cSWill Deacon #define INITRD_ALIGN	4
166*7c0e8b0cSWill Deacon #define SMP_PEN_ALIGN	PAGE_SIZE
167*7c0e8b0cSWill Deacon int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd,
168*7c0e8b0cSWill Deacon 		     const char *kernel_cmdline)
169*7c0e8b0cSWill Deacon {
170*7c0e8b0cSWill Deacon 	void *pos, *kernel_end, *limit;
171*7c0e8b0cSWill Deacon 	unsigned long guest_addr;
172*7c0e8b0cSWill Deacon 
173*7c0e8b0cSWill Deacon 	if (lseek(fd_kernel, 0, SEEK_SET) < 0)
174*7c0e8b0cSWill Deacon 		die_perror("lseek");
175*7c0e8b0cSWill Deacon 
176*7c0e8b0cSWill Deacon 	/*
177*7c0e8b0cSWill Deacon 	 * Linux requires the initrd, pen and dtb to be mapped inside
178*7c0e8b0cSWill Deacon 	 * lowmem, so we can't just place them at the top of memory.
179*7c0e8b0cSWill Deacon 	 */
180*7c0e8b0cSWill Deacon 	limit = kvm->ram_start + min(kvm->ram_size, (u64)SZ_256M) - 1;
181*7c0e8b0cSWill Deacon 
182*7c0e8b0cSWill Deacon 	pos = kvm->ram_start + ARM_KERN_OFFSET;
183*7c0e8b0cSWill Deacon 	kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos);
184*7c0e8b0cSWill Deacon 	if (read_image(fd_kernel, &pos, limit) == -ENOMEM)
185*7c0e8b0cSWill Deacon 		die("kernel image too big to contain in guest memory.");
186*7c0e8b0cSWill Deacon 
187*7c0e8b0cSWill Deacon 	kernel_end = pos;
188*7c0e8b0cSWill Deacon 	pr_info("Loaded kernel to 0x%llx (%llu bytes)",
189*7c0e8b0cSWill Deacon 		kvm->arch.kern_guest_start,
190*7c0e8b0cSWill Deacon 		host_to_guest_flat(kvm, pos) - kvm->arch.kern_guest_start);
191*7c0e8b0cSWill Deacon 
192*7c0e8b0cSWill Deacon 	/*
193*7c0e8b0cSWill Deacon 	 * Now load backwards from the end of memory so the kernel
194*7c0e8b0cSWill Deacon 	 * decompressor has plenty of space to work with. First up is
195*7c0e8b0cSWill Deacon 	 * the SMP pen if we have more than one virtual CPU...
196*7c0e8b0cSWill Deacon 	 */
197*7c0e8b0cSWill Deacon 	pos = limit;
198*7c0e8b0cSWill Deacon 	if (kvm->cfg.nrcpus > 1) {
199*7c0e8b0cSWill Deacon 		pos -= (ARM_SMP_PEN_SIZE + SMP_PEN_ALIGN);
200*7c0e8b0cSWill Deacon 		guest_addr = ALIGN(host_to_guest_flat(kvm, pos), SMP_PEN_ALIGN);
201*7c0e8b0cSWill Deacon 		pos = guest_flat_to_host(kvm, guest_addr);
202*7c0e8b0cSWill Deacon 		if (pos < kernel_end)
203*7c0e8b0cSWill Deacon 			die("SMP pen overlaps with kernel image.");
204*7c0e8b0cSWill Deacon 
205*7c0e8b0cSWill Deacon 		kvm->arch.smp_pen_guest_start = guest_addr;
206*7c0e8b0cSWill Deacon 		pr_info("Placing SMP pen at 0x%llx - 0x%llx",
207*7c0e8b0cSWill Deacon 			kvm->arch.smp_pen_guest_start,
208*7c0e8b0cSWill Deacon 			host_to_guest_flat(kvm, limit));
209*7c0e8b0cSWill Deacon 		limit = pos;
210*7c0e8b0cSWill Deacon 	}
211*7c0e8b0cSWill Deacon 
212*7c0e8b0cSWill Deacon 	/* ...now the device tree blob... */
213*7c0e8b0cSWill Deacon 	pos -= (FDT_MAX_SIZE + FDT_ALIGN);
214*7c0e8b0cSWill Deacon 	guest_addr = ALIGN(host_to_guest_flat(kvm, pos), FDT_ALIGN);
215*7c0e8b0cSWill Deacon 	pos = guest_flat_to_host(kvm, guest_addr);
216*7c0e8b0cSWill Deacon 	if (pos < kernel_end)
217*7c0e8b0cSWill Deacon 		die("fdt overlaps with kernel image.");
218*7c0e8b0cSWill Deacon 
219*7c0e8b0cSWill Deacon 	kvm->arch.dtb_guest_start = guest_addr;
220*7c0e8b0cSWill Deacon 	pr_info("Placing fdt at 0x%llx - 0x%llx",
221*7c0e8b0cSWill Deacon 		kvm->arch.dtb_guest_start,
222*7c0e8b0cSWill Deacon 		host_to_guest_flat(kvm, limit));
223*7c0e8b0cSWill Deacon 	limit = pos;
224*7c0e8b0cSWill Deacon 
225*7c0e8b0cSWill Deacon 	/* ... and finally the initrd, if we have one. */
226*7c0e8b0cSWill Deacon 	if (fd_initrd != -1) {
227*7c0e8b0cSWill Deacon 		struct stat sb;
228*7c0e8b0cSWill Deacon 		unsigned long initrd_start;
229*7c0e8b0cSWill Deacon 
230*7c0e8b0cSWill Deacon 		if (lseek(fd_initrd, 0, SEEK_SET) < 0)
231*7c0e8b0cSWill Deacon 			die_perror("lseek");
232*7c0e8b0cSWill Deacon 
233*7c0e8b0cSWill Deacon 		if (fstat(fd_initrd, &sb))
234*7c0e8b0cSWill Deacon 			die_perror("fstat");
235*7c0e8b0cSWill Deacon 
236*7c0e8b0cSWill Deacon 		pos -= (sb.st_size + INITRD_ALIGN);
237*7c0e8b0cSWill Deacon 		guest_addr = ALIGN(host_to_guest_flat(kvm, pos), INITRD_ALIGN);
238*7c0e8b0cSWill Deacon 		pos = guest_flat_to_host(kvm, guest_addr);
239*7c0e8b0cSWill Deacon 		if (pos < kernel_end)
240*7c0e8b0cSWill Deacon 			die("initrd overlaps with kernel image.");
241*7c0e8b0cSWill Deacon 
242*7c0e8b0cSWill Deacon 		initrd_start = guest_addr;
243*7c0e8b0cSWill Deacon 		if (read_image(fd_initrd, &pos, limit) == -ENOMEM)
244*7c0e8b0cSWill Deacon 			die("initrd too big to contain in guest memory.");
245*7c0e8b0cSWill Deacon 
246*7c0e8b0cSWill Deacon 		kvm->arch.initrd_guest_start = initrd_start;
247*7c0e8b0cSWill Deacon 		kvm->arch.initrd_size = host_to_guest_flat(kvm, pos) - initrd_start;
248*7c0e8b0cSWill Deacon 		pr_info("Loaded initrd to 0x%llx (%llu bytes)",
249*7c0e8b0cSWill Deacon 			kvm->arch.initrd_guest_start,
250*7c0e8b0cSWill Deacon 			kvm->arch.initrd_size);
251*7c0e8b0cSWill Deacon 	} else {
252*7c0e8b0cSWill Deacon 		kvm->arch.initrd_size = 0;
253*7c0e8b0cSWill Deacon 	}
254*7c0e8b0cSWill Deacon 
255*7c0e8b0cSWill Deacon 	strncpy(kern_cmdline, kernel_cmdline, COMMAND_LINE_SIZE);
256*7c0e8b0cSWill Deacon 	kern_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
257*7c0e8b0cSWill Deacon 
258*7c0e8b0cSWill Deacon 	return true;
259*7c0e8b0cSWill Deacon }
260*7c0e8b0cSWill Deacon 
261*7c0e8b0cSWill Deacon bool load_bzimage(struct kvm *kvm, int fd_kernel,
262*7c0e8b0cSWill Deacon 		  int fd_initrd, const char *kernel_cmdline, u16 vidmode)
263*7c0e8b0cSWill Deacon {
264*7c0e8b0cSWill Deacon 	/* To b or not to b? That is the zImage. */
265*7c0e8b0cSWill Deacon 	return false;
266*7c0e8b0cSWill Deacon }
267