xref: /kvmtool/riscv/fdt.c (revision a20adc64b4ea5dfb8c6ef9cec296830590b0950b)
17c9aac00SAnup Patel #include "kvm/devices.h"
27c9aac00SAnup Patel #include "kvm/fdt.h"
37c9aac00SAnup Patel #include "kvm/kvm.h"
47c9aac00SAnup Patel #include "kvm/kvm-cpu.h"
57c9aac00SAnup Patel 
67c9aac00SAnup Patel #include <stdbool.h>
77c9aac00SAnup Patel 
87c9aac00SAnup Patel #include <linux/byteorder.h>
97c9aac00SAnup Patel #include <linux/kernel.h>
107c9aac00SAnup Patel #include <linux/sizes.h>
117c9aac00SAnup Patel 
128aff29e1SAtish Patra struct isa_ext_info {
138aff29e1SAtish Patra 	const char *name;
148aff29e1SAtish Patra 	unsigned long ext_id;
158aff29e1SAtish Patra };
168aff29e1SAtish Patra 
178aff29e1SAtish Patra struct isa_ext_info isa_info_arr[] = {
18b346fabeSAnup Patel 	/* sorted alphabetically */
198d02d5a8SAnup Patel 	{"smstateen", KVM_RISCV_ISA_EXT_SMSTATEEN},
208659200fSAnup Patel 	{"ssaia", KVM_RISCV_ISA_EXT_SSAIA},
213c07aeafSAtish Patra 	{"sstc", KVM_RISCV_ISA_EXT_SSTC},
22ac16e943SAnup Patel 	{"svinval", KVM_RISCV_ISA_EXT_SVINVAL},
2356e2d678SAnup Patel 	{"svnapot", KVM_RISCV_ISA_EXT_SVNAPOT},
24b346fabeSAnup Patel 	{"svpbmt", KVM_RISCV_ISA_EXT_SVPBMT},
256331850dSAnup Patel 	{"zba", KVM_RISCV_ISA_EXT_ZBA},
268c1584e7SAnup Patel 	{"zbb", KVM_RISCV_ISA_EXT_ZBB},
278b4cc705SAnup Patel 	{"zbc", KVM_RISCV_ISA_EXT_ZBC},
28d9052a96SAnup Patel 	{"zbkb", KVM_RISCV_ISA_EXT_ZBKB},
29d9052a96SAnup Patel 	{"zbkc", KVM_RISCV_ISA_EXT_ZBKC},
30d9052a96SAnup Patel 	{"zbkx", KVM_RISCV_ISA_EXT_ZBKX},
316331850dSAnup Patel 	{"zbs", KVM_RISCV_ISA_EXT_ZBS},
329cf213d6SAnup Patel 	{"zfa", KVM_RISCV_ISA_EXT_ZFA},
33bd7f13c1SAnup Patel 	{"zfh", KVM_RISCV_ISA_EXT_ZFH},
34bd7f13c1SAnup Patel 	{"zfhmin", KVM_RISCV_ISA_EXT_ZFHMIN},
35798398f4SAndrew Jones 	{"zicbom", KVM_RISCV_ISA_EXT_ZICBOM},
368f1e47caSAndrew Jones 	{"zicboz", KVM_RISCV_ISA_EXT_ZICBOZ},
3766768569SAnup Patel 	{"zicntr", KVM_RISCV_ISA_EXT_ZICNTR},
388cd71ca5SAnup Patel 	{"zicond", KVM_RISCV_ISA_EXT_ZICOND},
3934366849SAnup Patel 	{"zicsr", KVM_RISCV_ISA_EXT_ZICSR},
4034366849SAnup Patel 	{"zifencei", KVM_RISCV_ISA_EXT_ZIFENCEI},
41fce28652SAnup Patel 	{"zihintntl", KVM_RISCV_ISA_EXT_ZIHINTNTL},
42b346fabeSAnup Patel 	{"zihintpause", KVM_RISCV_ISA_EXT_ZIHINTPAUSE},
4366768569SAnup Patel 	{"zihpm", KVM_RISCV_ISA_EXT_ZIHPM},
44d9052a96SAnup Patel 	{"zknd", KVM_RISCV_ISA_EXT_ZKND},
45d9052a96SAnup Patel 	{"zkne", KVM_RISCV_ISA_EXT_ZKNE},
46d9052a96SAnup Patel 	{"zknh", KVM_RISCV_ISA_EXT_ZKNH},
47d9052a96SAnup Patel 	{"zkr", KVM_RISCV_ISA_EXT_ZKR},
48d9052a96SAnup Patel 	{"zksed", KVM_RISCV_ISA_EXT_ZKSED},
49d9052a96SAnup Patel 	{"zksh", KVM_RISCV_ISA_EXT_ZKSH},
50d9052a96SAnup Patel 	{"zkt", KVM_RISCV_ISA_EXT_ZKT},
51*a20adc64SAnup Patel 	{"ztso", KVM_RISCV_ISA_EXT_ZTSO},
5265b58f72SAnup Patel 	{"zvbb", KVM_RISCV_ISA_EXT_ZVBB},
5365b58f72SAnup Patel 	{"zvbc", KVM_RISCV_ISA_EXT_ZVBC},
545a64c1eaSAnup Patel 	{"zvfh", KVM_RISCV_ISA_EXT_ZVFH},
555a64c1eaSAnup Patel 	{"zvfhmin", KVM_RISCV_ISA_EXT_ZVFHMIN},
5665b58f72SAnup Patel 	{"zvkb", KVM_RISCV_ISA_EXT_ZVKB},
5765b58f72SAnup Patel 	{"zvkg", KVM_RISCV_ISA_EXT_ZVKG},
5865b58f72SAnup Patel 	{"zvkned", KVM_RISCV_ISA_EXT_ZVKNED},
5965b58f72SAnup Patel 	{"zvknha", KVM_RISCV_ISA_EXT_ZVKNHA},
6065b58f72SAnup Patel 	{"zvknhb", KVM_RISCV_ISA_EXT_ZVKNHB},
6165b58f72SAnup Patel 	{"zvksed", KVM_RISCV_ISA_EXT_ZVKSED},
6265b58f72SAnup Patel 	{"zvksh", KVM_RISCV_ISA_EXT_ZVKSH},
6365b58f72SAnup Patel 	{"zvkt", KVM_RISCV_ISA_EXT_ZVKT},
648aff29e1SAtish Patra };
658aff29e1SAtish Patra 
667c9aac00SAnup Patel static void dump_fdt(const char *dtb_file, void *fdt)
677c9aac00SAnup Patel {
687c9aac00SAnup Patel 	int count, fd;
697c9aac00SAnup Patel 
707c9aac00SAnup Patel 	fd = open(dtb_file, O_CREAT | O_TRUNC | O_RDWR, 0666);
717c9aac00SAnup Patel 	if (fd < 0)
727c9aac00SAnup Patel 		die("Failed to write dtb to %s", dtb_file);
737c9aac00SAnup Patel 
747c9aac00SAnup Patel 	count = write(fd, fdt, FDT_MAX_SIZE);
757c9aac00SAnup Patel 	if (count < 0)
767c9aac00SAnup Patel 		die_perror("Failed to dump dtb");
777c9aac00SAnup Patel 
787c9aac00SAnup Patel 	pr_debug("Wrote %d bytes to dtb %s", count, dtb_file);
797c9aac00SAnup Patel 	close(fd);
807c9aac00SAnup Patel }
817c9aac00SAnup Patel 
827c9aac00SAnup Patel #define CPU_NAME_MAX_LEN 15
837c9aac00SAnup Patel static void generate_cpu_nodes(void *fdt, struct kvm *kvm)
847c9aac00SAnup Patel {
857c9aac00SAnup Patel 	int cpu, pos, i, index, valid_isa_len;
867c9aac00SAnup Patel 	const char *valid_isa_order = "IEMAFDQCLBJTPVNSUHKORWXYZG";
878aff29e1SAtish Patra 	int arr_sz = ARRAY_SIZE(isa_info_arr);
88ef89838eSAnup Patel 	unsigned long cbom_blksz = 0, cboz_blksz = 0, satp_mode = 0;
897c9aac00SAnup Patel 
907c9aac00SAnup Patel 	_FDT(fdt_begin_node(fdt, "cpus"));
917c9aac00SAnup Patel 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
927c9aac00SAnup Patel 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
937c9aac00SAnup Patel 	_FDT(fdt_property_cell(fdt, "timebase-frequency",
947c9aac00SAnup Patel 				kvm->cpus[0]->riscv_timebase));
957c9aac00SAnup Patel 
967c9aac00SAnup Patel 	for (cpu = 0; cpu < kvm->nrcpus; ++cpu) {
977c9aac00SAnup Patel 		char cpu_name[CPU_NAME_MAX_LEN];
987887b398SAnup Patel #define CPU_ISA_MAX_LEN (ARRAY_SIZE(isa_info_arr) * 16)
997c9aac00SAnup Patel 		char cpu_isa[CPU_ISA_MAX_LEN];
1007c9aac00SAnup Patel 		struct kvm_cpu *vcpu = kvm->cpus[cpu];
1018aff29e1SAtish Patra 		struct kvm_one_reg reg;
1028aff29e1SAtish Patra 		unsigned long isa_ext_out = 0;
1037c9aac00SAnup Patel 
1047c9aac00SAnup Patel 		snprintf(cpu_name, CPU_NAME_MAX_LEN, "cpu@%x", cpu);
1057c9aac00SAnup Patel 
1067c9aac00SAnup Patel 		snprintf(cpu_isa, CPU_ISA_MAX_LEN, "rv%ld", vcpu->riscv_xlen);
1077c9aac00SAnup Patel 		pos = strlen(cpu_isa);
1087c9aac00SAnup Patel 		valid_isa_len = strlen(valid_isa_order);
1097c9aac00SAnup Patel 		for (i = 0; i < valid_isa_len; i++) {
1107c9aac00SAnup Patel 			index = valid_isa_order[i] - 'A';
1117c9aac00SAnup Patel 			if (vcpu->riscv_isa & (1 << (index)))
1127c9aac00SAnup Patel 				cpu_isa[pos++] = 'a' + index;
1137c9aac00SAnup Patel 		}
1148aff29e1SAtish Patra 
1158aff29e1SAtish Patra 		for (i = 0; i < arr_sz; i++) {
1168aff29e1SAtish Patra 			reg.id = RISCV_ISA_EXT_REG(isa_info_arr[i].ext_id);
1178aff29e1SAtish Patra 			reg.addr = (unsigned long)&isa_ext_out;
1188aff29e1SAtish Patra 			if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
1198aff29e1SAtish Patra 				continue;
1208aff29e1SAtish Patra 			if (!isa_ext_out)
1218aff29e1SAtish Patra 				/* This extension is not available in hardware */
1228aff29e1SAtish Patra 				continue;
1238aff29e1SAtish Patra 
124e17d182aSAnup Patel 			if (kvm->cfg.arch.ext_disabled[isa_info_arr[i].ext_id]) {
125e17d182aSAnup Patel 				isa_ext_out = 0;
126e17d182aSAnup Patel 				if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
127e17d182aSAnup Patel 					pr_warning("Failed to disable %s ISA exension\n",
128e17d182aSAnup Patel 						   isa_info_arr[i].name);
129e17d182aSAnup Patel 				continue;
130e17d182aSAnup Patel 			}
131e17d182aSAnup Patel 
132798398f4SAndrew Jones 			if (isa_info_arr[i].ext_id == KVM_RISCV_ISA_EXT_ZICBOM && !cbom_blksz) {
133798398f4SAndrew Jones 				reg.id = RISCV_CONFIG_REG(zicbom_block_size);
134798398f4SAndrew Jones 				reg.addr = (unsigned long)&cbom_blksz;
135798398f4SAndrew Jones 				if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
136798398f4SAndrew Jones 					die("KVM_GET_ONE_REG failed (config.zicbom_block_size)");
137798398f4SAndrew Jones 			}
138798398f4SAndrew Jones 
1398f1e47caSAndrew Jones 			if (isa_info_arr[i].ext_id == KVM_RISCV_ISA_EXT_ZICBOZ && !cboz_blksz) {
1408f1e47caSAndrew Jones 				reg.id = RISCV_CONFIG_REG(zicboz_block_size);
1418f1e47caSAndrew Jones 				reg.addr = (unsigned long)&cboz_blksz;
1428f1e47caSAndrew Jones 				if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
1438f1e47caSAndrew Jones 					die("KVM_GET_ONE_REG failed (config.zicboz_block_size)");
1448f1e47caSAndrew Jones 			}
1458f1e47caSAndrew Jones 
1468aff29e1SAtish Patra 			if ((strlen(isa_info_arr[i].name) + pos + 1) >= CPU_ISA_MAX_LEN) {
147fcb07675SAnup Patel 				pr_warning("Insufficient space to append ISA exension %s\n",
148fcb07675SAnup Patel 					   isa_info_arr[i].name);
1498aff29e1SAtish Patra 				break;
1508aff29e1SAtish Patra 			}
1518aff29e1SAtish Patra 			pos += snprintf(cpu_isa + pos, CPU_ISA_MAX_LEN, "_%s",
1528aff29e1SAtish Patra 					isa_info_arr[i].name);
1538aff29e1SAtish Patra 		}
1547c9aac00SAnup Patel 		cpu_isa[pos] = '\0';
1557c9aac00SAnup Patel 
156ef89838eSAnup Patel 		reg.id = RISCV_CONFIG_REG(satp_mode);
157ef89838eSAnup Patel 		reg.addr = (unsigned long)&satp_mode;
158ef89838eSAnup Patel 		if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg) < 0)
159ef89838eSAnup Patel 			satp_mode = (vcpu->riscv_xlen == 64) ? 8 : 1;
160ef89838eSAnup Patel 
1617c9aac00SAnup Patel 		_FDT(fdt_begin_node(fdt, cpu_name));
1627c9aac00SAnup Patel 		_FDT(fdt_property_string(fdt, "device_type", "cpu"));
1637c9aac00SAnup Patel 		_FDT(fdt_property_string(fdt, "compatible", "riscv"));
164ef89838eSAnup Patel 		if (vcpu->riscv_xlen == 64) {
165ef89838eSAnup Patel 			switch (satp_mode) {
166ef89838eSAnup Patel 			case 10:
167ef89838eSAnup Patel 				_FDT(fdt_property_string(fdt, "mmu-type",
168ef89838eSAnup Patel 							 "riscv,sv57"));
169ef89838eSAnup Patel 				break;
170ef89838eSAnup Patel 			case 9:
1717c9aac00SAnup Patel 				_FDT(fdt_property_string(fdt, "mmu-type",
1727c9aac00SAnup Patel 							 "riscv,sv48"));
173ef89838eSAnup Patel 				break;
174ef89838eSAnup Patel 			case 8:
175ef89838eSAnup Patel 				_FDT(fdt_property_string(fdt, "mmu-type",
176ef89838eSAnup Patel 							 "riscv,sv39"));
177ef89838eSAnup Patel 				break;
178ef89838eSAnup Patel 			default:
179ef89838eSAnup Patel 				_FDT(fdt_property_string(fdt, "mmu-type",
180ef89838eSAnup Patel 							 "riscv,none"));
181ef89838eSAnup Patel 				break;
182ef89838eSAnup Patel 			}
183ef89838eSAnup Patel 		} else {
184ef89838eSAnup Patel 			switch (satp_mode) {
185ef89838eSAnup Patel 			case 1:
1867c9aac00SAnup Patel 				_FDT(fdt_property_string(fdt, "mmu-type",
1877c9aac00SAnup Patel 							 "riscv,sv32"));
188ef89838eSAnup Patel 				break;
189ef89838eSAnup Patel 			default:
190ef89838eSAnup Patel 				_FDT(fdt_property_string(fdt, "mmu-type",
191ef89838eSAnup Patel 							 "riscv,none"));
192ef89838eSAnup Patel 				break;
193ef89838eSAnup Patel 			}
194ef89838eSAnup Patel 		}
1957c9aac00SAnup Patel 		_FDT(fdt_property_string(fdt, "riscv,isa", cpu_isa));
196798398f4SAndrew Jones 		if (cbom_blksz)
197798398f4SAndrew Jones 			_FDT(fdt_property_cell(fdt, "riscv,cbom-block-size", cbom_blksz));
1988f1e47caSAndrew Jones 		if (cboz_blksz)
1998f1e47caSAndrew Jones 			_FDT(fdt_property_cell(fdt, "riscv,cboz-block-size", cboz_blksz));
2007c9aac00SAnup Patel 		_FDT(fdt_property_cell(fdt, "reg", cpu));
2017c9aac00SAnup Patel 		_FDT(fdt_property_string(fdt, "status", "okay"));
2027c9aac00SAnup Patel 
2037c9aac00SAnup Patel 		_FDT(fdt_begin_node(fdt, "interrupt-controller"));
2047c9aac00SAnup Patel 		_FDT(fdt_property_string(fdt, "compatible", "riscv,cpu-intc"));
2057c9aac00SAnup Patel 		_FDT(fdt_property_cell(fdt, "#interrupt-cells", 1));
2067c9aac00SAnup Patel 		_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
2077c9aac00SAnup Patel 		_FDT(fdt_property_cell(fdt, "phandle",
2087c9aac00SAnup Patel 					PHANDLE_CPU_INTC_BASE + cpu));
2097c9aac00SAnup Patel 		_FDT(fdt_end_node(fdt));
2107c9aac00SAnup Patel 
2117c9aac00SAnup Patel 		_FDT(fdt_end_node(fdt));
2127c9aac00SAnup Patel 	}
2137c9aac00SAnup Patel 
2147c9aac00SAnup Patel 	_FDT(fdt_end_node(fdt));
2157c9aac00SAnup Patel }
2167c9aac00SAnup Patel 
2177c9aac00SAnup Patel static int setup_fdt(struct kvm *kvm)
2187c9aac00SAnup Patel {
2197c9aac00SAnup Patel 	struct device_header *dev_hdr;
2207c9aac00SAnup Patel 	u8 staging_fdt[FDT_MAX_SIZE];
2217c9aac00SAnup Patel 	u64 mem_reg_prop[]	= {
2227c9aac00SAnup Patel 		cpu_to_fdt64(kvm->arch.memory_guest_start),
2237c9aac00SAnup Patel 		cpu_to_fdt64(kvm->ram_size),
2247c9aac00SAnup Patel 	};
225ed805be5SAnup Patel 	char *str;
2267c9aac00SAnup Patel 	void *fdt		= staging_fdt;
2277c9aac00SAnup Patel 	void *fdt_dest		= guest_flat_to_host(kvm,
2287c9aac00SAnup Patel 						     kvm->arch.dtb_guest_start);
2297c9aac00SAnup Patel 	void (*generate_mmio_fdt_nodes)(void *, struct device_header *,
2307c9aac00SAnup Patel 					void (*)(void *, u8, enum irq_type));
2317c9aac00SAnup Patel 
2327c9aac00SAnup Patel 	/* Create new tree without a reserve map */
2337c9aac00SAnup Patel 	_FDT(fdt_create(fdt, FDT_MAX_SIZE));
2347c9aac00SAnup Patel 	_FDT(fdt_finish_reservemap(fdt));
2357c9aac00SAnup Patel 
2367c9aac00SAnup Patel 	/* Header */
2377c9aac00SAnup Patel 	_FDT(fdt_begin_node(fdt, ""));
2387c9aac00SAnup Patel 	_FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt"));
2397c9aac00SAnup Patel 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
2407c9aac00SAnup Patel 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
2417c9aac00SAnup Patel 
2427c9aac00SAnup Patel 	/* /chosen */
2437c9aac00SAnup Patel 	_FDT(fdt_begin_node(fdt, "chosen"));
2447c9aac00SAnup Patel 
2457c9aac00SAnup Patel 	/* Pass on our amended command line to a Linux kernel only. */
2467c9aac00SAnup Patel 	if (kvm->cfg.firmware_filename) {
2477c9aac00SAnup Patel 		if (kvm->cfg.kernel_cmdline)
2487c9aac00SAnup Patel 			_FDT(fdt_property_string(fdt, "bootargs",
2497c9aac00SAnup Patel 						 kvm->cfg.kernel_cmdline));
2507c9aac00SAnup Patel 	} else
2517c9aac00SAnup Patel 		_FDT(fdt_property_string(fdt, "bootargs",
2527c9aac00SAnup Patel 					 kvm->cfg.real_cmdline));
2537c9aac00SAnup Patel 
2547c9aac00SAnup Patel 	_FDT(fdt_property_string(fdt, "stdout-path", "serial0"));
2557c9aac00SAnup Patel 
2567c9aac00SAnup Patel 	/* Initrd */
2577c9aac00SAnup Patel 	if (kvm->arch.initrd_size != 0) {
2587c9aac00SAnup Patel 		u64 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start);
2597c9aac00SAnup Patel 		u64 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start +
2607c9aac00SAnup Patel 					       kvm->arch.initrd_size);
2617c9aac00SAnup Patel 
2627c9aac00SAnup Patel 		_FDT(fdt_property(fdt, "linux,initrd-start",
2637c9aac00SAnup Patel 				   &ird_st_prop, sizeof(ird_st_prop)));
2647c9aac00SAnup Patel 		_FDT(fdt_property(fdt, "linux,initrd-end",
2657c9aac00SAnup Patel 				   &ird_end_prop, sizeof(ird_end_prop)));
2667c9aac00SAnup Patel 	}
2677c9aac00SAnup Patel 
2687c9aac00SAnup Patel 	_FDT(fdt_end_node(fdt));
2697c9aac00SAnup Patel 
2707c9aac00SAnup Patel 	/* Memory */
2717c9aac00SAnup Patel 	_FDT(fdt_begin_node(fdt, "memory"));
2727c9aac00SAnup Patel 	_FDT(fdt_property_string(fdt, "device_type", "memory"));
2737c9aac00SAnup Patel 	_FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop)));
2747c9aac00SAnup Patel 	_FDT(fdt_end_node(fdt));
2757c9aac00SAnup Patel 
2767c9aac00SAnup Patel 	/* CPUs */
2777c9aac00SAnup Patel 	generate_cpu_nodes(fdt, kvm);
2787c9aac00SAnup Patel 
2790dff3501SAnup Patel 	/* IRQCHIP */
2800dff3501SAnup Patel 	if (!riscv_irqchip_generate_fdt_node)
2810dff3501SAnup Patel 		die("No way to generate IRQCHIP FDT node\n");
2820dff3501SAnup Patel 	riscv_irqchip_generate_fdt_node(fdt, kvm);
2830dff3501SAnup Patel 
2847c9aac00SAnup Patel 	/* Simple Bus */
2857c9aac00SAnup Patel 	_FDT(fdt_begin_node(fdt, "smb"));
2867c9aac00SAnup Patel 	_FDT(fdt_property_string(fdt, "compatible", "simple-bus"));
2877c9aac00SAnup Patel 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
2887c9aac00SAnup Patel 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
2890dff3501SAnup Patel 	_FDT(fdt_property_cell(fdt, "interrupt-parent",
2900dff3501SAnup Patel 			       riscv_irqchip_phandle));
2917c9aac00SAnup Patel 	_FDT(fdt_property(fdt, "ranges", NULL, 0));
2927c9aac00SAnup Patel 
2937c9aac00SAnup Patel 	/* Virtio MMIO devices */
2947c9aac00SAnup Patel 	dev_hdr = device__first_dev(DEVICE_BUS_MMIO);
2957c9aac00SAnup Patel 	while (dev_hdr) {
2967c9aac00SAnup Patel 		generate_mmio_fdt_nodes = dev_hdr->data;
2970dff3501SAnup Patel 		generate_mmio_fdt_nodes(fdt, dev_hdr,
2980dff3501SAnup Patel 					riscv__generate_irq_prop);
2997c9aac00SAnup Patel 		dev_hdr = device__next_dev(dev_hdr);
3007c9aac00SAnup Patel 	}
3017c9aac00SAnup Patel 
3027c9aac00SAnup Patel 	/* IOPORT devices */
3037c9aac00SAnup Patel 	dev_hdr = device__first_dev(DEVICE_BUS_IOPORT);
3047c9aac00SAnup Patel 	while (dev_hdr) {
3057c9aac00SAnup Patel 		generate_mmio_fdt_nodes = dev_hdr->data;
3060dff3501SAnup Patel 		generate_mmio_fdt_nodes(fdt, dev_hdr,
3070dff3501SAnup Patel 					riscv__generate_irq_prop);
3087c9aac00SAnup Patel 		dev_hdr = device__next_dev(dev_hdr);
3097c9aac00SAnup Patel 	}
3107c9aac00SAnup Patel 
311cdd7d8ccSAnup Patel 	/* PCI host controller */
312cdd7d8ccSAnup Patel 	pci__generate_fdt_nodes(fdt);
313cdd7d8ccSAnup Patel 
3147c9aac00SAnup Patel 	_FDT(fdt_end_node(fdt));
3157c9aac00SAnup Patel 
3167c9aac00SAnup Patel 	if (fdt_stdout_path) {
317ed805be5SAnup Patel 		str = malloc(strlen(fdt_stdout_path) + strlen("/smb") + 1);
318ed805be5SAnup Patel 		sprintf(str, "/smb%s", fdt_stdout_path);
3197c9aac00SAnup Patel 		free(fdt_stdout_path);
3207c9aac00SAnup Patel 		fdt_stdout_path = NULL;
321ed805be5SAnup Patel 
322ed805be5SAnup Patel 		_FDT(fdt_begin_node(fdt, "aliases"));
323ed805be5SAnup Patel 		_FDT(fdt_property_string(fdt, "serial0", str));
324ed805be5SAnup Patel 		_FDT(fdt_end_node(fdt));
325ed805be5SAnup Patel 		free(str);
3267c9aac00SAnup Patel 	}
3277c9aac00SAnup Patel 
3287c9aac00SAnup Patel 	/* Finalise. */
3297c9aac00SAnup Patel 	_FDT(fdt_end_node(fdt));
3307c9aac00SAnup Patel 	_FDT(fdt_finish(fdt));
3317c9aac00SAnup Patel 
3327c9aac00SAnup Patel 	_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
3337c9aac00SAnup Patel 	_FDT(fdt_pack(fdt_dest));
3347c9aac00SAnup Patel 
3357c9aac00SAnup Patel 	if (kvm->cfg.arch.dump_dtb_filename)
3367c9aac00SAnup Patel 		dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest);
3377c9aac00SAnup Patel 	return 0;
3387c9aac00SAnup Patel }
3397c9aac00SAnup Patel late_init(setup_fdt);
340