Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / common / include / segments.h
CommitLineData
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
55extern "C" {
56#endif
57
58#ifndef _ASM
59
60struct 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
70typedef 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] */ ;\
2450: ;\
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 ;\
2601: ;\
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 ;\
2672: ;\
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 */