17c0e8b0cSWill Deacon #include "kvm/kvm.h"
27c0e8b0cSWill Deacon #include "kvm/term.h"
37c0e8b0cSWill Deacon #include "kvm/util.h"
497e65b5fSWill Deacon #include "kvm/8250-serial.h"
57c0e8b0cSWill Deacon #include "kvm/virtio-console.h"
63c8aec9eSAndre Przywara #include "kvm/fdt.h"
77c0e8b0cSWill Deacon
87c0e8b0cSWill Deacon #include "arm-common/gic.h"
97c0e8b0cSWill Deacon
107c0e8b0cSWill Deacon #include <linux/kernel.h>
117c0e8b0cSWill Deacon #include <linux/kvm.h>
129eb3dbcbSWill Deacon #include <linux/sizes.h>
137c0e8b0cSWill Deacon
147c0e8b0cSWill Deacon struct kvm_ext kvm_req_ext[] = {
157c0e8b0cSWill Deacon { DEFINE_KVM_EXT(KVM_CAP_IRQCHIP) },
167c0e8b0cSWill Deacon { DEFINE_KVM_EXT(KVM_CAP_ONE_REG) },
1761076240SWill Deacon { DEFINE_KVM_EXT(KVM_CAP_ARM_PSCI) },
187c0e8b0cSWill Deacon { 0, 0 },
197c0e8b0cSWill Deacon };
207c0e8b0cSWill Deacon
kvm__arch_cpu_supports_vm(void)217c0e8b0cSWill Deacon bool kvm__arch_cpu_supports_vm(void)
227c0e8b0cSWill Deacon {
237c0e8b0cSWill Deacon /* The KVM capability check is enough. */
247c0e8b0cSWill Deacon return true;
257c0e8b0cSWill Deacon }
267c0e8b0cSWill Deacon
kvm__init_ram(struct kvm * kvm)277c0e8b0cSWill Deacon void kvm__init_ram(struct kvm *kvm)
287c0e8b0cSWill Deacon {
297c0e8b0cSWill Deacon u64 phys_start, phys_size;
307c0e8b0cSWill Deacon void *host_mem;
31a37dad0eSJulien Grall int err;
32a37dad0eSJulien Grall
33a37dad0eSJulien Grall /*
34a37dad0eSJulien Grall * Allocate guest memory. We must align our buffer to 64K to
35a37dad0eSJulien Grall * correlate with the maximum guest page size for virtio-mmio.
36a37dad0eSJulien Grall * If using THP, then our minimal alignment becomes 2M.
37a37dad0eSJulien Grall * 2M trumps 64K, so let's go with that.
38a37dad0eSJulien Grall */
39a37dad0eSJulien Grall kvm->ram_size = kvm->cfg.ram_size;
40*77b108c6SSuzuki K Poulose kvm->arch.ram_alloc_size = kvm->ram_size;
41*77b108c6SSuzuki K Poulose if (!kvm->cfg.hugetlbfs_path)
42*77b108c6SSuzuki K Poulose kvm->arch.ram_alloc_size += SZ_2M;
43a37dad0eSJulien Grall kvm->arch.ram_alloc_start = mmap_anon_or_hugetlbfs(kvm,
44a37dad0eSJulien Grall kvm->cfg.hugetlbfs_path,
45a37dad0eSJulien Grall kvm->arch.ram_alloc_size);
46a37dad0eSJulien Grall
47a37dad0eSJulien Grall if (kvm->arch.ram_alloc_start == MAP_FAILED)
48a37dad0eSJulien Grall die("Failed to map %lld bytes for guest memory (%d)",
49a37dad0eSJulien Grall kvm->arch.ram_alloc_size, errno);
50a37dad0eSJulien Grall
51a37dad0eSJulien Grall kvm->ram_start = (void *)ALIGN((unsigned long)kvm->arch.ram_alloc_start,
52a37dad0eSJulien Grall SZ_2M);
53a37dad0eSJulien Grall
54a37dad0eSJulien Grall madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
55a37dad0eSJulien Grall MADV_MERGEABLE);
56a37dad0eSJulien Grall
57a37dad0eSJulien Grall madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
58a37dad0eSJulien Grall MADV_HUGEPAGE);
597c0e8b0cSWill Deacon
608b91a182SAlexandru Elisei phys_start = kvm->cfg.ram_addr;
617c0e8b0cSWill Deacon phys_size = kvm->ram_size;
627c0e8b0cSWill Deacon host_mem = kvm->ram_start;
637c0e8b0cSWill Deacon
648f46c736SJean-Philippe Brucker err = kvm__register_ram(kvm, phys_start, phys_size, host_mem);
657c0e8b0cSWill Deacon if (err)
667c0e8b0cSWill Deacon die("Failed to register %lld bytes of memory at physical "
677c0e8b0cSWill Deacon "address 0x%llx [err %d]", phys_size, phys_start, err);
687c0e8b0cSWill Deacon
697c0e8b0cSWill Deacon kvm->arch.memory_guest_start = phys_start;
708b91a182SAlexandru Elisei
718b91a182SAlexandru Elisei pr_debug("RAM created at 0x%llx - 0x%llx",
728b91a182SAlexandru Elisei phys_start, phys_start + phys_size - 1);
737c0e8b0cSWill Deacon }
747c0e8b0cSWill Deacon
kvm__arch_delete_ram(struct kvm * kvm)757c0e8b0cSWill Deacon void kvm__arch_delete_ram(struct kvm *kvm)
767c0e8b0cSWill Deacon {
779eb3dbcbSWill Deacon munmap(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size);
787c0e8b0cSWill Deacon }
797c0e8b0cSWill Deacon
kvm__arch_read_term(struct kvm * kvm)8012c406a8SJonathan Austin void kvm__arch_read_term(struct kvm *kvm)
817c0e8b0cSWill Deacon {
8297e65b5fSWill Deacon serial8250__update_consoles(kvm);
837c0e8b0cSWill Deacon virtio_console__inject_interrupt(kvm);
847c0e8b0cSWill Deacon }
857c0e8b0cSWill Deacon
kvm__arch_set_cmdline(char * cmdline,bool video)867c0e8b0cSWill Deacon void kvm__arch_set_cmdline(char *cmdline, bool video)
877c0e8b0cSWill Deacon {
887c0e8b0cSWill Deacon }
897c0e8b0cSWill Deacon
kvm__arch_init(struct kvm * kvm)905e9c654eSJulien Grall void kvm__arch_init(struct kvm *kvm)
917c0e8b0cSWill Deacon {
9269b9a17aSMarc Zyngier /* Create the virtual GIC. */
9343d2781cSAndre Przywara if (gic__create(kvm, kvm->cfg.arch.irqchip))
9469b9a17aSMarc Zyngier die("Failed to create virtual GIC");
955657dd3eSAlexandru Elisei
965657dd3eSAlexandru Elisei kvm__arch_enable_mte(kvm);
977c0e8b0cSWill Deacon }
983c8aec9eSAndre Przywara
993c8aec9eSAndre Przywara #define FDT_ALIGN SZ_2M
1003c8aec9eSAndre Przywara #define INITRD_ALIGN 4
kvm__arch_load_kernel_image(struct kvm * kvm,int fd_kernel,int fd_initrd,const char * kernel_cmdline)1013c8aec9eSAndre Przywara bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
1023c8aec9eSAndre Przywara const char *kernel_cmdline)
1033c8aec9eSAndre Przywara {
1043c8aec9eSAndre Przywara void *pos, *kernel_end, *limit;
1053c8aec9eSAndre Przywara unsigned long guest_addr;
1063c8aec9eSAndre Przywara ssize_t file_size;
1073c8aec9eSAndre Przywara
1083c8aec9eSAndre Przywara /*
1093c8aec9eSAndre Przywara * Linux requires the initrd and dtb to be mapped inside lowmem,
1103c8aec9eSAndre Przywara * so we can't just place them at the top of memory.
1113c8aec9eSAndre Przywara */
1123c8aec9eSAndre Przywara limit = kvm->ram_start + min(kvm->ram_size, (u64)SZ_256M) - 1;
1133c8aec9eSAndre Przywara
114fd0a05bdSMarc Zyngier pos = kvm->ram_start + kvm__arch_get_kern_offset(kvm, fd_kernel);
1153c8aec9eSAndre Przywara kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos);
1163c8aec9eSAndre Przywara file_size = read_file(fd_kernel, pos, limit - pos);
1173c8aec9eSAndre Przywara if (file_size < 0) {
1183c8aec9eSAndre Przywara if (errno == ENOMEM)
1193c8aec9eSAndre Przywara die("kernel image too big to contain in guest memory.");
1203c8aec9eSAndre Przywara
1213c8aec9eSAndre Przywara die_perror("kernel read");
1223c8aec9eSAndre Przywara }
1233c8aec9eSAndre Przywara kernel_end = pos + file_size;
124e1c7c62aSAndre Przywara pr_debug("Loaded kernel to 0x%llx (%zd bytes)",
1253c8aec9eSAndre Przywara kvm->arch.kern_guest_start, file_size);
1263c8aec9eSAndre Przywara
1273c8aec9eSAndre Przywara /*
1283c8aec9eSAndre Przywara * Now load backwards from the end of memory so the kernel
1293c8aec9eSAndre Przywara * decompressor has plenty of space to work with. First up is
1303c8aec9eSAndre Przywara * the device tree blob...
1313c8aec9eSAndre Przywara */
1323c8aec9eSAndre Przywara pos = limit;
1333c8aec9eSAndre Przywara pos -= (FDT_MAX_SIZE + FDT_ALIGN);
1343c8aec9eSAndre Przywara guest_addr = ALIGN(host_to_guest_flat(kvm, pos), FDT_ALIGN);
1353c8aec9eSAndre Przywara pos = guest_flat_to_host(kvm, guest_addr);
1363c8aec9eSAndre Przywara if (pos < kernel_end)
1373c8aec9eSAndre Przywara die("fdt overlaps with kernel image.");
1383c8aec9eSAndre Przywara
1393c8aec9eSAndre Przywara kvm->arch.dtb_guest_start = guest_addr;
140e1c7c62aSAndre Przywara pr_debug("Placing fdt at 0x%llx - 0x%llx",
1413c8aec9eSAndre Przywara kvm->arch.dtb_guest_start,
1423c8aec9eSAndre Przywara host_to_guest_flat(kvm, limit));
1433c8aec9eSAndre Przywara limit = pos;
1443c8aec9eSAndre Przywara
1453c8aec9eSAndre Przywara /* ... and finally the initrd, if we have one. */
1463c8aec9eSAndre Przywara if (fd_initrd != -1) {
1473c8aec9eSAndre Przywara struct stat sb;
1483c8aec9eSAndre Przywara unsigned long initrd_start;
1493c8aec9eSAndre Przywara
1503c8aec9eSAndre Przywara if (fstat(fd_initrd, &sb))
1513c8aec9eSAndre Przywara die_perror("fstat");
1523c8aec9eSAndre Przywara
1533c8aec9eSAndre Przywara pos -= (sb.st_size + INITRD_ALIGN);
1543c8aec9eSAndre Przywara guest_addr = ALIGN(host_to_guest_flat(kvm, pos), INITRD_ALIGN);
1553c8aec9eSAndre Przywara pos = guest_flat_to_host(kvm, guest_addr);
1563c8aec9eSAndre Przywara if (pos < kernel_end)
1573c8aec9eSAndre Przywara die("initrd overlaps with kernel image.");
1583c8aec9eSAndre Przywara
1593c8aec9eSAndre Przywara initrd_start = guest_addr;
1603c8aec9eSAndre Przywara file_size = read_file(fd_initrd, pos, limit - pos);
1613c8aec9eSAndre Przywara if (file_size == -1) {
1623c8aec9eSAndre Przywara if (errno == ENOMEM)
1633c8aec9eSAndre Przywara die("initrd too big to contain in guest memory.");
1643c8aec9eSAndre Przywara
1653c8aec9eSAndre Przywara die_perror("initrd read");
1663c8aec9eSAndre Przywara }
1673c8aec9eSAndre Przywara
1683c8aec9eSAndre Przywara kvm->arch.initrd_guest_start = initrd_start;
1693c8aec9eSAndre Przywara kvm->arch.initrd_size = file_size;
170e1c7c62aSAndre Przywara pr_debug("Loaded initrd to 0x%llx (%llu bytes)",
1713c8aec9eSAndre Przywara kvm->arch.initrd_guest_start,
1723c8aec9eSAndre Przywara kvm->arch.initrd_size);
1733c8aec9eSAndre Przywara } else {
1743c8aec9eSAndre Przywara kvm->arch.initrd_size = 0;
1753c8aec9eSAndre Przywara }
1763c8aec9eSAndre Przywara
1773c8aec9eSAndre Przywara return true;
1783c8aec9eSAndre Przywara }
179f269c81dSJulien Thierry
validate_fw_addr(struct kvm * kvm,u64 fw_addr)1809afefd6cSJulien Thierry static bool validate_fw_addr(struct kvm *kvm, u64 fw_addr)
1819afefd6cSJulien Thierry {
1829afefd6cSJulien Thierry u64 ram_phys;
1839afefd6cSJulien Thierry
1849afefd6cSJulien Thierry ram_phys = host_to_guest_flat(kvm, kvm->ram_start);
1859afefd6cSJulien Thierry
1869afefd6cSJulien Thierry if (fw_addr < ram_phys || fw_addr >= ram_phys + kvm->ram_size) {
1879afefd6cSJulien Thierry pr_err("Provide --firmware-address an address in RAM: "
1889afefd6cSJulien Thierry "0x%016llx - 0x%016llx",
1899afefd6cSJulien Thierry ram_phys, ram_phys + kvm->ram_size);
1909afefd6cSJulien Thierry
1919afefd6cSJulien Thierry return false;
1929afefd6cSJulien Thierry }
1939afefd6cSJulien Thierry
1949afefd6cSJulien Thierry return true;
1959afefd6cSJulien Thierry }
1969afefd6cSJulien Thierry
kvm__load_firmware(struct kvm * kvm,const char * firmware_filename)197f269c81dSJulien Thierry bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
198f269c81dSJulien Thierry {
1999afefd6cSJulien Thierry u64 fw_addr = kvm->cfg.arch.fw_addr;
2009afefd6cSJulien Thierry void *host_pos;
2019afefd6cSJulien Thierry void *limit;
2029afefd6cSJulien Thierry ssize_t fw_sz;
2039afefd6cSJulien Thierry int fd;
2049afefd6cSJulien Thierry
2059afefd6cSJulien Thierry limit = kvm->ram_start + kvm->ram_size;
2069afefd6cSJulien Thierry
2079afefd6cSJulien Thierry /* For default firmware address, lets load it at the begining of RAM */
2089afefd6cSJulien Thierry if (fw_addr == 0)
2098b91a182SAlexandru Elisei fw_addr = kvm->arch.memory_guest_start;
2109afefd6cSJulien Thierry
2119afefd6cSJulien Thierry if (!validate_fw_addr(kvm, fw_addr))
2129afefd6cSJulien Thierry die("Bad firmware destination: 0x%016llx", fw_addr);
2139afefd6cSJulien Thierry
2149afefd6cSJulien Thierry fd = open(firmware_filename, O_RDONLY);
2159afefd6cSJulien Thierry if (fd < 0)
216f269c81dSJulien Thierry return false;
2179afefd6cSJulien Thierry
2189afefd6cSJulien Thierry host_pos = guest_flat_to_host(kvm, fw_addr);
2199afefd6cSJulien Thierry if (!host_pos || host_pos < kvm->ram_start)
2209afefd6cSJulien Thierry return false;
2219afefd6cSJulien Thierry
2229afefd6cSJulien Thierry fw_sz = read_file(fd, host_pos, limit - host_pos);
2239afefd6cSJulien Thierry if (fw_sz < 0)
2249afefd6cSJulien Thierry die("failed to load firmware");
2259afefd6cSJulien Thierry close(fd);
2269afefd6cSJulien Thierry
2279afefd6cSJulien Thierry /* Kernel isn't loaded by kvm, point start address to firmware */
2289afefd6cSJulien Thierry kvm->arch.kern_guest_start = fw_addr;
229c334a68eSAlexandru Elisei pr_debug("Loaded firmware to 0x%llx (%zd bytes)",
230c334a68eSAlexandru Elisei kvm->arch.kern_guest_start, fw_sz);
2319afefd6cSJulien Thierry
2329afefd6cSJulien Thierry /* Load dtb just after the firmware image*/
2339afefd6cSJulien Thierry host_pos += fw_sz;
2349afefd6cSJulien Thierry if (host_pos + FDT_MAX_SIZE > limit)
2359afefd6cSJulien Thierry die("not enough space to load fdt");
2369afefd6cSJulien Thierry
2379afefd6cSJulien Thierry kvm->arch.dtb_guest_start = ALIGN(host_to_guest_flat(kvm, host_pos),
2389afefd6cSJulien Thierry FDT_ALIGN);
239c334a68eSAlexandru Elisei pr_debug("Placing fdt at 0x%llx - 0x%llx",
2409afefd6cSJulien Thierry kvm->arch.dtb_guest_start,
2419afefd6cSJulien Thierry kvm->arch.dtb_guest_start + FDT_MAX_SIZE);
2429afefd6cSJulien Thierry
2439afefd6cSJulien Thierry return true;
244f269c81dSJulien Thierry }
245f269c81dSJulien Thierry
kvm__arch_setup_firmware(struct kvm * kvm)246f269c81dSJulien Thierry int kvm__arch_setup_firmware(struct kvm *kvm)
247f269c81dSJulien Thierry {
248f269c81dSJulien Thierry return 0;
249f269c81dSJulien Thierry }
250