#ifndef		_REGIONREG_H_
#define		_REGIONREG_H_
#define XEN_DEFAULT_RID		7
#define	IA64_MIN_IMPL_RID_MSB	17
#define _REGION_ID(x)   ({ia64_rr _v; _v.rrval = (long) (x); _v.rid;})
#define _REGION_PAGE_SIZE(x)    ({ia64_rr _v; _v.rrval = (long) (x); _v.ps;})
#define _REGION_HW_WALKER(x)    ({ia64_rr _v; _v.rrval = (long) (x); _v.ve;})
#define _MAKE_RR(r, sz, v) ({ia64_rr _v; _v.rrval=0;_v.rid=(r);_v.ps=(sz);_v.ve=(v);_v.rrval;})

typedef union ia64_rr {
        struct {
                unsigned long  ve :   1;        /* enable hw walker */
                unsigned long  reserved0   :   1;        /* reserved */
                unsigned long  ps :   6;        /* log page size */
                unsigned long  rid:  24;        /* region id */
                unsigned long  reserved1   :  32;        /* reserved */
        };
        unsigned long rrval;
} ia64_rr;

//
// region register macros
//
#define RR_TO_VE(arg) (((arg) >> 0) & 0x0000000000000001)
#define RR_VE(arg) (((arg) & 0x0000000000000001) << 0)
#define RR_VE_MASK 0x0000000000000001L
#define RR_VE_SHIFT 0
#define RR_TO_PS(arg) (((arg) >> 2) & 0x000000000000003f)
#define RR_PS(arg) (((arg) & 0x000000000000003f) << 2)
#define RR_PS_MASK 0x00000000000000fcL
#define RR_PS_SHIFT 2
#define RR_TO_RID(arg) (((arg) >> 8) & 0x0000000000ffffff)
#define RR_RID(arg) (((arg) & 0x0000000000ffffff) << 8)
#define RR_RID_MASK 0x00000000ffffff00L


int set_one_rr(unsigned long rr, unsigned long val);

// This function is purely for performance... apparently scrambling
//  bits in the region id makes for better hashing, which means better
//  use of the VHPT, which means better performance
// Note that the only time a RID should be mangled is when it is stored in
//  a region register; anytime it is "viewable" outside of this module,
//  it should be unmangled

// NOTE: this function is also implemented in assembly code in hyper_set_rr!!
// Must ensure these two remain consistent!
static inline unsigned long
vmMangleRID(unsigned long RIDVal)
{
	union bits64 { unsigned char bytes[4]; unsigned long uint; };

	union bits64 t;
	unsigned char tmp;

	t.uint = RIDVal;
	tmp = t.bytes[1];
	t.bytes[1] = t.bytes[3];
	t.bytes[3] = tmp;

	return t.uint;
}

// since vmMangleRID is symmetric, use it for unmangling also
#define vmUnmangleRID(x)	vmMangleRID(x)

extern void init_rid_allocator (void);

struct domain;

/* Allocate RIDs range and metaphysical RIDs for domain d.
   If ridbits is 0, a default value is used instead.  */
extern int allocate_rid_range(struct domain *d, unsigned long ridbits);
extern int deallocate_rid_range(struct domain *d);

struct vcpu;
extern void init_all_rr(struct vcpu *v);

extern int set_metaphysical_rr0(void);

extern void load_region_regs(struct vcpu *v);

#endif		/* !_REGIONREG_H_ */
