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, ®))
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, ®))
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