xref: /kvmtool/powerpc/spapr_hcall.c (revision 015785d4efcc6fde5f6d1c79e4adced42283efb2)
1 /*
2  * SPAPR hypercalls
3  *
4  * Borrowed heavily from QEMU's spapr_hcall.c,
5  * Copyright (c) 2010 David Gibson, IBM Corporation.
6  *
7  * Copyright (c) 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License version 2 as published
11  * by the Free Software Foundation.
12  */
13 
14 #include "spapr.h"
15 #include "kvm/util.h"
16 #include "kvm/kvm.h"
17 #include "kvm/kvm-cpu.h"
18 
19 #include <stdio.h>
20 #include <assert.h>
21 #include <sys/eventfd.h>
22 
23 static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
24 static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX -
25 					     KVMPPC_HCALL_BASE + 1];
26 
h_set_dabr(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)27 static target_ulong h_set_dabr(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
28 {
29 	/* FIXME:  Implement this for -PR.  (-HV does this in kernel.) */
30 	return H_HARDWARE;
31 }
32 
h_rtas(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)33 static target_ulong h_rtas(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
34 {
35 	target_ulong rtas_r3 = args[0];
36 	/*
37 	 * Pointer read from phys mem; these ptrs cannot be MMIO (!) so just
38 	 * reference guest RAM directly.
39 	 */
40 	uint32_t token, nargs, nret;
41 
42 	token = rtas_ld(vcpu->kvm, rtas_r3, 0);
43 	nargs = rtas_ld(vcpu->kvm, rtas_r3, 1);
44 	nret  = rtas_ld(vcpu->kvm, rtas_r3, 2);
45 
46 	return spapr_rtas_call(vcpu, token, nargs, rtas_r3 + 12,
47 			       nret, rtas_r3 + 12 + 4*nargs);
48 }
49 
h_logical_load(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)50 static target_ulong h_logical_load(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
51 {
52 	/* SLOF will require these, though kernel doesn't. */
53 	die(__PRETTY_FUNCTION__);
54 	return H_PARAMETER;
55 }
56 
h_logical_store(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)57 static target_ulong h_logical_store(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
58 {
59 	/* SLOF will require these, though kernel doesn't. */
60 	die(__PRETTY_FUNCTION__);
61 	return H_PARAMETER;
62 }
63 
h_logical_icbi(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)64 static target_ulong h_logical_icbi(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
65 {
66 	/* KVM will trap this in the kernel.  Die if it misses. */
67 	die(__PRETTY_FUNCTION__);
68 	return H_SUCCESS;
69 }
70 
h_logical_dcbf(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)71 static target_ulong h_logical_dcbf(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
72 {
73 	/* KVM will trap this in the kernel.  Die if it misses. */
74 	die(__PRETTY_FUNCTION__);
75 	return H_SUCCESS;
76 }
77 
78 struct lpcr_data {
79 	struct kvm_cpu	*cpu;
80 	int		mode;
81 };
82 
get_cpu_lpcr(struct kvm_cpu * vcpu,target_ulong * lpcr)83 static void get_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr)
84 {
85 	struct kvm_one_reg reg = {
86 		.id = KVM_REG_PPC_LPCR_64,
87 		.addr = (__u64)lpcr
88 	};
89 
90 	if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg))
91 		die("Couldn't read vcpu reg?!");
92 }
93 
set_cpu_lpcr(struct kvm_cpu * vcpu,target_ulong * lpcr)94 static void set_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr)
95 {
96 	struct kvm_one_reg reg = {
97 		.id = KVM_REG_PPC_LPCR_64,
98 		.addr = (__u64)lpcr
99 	};
100 
101 	if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg))
102 		die("Couldn't write vcpu reg?!");
103 }
104 
set_endian_task(struct kvm_cpu * vcpu,void * data)105 static void set_endian_task(struct kvm_cpu *vcpu, void *data)
106 {
107 	target_ulong mflags = (target_ulong)data;
108 	target_ulong lpcr;
109 
110 	get_cpu_lpcr(vcpu, &lpcr);
111 
112 	if (mflags == H_SET_MODE_ENDIAN_BIG)
113 		lpcr &= ~LPCR_ILE;
114 	else
115 		lpcr |= LPCR_ILE;
116 
117 	set_cpu_lpcr(vcpu, &lpcr);
118 }
119 
h_set_mode(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)120 static target_ulong h_set_mode(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
121 {
122 	int ret;
123 
124 	switch (args[1]) {
125 	case H_SET_MODE_RESOURCE_LE: {
126 		struct kvm_cpu_task task;
127 		task.func = set_endian_task;
128 		task.data = (void *)args[0];
129 		kvm_cpu__run_on_all_cpus(vcpu->kvm, &task);
130 		ret = H_SUCCESS;
131 		break;
132 	}
133 	default:
134 		ret = H_FUNCTION;
135 		break;
136 	}
137 
138 	return ret;
139 }
140 
141 
spapr_register_hypercall(target_ulong opcode,spapr_hcall_fn fn)142 void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
143 {
144 	spapr_hcall_fn *slot;
145 
146 	if (opcode <= MAX_HCALL_OPCODE) {
147 		assert((opcode & 0x3) == 0);
148 
149 		slot = &papr_hypercall_table[opcode / 4];
150 	} else {
151 		assert((opcode >= KVMPPC_HCALL_BASE) &&
152 		       (opcode <= KVMPPC_HCALL_MAX));
153 
154 		slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
155 	}
156 
157 	assert(!(*slot) || (fn == *slot));
158 	*slot = fn;
159 }
160 
spapr_hypercall(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)161 target_ulong spapr_hypercall(struct kvm_cpu *vcpu, target_ulong opcode,
162 			     target_ulong *args)
163 {
164 	if ((opcode <= MAX_HCALL_OPCODE)
165 	    && ((opcode & 0x3) == 0)) {
166 		spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
167 
168 		if (fn) {
169 			return fn(vcpu, opcode, args);
170 		}
171 	} else if ((opcode >= KVMPPC_HCALL_BASE) &&
172 		   (opcode <= KVMPPC_HCALL_MAX)) {
173 		spapr_hcall_fn fn = kvmppc_hypercall_table[opcode -
174 							   KVMPPC_HCALL_BASE];
175 
176 		if (fn) {
177 			return fn(vcpu, opcode, args);
178 		}
179 	}
180 
181 	hcall_dprintf("Unimplemented hcall 0x%lx\n", opcode);
182 	return H_FUNCTION;
183 }
184 
hypercall_init(void)185 void hypercall_init(void)
186 {
187 	/* hcall-dabr */
188 	spapr_register_hypercall(H_SET_DABR, h_set_dabr);
189 
190 	spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
191 	spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
192 	spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
193 	spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
194 	spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
195 	spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
196 	spapr_register_hypercall(H_SET_MODE, h_set_mode);
197 
198 	/* KVM-PPC specific hcalls */
199 	spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
200 }
201