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