12e996783SAnup Patel #include "kvm/kvm.h" 22e996783SAnup Patel #include "kvm/util.h" 3867159a7SAnup Patel #include "kvm/8250-serial.h" 4867159a7SAnup Patel #include "kvm/virtio-console.h" 52e996783SAnup Patel #include "kvm/fdt.h" 62e996783SAnup Patel 72e996783SAnup Patel #include <linux/kernel.h> 82e996783SAnup Patel #include <linux/kvm.h> 92e996783SAnup Patel #include <linux/sizes.h> 102e996783SAnup Patel 112e996783SAnup Patel struct kvm_ext kvm_req_ext[] = { 122e996783SAnup Patel { DEFINE_KVM_EXT(KVM_CAP_ONE_REG) }, 132e996783SAnup Patel { 0, 0 }, 142e996783SAnup Patel }; 152e996783SAnup Patel 16*abe3f28aSAlexandru Elisei void kvm__arch_validate_cfg(struct kvm *kvm) 17*abe3f28aSAlexandru Elisei { 18*abe3f28aSAlexandru Elisei } 19*abe3f28aSAlexandru Elisei 202e996783SAnup Patel bool kvm__arch_cpu_supports_vm(void) 212e996783SAnup Patel { 222e996783SAnup Patel /* The KVM capability check is enough. */ 232e996783SAnup Patel return true; 242e996783SAnup Patel } 252e996783SAnup Patel 262e996783SAnup Patel void kvm__init_ram(struct kvm *kvm) 272e996783SAnup Patel { 28867159a7SAnup Patel int err; 29867159a7SAnup Patel u64 phys_start, phys_size; 30867159a7SAnup Patel void *host_mem; 31867159a7SAnup Patel 32867159a7SAnup Patel phys_start = RISCV_RAM; 33867159a7SAnup Patel phys_size = kvm->ram_size; 34867159a7SAnup Patel host_mem = kvm->ram_start; 35867159a7SAnup Patel 36867159a7SAnup Patel err = kvm__register_ram(kvm, phys_start, phys_size, host_mem); 37867159a7SAnup Patel if (err) 38867159a7SAnup Patel die("Failed to register %lld bytes of memory at physical " 39867159a7SAnup Patel "address 0x%llx [err %d]", phys_size, phys_start, err); 40867159a7SAnup Patel 41867159a7SAnup Patel kvm->arch.memory_guest_start = phys_start; 422e996783SAnup Patel } 432e996783SAnup Patel 442e996783SAnup Patel void kvm__arch_delete_ram(struct kvm *kvm) 452e996783SAnup Patel { 46867159a7SAnup Patel munmap(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size); 472e996783SAnup Patel } 482e996783SAnup Patel 492e996783SAnup Patel void kvm__arch_read_term(struct kvm *kvm) 502e996783SAnup Patel { 51867159a7SAnup Patel serial8250__update_consoles(kvm); 52867159a7SAnup Patel virtio_console__inject_interrupt(kvm); 532e996783SAnup Patel } 542e996783SAnup Patel 552e996783SAnup Patel void kvm__arch_set_cmdline(char *cmdline, bool video) 562e996783SAnup Patel { 572e996783SAnup Patel } 582e996783SAnup Patel 592e996783SAnup Patel void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size) 602e996783SAnup Patel { 61867159a7SAnup Patel /* 62867159a7SAnup Patel * Allocate guest memory. We must align our buffer to 64K to 63867159a7SAnup Patel * correlate with the maximum guest page size for virtio-mmio. 64867159a7SAnup Patel * If using THP, then our minimal alignment becomes 2M. 65867159a7SAnup Patel * 2M trumps 64K, so let's go with that. 66867159a7SAnup Patel */ 67867159a7SAnup Patel kvm->ram_size = min(ram_size, (u64)RISCV_MAX_MEMORY(kvm)); 68867159a7SAnup Patel kvm->arch.ram_alloc_size = kvm->ram_size + SZ_2M; 69867159a7SAnup Patel kvm->arch.ram_alloc_start = mmap_anon_or_hugetlbfs(kvm, hugetlbfs_path, 70867159a7SAnup Patel kvm->arch.ram_alloc_size); 71867159a7SAnup Patel 72867159a7SAnup Patel if (kvm->arch.ram_alloc_start == MAP_FAILED) 73867159a7SAnup Patel die("Failed to map %lld bytes for guest memory (%d)", 74867159a7SAnup Patel kvm->arch.ram_alloc_size, errno); 75867159a7SAnup Patel 76867159a7SAnup Patel kvm->ram_start = (void *)ALIGN((unsigned long)kvm->arch.ram_alloc_start, 77867159a7SAnup Patel SZ_2M); 78867159a7SAnup Patel 79867159a7SAnup Patel madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size, 80867159a7SAnup Patel MADV_MERGEABLE); 81867159a7SAnup Patel 82867159a7SAnup Patel madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size, 83867159a7SAnup Patel MADV_HUGEPAGE); 842e996783SAnup Patel } 852e996783SAnup Patel 86867159a7SAnup Patel #define FDT_ALIGN SZ_4M 87867159a7SAnup Patel #define INITRD_ALIGN 8 882e996783SAnup Patel bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd, 892e996783SAnup Patel const char *kernel_cmdline) 902e996783SAnup Patel { 91867159a7SAnup Patel void *pos, *kernel_end, *limit; 92867159a7SAnup Patel unsigned long guest_addr, kernel_offset; 93867159a7SAnup Patel ssize_t file_size; 94867159a7SAnup Patel 95867159a7SAnup Patel /* 96867159a7SAnup Patel * Linux requires the initrd and dtb to be mapped inside lowmem, 97867159a7SAnup Patel * so we can't just place them at the top of memory. 98867159a7SAnup Patel */ 99867159a7SAnup Patel limit = kvm->ram_start + min(kvm->ram_size, (u64)SZ_256M) - 1; 100867159a7SAnup Patel 101867159a7SAnup Patel #if __riscv_xlen == 64 102867159a7SAnup Patel /* Linux expects to be booted at 2M boundary for RV64 */ 103867159a7SAnup Patel kernel_offset = 0x200000; 104867159a7SAnup Patel #else 105867159a7SAnup Patel /* Linux expects to be booted at 4M boundary for RV32 */ 106867159a7SAnup Patel kernel_offset = 0x400000; 107867159a7SAnup Patel #endif 108867159a7SAnup Patel 109867159a7SAnup Patel pos = kvm->ram_start + kernel_offset; 110867159a7SAnup Patel kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos); 111867159a7SAnup Patel file_size = read_file(fd_kernel, pos, limit - pos); 112867159a7SAnup Patel if (file_size < 0) { 113867159a7SAnup Patel if (errno == ENOMEM) 114867159a7SAnup Patel die("kernel image too big to fit in guest memory."); 115867159a7SAnup Patel 116867159a7SAnup Patel die_perror("kernel read"); 117867159a7SAnup Patel } 118867159a7SAnup Patel kernel_end = pos + file_size; 119867159a7SAnup Patel pr_debug("Loaded kernel to 0x%llx (%zd bytes)", 120867159a7SAnup Patel kvm->arch.kern_guest_start, file_size); 121867159a7SAnup Patel 122867159a7SAnup Patel /* Place FDT just after kernel at FDT_ALIGN address */ 123867159a7SAnup Patel pos = kernel_end + FDT_ALIGN; 124867159a7SAnup Patel guest_addr = ALIGN(host_to_guest_flat(kvm, pos), FDT_ALIGN); 125867159a7SAnup Patel pos = guest_flat_to_host(kvm, guest_addr); 126867159a7SAnup Patel if (pos < kernel_end) 127867159a7SAnup Patel die("fdt overlaps with kernel image."); 128867159a7SAnup Patel 129867159a7SAnup Patel kvm->arch.dtb_guest_start = guest_addr; 130867159a7SAnup Patel pr_debug("Placing fdt at 0x%llx - 0x%llx", 131867159a7SAnup Patel kvm->arch.dtb_guest_start, 132867159a7SAnup Patel host_to_guest_flat(kvm, limit)); 133867159a7SAnup Patel 134867159a7SAnup Patel /* ... and finally the initrd, if we have one. */ 135867159a7SAnup Patel if (fd_initrd != -1) { 136867159a7SAnup Patel struct stat sb; 137867159a7SAnup Patel unsigned long initrd_start; 138867159a7SAnup Patel 139867159a7SAnup Patel if (fstat(fd_initrd, &sb)) 140867159a7SAnup Patel die_perror("fstat"); 141867159a7SAnup Patel 142867159a7SAnup Patel pos = limit - (sb.st_size + INITRD_ALIGN); 143867159a7SAnup Patel guest_addr = ALIGN(host_to_guest_flat(kvm, pos), INITRD_ALIGN); 144867159a7SAnup Patel pos = guest_flat_to_host(kvm, guest_addr); 145867159a7SAnup Patel if (pos < kernel_end) 146867159a7SAnup Patel die("initrd overlaps with kernel image."); 147867159a7SAnup Patel 148867159a7SAnup Patel initrd_start = guest_addr; 149867159a7SAnup Patel file_size = read_file(fd_initrd, pos, limit - pos); 150867159a7SAnup Patel if (file_size == -1) { 151867159a7SAnup Patel if (errno == ENOMEM) 152867159a7SAnup Patel die("initrd too big to fit in guest memory."); 153867159a7SAnup Patel 154867159a7SAnup Patel die_perror("initrd read"); 155867159a7SAnup Patel } 156867159a7SAnup Patel 157867159a7SAnup Patel kvm->arch.initrd_guest_start = initrd_start; 158867159a7SAnup Patel kvm->arch.initrd_size = file_size; 159867159a7SAnup Patel pr_debug("Loaded initrd to 0x%llx (%llu bytes)", 160867159a7SAnup Patel kvm->arch.initrd_guest_start, 161867159a7SAnup Patel kvm->arch.initrd_size); 162867159a7SAnup Patel } else { 163867159a7SAnup Patel kvm->arch.initrd_size = 0; 164867159a7SAnup Patel } 165867159a7SAnup Patel 1662e996783SAnup Patel return true; 1672e996783SAnup Patel } 1682e996783SAnup Patel 1692e996783SAnup Patel bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename) 1702e996783SAnup Patel { 1712e996783SAnup Patel /* TODO: Firmware loading to be supported later. */ 1722e996783SAnup Patel return false; 1732e996783SAnup Patel } 1742e996783SAnup Patel 1752e996783SAnup Patel int kvm__arch_setup_firmware(struct kvm *kvm) 1762e996783SAnup Patel { 1772e996783SAnup Patel return 0; 1782e996783SAnup Patel } 179