setup_fdt
guestにdeviceの情報を伝えるために,device treeを作って,FDTにして,メモリに展開する
device treeの内容物は
chosen
kernelのcmdline引数
initrdの場所(始点,終点)
memory
cpu
smb(simple bus)
virtio-mmio devices
portio devices
aliases (stdio)
serial0
これらをlibfdtのinterfaceに従って生成
最後に,fdt_packして,Flattened Device Treeを作る
そして,kvm->cfg.arch.dump_dtb_filenameへ保存する
code:c
dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest);
あとで,これを,guestのメモリに展開する
code:riscv/fdt.c
static int setup_fdt(struct kvm *kvm)
{
struct device_header *dev_hdr;
u64 mem_reg_prop[] = {
cpu_to_fdt64(kvm->arch.memory_guest_start),
cpu_to_fdt64(kvm->ram_size),
};
void *fdt = staging_fdt;
void *fdt_dest = guest_flat_to_host(kvm,
kvm->arch.dtb_guest_start);
void (*generate_mmio_fdt_nodes)(void *, struct device_header *,
void (*)(void *, u8, enum irq_type));
/* Create new tree without a reserve map */
_FDT(fdt_create(fdt, FDT_MAX_SIZE));
_FDT(fdt_finish_reservemap(fdt));
/* Header */
_FDT(fdt_begin_node(fdt, ""));
_FDT(fdt_property_cell(fdt, "interrupt-parent", PHANDLE_PLIC));
_FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt"));
_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
/* /chosen */
_FDT(fdt_begin_node(fdt, "chosen"));
/* Pass on our amended command line to a Linux kernel only. */
if (kvm->cfg.firmware_filename) {
if (kvm->cfg.kernel_cmdline)
_FDT(fdt_property_string(fdt, "bootargs",
kvm->cfg.kernel_cmdline));
} else
_FDT(fdt_property_string(fdt, "bootargs",
kvm->cfg.real_cmdline));
_FDT(fdt_property_string(fdt, "stdout-path", "serial0"));
/* Initrd */
if (kvm->arch.initrd_size != 0) {
u64 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start);
u64 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start +
kvm->arch.initrd_size);
_FDT(fdt_property(fdt, "linux,initrd-start",
&ird_st_prop, sizeof(ird_st_prop)));
_FDT(fdt_property(fdt, "linux,initrd-end",
&ird_end_prop, sizeof(ird_end_prop)));
}
_FDT(fdt_end_node(fdt));
/* Memory */
_FDT(fdt_begin_node(fdt, "memory"));
_FDT(fdt_property_string(fdt, "device_type", "memory"));
_FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop)));
_FDT(fdt_end_node(fdt));
/* CPUs */
generate_cpu_nodes(fdt, kvm);
/* Simple Bus */
_FDT(fdt_begin_node(fdt, "smb"));
_FDT(fdt_property_string(fdt, "compatible", "simple-bus"));
_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
_FDT(fdt_property(fdt, "ranges", NULL, 0));
/* Virtio MMIO devices */
dev_hdr = device__first_dev(DEVICE_BUS_MMIO);
while (dev_hdr) {
generate_mmio_fdt_nodes = dev_hdr->data;
generate_mmio_fdt_nodes(fdt, dev_hdr, plic__generate_irq_prop);
dev_hdr = device__next_dev(dev_hdr);
}
/* IOPORT devices */
dev_hdr = device__first_dev(DEVICE_BUS_IOPORT);
while (dev_hdr) {
generate_mmio_fdt_nodes = dev_hdr->data;
generate_mmio_fdt_nodes(fdt, dev_hdr, plic__generate_irq_prop);
dev_hdr = device__next_dev(dev_hdr);
}
_FDT(fdt_end_node(fdt));
if (fdt_stdout_path) {
_FDT(fdt_begin_node(fdt, "aliases"));
_FDT(fdt_property_string(fdt, "serial0", fdt_stdout_path));
_FDT(fdt_end_node(fdt));
free(fdt_stdout_path);
fdt_stdout_path = NULL;
}
/* Finalise. */
_FDT(fdt_end_node(fdt));
_FDT(fdt_finish(fdt));
_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
_FDT(fdt_pack(fdt_dest));
if (kvm->cfg.arch.dump_dtb_filename)
dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest);
return 0;
}