Commit 9afefd6c authored by Julien Thierry's avatar Julien Thierry Committed by Will Deacon
Browse files

arm: Support firmware loading



Implement firmware image loading for arm and set the boot start address
to the firmware address.

Add an option for the user to specify where to map the firmware.
Signed-off-by: default avatarJulien Thierry <julien.thierry@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent 13498576
...@@ -131,7 +131,19 @@ static int setup_fdt(struct kvm *kvm) ...@@ -131,7 +131,19 @@ static int setup_fdt(struct kvm *kvm)
/* /chosen */ /* /chosen */
_FDT(fdt_begin_node(fdt, "chosen")); _FDT(fdt_begin_node(fdt, "chosen"));
_FDT(fdt_property_cell(fdt, "linux,pci-probe-only", 1)); _FDT(fdt_property_cell(fdt, "linux,pci-probe-only", 1));
_FDT(fdt_property_string(fdt, "bootargs", kvm->cfg.real_cmdline));
if (kvm->cfg.firmware_filename) {
/*
* When using a firmware, command line is not passed through DT,
* or the firmware can add it itself
*/
if (kvm->cfg.kernel_cmdline)
pr_warning("Ignoring custom bootargs: %s\n",
kvm->cfg.kernel_cmdline);
} else
_FDT(fdt_property_string(fdt, "bootargs",
kvm->cfg.real_cmdline));
_FDT(fdt_property_u64(fdt, "kaslr-seed", kvm->cfg.arch.kaslr_seed)); _FDT(fdt_property_u64(fdt, "kaslr-seed", kvm->cfg.arch.kaslr_seed));
/* Initrd */ /* Initrd */
......
...@@ -11,6 +11,7 @@ struct kvm_config_arch { ...@@ -11,6 +11,7 @@ struct kvm_config_arch {
bool has_pmuv3; bool has_pmuv3;
u64 kaslr_seed; u64 kaslr_seed;
enum irqchip_type irqchip; enum irqchip_type irqchip;
u64 fw_addr;
}; };
int irqchip_parser(const struct option *opt, const char *arg, int unset); int irqchip_parser(const struct option *opt, const char *arg, int unset);
...@@ -30,6 +31,8 @@ int irqchip_parser(const struct option *opt, const char *arg, int unset); ...@@ -30,6 +31,8 @@ int irqchip_parser(const struct option *opt, const char *arg, int unset);
OPT_CALLBACK('\0', "irqchip", &(cfg)->irqchip, \ OPT_CALLBACK('\0', "irqchip", &(cfg)->irqchip, \
"[gicv2|gicv2m|gicv3|gicv3-its]", \ "[gicv2|gicv2m|gicv3|gicv3-its]", \
"Type of interrupt controller to emulate in the guest", \ "Type of interrupt controller to emulate in the guest", \
irqchip_parser, NULL), irqchip_parser, NULL), \
OPT_U64('\0', "firmware-address", &(cfg)->fw_addr, \
"Address where firmware should be loaded"),
#endif /* ARM_COMMON__KVM_CONFIG_ARCH_H */ #endif /* ARM_COMMON__KVM_CONFIG_ARCH_H */
...@@ -169,9 +169,68 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd, ...@@ -169,9 +169,68 @@ bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
return true; return true;
} }
static bool validate_fw_addr(struct kvm *kvm, u64 fw_addr)
{
u64 ram_phys;
ram_phys = host_to_guest_flat(kvm, kvm->ram_start);
if (fw_addr < ram_phys || fw_addr >= ram_phys + kvm->ram_size) {
pr_err("Provide --firmware-address an address in RAM: "
"0x%016llx - 0x%016llx",
ram_phys, ram_phys + kvm->ram_size);
return false;
}
return true;
}
bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename) bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
{ {
return false; u64 fw_addr = kvm->cfg.arch.fw_addr;
void *host_pos;
void *limit;
ssize_t fw_sz;
int fd;
limit = kvm->ram_start + kvm->ram_size;
/* For default firmware address, lets load it at the begining of RAM */
if (fw_addr == 0)
fw_addr = ARM_MEMORY_AREA;
if (!validate_fw_addr(kvm, fw_addr))
die("Bad firmware destination: 0x%016llx", fw_addr);
fd = open(firmware_filename, O_RDONLY);
if (fd < 0)
return false;
host_pos = guest_flat_to_host(kvm, fw_addr);
if (!host_pos || host_pos < kvm->ram_start)
return false;
fw_sz = read_file(fd, host_pos, limit - host_pos);
if (fw_sz < 0)
die("failed to load firmware");
close(fd);
/* Kernel isn't loaded by kvm, point start address to firmware */
kvm->arch.kern_guest_start = fw_addr;
/* Load dtb just after the firmware image*/
host_pos += fw_sz;
if (host_pos + FDT_MAX_SIZE > limit)
die("not enough space to load fdt");
kvm->arch.dtb_guest_start = ALIGN(host_to_guest_flat(kvm, host_pos),
FDT_ALIGN);
pr_info("Placing fdt at 0x%llx - 0x%llx",
kvm->arch.dtb_guest_start,
kvm->arch.dtb_guest_start + FDT_MAX_SIZE);
return true;
} }
int kvm__arch_setup_firmware(struct kvm *kvm) int kvm__arch_setup_firmware(struct kvm *kvm)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment