xref: /kvmtool/riscv/kvm.c (revision 3f7e48f621bb229aad995111a20251dc027bf953)
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*3f7e48f6SAlexandru Elisei u64 kvm__arch_default_ram_address(void)
17*3f7e48f6SAlexandru Elisei {
18*3f7e48f6SAlexandru Elisei 	return RISCV_RAM;
19*3f7e48f6SAlexandru Elisei }
20*3f7e48f6SAlexandru Elisei 
21abe3f28aSAlexandru Elisei void kvm__arch_validate_cfg(struct kvm *kvm)
22abe3f28aSAlexandru Elisei {
23abe3f28aSAlexandru Elisei }
24abe3f28aSAlexandru Elisei 
252e996783SAnup Patel bool kvm__arch_cpu_supports_vm(void)
262e996783SAnup Patel {
272e996783SAnup Patel 	/* The KVM capability check is enough. */
282e996783SAnup Patel 	return true;
292e996783SAnup Patel }
302e996783SAnup Patel 
312e996783SAnup Patel void kvm__init_ram(struct kvm *kvm)
322e996783SAnup Patel {
33867159a7SAnup Patel 	int err;
34867159a7SAnup Patel 	u64 phys_start, phys_size;
35867159a7SAnup Patel 	void *host_mem;
36867159a7SAnup Patel 
37867159a7SAnup Patel 	phys_start	= RISCV_RAM;
38867159a7SAnup Patel 	phys_size	= kvm->ram_size;
39867159a7SAnup Patel 	host_mem	= kvm->ram_start;
40867159a7SAnup Patel 
41867159a7SAnup Patel 	err = kvm__register_ram(kvm, phys_start, phys_size, host_mem);
42867159a7SAnup Patel 	if (err)
43867159a7SAnup Patel 		die("Failed to register %lld bytes of memory at physical "
44867159a7SAnup Patel 		    "address 0x%llx [err %d]", phys_size, phys_start, err);
45867159a7SAnup Patel 
46867159a7SAnup Patel 	kvm->arch.memory_guest_start = phys_start;
472e996783SAnup Patel }
482e996783SAnup Patel 
492e996783SAnup Patel void kvm__arch_delete_ram(struct kvm *kvm)
502e996783SAnup Patel {
51867159a7SAnup Patel 	munmap(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size);
522e996783SAnup Patel }
532e996783SAnup Patel 
542e996783SAnup Patel void kvm__arch_read_term(struct kvm *kvm)
552e996783SAnup Patel {
56867159a7SAnup Patel 	serial8250__update_consoles(kvm);
57867159a7SAnup Patel 	virtio_console__inject_interrupt(kvm);
582e996783SAnup Patel }
592e996783SAnup Patel 
602e996783SAnup Patel void kvm__arch_set_cmdline(char *cmdline, bool video)
612e996783SAnup Patel {
622e996783SAnup Patel }
632e996783SAnup Patel 
645e9c654eSJulien Grall void kvm__arch_init(struct kvm *kvm)
652e996783SAnup Patel {
66867159a7SAnup Patel 	/*
67867159a7SAnup Patel 	 * Allocate guest memory. We must align our buffer to 64K to
68867159a7SAnup Patel 	 * correlate with the maximum guest page size for virtio-mmio.
69867159a7SAnup Patel 	 * If using THP, then our minimal alignment becomes 2M.
70867159a7SAnup Patel 	 * 2M trumps 64K, so let's go with that.
71867159a7SAnup Patel 	 */
725e9c654eSJulien Grall 	kvm->ram_size = min(kvm->cfg.ram_size, (u64)RISCV_MAX_MEMORY(kvm));
73867159a7SAnup Patel 	kvm->arch.ram_alloc_size = kvm->ram_size + SZ_2M;
745e9c654eSJulien Grall 	kvm->arch.ram_alloc_start = mmap_anon_or_hugetlbfs(kvm,
755e9c654eSJulien Grall 						kvm->cfg.hugetlbfs_path,
76867159a7SAnup Patel 						kvm->arch.ram_alloc_size);
77867159a7SAnup Patel 
78867159a7SAnup Patel 	if (kvm->arch.ram_alloc_start == MAP_FAILED)
79867159a7SAnup Patel 		die("Failed to map %lld bytes for guest memory (%d)",
80867159a7SAnup Patel 		    kvm->arch.ram_alloc_size, errno);
81867159a7SAnup Patel 
82867159a7SAnup Patel 	kvm->ram_start = (void *)ALIGN((unsigned long)kvm->arch.ram_alloc_start,
83867159a7SAnup Patel 					SZ_2M);
84867159a7SAnup Patel 
85867159a7SAnup Patel 	madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
86867159a7SAnup Patel 		MADV_MERGEABLE);
87867159a7SAnup Patel 
88867159a7SAnup Patel 	madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
89867159a7SAnup Patel 		MADV_HUGEPAGE);
902e996783SAnup Patel }
912e996783SAnup Patel 
92867159a7SAnup Patel #define FDT_ALIGN	SZ_4M
93867159a7SAnup Patel #define INITRD_ALIGN	8
942e996783SAnup Patel bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
952e996783SAnup Patel 				 const char *kernel_cmdline)
962e996783SAnup Patel {
97867159a7SAnup Patel 	void *pos, *kernel_end, *limit;
98867159a7SAnup Patel 	unsigned long guest_addr, kernel_offset;
99867159a7SAnup Patel 	ssize_t file_size;
100867159a7SAnup Patel 
101867159a7SAnup Patel 	/*
102867159a7SAnup Patel 	 * Linux requires the initrd and dtb to be mapped inside lowmem,
103867159a7SAnup Patel 	 * so we can't just place them at the top of memory.
104867159a7SAnup Patel 	 */
105867159a7SAnup Patel 	limit = kvm->ram_start + min(kvm->ram_size, (u64)SZ_256M) - 1;
106867159a7SAnup Patel 
107867159a7SAnup Patel #if __riscv_xlen == 64
108867159a7SAnup Patel 	/* Linux expects to be booted at 2M boundary for RV64 */
109867159a7SAnup Patel 	kernel_offset = 0x200000;
110867159a7SAnup Patel #else
111867159a7SAnup Patel 	/* Linux expects to be booted at 4M boundary for RV32 */
112867159a7SAnup Patel 	kernel_offset = 0x400000;
113867159a7SAnup Patel #endif
114867159a7SAnup Patel 
115867159a7SAnup Patel 	pos = kvm->ram_start + kernel_offset;
116867159a7SAnup Patel 	kvm->arch.kern_guest_start = host_to_guest_flat(kvm, pos);
117867159a7SAnup Patel 	file_size = read_file(fd_kernel, pos, limit - pos);
118867159a7SAnup Patel 	if (file_size < 0) {
119867159a7SAnup Patel 		if (errno == ENOMEM)
120867159a7SAnup Patel 			die("kernel image too big to fit in guest memory.");
121867159a7SAnup Patel 
122867159a7SAnup Patel 		die_perror("kernel read");
123867159a7SAnup Patel 	}
124867159a7SAnup Patel 	kernel_end = pos + file_size;
125867159a7SAnup Patel 	pr_debug("Loaded kernel to 0x%llx (%zd bytes)",
126867159a7SAnup Patel 		 kvm->arch.kern_guest_start, file_size);
127867159a7SAnup Patel 
128867159a7SAnup Patel 	/* Place FDT just after kernel at FDT_ALIGN address */
129867159a7SAnup Patel 	pos = kernel_end + FDT_ALIGN;
130867159a7SAnup Patel 	guest_addr = ALIGN(host_to_guest_flat(kvm, pos), FDT_ALIGN);
131867159a7SAnup Patel 	pos = guest_flat_to_host(kvm, guest_addr);
132867159a7SAnup Patel 	if (pos < kernel_end)
133867159a7SAnup Patel 		die("fdt overlaps with kernel image.");
134867159a7SAnup Patel 
135867159a7SAnup Patel 	kvm->arch.dtb_guest_start = guest_addr;
136867159a7SAnup Patel 	pr_debug("Placing fdt at 0x%llx - 0x%llx",
137867159a7SAnup Patel 		 kvm->arch.dtb_guest_start,
138867159a7SAnup Patel 		 host_to_guest_flat(kvm, limit));
139867159a7SAnup Patel 
140867159a7SAnup Patel 	/* ... and finally the initrd, if we have one. */
141867159a7SAnup Patel 	if (fd_initrd != -1) {
142867159a7SAnup Patel 		struct stat sb;
143867159a7SAnup Patel 		unsigned long initrd_start;
144867159a7SAnup Patel 
145867159a7SAnup Patel 		if (fstat(fd_initrd, &sb))
146867159a7SAnup Patel 			die_perror("fstat");
147867159a7SAnup Patel 
148867159a7SAnup Patel 		pos = limit - (sb.st_size + INITRD_ALIGN);
149867159a7SAnup Patel 		guest_addr = ALIGN(host_to_guest_flat(kvm, pos), INITRD_ALIGN);
150867159a7SAnup Patel 		pos = guest_flat_to_host(kvm, guest_addr);
151867159a7SAnup Patel 		if (pos < kernel_end)
152867159a7SAnup Patel 			die("initrd overlaps with kernel image.");
153867159a7SAnup Patel 
154867159a7SAnup Patel 		initrd_start = guest_addr;
155867159a7SAnup Patel 		file_size = read_file(fd_initrd, pos, limit - pos);
156867159a7SAnup Patel 		if (file_size == -1) {
157867159a7SAnup Patel 			if (errno == ENOMEM)
158867159a7SAnup Patel 				die("initrd too big to fit in guest memory.");
159867159a7SAnup Patel 
160867159a7SAnup Patel 			die_perror("initrd read");
161867159a7SAnup Patel 		}
162867159a7SAnup Patel 
163867159a7SAnup Patel 		kvm->arch.initrd_guest_start = initrd_start;
164867159a7SAnup Patel 		kvm->arch.initrd_size = file_size;
165867159a7SAnup Patel 		pr_debug("Loaded initrd to 0x%llx (%llu bytes)",
166867159a7SAnup Patel 			 kvm->arch.initrd_guest_start,
167867159a7SAnup Patel 			 kvm->arch.initrd_size);
168867159a7SAnup Patel 	} else {
169867159a7SAnup Patel 		kvm->arch.initrd_size = 0;
170867159a7SAnup Patel 	}
171867159a7SAnup Patel 
1722e996783SAnup Patel 	return true;
1732e996783SAnup Patel }
1742e996783SAnup Patel 
1752e996783SAnup Patel bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
1762e996783SAnup Patel {
1772e996783SAnup Patel 	/* TODO: Firmware loading to be supported later. */
1782e996783SAnup Patel 	return false;
1792e996783SAnup Patel }
1802e996783SAnup Patel 
1812e996783SAnup Patel int kvm__arch_setup_firmware(struct kvm *kvm)
1822e996783SAnup Patel {
1832e996783SAnup Patel 	return 0;
1842e996783SAnup Patel }
185