xref: /kvmtool/arm/fdt.c (revision cd9a8066c90f32f0888d32a6e7f80f55ae4cde5f)
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"
816242d27SWill Deacon #include "arm-common/pci.h"
97c0e8b0cSWill Deacon 
107c0e8b0cSWill Deacon #include <stdbool.h>
117c0e8b0cSWill Deacon 
127c0e8b0cSWill Deacon #include <linux/byteorder.h>
137c0e8b0cSWill Deacon #include <linux/kernel.h>
147c0e8b0cSWill Deacon #include <linux/sizes.h>
15c2dad402SAnup Patel #include <linux/psci.h>
167c0e8b0cSWill Deacon 
177c0e8b0cSWill Deacon bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
187c0e8b0cSWill Deacon {
197c0e8b0cSWill Deacon 	return false;
207c0e8b0cSWill Deacon }
217c0e8b0cSWill Deacon 
227c0e8b0cSWill Deacon int kvm__arch_setup_firmware(struct kvm *kvm)
237c0e8b0cSWill Deacon {
247c0e8b0cSWill Deacon 	return 0;
257c0e8b0cSWill Deacon }
267c0e8b0cSWill Deacon 
27ba27ff46SWill Deacon static void dump_fdt(const char *dtb_file, void *fdt)
287c0e8b0cSWill Deacon {
297c0e8b0cSWill Deacon 	int count, fd;
307c0e8b0cSWill Deacon 
31ba27ff46SWill Deacon 	fd = open(dtb_file, O_CREAT | O_TRUNC | O_RDWR, 0666);
327c0e8b0cSWill Deacon 	if (fd < 0)
33ba27ff46SWill Deacon 		die("Failed to write dtb to %s", dtb_file);
347c0e8b0cSWill Deacon 
357c0e8b0cSWill Deacon 	count = write(fd, fdt, FDT_MAX_SIZE);
367c0e8b0cSWill Deacon 	if (count < 0)
377c0e8b0cSWill Deacon 		die_perror("Failed to dump dtb");
387c0e8b0cSWill Deacon 
39ba27ff46SWill Deacon 	pr_info("Wrote %d bytes to dtb %s\n", count, dtb_file);
407c0e8b0cSWill Deacon 	close(fd);
417c0e8b0cSWill Deacon }
427c0e8b0cSWill Deacon 
43beff7ae0SMarc Zyngier #define CPU_NAME_MAX_LEN 8
44beff7ae0SMarc Zyngier static void generate_cpu_nodes(void *fdt, struct kvm *kvm)
45beff7ae0SMarc Zyngier {
46beff7ae0SMarc Zyngier 	int cpu;
47beff7ae0SMarc Zyngier 
48beff7ae0SMarc Zyngier 	_FDT(fdt_begin_node(fdt, "cpus"));
49beff7ae0SMarc Zyngier 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
50beff7ae0SMarc Zyngier 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
51beff7ae0SMarc Zyngier 
52beff7ae0SMarc Zyngier 	for (cpu = 0; cpu < kvm->nrcpus; ++cpu) {
53beff7ae0SMarc Zyngier 		char cpu_name[CPU_NAME_MAX_LEN];
54d06bc640SMarc Zyngier 		struct kvm_cpu *vcpu = kvm->cpus[cpu];
55d06bc640SMarc Zyngier 		unsigned long mpidr = kvm_cpu__get_vcpu_mpidr(vcpu);
56beff7ae0SMarc Zyngier 
57d06bc640SMarc Zyngier 		mpidr &= ARM_MPIDR_HWID_BITMASK;
58d06bc640SMarc Zyngier 		snprintf(cpu_name, CPU_NAME_MAX_LEN, "cpu@%lx", mpidr);
59beff7ae0SMarc Zyngier 
60beff7ae0SMarc Zyngier 		_FDT(fdt_begin_node(fdt, cpu_name));
61beff7ae0SMarc Zyngier 		_FDT(fdt_property_string(fdt, "device_type", "cpu"));
62d06bc640SMarc Zyngier 		_FDT(fdt_property_string(fdt, "compatible", vcpu->cpu_compatible));
63beff7ae0SMarc Zyngier 
64beff7ae0SMarc Zyngier 		if (kvm->nrcpus > 1)
65beff7ae0SMarc Zyngier 			_FDT(fdt_property_string(fdt, "enable-method", "psci"));
66beff7ae0SMarc Zyngier 
67d06bc640SMarc Zyngier 		_FDT(fdt_property_cell(fdt, "reg", mpidr));
68beff7ae0SMarc Zyngier 		_FDT(fdt_end_node(fdt));
69beff7ae0SMarc Zyngier 	}
70beff7ae0SMarc Zyngier 
71beff7ae0SMarc Zyngier 	_FDT(fdt_end_node(fdt));
72beff7ae0SMarc Zyngier }
73beff7ae0SMarc Zyngier 
742bfd9ac3SAndre Przywara static void generate_irq_prop(void *fdt, u8 irq, enum irq_type irq_type)
757c0e8b0cSWill Deacon {
767c0e8b0cSWill Deacon 	u32 irq_prop[] = {
777c0e8b0cSWill Deacon 		cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI),
782454c7dcSWill Deacon 		cpu_to_fdt32(irq - GIC_SPI_IRQ_BASE),
792bfd9ac3SAndre Przywara 		cpu_to_fdt32(irq_type)
807c0e8b0cSWill Deacon 	};
817c0e8b0cSWill Deacon 
827c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop)));
837c0e8b0cSWill Deacon }
847c0e8b0cSWill Deacon 
85c2dad402SAnup Patel struct psci_fns {
86c2dad402SAnup Patel 	u32 cpu_suspend;
87c2dad402SAnup Patel 	u32 cpu_off;
88c2dad402SAnup Patel 	u32 cpu_on;
89c2dad402SAnup Patel 	u32 migrate;
90c2dad402SAnup Patel };
91c2dad402SAnup Patel 
92c2dad402SAnup Patel static struct psci_fns psci_0_1_fns = {
93c2dad402SAnup Patel 	.cpu_suspend = KVM_PSCI_FN_CPU_SUSPEND,
94c2dad402SAnup Patel 	.cpu_off = KVM_PSCI_FN_CPU_OFF,
95c2dad402SAnup Patel 	.cpu_on = KVM_PSCI_FN_CPU_ON,
96c2dad402SAnup Patel 	.migrate = KVM_PSCI_FN_MIGRATE,
97c2dad402SAnup Patel };
98c2dad402SAnup Patel 
99c2dad402SAnup Patel static struct psci_fns psci_0_2_aarch32_fns = {
100c2dad402SAnup Patel 	.cpu_suspend = PSCI_0_2_FN_CPU_SUSPEND,
101c2dad402SAnup Patel 	.cpu_off = PSCI_0_2_FN_CPU_OFF,
102c2dad402SAnup Patel 	.cpu_on = PSCI_0_2_FN_CPU_ON,
103c2dad402SAnup Patel 	.migrate = PSCI_0_2_FN_MIGRATE,
104c2dad402SAnup Patel };
105c2dad402SAnup Patel 
106c2dad402SAnup Patel static struct psci_fns psci_0_2_aarch64_fns = {
107c2dad402SAnup Patel 	.cpu_suspend = PSCI_0_2_FN64_CPU_SUSPEND,
108c2dad402SAnup Patel 	.cpu_off = PSCI_0_2_FN_CPU_OFF,
109c2dad402SAnup Patel 	.cpu_on = PSCI_0_2_FN64_CPU_ON,
110c2dad402SAnup Patel 	.migrate = PSCI_0_2_FN64_MIGRATE,
111c2dad402SAnup Patel };
112c2dad402SAnup Patel 
1137c0e8b0cSWill Deacon static int setup_fdt(struct kvm *kvm)
1147c0e8b0cSWill Deacon {
1157c0e8b0cSWill Deacon 	struct device_header *dev_hdr;
1167c0e8b0cSWill Deacon 	u8 staging_fdt[FDT_MAX_SIZE];
1177c0e8b0cSWill Deacon 	u64 mem_reg_prop[]	= {
1187c0e8b0cSWill Deacon 		cpu_to_fdt64(kvm->arch.memory_guest_start),
1197c0e8b0cSWill Deacon 		cpu_to_fdt64(kvm->ram_size),
1207c0e8b0cSWill Deacon 	};
121c2dad402SAnup Patel 	struct psci_fns *fns;
1227c0e8b0cSWill Deacon 	void *fdt		= staging_fdt;
1237c0e8b0cSWill Deacon 	void *fdt_dest		= guest_flat_to_host(kvm,
1247c0e8b0cSWill Deacon 						     kvm->arch.dtb_guest_start);
1252454c7dcSWill Deacon 	void (*generate_mmio_fdt_nodes)(void *, struct device_header *,
1262bfd9ac3SAndre Przywara 					void (*)(void *, u8, enum irq_type));
1272454c7dcSWill Deacon 	void (*generate_cpu_peripheral_fdt_nodes)(void *, struct kvm *, u32)
1287c0e8b0cSWill Deacon 					= kvm->cpus[0]->generate_fdt_nodes;
1297c0e8b0cSWill Deacon 
1307c0e8b0cSWill Deacon 	/* Create new tree without a reserve map */
1317c0e8b0cSWill Deacon 	_FDT(fdt_create(fdt, FDT_MAX_SIZE));
1327c0e8b0cSWill Deacon 	_FDT(fdt_finish_reservemap(fdt));
1337c0e8b0cSWill Deacon 
1347c0e8b0cSWill Deacon 	/* Header */
1357c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, ""));
136*cd9a8066SAndre Przywara 	_FDT(fdt_property_cell(fdt, "interrupt-parent", PHANDLE_GIC));
1377c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt"));
1387c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
1397c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
1407c0e8b0cSWill Deacon 
1417c0e8b0cSWill Deacon 	/* /chosen */
1427c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "chosen"));
1431fcf0d77SWill Deacon 	_FDT(fdt_property_cell(fdt, "linux,pci-probe-only", 1));
1443c8aec9eSAndre Przywara 	_FDT(fdt_property_string(fdt, "bootargs", kvm->cfg.real_cmdline));
1457c0e8b0cSWill Deacon 
1467c0e8b0cSWill Deacon 	/* Initrd */
1477c0e8b0cSWill Deacon 	if (kvm->arch.initrd_size != 0) {
148bd33695dSAndre Przywara 		u64 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start);
149bd33695dSAndre Przywara 		u64 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start +
1507c0e8b0cSWill Deacon 					       kvm->arch.initrd_size);
1517c0e8b0cSWill Deacon 
1527c0e8b0cSWill Deacon 		_FDT(fdt_property(fdt, "linux,initrd-start",
1537c0e8b0cSWill Deacon 				   &ird_st_prop, sizeof(ird_st_prop)));
1547c0e8b0cSWill Deacon 		_FDT(fdt_property(fdt, "linux,initrd-end",
1557c0e8b0cSWill Deacon 				   &ird_end_prop, sizeof(ird_end_prop)));
1567c0e8b0cSWill Deacon 	}
1577c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
1587c0e8b0cSWill Deacon 
1597c0e8b0cSWill Deacon 	/* Memory */
1607c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "memory"));
1617c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "device_type", "memory"));
1627c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop)));
1637c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
1647c0e8b0cSWill Deacon 
1657c0e8b0cSWill Deacon 	/* CPU and peripherals (interrupt controller, timers, etc) */
166beff7ae0SMarc Zyngier 	generate_cpu_nodes(fdt, kvm);
1672454c7dcSWill Deacon 	if (generate_cpu_peripheral_fdt_nodes)
168*cd9a8066SAndre Przywara 		generate_cpu_peripheral_fdt_nodes(fdt, kvm, PHANDLE_GIC);
1697c0e8b0cSWill Deacon 
1707c0e8b0cSWill Deacon 	/* Virtio MMIO devices */
1717c0e8b0cSWill Deacon 	dev_hdr = device__first_dev(DEVICE_BUS_MMIO);
1727c0e8b0cSWill Deacon 	while (dev_hdr) {
1732454c7dcSWill Deacon 		generate_mmio_fdt_nodes = dev_hdr->data;
1742454c7dcSWill Deacon 		generate_mmio_fdt_nodes(fdt, dev_hdr, generate_irq_prop);
1757c0e8b0cSWill Deacon 		dev_hdr = device__next_dev(dev_hdr);
1767c0e8b0cSWill Deacon 	}
1777c0e8b0cSWill Deacon 
178ed7b31c9SWill Deacon 	/* IOPORT devices (!) */
179ed7b31c9SWill Deacon 	dev_hdr = device__first_dev(DEVICE_BUS_IOPORT);
180ed7b31c9SWill Deacon 	while (dev_hdr) {
181ed7b31c9SWill Deacon 		generate_mmio_fdt_nodes = dev_hdr->data;
182ed7b31c9SWill Deacon 		generate_mmio_fdt_nodes(fdt, dev_hdr, generate_irq_prop);
183ed7b31c9SWill Deacon 		dev_hdr = device__next_dev(dev_hdr);
184ed7b31c9SWill Deacon 	}
185ed7b31c9SWill Deacon 
18616242d27SWill Deacon 	/* PCI host controller */
187*cd9a8066SAndre Przywara 	pci__generate_fdt_nodes(fdt, PHANDLE_GIC);
18816242d27SWill Deacon 
18961076240SWill Deacon 	/* PSCI firmware */
19061076240SWill Deacon 	_FDT(fdt_begin_node(fdt, "psci"));
191c2dad402SAnup Patel 	if (kvm__supports_extension(kvm, KVM_CAP_ARM_PSCI_0_2)) {
192c2dad402SAnup Patel 		const char compatible[] = "arm,psci-0.2\0arm,psci";
193c2dad402SAnup Patel 		_FDT(fdt_property(fdt, "compatible",
194c2dad402SAnup Patel 				  compatible, sizeof(compatible)));
195c2dad402SAnup Patel 		if (kvm->cfg.arch.aarch32_guest)
196c2dad402SAnup Patel 			fns = &psci_0_2_aarch32_fns;
197c2dad402SAnup Patel 		else
198c2dad402SAnup Patel 			fns = &psci_0_2_aarch64_fns;
199c2dad402SAnup Patel 	} else {
20061076240SWill Deacon 		_FDT(fdt_property_string(fdt, "compatible", "arm,psci"));
201c2dad402SAnup Patel 		fns = &psci_0_1_fns;
202c2dad402SAnup Patel 	}
20361076240SWill Deacon 	_FDT(fdt_property_string(fdt, "method", "hvc"));
204c2dad402SAnup Patel 	_FDT(fdt_property_cell(fdt, "cpu_suspend", fns->cpu_suspend));
205c2dad402SAnup Patel 	_FDT(fdt_property_cell(fdt, "cpu_off", fns->cpu_off));
206c2dad402SAnup Patel 	_FDT(fdt_property_cell(fdt, "cpu_on", fns->cpu_on));
207c2dad402SAnup Patel 	_FDT(fdt_property_cell(fdt, "migrate", fns->migrate));
20861076240SWill Deacon 	_FDT(fdt_end_node(fdt));
20961076240SWill Deacon 
2107c0e8b0cSWill Deacon 	/* Finalise. */
2117c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
2127c0e8b0cSWill Deacon 	_FDT(fdt_finish(fdt));
2137c0e8b0cSWill Deacon 
2147c0e8b0cSWill Deacon 	_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
2157c0e8b0cSWill Deacon 	_FDT(fdt_pack(fdt_dest));
2167c0e8b0cSWill Deacon 
217ba27ff46SWill Deacon 	if (kvm->cfg.arch.dump_dtb_filename)
218ba27ff46SWill Deacon 		dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest);
2197c0e8b0cSWill Deacon 	return 0;
2207c0e8b0cSWill Deacon }
2217c0e8b0cSWill Deacon late_init(setup_fdt);
222