Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * Hypervisor Software File: segments.h | |
5 | * | |
6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
7 | * | |
8 | * - Do no alter or remove copyright notices | |
9 | * | |
10 | * - Redistribution and use of this software in source and binary forms, with | |
11 | * or without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistribution of source code must retain the above copyright notice, | |
15 | * this list of conditions and the following disclaimer. | |
16 | * | |
17 | * - Redistribution in binary form must reproduce the above copyright notice, | |
18 | * this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * | |
21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors | |
22 | * may be used to endorse or promote products derived from this software | |
23 | * without specific prior written permission. | |
24 | * | |
25 | * This software is provided "AS IS," without a warranty of any kind. | |
26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
37 | * | |
38 | * You acknowledge that this software is not designed, licensed or | |
39 | * intended for use in the design, construction, operation or maintenance of | |
40 | * any nuclear facility. | |
41 | * | |
42 | * ========== Copyright Header End ============================================ | |
43 | */ | |
44 | /* | |
45 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | |
46 | * Use is subject to license terms. | |
47 | */ | |
48 | ||
49 | #ifndef _SEGMENTS_H | |
50 | #define _SEGMENTS_H | |
51 | ||
52 | #pragma ident "@(#)segments.h 1.2 07/05/15 SMI" | |
53 | ||
54 | #ifdef __cplusplus | |
55 | extern "C" { | |
56 | #endif | |
57 | ||
58 | #ifndef _ASM | |
59 | ||
60 | struct ra2pa_segment { | |
61 | uint64_t base; | |
62 | uint64_t limit; | |
63 | uint64_t offset; | |
64 | uint8_t flags; | |
65 | uint8_t _pad1; | |
66 | uint16_t _pad2; | |
67 | uint32_t _pad3; | |
68 | }; | |
69 | ||
70 | typedef struct ra2pa_segment ra2pa_segment_t; | |
71 | ||
72 | #endif /* _ASM */ | |
73 | ||
74 | ||
75 | #define INVALID_SEGMENT_SIZE (-1) | |
76 | ||
77 | /* flags for ra2pa_segment.flags */ | |
78 | #define INVALID_SEGMENT (0) | |
79 | #define MEM_SEGMENT (1 << 0) | |
80 | #define IO_SEGMENT (1 << 1) | |
81 | ||
82 | /* | |
83 | * The following macros apply for the ra->pa and pa->ra conversion | |
84 | * using the segmented memory mechanism. | |
85 | * This allows a guest's memory to be apportioned in multiple | |
86 | * dis-contiguous blocks, as well as supporting the various | |
87 | * IO address spaces that are relevent only if the specific IO | |
88 | * busses are indeed placed in the guest's real address spaces. | |
89 | * | |
90 | * This scheme replaces the old linear base & bounds range check which | |
91 | * was broken anyway. | |
92 | * | |
93 | * We use the upper (64-RA2PA_SHIFT) bits of any RA as the index into a | |
94 | * simple linear "page table". The index retrieves a guest specific | |
95 | * entry describing a memory segment to be checked and translated. | |
96 | * A simple base & bounds is checked using values described within the | |
97 | * segment .. a simple offset is applied to convert the RA to a PA | |
98 | * within the segment. | |
99 | * | |
100 | * Once a segment is found the base RA is guaranteed to be sane. | |
101 | * However, in many cases the SIZE value comes from the guest | |
102 | * OS and if negative causes lots of problems with range testing. | |
103 | * | |
104 | * So we wrap the weaker form of this macro with one which tests the | |
105 | * size for being negative before handing off to the weaker macro. | |
106 | * Though the form with the size check only takes a register as | |
107 | * its size parameter. The wrapped form can also take a small | |
108 | * constant. | |
109 | * | |
110 | * The largest defined page size for 4v is 34 bits (13+7*3) thus | |
111 | * we can place each segment at this boundary without the risk | |
112 | * of having a need for a larger page size. | |
113 | * Actually the algorithm works for smaller segment sizes too | |
114 | * because each segment holds a full base and bounds. | |
115 | * | |
116 | * The segmentation arrangement causes problems with supporting | |
117 | * live migration. We are constrained to be able to support the | |
118 | * same segmentation map on the target system. This is easier | |
119 | * if the segmentation separation is as wide as possible - hence | |
120 | * the choice of 34 bits as the index shift. | |
121 | * | |
122 | * We arrange the RA bit range to be big enough to also pick up the | |
123 | * the IO bus address ranges. Fortunately each bus has a separation | |
124 | * in the address space of at least 34 bits ... | |
125 | */ | |
126 | ||
127 | #define MAX_RA_BITS 40 | |
128 | #define RA2PA_SHIFT 34 /* largest possible 4v page size */ | |
129 | ||
130 | #define RA2PA_SEGMENT_SHIFT 5 /* size of ra2pa_segment struct */ | |
131 | #define NUM_RA2PA_SEGMENT_BITS (MAX_RA_BITS-RA2PA_SHIFT) | |
132 | #define NUM_RA2PA_SEGMENTS (1<<NUM_RA2PA_SEGMENT_BITS) | |
133 | ||
134 | /* BEGIN CSTYLED */ | |
135 | #define RA2PA_RANGE_CONV_UNK_SIZE(guestp, raddr, size, fail_label, segp, paddr)\ | |
136 | brlez,pn size, fail_label ;\ | |
137 | RA2PA_RANGE_CONV(guestp, raddr, size, fail_label, segp, paddr) | |
138 | /* END CSTYLED */ | |
139 | ||
140 | /* | |
141 | * Macro to check range assuming that size is limited and | |
142 | * positive. The first instn of this macro must be able to | |
143 | * function in the delay slot of the last instn of the outer | |
144 | * macro. | |
145 | */ | |
146 | /* BEGIN CSTYLED */ | |
147 | #define RA2PA_RANGE_CONV(guestp, raddr, size, fail_label, segp, paddr) \ | |
148 | srlx raddr, RA2PA_SHIFT, segp ;\ | |
149 | cmp segp, NUM_RA2PA_SEGMENTS ;\ | |
150 | /* can branch on signed as srlx makes the number +ve */ ;\ | |
151 | bge,pn %xcc, fail_label ;\ | |
152 | sllx segp, RA2PA_SEGMENT_SHIFT, segp ;\ | |
153 | add segp, GUEST_RA2PA_SEGMENT, segp ;\ | |
154 | add guestp, segp, segp ;\ | |
155 | ldub [segp + RA2PA_SEGMENT_FLAGS], paddr ;\ | |
156 | btst MEM_SEGMENT, paddr ;\ | |
157 | bz,pn %xcc, fail_label ;\ | |
158 | ldx [segp + RA2PA_SEGMENT_BASE], paddr ;\ | |
159 | cmp paddr, raddr ;\ | |
160 | bgu,pn %xcc, fail_label ;\ | |
161 | ldx [segp + RA2PA_SEGMENT_LIMIT], paddr ;\ | |
162 | sub paddr, raddr, paddr ;\ | |
163 | cmp paddr, size ;\ | |
164 | blt,pn %xcc, fail_label ;\ | |
165 | ldx [segp + RA2PA_SEGMENT_OFFSET], paddr ;\ | |
166 | add paddr, raddr, paddr | |
167 | /* END CSTYLED */ | |
168 | ||
169 | /* | |
170 | * Check range, no RA->PA conversion | |
171 | */ | |
172 | /* BEGIN CSTYLED */ | |
173 | #define RA2PA_RANGE_CHECK(guestp, raddr, size, fail_label, scr1) \ | |
174 | srlx raddr, RA2PA_SHIFT, scr1 ;\ | |
175 | cmp scr1, NUM_RA2PA_SEGMENTS ;\ | |
176 | /* can branch on signed as srlx makes the number +ve */ ;\ | |
177 | bge,pn %xcc, fail_label ;\ | |
178 | sllx scr1, RA2PA_SEGMENT_SHIFT, scr1 ;\ | |
179 | add scr1, GUEST_RA2PA_SEGMENT, scr1 ;\ | |
180 | add guestp, scr1, scr1 ;\ | |
181 | ldub [scr1 + RA2PA_SEGMENT_FLAGS], scr1 ;\ | |
182 | btst MEM_SEGMENT, scr1 ;\ | |
183 | bz,pn %xcc, fail_label ;\ | |
184 | srlx raddr, RA2PA_SHIFT, scr1 ;\ | |
185 | sllx scr1, RA2PA_SEGMENT_SHIFT, scr1 ;\ | |
186 | add scr1, GUEST_RA2PA_SEGMENT, scr1 ;\ | |
187 | add guestp, scr1, scr1 ;\ | |
188 | ldx [scr1 + RA2PA_SEGMENT_BASE], scr1 ;\ | |
189 | cmp scr1, raddr ;\ | |
190 | bgu,pn %xcc, fail_label ;\ | |
191 | srlx raddr, RA2PA_SHIFT, scr1 ;\ | |
192 | sllx scr1, RA2PA_SEGMENT_SHIFT, scr1 ;\ | |
193 | add scr1, GUEST_RA2PA_SEGMENT, scr1 ;\ | |
194 | add guestp, scr1, scr1 ;\ | |
195 | ldx [scr1 + RA2PA_SEGMENT_LIMIT], scr1 ;\ | |
196 | sub scr1, raddr, scr1 ;\ | |
197 | cmp scr1, size ;\ | |
198 | blt,pn %xcc, fail_label ;\ | |
199 | nop | |
200 | /* END CSTYLED */ | |
201 | ||
202 | /* | |
203 | * Macro to convert RA to PA. RA must be valid for this guest. | |
204 | */ | |
205 | /* BEGIN CSTYLED */ | |
206 | #define RA2PA_CONV(guestp, raddr, paddr, segp) \ | |
207 | srlx raddr, RA2PA_SHIFT, segp ;\ | |
208 | sllx segp, RA2PA_SEGMENT_SHIFT, segp ;\ | |
209 | add segp, GUEST_RA2PA_SEGMENT, segp ;\ | |
210 | add guestp, segp, segp ;\ | |
211 | ldx [segp + RA2PA_SEGMENT_OFFSET], segp ;\ | |
212 | add raddr, segp, paddr | |
213 | ||
214 | /* | |
215 | * macro to get segment pointer for an RA. Returns (0) in segp | |
216 | * if RA not valid for this guest. | |
217 | */ | |
218 | #define RA_GET_SEGMENT(guestp, raddr, segp, scr) \ | |
219 | srlx raddr, RA2PA_SHIFT, segp ;\ | |
220 | sllx segp, RA2PA_SEGMENT_SHIFT, segp ;\ | |
221 | add segp, GUEST_RA2PA_SEGMENT, segp ;\ | |
222 | add guestp, segp, segp ;\ | |
223 | ldub [segp + RA2PA_SEGMENT_FLAGS], scr ;\ | |
224 | btst (MEM_SEGMENT | IO_SEGMENT), scr ;\ | |
225 | move %xcc, %g0, segp | |
226 | ||
227 | /* END CSTYLED */ | |
228 | ||
229 | ||
230 | /* BEGIN CSTYLED */ | |
231 | /* | |
232 | * Find the segment containing a PA and return the corresponding RA. | |
233 | * | |
234 | * guestp &guest struct, preserved | |
235 | * paddr Physical Address to translate, preserved | |
236 | * raddr Real Address for this PA (-1 if no translation) | |
237 | * scrN clobbered | |
238 | * scr2 ret of non zero if no segment found containing this PA | |
239 | */ | |
240 | #define PA2RA_CONV(guestp, paddr, raddr, scr1, scr2) \ | |
241 | .pushlocals ;\ | |
242 | add guestp, ((NUM_RA2PA_SEGMENTS - 1) * RA2PA_SEGMENT_SIZE) \ | |
243 | + GUEST_RA2PA_SEGMENT, scr1 ;\ | |
244 | /* &guest.ra2pa_segment[N-1] */ ;\ | |
245 | 0: ;\ | |
246 | ldx [scr1 + RA2PA_SEGMENT_BASE], scr2 /* RA base */ ;\ | |
247 | brlz,pn scr2, 1f /* segment not in use */ ;\ | |
248 | nop ;\ | |
249 | ldx [scr1 + RA2PA_SEGMENT_OFFSET], raddr /* RA offset */ ;\ | |
250 | sub paddr, raddr, raddr /* PA->RA */ ;\ | |
251 | cmp raddr, scr2 /* RA < segment.base ? */ ;\ | |
252 | blu,pn %xcc, 1f ;\ | |
253 | nop ;\ | |
254 | ldx [scr1 + RA2PA_SEGMENT_LIMIT], scr2 /* RA limit */ ;\ | |
255 | cmp raddr, scr2 /* RA > segment.limit ? */ ;\ | |
256 | bgu,pn %xcc, 1f /* yes, next segment */ ;\ | |
257 | nop ;\ | |
258 | ba 2f /* no, we are done */ ;\ | |
259 | mov 0, scr2 ;\ | |
260 | 1: ;\ | |
261 | add guestp, GUEST_RA2PA_SEGMENT, scr2 ;\ | |
262 | cmp scr1, scr2 /* scr2 &guest.ra2pa_segment[0] */ ;\ | |
263 | bne,pt %xcc, 0b /* next segment */ ;\ | |
264 | sub scr1, RA2PA_SEGMENT_SIZE, scr1 ;\ | |
265 | mov 1, scr2 /* no segment found, ret fail */ ;\ | |
266 | mov -1, raddr ;\ | |
267 | 2: ;\ | |
268 | .poplocals | |
269 | /* END CSTYLED */ | |
270 | ||
271 | #ifdef CONFIG_PCIE | |
272 | ||
273 | /* | |
274 | * Note: Could just use RA2PA_RANGE_CONV_UNK_SIZE() macro, but that would | |
275 | * involve an extra memory access for RA2PA_SEGMENT_OFFSET. | |
276 | */ | |
277 | /* BEGIN CSTYLED */ | |
278 | #define RANGE_CHECK_IO(guestp, raddr, size, pass_label, fail_label, segp, scr) \ | |
279 | srlx raddr, RA2PA_SHIFT, segp ;\ | |
280 | cmp segp, NUM_RA2PA_SEGMENTS ;\ | |
281 | /* can branch on signed as srlx makes the number +ve */ ;\ | |
282 | bge,pn %xcc, fail_label ;\ | |
283 | sllx segp, RA2PA_SEGMENT_SHIFT, segp ;\ | |
284 | add segp, GUEST_RA2PA_SEGMENT, segp ;\ | |
285 | add guestp, segp, segp ;\ | |
286 | ldub [segp + RA2PA_SEGMENT_FLAGS], scr ;\ | |
287 | btst IO_SEGMENT, scr ;\ | |
288 | bz,pn %xcc, fail_label ;\ | |
289 | ldx [segp + RA2PA_SEGMENT_BASE], scr ;\ | |
290 | cmp scr, raddr ;\ | |
291 | bgu,pn %xcc, fail_label ;\ | |
292 | ldx [segp + RA2PA_SEGMENT_LIMIT], scr ;\ | |
293 | sub scr, raddr, scr ;\ | |
294 | cmp scr, size ;\ | |
295 | bge,pn %xcc, pass_label ;\ | |
296 | nop ;\ | |
297 | ba %xcc, fail_label ;\ | |
298 | nop | |
299 | #else /* !CONFIG_PCIE */ | |
300 | #define RANGE_CHECK_IO(hstruct, raddr, size, pass_lbl, fail_lbl, \ | |
301 | scr1, scr2) \ | |
302 | ba,a fail_lbl ;\ | |
303 | .empty | |
304 | /* END CSTYLED */ | |
305 | #endif /* CONFIG_PCIE */ | |
306 | ||
307 | #ifdef __cplusplus | |
308 | } | |
309 | #endif | |
310 | ||
311 | #endif /* _SEGMENTS_H */ |