xref: /kvmtool/riscv/fdt.c (revision fa958fb68cfbab62b798ec7fe78b150a2dfafaf8)
1 #include "kvm/devices.h"
2 #include "kvm/fdt.h"
3 #include "kvm/kvm.h"
4 #include "kvm/kvm-cpu.h"
5 
6 #include <stdbool.h>
7 
8 #include <linux/byteorder.h>
9 #include <linux/kernel.h>
10 #include <linux/sizes.h>
11 
12 struct isa_ext_info {
13 	const char *name;
14 	unsigned long ext_id;
15 };
16 
17 struct isa_ext_info isa_info_arr[] = {
18 	/* sorted alphabetically */
19 	{"smstateen", KVM_RISCV_ISA_EXT_SMSTATEEN},
20 	{"ssaia", KVM_RISCV_ISA_EXT_SSAIA},
21 	{"sscofpmf", KVM_RISCV_ISA_EXT_SSCOFPMF},
22 	{"sstc", KVM_RISCV_ISA_EXT_SSTC},
23 	{"svinval", KVM_RISCV_ISA_EXT_SVINVAL},
24 	{"svnapot", KVM_RISCV_ISA_EXT_SVNAPOT},
25 	{"svpbmt", KVM_RISCV_ISA_EXT_SVPBMT},
26 	{"zacas", KVM_RISCV_ISA_EXT_ZACAS},
27 	{"zba", KVM_RISCV_ISA_EXT_ZBA},
28 	{"zbb", KVM_RISCV_ISA_EXT_ZBB},
29 	{"zbc", KVM_RISCV_ISA_EXT_ZBC},
30 	{"zbkb", KVM_RISCV_ISA_EXT_ZBKB},
31 	{"zbkc", KVM_RISCV_ISA_EXT_ZBKC},
32 	{"zbkx", KVM_RISCV_ISA_EXT_ZBKX},
33 	{"zbs", KVM_RISCV_ISA_EXT_ZBS},
34 	{"zfa", KVM_RISCV_ISA_EXT_ZFA},
35 	{"zfh", KVM_RISCV_ISA_EXT_ZFH},
36 	{"zfhmin", KVM_RISCV_ISA_EXT_ZFHMIN},
37 	{"zicbom", KVM_RISCV_ISA_EXT_ZICBOM},
38 	{"zicboz", KVM_RISCV_ISA_EXT_ZICBOZ},
39 	{"zicntr", KVM_RISCV_ISA_EXT_ZICNTR},
40 	{"zicond", KVM_RISCV_ISA_EXT_ZICOND},
41 	{"zicsr", KVM_RISCV_ISA_EXT_ZICSR},
42 	{"zifencei", KVM_RISCV_ISA_EXT_ZIFENCEI},
43 	{"zihintntl", KVM_RISCV_ISA_EXT_ZIHINTNTL},
44 	{"zihintpause", KVM_RISCV_ISA_EXT_ZIHINTPAUSE},
45 	{"zihpm", KVM_RISCV_ISA_EXT_ZIHPM},
46 	{"zknd", KVM_RISCV_ISA_EXT_ZKND},
47 	{"zkne", KVM_RISCV_ISA_EXT_ZKNE},
48 	{"zknh", KVM_RISCV_ISA_EXT_ZKNH},
49 	{"zkr", KVM_RISCV_ISA_EXT_ZKR},
50 	{"zksed", KVM_RISCV_ISA_EXT_ZKSED},
51 	{"zksh", KVM_RISCV_ISA_EXT_ZKSH},
52 	{"zkt", KVM_RISCV_ISA_EXT_ZKT},
53 	{"ztso", KVM_RISCV_ISA_EXT_ZTSO},
54 	{"zvbb", KVM_RISCV_ISA_EXT_ZVBB},
55 	{"zvbc", KVM_RISCV_ISA_EXT_ZVBC},
56 	{"zvfh", KVM_RISCV_ISA_EXT_ZVFH},
57 	{"zvfhmin", KVM_RISCV_ISA_EXT_ZVFHMIN},
58 	{"zvkb", KVM_RISCV_ISA_EXT_ZVKB},
59 	{"zvkg", KVM_RISCV_ISA_EXT_ZVKG},
60 	{"zvkned", KVM_RISCV_ISA_EXT_ZVKNED},
61 	{"zvknha", KVM_RISCV_ISA_EXT_ZVKNHA},
62 	{"zvknhb", KVM_RISCV_ISA_EXT_ZVKNHB},
63 	{"zvksed", KVM_RISCV_ISA_EXT_ZVKSED},
64 	{"zvksh", KVM_RISCV_ISA_EXT_ZVKSH},
65 	{"zvkt", KVM_RISCV_ISA_EXT_ZVKT},
66 };
67 
dump_fdt(const char * dtb_file,void * fdt)68 static void dump_fdt(const char *dtb_file, void *fdt)
69 {
70 	int count, fd;
71 
72 	fd = open(dtb_file, O_CREAT | O_TRUNC | O_RDWR, 0666);
73 	if (fd < 0)
74 		die("Failed to write dtb to %s", dtb_file);
75 
76 	count = write(fd, fdt, FDT_MAX_SIZE);
77 	if (count < 0)
78 		die_perror("Failed to dump dtb");
79 
80 	pr_debug("Wrote %d bytes to dtb %s", count, dtb_file);
81 	close(fd);
82 }
83 
84 #define CPU_NAME_MAX_LEN 15
generate_cpu_nodes(void * fdt,struct kvm * kvm)85 static void generate_cpu_nodes(void *fdt, struct kvm *kvm)
86 {
87 	int cpu, pos, i, index, valid_isa_len;
88 	const char *valid_isa_order = "IEMAFDQCLBJTPVNSUHKORWXYZG";
89 	int arr_sz = ARRAY_SIZE(isa_info_arr);
90 	unsigned long cbom_blksz = 0, cboz_blksz = 0, satp_mode = 0;
91 
92 	_FDT(fdt_begin_node(fdt, "cpus"));
93 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
94 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
95 	_FDT(fdt_property_cell(fdt, "timebase-frequency",
96 				kvm->cpus[0]->riscv_timebase));
97 
98 	for (cpu = 0; cpu < kvm->nrcpus; ++cpu) {
99 		char cpu_name[CPU_NAME_MAX_LEN];
100 #define CPU_ISA_MAX_LEN (ARRAY_SIZE(isa_info_arr) * 16)
101 		char cpu_isa[CPU_ISA_MAX_LEN];
102 		struct kvm_cpu *vcpu = kvm->cpus[cpu];
103 		struct kvm_one_reg reg;
104 		unsigned long isa_ext_out = 0;
105 
106 		snprintf(cpu_name, CPU_NAME_MAX_LEN, "cpu@%x", cpu);
107 
108 		snprintf(cpu_isa, CPU_ISA_MAX_LEN, "rv%ld", vcpu->riscv_xlen);
109 		pos = strlen(cpu_isa);
110 		valid_isa_len = strlen(valid_isa_order);
111 		for (i = 0; i < valid_isa_len; i++) {
112 			index = valid_isa_order[i] - 'A';
113 			if (vcpu->riscv_isa & (1 << (index)))
114 				cpu_isa[pos++] = 'a' + index;
115 		}
116 
117 		for (i = 0; i < arr_sz; i++) {
118 			reg.id = RISCV_ISA_EXT_REG(isa_info_arr[i].ext_id);
119 			reg.addr = (unsigned long)&isa_ext_out;
120 			if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
121 				continue;
122 			if (!isa_ext_out)
123 				/* This extension is not available in hardware */
124 				continue;
125 
126 			if (kvm->cfg.arch.ext_disabled[isa_info_arr[i].ext_id]) {
127 				isa_ext_out = 0;
128 				if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
129 					pr_warning("Failed to disable %s ISA exension\n",
130 						   isa_info_arr[i].name);
131 				continue;
132 			}
133 
134 			if (isa_info_arr[i].ext_id == KVM_RISCV_ISA_EXT_ZICBOM && !cbom_blksz) {
135 				reg.id = RISCV_CONFIG_REG(zicbom_block_size);
136 				reg.addr = (unsigned long)&cbom_blksz;
137 				if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
138 					die("KVM_GET_ONE_REG failed (config.zicbom_block_size)");
139 			}
140 
141 			if (isa_info_arr[i].ext_id == KVM_RISCV_ISA_EXT_ZICBOZ && !cboz_blksz) {
142 				reg.id = RISCV_CONFIG_REG(zicboz_block_size);
143 				reg.addr = (unsigned long)&cboz_blksz;
144 				if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
145 					die("KVM_GET_ONE_REG failed (config.zicboz_block_size)");
146 			}
147 
148 			if ((strlen(isa_info_arr[i].name) + pos + 1) >= CPU_ISA_MAX_LEN) {
149 				pr_warning("Insufficient space to append ISA exension %s\n",
150 					   isa_info_arr[i].name);
151 				break;
152 			}
153 			pos += snprintf(cpu_isa + pos, CPU_ISA_MAX_LEN, "_%s",
154 					isa_info_arr[i].name);
155 		}
156 		cpu_isa[pos] = '\0';
157 
158 		reg.id = RISCV_CONFIG_REG(satp_mode);
159 		reg.addr = (unsigned long)&satp_mode;
160 		if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
161 			satp_mode = (vcpu->riscv_xlen == 64) ? 8 : 1;
162 
163 		_FDT(fdt_begin_node(fdt, cpu_name));
164 		_FDT(fdt_property_string(fdt, "device_type", "cpu"));
165 		_FDT(fdt_property_string(fdt, "compatible", "riscv"));
166 		if (vcpu->riscv_xlen == 64) {
167 			switch (satp_mode) {
168 			case 10:
169 				_FDT(fdt_property_string(fdt, "mmu-type",
170 							 "riscv,sv57"));
171 				break;
172 			case 9:
173 				_FDT(fdt_property_string(fdt, "mmu-type",
174 							 "riscv,sv48"));
175 				break;
176 			case 8:
177 				_FDT(fdt_property_string(fdt, "mmu-type",
178 							 "riscv,sv39"));
179 				break;
180 			default:
181 				_FDT(fdt_property_string(fdt, "mmu-type",
182 							 "riscv,none"));
183 				break;
184 			}
185 		} else {
186 			switch (satp_mode) {
187 			case 1:
188 				_FDT(fdt_property_string(fdt, "mmu-type",
189 							 "riscv,sv32"));
190 				break;
191 			default:
192 				_FDT(fdt_property_string(fdt, "mmu-type",
193 							 "riscv,none"));
194 				break;
195 			}
196 		}
197 		_FDT(fdt_property_string(fdt, "riscv,isa", cpu_isa));
198 		if (cbom_blksz)
199 			_FDT(fdt_property_cell(fdt, "riscv,cbom-block-size", cbom_blksz));
200 		if (cboz_blksz)
201 			_FDT(fdt_property_cell(fdt, "riscv,cboz-block-size", cboz_blksz));
202 		_FDT(fdt_property_cell(fdt, "reg", cpu));
203 		_FDT(fdt_property_string(fdt, "status", "okay"));
204 
205 		_FDT(fdt_begin_node(fdt, "interrupt-controller"));
206 		_FDT(fdt_property_string(fdt, "compatible", "riscv,cpu-intc"));
207 		_FDT(fdt_property_cell(fdt, "#interrupt-cells", 1));
208 		_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
209 		_FDT(fdt_property_cell(fdt, "phandle",
210 					PHANDLE_CPU_INTC_BASE + cpu));
211 		_FDT(fdt_end_node(fdt));
212 
213 		_FDT(fdt_end_node(fdt));
214 	}
215 
216 	_FDT(fdt_end_node(fdt));
217 }
218 
setup_fdt(struct kvm * kvm)219 static int setup_fdt(struct kvm *kvm)
220 {
221 	struct device_header *dev_hdr;
222 	u8 staging_fdt[FDT_MAX_SIZE];
223 	u64 mem_reg_prop[]	= {
224 		cpu_to_fdt64(kvm->arch.memory_guest_start),
225 		cpu_to_fdt64(kvm->ram_size),
226 	};
227 	char *str;
228 	void *fdt		= staging_fdt;
229 	void *fdt_dest		= guest_flat_to_host(kvm,
230 						     kvm->arch.dtb_guest_start);
231 	void (*generate_mmio_fdt_nodes)(void *, struct device_header *,
232 					void (*)(void *, u8, enum irq_type));
233 
234 	/* Create new tree without a reserve map */
235 	_FDT(fdt_create(fdt, FDT_MAX_SIZE));
236 	_FDT(fdt_finish_reservemap(fdt));
237 
238 	/* Header */
239 	_FDT(fdt_begin_node(fdt, ""));
240 	_FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt"));
241 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
242 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
243 
244 	/* /chosen */
245 	_FDT(fdt_begin_node(fdt, "chosen"));
246 
247 	/* Pass on our amended command line to a Linux kernel only. */
248 	if (kvm->cfg.firmware_filename) {
249 		if (kvm->cfg.kernel_cmdline)
250 			_FDT(fdt_property_string(fdt, "bootargs",
251 						 kvm->cfg.kernel_cmdline));
252 	} else
253 		_FDT(fdt_property_string(fdt, "bootargs",
254 					 kvm->cfg.real_cmdline));
255 
256 	_FDT(fdt_property_string(fdt, "stdout-path", "serial0"));
257 
258 	/* Initrd */
259 	if (kvm->arch.initrd_size != 0) {
260 		u64 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start);
261 		u64 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start +
262 					       kvm->arch.initrd_size);
263 
264 		_FDT(fdt_property(fdt, "linux,initrd-start",
265 				   &ird_st_prop, sizeof(ird_st_prop)));
266 		_FDT(fdt_property(fdt, "linux,initrd-end",
267 				   &ird_end_prop, sizeof(ird_end_prop)));
268 	}
269 
270 	_FDT(fdt_end_node(fdt));
271 
272 	/* Memory */
273 	_FDT(fdt_begin_node(fdt, "memory"));
274 	_FDT(fdt_property_string(fdt, "device_type", "memory"));
275 	_FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop)));
276 	_FDT(fdt_end_node(fdt));
277 
278 	/* CPUs */
279 	generate_cpu_nodes(fdt, kvm);
280 
281 	/* IRQCHIP */
282 	if (!riscv_irqchip_generate_fdt_node)
283 		die("No way to generate IRQCHIP FDT node\n");
284 	riscv_irqchip_generate_fdt_node(fdt, kvm);
285 
286 	/* Simple Bus */
287 	_FDT(fdt_begin_node(fdt, "smb"));
288 	_FDT(fdt_property_string(fdt, "compatible", "simple-bus"));
289 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
290 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
291 	_FDT(fdt_property_cell(fdt, "interrupt-parent",
292 			       riscv_irqchip_phandle));
293 	_FDT(fdt_property(fdt, "ranges", NULL, 0));
294 
295 	/* Virtio MMIO devices */
296 	dev_hdr = device__first_dev(DEVICE_BUS_MMIO);
297 	while (dev_hdr) {
298 		generate_mmio_fdt_nodes = dev_hdr->data;
299 		generate_mmio_fdt_nodes(fdt, dev_hdr,
300 					riscv__generate_irq_prop);
301 		dev_hdr = device__next_dev(dev_hdr);
302 	}
303 
304 	/* IOPORT devices */
305 	dev_hdr = device__first_dev(DEVICE_BUS_IOPORT);
306 	while (dev_hdr) {
307 		generate_mmio_fdt_nodes = dev_hdr->data;
308 		generate_mmio_fdt_nodes(fdt, dev_hdr,
309 					riscv__generate_irq_prop);
310 		dev_hdr = device__next_dev(dev_hdr);
311 	}
312 
313 	/* PCI host controller */
314 	pci__generate_fdt_nodes(fdt);
315 
316 	_FDT(fdt_end_node(fdt));
317 
318 	if (fdt_stdout_path) {
319 		str = malloc(strlen(fdt_stdout_path) + strlen("/smb") + 1);
320 		sprintf(str, "/smb%s", fdt_stdout_path);
321 		free(fdt_stdout_path);
322 		fdt_stdout_path = NULL;
323 
324 		_FDT(fdt_begin_node(fdt, "aliases"));
325 		_FDT(fdt_property_string(fdt, "serial0", str));
326 		_FDT(fdt_end_node(fdt));
327 		free(str);
328 	}
329 
330 	/* Finalise. */
331 	_FDT(fdt_end_node(fdt));
332 	_FDT(fdt_finish(fdt));
333 
334 	_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
335 	_FDT(fdt_pack(fdt_dest));
336 
337 	if (kvm->cfg.arch.dump_dtb_filename)
338 		dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest);
339 	return 0;
340 }
341 late_init(setup_fdt);
342