* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: segments.h
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* - Do no alter or remove copyright notices
* - Redistribution and use of this software in source and binary forms, with
* or without modification, are permitted provided that the following
* - Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of Sun Microsystems, Inc. or the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or maintenance of
* ========== Copyright Header End ============================================
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
#pragma ident "@(#)segments.h 1.2 07/05/15 SMI"
typedef struct ra2pa_segment ra2pa_segment_t
;
#define INVALID_SEGMENT_SIZE (-1)
/* flags for ra2pa_segment.flags */
#define INVALID_SEGMENT (0)
#define MEM_SEGMENT (1 << 0)
#define IO_SEGMENT (1 << 1)
* The following macros apply for the ra->pa and pa->ra conversion
* using the segmented memory mechanism.
* This allows a guest's memory to be apportioned in multiple
* dis-contiguous blocks, as well as supporting the various
* IO address spaces that are relevent only if the specific IO
* busses are indeed placed in the guest's real address spaces.
* This scheme replaces the old linear base & bounds range check which
* We use the upper (64-RA2PA_SHIFT) bits of any RA as the index into a
* simple linear "page table". The index retrieves a guest specific
* entry describing a memory segment to be checked and translated.
* A simple base & bounds is checked using values described within the
* segment .. a simple offset is applied to convert the RA to a PA
* Once a segment is found the base RA is guaranteed to be sane.
* However, in many cases the SIZE value comes from the guest
* OS and if negative causes lots of problems with range testing.
* So we wrap the weaker form of this macro with one which tests the
* size for being negative before handing off to the weaker macro.
* Though the form with the size check only takes a register as
* its size parameter. The wrapped form can also take a small
* The largest defined page size for 4v is 34 bits (13+7*3) thus
* we can place each segment at this boundary without the risk
* of having a need for a larger page size.
* Actually the algorithm works for smaller segment sizes too
* because each segment holds a full base and bounds.
* The segmentation arrangement causes problems with supporting
* live migration. We are constrained to be able to support the
* same segmentation map on the target system. This is easier
* if the segmentation separation is as wide as possible - hence
* the choice of 34 bits as the index shift.
* We arrange the RA bit range to be big enough to also pick up the
* the IO bus address ranges. Fortunately each bus has a separation
* in the address space of at least 34 bits ...
#define RA2PA_SHIFT 34 /* largest possible 4v page size */
#define RA2PA_SEGMENT_SHIFT 5 /* size of ra2pa_segment struct */
#define NUM_RA2PA_SEGMENT_BITS (MAX_RA_BITS-RA2PA_SHIFT)
#define NUM_RA2PA_SEGMENTS (1<<NUM_RA2PA_SEGMENT_BITS)
#define RA2PA_RANGE_CONV_UNK_SIZE(guestp, raddr, size, fail_label, segp, paddr)\
brlez,pn size, fail_label ;\
RA2PA_RANGE_CONV(guestp, raddr, size, fail_label, segp, paddr)
* Macro to check range assuming that size is limited and
* positive. The first instn of this macro must be able to
* function in the delay slot of the last instn of the outer
#define RA2PA_RANGE_CONV(guestp, raddr, size, fail_label, segp, paddr) \
srlx raddr, RA2PA_SHIFT, segp ;\
cmp segp, NUM_RA2PA_SEGMENTS ;\
/* can branch on signed as srlx makes the number +ve */ ;\
bge,pn %xcc, fail_label ;\
sllx segp, RA2PA_SEGMENT_SHIFT, segp ;\
add segp, GUEST_RA2PA_SEGMENT, segp ;\
add guestp, segp, segp ;\
ldub [segp + RA2PA_SEGMENT_FLAGS], paddr ;\
btst MEM_SEGMENT, paddr ;\
bz,pn %xcc, fail_label ;\
ldx [segp + RA2PA_SEGMENT_BASE], paddr ;\
bgu,pn %xcc, fail_label ;\
ldx [segp + RA2PA_SEGMENT_LIMIT], paddr ;\
sub paddr, raddr, paddr ;\
blt,pn %xcc, fail_label ;\
ldx [segp + RA2PA_SEGMENT_OFFSET], paddr ;\
* Check range, no RA->PA conversion
#define RA2PA_RANGE_CHECK(guestp, raddr, size, fail_label, scr1) \
srlx raddr, RA2PA_SHIFT, scr1 ;\
cmp scr1, NUM_RA2PA_SEGMENTS ;\
/* can branch on signed as srlx makes the number +ve */ ;\
bge,pn %xcc, fail_label ;\
sllx scr1, RA2PA_SEGMENT_SHIFT, scr1 ;\
add scr1, GUEST_RA2PA_SEGMENT, scr1 ;\
add guestp, scr1, scr1 ;\
ldub [scr1 + RA2PA_SEGMENT_FLAGS], scr1 ;\
btst MEM_SEGMENT, scr1 ;\
bz,pn %xcc, fail_label ;\
srlx raddr, RA2PA_SHIFT, scr1 ;\
sllx scr1, RA2PA_SEGMENT_SHIFT, scr1 ;\
add scr1, GUEST_RA2PA_SEGMENT, scr1 ;\
add guestp, scr1, scr1 ;\
ldx [scr1 + RA2PA_SEGMENT_BASE], scr1 ;\
bgu,pn %xcc, fail_label ;\
srlx raddr, RA2PA_SHIFT, scr1 ;\
sllx scr1, RA2PA_SEGMENT_SHIFT, scr1 ;\
add scr1, GUEST_RA2PA_SEGMENT, scr1 ;\
add guestp, scr1, scr1 ;\
ldx [scr1 + RA2PA_SEGMENT_LIMIT], scr1 ;\
blt,pn %xcc, fail_label ;\
* Macro to convert RA to PA. RA must be valid for this guest.
#define RA2PA_CONV(guestp, raddr, paddr, segp) \
srlx raddr, RA2PA_SHIFT, segp ;\
sllx segp, RA2PA_SEGMENT_SHIFT, segp ;\
add segp, GUEST_RA2PA_SEGMENT, segp ;\
add guestp, segp, segp ;\
ldx [segp + RA2PA_SEGMENT_OFFSET], segp ;\
* macro to get segment pointer for an RA. Returns (0) in segp
* if RA not valid for this guest.
#define RA_GET_SEGMENT(guestp, raddr, segp, scr) \
srlx raddr, RA2PA_SHIFT, segp ;\
sllx segp, RA2PA_SEGMENT_SHIFT, segp ;\
add segp, GUEST_RA2PA_SEGMENT, segp ;\
add guestp, segp, segp ;\
ldub [segp + RA2PA_SEGMENT_FLAGS], scr ;\
btst (MEM_SEGMENT | IO_SEGMENT), scr ;\
* Find the segment containing a PA and return the corresponding RA.
* guestp &guest struct, preserved
* paddr Physical Address to translate, preserved
* raddr Real Address for this PA (-1 if no translation)
* scr2 ret of non zero if no segment found containing this PA
#define PA2RA_CONV(guestp, paddr, raddr, scr1, scr2) \
add guestp, ((NUM_RA2PA_SEGMENTS - 1) * RA2PA_SEGMENT_SIZE) \
+ GUEST_RA2PA_SEGMENT, scr1 ;\
/* &guest.ra2pa_segment[N-1] */ ;\
ldx [scr1 + RA2PA_SEGMENT_BASE], scr2 /* RA base */ ;\
brlz,pn scr2, 1f /* segment not in use */ ;\
ldx [scr1 + RA2PA_SEGMENT_OFFSET], raddr /* RA offset */ ;\
sub paddr, raddr, raddr /* PA->RA */ ;\
cmp raddr, scr2 /* RA < segment.base ? */ ;\
ldx [scr1 + RA2PA_SEGMENT_LIMIT], scr2 /* RA limit */ ;\
cmp raddr, scr2 /* RA > segment.limit ? */ ;\
bgu,pn %xcc, 1f /* yes, next segment */ ;\
ba 2f /* no, we are done */ ;\
add guestp, GUEST_RA2PA_SEGMENT, scr2 ;\
cmp scr1, scr2 /* scr2 &guest.ra2pa_segment[0] */ ;\
bne,pt %xcc, 0b /* next segment */ ;\
sub scr1, RA2PA_SEGMENT_SIZE, scr1 ;\
mov 1, scr2 /* no segment found, ret fail */ ;\
* Note: Could just use RA2PA_RANGE_CONV_UNK_SIZE() macro, but that would
* involve an extra memory access for RA2PA_SEGMENT_OFFSET.
#define RANGE_CHECK_IO(guestp, raddr, size, pass_label, fail_label, segp, scr) \
srlx raddr, RA2PA_SHIFT, segp ;\
cmp segp, NUM_RA2PA_SEGMENTS ;\
/* can branch on signed as srlx makes the number +ve */ ;\
bge,pn %xcc, fail_label ;\
sllx segp, RA2PA_SEGMENT_SHIFT, segp ;\
add segp, GUEST_RA2PA_SEGMENT, segp ;\
add guestp, segp, segp ;\
ldub [segp + RA2PA_SEGMENT_FLAGS], scr ;\
bz,pn %xcc, fail_label ;\
ldx [segp + RA2PA_SEGMENT_BASE], scr ;\
bgu,pn %xcc, fail_label ;\
ldx [segp + RA2PA_SEGMENT_LIMIT], scr ;\
bge,pn %xcc, pass_label ;\
#define RANGE_CHECK_IO(hstruct, raddr, size, pass_lbl, fail_lbl, \