1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
|
/*
* access guest memory
*
* Copyright IBM Corp. 2008, 2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
* as published by the Free Software Foundation.
*
* Author(s): Carsten Otte <cotte@de.ibm.com>
*/
#ifndef __KVM_S390_GACCESS_H
#define __KVM_S390_GACCESS_H
#include <linux/compiler.h>
#include <linux/kvm_host.h>
#include <linux/uaccess.h>
#include <linux/ptrace.h>
#include "kvm-s390.h"
/* Convert real to absolute address by applying the prefix of the CPU */
static inline unsigned long kvm_s390_real_to_abs(struct kvm_vcpu *vcpu,
unsigned long gaddr)
{
unsigned long prefix = vcpu->arch.sie_block->prefix;
if (gaddr < 2 * PAGE_SIZE)
gaddr += prefix;
else if (gaddr >= prefix && gaddr < prefix + 2 * PAGE_SIZE)
gaddr -= prefix;
return gaddr;
}
/**
* kvm_s390_logical_to_effective - convert guest logical to effective address
* @vcpu: guest virtual cpu
* @ga: guest logical address
*
* Convert a guest vcpu logical address to a guest vcpu effective address by
* applying the rules of the vcpu's addressing mode defined by PSW bits 31
* and 32 (extendended/basic addressing mode).
*
* Depending on the vcpu's addressing mode the upper 40 bits (24 bit addressing
* mode), 33 bits (31 bit addressing mode) or no bits (64 bit addressing mode)
* of @ga will be zeroed and the remaining bits will be returned.
*/
static inline unsigned long kvm_s390_logical_to_effective(struct kvm_vcpu *vcpu,
unsigned long ga)
{
psw_t *psw = &vcpu->arch.sie_block->gpsw;
if (psw_bits(*psw).eaba == PSW_AMODE_64BIT)
return ga;
if (psw_bits(*psw).eaba == PSW_AMODE_31BIT)
return ga & ((1UL << 31) - 1);
return ga & ((1UL << 24) - 1);
}
/*
* put_guest_lc, read_guest_lc and write_guest_lc are guest access functions
* which shall only be used to access the lowcore of a vcpu.
* These functions should be used for e.g. interrupt handlers where no
* guest memory access protection facilities, like key or low address
* protection, are applicable.
* At a later point guest vcpu lowcore access should happen via pinned
* prefix pages, so that these pages can be accessed directly via the
* kernel mapping. All of these *_lc functions can be removed then.
*/
/**
* put_guest_lc - write a simple variable to a guest vcpu's lowcore
* @vcpu: virtual cpu
* @x: value to copy to guest
* @gra: vcpu's destination guest real address
*
* Copies a simple value from kernel space to a guest vcpu's lowcore.
* The size of the variable may be 1, 2, 4 or 8 bytes. The destination
* must be located in the vcpu's lowcore. Otherwise the result is undefined.
*
* Returns zero on success or -EFAULT on error.
*
* Note: an error indicates that either the kernel is out of memory or
* the guest memory mapping is broken. In any case the best solution
* would be to terminate the guest.
* It is wrong to inject a guest exception.
*/
#define put_guest_lc(vcpu, x, gra) \
({ \
struct kvm_vcpu *__vcpu = (vcpu); \
__typeof__(*(gra)) __x = (x); \
unsigned long __gpa; \
\
__gpa = (unsigned long)(gra); \
__gpa += __vcpu->arch.sie_block->prefix; \
kvm_write_guest(__vcpu->kvm, __gpa, &__x, sizeof(__x)); \
})
/**
* write_guest_lc - copy data from kernel space to guest vcpu's lowcore
* @vcpu: virtual cpu
* @gra: vcpu's source guest real address
* @data: source address in kernel space
* @len: number of bytes to copy
*
* Copy data from kernel space to guest vcpu's lowcore. The entire range must
* be located within the vcpu's lowcore, otherwise the result is undefined.
*
* Returns zero on success or -EFAULT on error.
*
* Note: an error indicates that either the kernel is out of memory or
* the guest memory mapping is broken. In any case the best solution
* would be to terminate the guest.
* It is wrong to inject a guest exception.
*/
static inline __must_check
int write_guest_lc(struct kvm_vcpu *vcpu, unsigned long gra, void *data,
unsigned long len)
{
unsigned long gpa = gra + vcpu->arch.sie_block->prefix;
return kvm_write_guest(vcpu->kvm, gpa, data, len);
}
/**
* read_guest_lc - copy data from guest vcpu's lowcore to kernel space
* @vcpu: virtual cpu
* @gra: vcpu's source guest real address
* @data: destination address in kernel space
* @len: number of bytes to copy
*
* Copy data from guest vcpu's lowcore to kernel space. The entire range must
* be located within the vcpu's lowcore, otherwise the result is undefined.
*
* Returns zero on success or -EFAULT on error.
*
* Note: an error indicates that either the kernel is out of memory or
* the guest memory mapping is broken. In any case the best solution
* would be to terminate the guest.
* It is wrong to inject a guest exception.
*/
static inline __must_check
int read_guest_lc(struct kvm_vcpu *vcpu, unsigned long gra, void *data,
unsigned long len)
{
unsigned long gpa = gra + vcpu->arch.sie_block->prefix;
return kvm_read_guest(vcpu->kvm, gpa, data, len);
}
int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data,
unsigned long len, int write);
int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
void *data, unsigned long len, int write);
/**
* write_guest - copy data from kernel space to guest space
* @vcpu: virtual cpu
* @ga: guest address
* @data: source address in kernel space
* @len: number of bytes to copy
*
* Copy @len bytes from @data (kernel space) to @ga (guest address).
* In order to copy data to guest space the PSW of the vcpu is inspected:
* If DAT is off data will be copied to guest real or absolute memory.
* If DAT is on data will be copied to the address space as specified by
* the address space bits of the PSW:
* Primary, secondory or home space (access register mode is currently not
* implemented).
* The addressing mode of the PSW is also inspected, so that address wrap
* around is taken into account for 24-, 31- and 64-bit addressing mode,
* if the to be copied data crosses page boundaries in guest address space.
* In addition also low address and DAT protection are inspected before
* copying any data (key protection is currently not implemented).
*
* This function modifies the 'struct kvm_s390_pgm_info pgm' member of @vcpu.
* In case of an access exception (e.g. protection exception) pgm will contain
* all data necessary so that a subsequent call to 'kvm_s390_inject_prog_vcpu()'
* will inject a correct exception into the guest.
* If no access exception happened, the contents of pgm are undefined when
* this function returns.
*
* Returns: - zero on success
* - a negative value if e.g. the guest mapping is broken or in
* case of out-of-memory. In this case the contents of pgm are
* undefined. Also parts of @data may have been copied to guest
* space.
* - a positive value if an access exception happened. In this case
* the returned value is the program interruption code and the
* contents of pgm may be used to inject an exception into the
* guest. No data has been copied to guest space.
*
* Note: in case an access exception is recognized no data has been copied to
* guest space (this is also true, if the to be copied data would cross
* one or more page boundaries in guest space).
* Therefore this function may be used for nullifying and suppressing
* instruction emulation.
* It may also be used for terminating instructions, if it is undefined
* if data has been changed in guest space in case of an exception.
*/
static inline __must_check
int write_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data,
unsigned long len)
{
return access_guest(vcpu, ga, data, len, 1);
}
/**
* read_guest - copy data from guest space to kernel space
* @vcpu: virtual cpu
* @ga: guest address
* @data: destination address in kernel space
* @len: number of bytes to copy
*
* Copy @len bytes from @ga (guest address) to @data (kernel space).
*
* The behaviour of read_guest is identical to write_guest, except that
* data will be copied from guest space to kernel space.
*/
static inline __must_check
int read_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data,
unsigned long len)
{
return access_guest(vcpu, ga, data, len, 0);
}
/**
* write_guest_abs - copy data from kernel space to guest space absolute
* @vcpu: virtual cpu
* @gpa: guest physical (absolute) address
* @data: source address in kernel space
* @len: number of bytes to copy
*
* Copy @len bytes from @data (kernel space) to @gpa (guest absolute address).
* It is up to the caller to ensure that the entire guest memory range is
* valid memory before calling this function.
* Guest low address and key protection are not checked.
*
* Returns zero on success or -EFAULT on error.
*
* If an error occurs data may have been copied partially to guest memory.
*/
static inline __must_check
int write_guest_abs(struct kvm_vcpu *vcpu, unsigned long gpa, void *data,
unsigned long len)
{
return kvm_write_guest(vcpu->kvm, gpa, data, len);
}
/**
* read_guest_abs - copy data from guest space absolute to kernel space
* @vcpu: virtual cpu
* @gpa: guest physical (absolute) address
* @data: destination address in kernel space
* @len: number of bytes to copy
*
* Copy @len bytes from @gpa (guest absolute address) to @data (kernel space).
* It is up to the caller to ensure that the entire guest memory range is
* valid memory before calling this function.
* Guest key protection is not checked.
*
* Returns zero on success or -EFAULT on error.
*
* If an error occurs data may have been copied partially to kernel space.
*/
static inline __must_check
int read_guest_abs(struct kvm_vcpu *vcpu, unsigned long gpa, void *data,
unsigned long len)
{
return kvm_read_guest(vcpu->kvm, gpa, data, len);
}
/**
* write_guest_real - copy data from kernel space to guest space real
* @vcpu: virtual cpu
* @gra: guest real address
* @data: source address in kernel space
* @len: number of bytes to copy
*
* Copy @len bytes from @data (kernel space) to @gra (guest real address).
* It is up to the caller to ensure that the entire guest memory range is
* valid memory before calling this function.
* Guest low address and key protection are not checked.
*
* Returns zero on success or -EFAULT on error.
*
* If an error occurs data may have been copied partially to guest memory.
*/
static inline __must_check
int write_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, void *data,
unsigned long len)
{
return access_guest_real(vcpu, gra, data, len, 1);
}
/**
* read_guest_real - copy data from guest space real to kernel space
* @vcpu: virtual cpu
* @gra: guest real address
* @data: destination address in kernel space
* @len: number of bytes to copy
*
* Copy @len bytes from @gra (guest real address) to @data (kernel space).
* It is up to the caller to ensure that the entire guest memory range is
* valid memory before calling this function.
* Guest key protection is not checked.
*
* Returns zero on success or -EFAULT on error.
*
* If an error occurs data may have been copied partially to kernel space.
*/
static inline __must_check
int read_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, void *data,
unsigned long len)
{
return access_guest_real(vcpu, gra, data, len, 0);
}
int ipte_lock_held(struct kvm_vcpu *vcpu);
#endif /* __KVM_S390_GACCESS_H */
|