xref: /kvmtool/mips/kvm-cpu.c (revision 7281a8db199b95e47ff80c73765709372cd08f1e)
1 #include "kvm/kvm-cpu.h"
2 #include "kvm/term.h"
3 
4 #include <stdlib.h>
5 
6 static int debug_fd;
7 
kvm_cpu__set_debug_fd(int fd)8 void kvm_cpu__set_debug_fd(int fd)
9 {
10 	debug_fd = fd;
11 }
12 
kvm_cpu__get_debug_fd(void)13 int kvm_cpu__get_debug_fd(void)
14 {
15 	return debug_fd;
16 }
17 
kvm_cpu__delete(struct kvm_cpu * vcpu)18 void kvm_cpu__delete(struct kvm_cpu *vcpu)
19 {
20 	free(vcpu);
21 }
22 
kvm_cpu__new(struct kvm * kvm)23 static struct kvm_cpu *kvm_cpu__new(struct kvm *kvm)
24 {
25 	struct kvm_cpu *vcpu;
26 
27 	vcpu = calloc(1, sizeof(*vcpu));
28 	if (!vcpu)
29 		return NULL;
30 
31 	vcpu->kvm = kvm;
32 
33 	return vcpu;
34 }
35 
kvm_cpu__arch_init(struct kvm * kvm,unsigned long cpu_id)36 struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id)
37 {
38 	struct kvm_cpu *vcpu;
39 	int mmap_size;
40 	int coalesced_offset;
41 
42 	vcpu = kvm_cpu__new(kvm);
43 	if (!vcpu)
44 		return NULL;
45 
46 	vcpu->cpu_id = cpu_id;
47 
48 	vcpu->vcpu_fd = ioctl(vcpu->kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
49 	if (vcpu->vcpu_fd < 0)
50 		die_perror("KVM_CREATE_VCPU ioctl");
51 
52 	mmap_size = ioctl(vcpu->kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
53 	if (mmap_size < 0)
54 		die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
55 
56 	vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED, vcpu->vcpu_fd, 0);
57 	if (vcpu->kvm_run == MAP_FAILED)
58 		die("unable to mmap vcpu fd");
59 
60 	vcpu->is_running = true;
61 
62 	coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_COALESCED_MMIO);
63 	if (coalesced_offset)
64 		vcpu->ring = (void *)vcpu->kvm_run + (coalesced_offset * PAGE_SIZE);
65 
66 	return vcpu;
67 }
68 
kvm_cpu__setup_regs(struct kvm_cpu * vcpu)69 static void kvm_cpu__setup_regs(struct kvm_cpu *vcpu)
70 {
71 	uint32_t v;
72 	struct kvm_one_reg one_reg;
73 
74 	memset(&vcpu->regs, 0, sizeof(vcpu->regs));
75 	vcpu->regs.pc = vcpu->kvm->arch.entry_point;
76 	vcpu->regs.gpr[4] = vcpu->kvm->arch.argc;
77 	vcpu->regs.gpr[5] = vcpu->kvm->arch.argv;
78 
79 	if (ioctl(vcpu->vcpu_fd, KVM_SET_REGS, &vcpu->regs) < 0)
80 		die_perror("KVM_SET_REGS failed");
81 
82 
83 	one_reg.id = KVM_REG_MIPS | KVM_REG_SIZE_U32 | (0x10000 + 8 * 12 + 0); /* Status */
84 	one_reg.addr = (unsigned long)(uint32_t *)&v;
85 	v = 6;
86 
87 	if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &one_reg) < 0)
88 		die_perror("KVM_SET_ONE_REG failed");
89 }
90 
91 /**
92  * kvm_cpu__reset_vcpu - reset virtual CPU to a known state
93  */
kvm_cpu__reset_vcpu(struct kvm_cpu * vcpu)94 void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu)
95 {
96 	kvm_cpu__setup_regs(vcpu);
97 }
98 
kvm_cpu__hypercall_write_cons(struct kvm_cpu * vcpu)99 static bool kvm_cpu__hypercall_write_cons(struct kvm_cpu *vcpu)
100 {
101 	int term = (int)vcpu->kvm_run->hypercall.args[0];
102 	u64 addr = vcpu->kvm_run->hypercall.args[1];
103 	int len = (int)vcpu->kvm_run->hypercall.args[2];
104 	char *host_addr;
105 
106 	if (term < 0 || term >= TERM_MAX_DEVS) {
107 		pr_warning("hypercall_write_cons term out of range <%d>", term);
108 		return false;
109 	}
110 
111 	if ((addr & 0xffffffffc0000000ull) == 0xffffffff80000000ull)
112 		addr &= 0x1ffffffful; /* Convert KSEG{0,1} to physical. */
113 	if ((addr & 0xc000000000000000ull) == 0x8000000000000000ull)
114 		addr &= 0x07ffffffffffffffull; /* Convert XKPHYS to pysical */
115 
116 	host_addr = guest_flat_to_host(vcpu->kvm, addr);
117 	if (!host_addr) {
118 		pr_warning("hypercall_write_cons unmapped physaddr %llx", (unsigned long long)addr);
119 		return false;
120 	}
121 
122 	if ((len <= 0) || !host_ptr_in_ram(vcpu->kvm, host_addr + len)) {
123 		pr_warning("hypercall_write_cons len out of range <%d>", len);
124 		return false;
125 	}
126 
127 	term_putc(host_addr, len, term);
128 
129 	return true;
130 }
131 
132 #define KVM_HC_MIPS_CONSOLE_OUTPUT 8
kvm_cpu__handle_exit(struct kvm_cpu * vcpu)133 bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
134 {
135 	switch(vcpu->kvm_run->exit_reason) {
136 	case KVM_EXIT_HYPERCALL:
137 		if (vcpu->kvm_run->hypercall.nr == KVM_HC_MIPS_CONSOLE_OUTPUT) {
138 			return kvm_cpu__hypercall_write_cons(vcpu);
139 		} else {
140 			pr_warning("KVM_EXIT_HYPERCALL unrecognized call %llu",
141 				   (unsigned long long)vcpu->kvm_run->hypercall.nr);
142 			return false;
143 		}
144 	case KVM_EXIT_EXCEPTION:
145 	case KVM_EXIT_INTERNAL_ERROR:
146 		return false;
147 	default:
148 		break;
149 	}
150 	return false;
151 }
152 
kvm_cpu__arch_nmi(struct kvm_cpu * cpu)153 void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
154 {
155 }
156 
kvm_cpu__show_registers(struct kvm_cpu * vcpu)157 void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
158 {
159 	struct kvm_regs regs;
160 
161 	if (ioctl(vcpu->vcpu_fd, KVM_GET_REGS, &regs) < 0)
162 		die("KVM_GET_REGS failed");
163 	dprintf(debug_fd, "\n Registers:\n");
164 	dprintf(debug_fd,   " ----------\n");
165 	dprintf(debug_fd, "$0   : %016llx %016llx %016llx %016llx\n",
166 		(unsigned long long)regs.gpr[0],
167 		(unsigned long long)regs.gpr[1],
168 		(unsigned long long)regs.gpr[2],
169 		(unsigned long long)regs.gpr[3]);
170 	dprintf(debug_fd, "$4   : %016llx %016llx %016llx %016llx\n",
171 		(unsigned long long)regs.gpr[4],
172 		(unsigned long long)regs.gpr[5],
173 		(unsigned long long)regs.gpr[6],
174 		(unsigned long long)regs.gpr[7]);
175 	dprintf(debug_fd, "$8   : %016llx %016llx %016llx %016llx\n",
176 		(unsigned long long)regs.gpr[8],
177 		(unsigned long long)regs.gpr[9],
178 		(unsigned long long)regs.gpr[10],
179 		(unsigned long long)regs.gpr[11]);
180 	dprintf(debug_fd, "$12  : %016llx %016llx %016llx %016llx\n",
181 		(unsigned long long)regs.gpr[12],
182 		(unsigned long long)regs.gpr[13],
183 		(unsigned long long)regs.gpr[14],
184 		(unsigned long long)regs.gpr[15]);
185 	dprintf(debug_fd, "$16  : %016llx %016llx %016llx %016llx\n",
186 		(unsigned long long)regs.gpr[16],
187 		(unsigned long long)regs.gpr[17],
188 		(unsigned long long)regs.gpr[18],
189 		(unsigned long long)regs.gpr[19]);
190 	dprintf(debug_fd, "$20  : %016llx %016llx %016llx %016llx\n",
191 		(unsigned long long)regs.gpr[20],
192 		(unsigned long long)regs.gpr[21],
193 		(unsigned long long)regs.gpr[22],
194 		(unsigned long long)regs.gpr[23]);
195 	dprintf(debug_fd, "$24  : %016llx %016llx %016llx %016llx\n",
196 		(unsigned long long)regs.gpr[24],
197 		(unsigned long long)regs.gpr[25],
198 		(unsigned long long)regs.gpr[26],
199 		(unsigned long long)regs.gpr[27]);
200 	dprintf(debug_fd, "$28  : %016llx %016llx %016llx %016llx\n",
201 		(unsigned long long)regs.gpr[28],
202 		(unsigned long long)regs.gpr[29],
203 		(unsigned long long)regs.gpr[30],
204 		(unsigned long long)regs.gpr[31]);
205 
206 	dprintf(debug_fd, "hi   : %016llx\n", (unsigned long long)regs.hi);
207 	dprintf(debug_fd, "lo   : %016llx\n", (unsigned long long)regs.lo);
208 	dprintf(debug_fd, "epc  : %016llx\n", (unsigned long long)regs.pc);
209 
210 	dprintf(debug_fd, "\n");
211 }
212 
kvm_cpu__show_code(struct kvm_cpu * vcpu)213 void kvm_cpu__show_code(struct kvm_cpu *vcpu)
214 {
215 }
216 
kvm_cpu__show_page_tables(struct kvm_cpu * vcpu)217 void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
218 {
219 }
220