xref: /kvmtool/riscv/kvm.c (revision abe3f28a9c0700837aca75887f0cd65c6371e2e4)
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