#ifndef __ASM_X86_MTRR_H__
#define __ASM_X86_MTRR_H__

#include <xen/mm.h>

/* These are the region types. They match the architectural specification. */
#define MTRR_TYPE_UNCACHABLE 0
#define MTRR_TYPE_WRCOMB     1
#define MTRR_TYPE_WRTHROUGH  4
#define MTRR_TYPE_WRPROT     5
#define MTRR_TYPE_WRBACK     6
#define MTRR_NUM_TYPES       7
#define MEMORY_NUM_TYPES     MTRR_NUM_TYPES
#define NO_HARDCODE_MEM_TYPE    MTRR_NUM_TYPES

#define NORMAL_CACHE_MODE          0
#define NO_FILL_CACHE_MODE         2

enum {
    PAT_TYPE_UNCACHABLE=0,
    PAT_TYPE_WRCOMB=1,
    PAT_TYPE_WRTHROUGH=4,
    PAT_TYPE_WRPROT=5,
    PAT_TYPE_WRBACK=6,
    PAT_TYPE_UC_MINUS=7,
    PAT_TYPE_NUMS
};

#define INVALID_MEM_TYPE PAT_TYPE_NUMS

/* In the Intel processor's MTRR interface, the MTRR type is always held in
   an 8 bit field: */
typedef u8 mtrr_type;

#define MTRR_PHYSMASK_VALID_BIT  11
#define MTRR_PHYSMASK_VALID      (1 << MTRR_PHYSMASK_VALID_BIT)
#define MTRR_PHYSMASK_SHIFT      12
#define MTRR_PHYSBASE_TYPE_MASK  0xff
#define MTRR_PHYSBASE_SHIFT      12
/* Number of variable range MSR pairs we emulate for HVM guests: */
#define MTRR_VCNT                8
/* Maximum number of variable range MSR pairs if FE is supported. */
#define MTRR_VCNT_MAX            ((MSR_MTRRfix64K_00000 - \
                                   MSR_IA32_MTRR_PHYSBASE(0)) / 2)

struct mtrr_var_range {
	uint64_t base;
	uint64_t mask;
};

#define NUM_FIXED_RANGES 88
#define NUM_FIXED_MSR 11
struct mtrr_state {
	struct mtrr_var_range *var_ranges;
	mtrr_type fixed_ranges[NUM_FIXED_RANGES];
	bool enabled;
	bool fixed_enabled;
	bool have_fixed;
	mtrr_type def_type;

	u64       mtrr_cap;
	/* ranges in var MSRs are overlapped or not:0(no overlapped) */
	bool_t    overlapped;
};
extern struct mtrr_state mtrr_state;

extern void mtrr_save_fixed_ranges(void *);
extern void mtrr_save_state(void);
extern int mtrr_add(unsigned long base, unsigned long size,
                    unsigned int type, char increment);
extern int mtrr_add_page(unsigned long base, unsigned long size,
                         unsigned int type, char increment);
extern int mtrr_del(int reg, unsigned long base, unsigned long size);
extern int mtrr_del_page(int reg, unsigned long base, unsigned long size);
extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi);
extern u32 get_pat_flags(struct vcpu *v, u32 gl1e_flags, paddr_t gpaddr,
                  paddr_t spaddr, uint8_t gmtrr_mtype);
extern int epte_get_entry_emt(struct domain *, unsigned long gfn, mfn_t mfn,
                              unsigned int order, uint8_t *ipat,
                              bool_t direct_mmio);
extern void ept_change_entry_emt_with_range(
    struct domain *d, unsigned long start_gfn, unsigned long end_gfn);
extern unsigned char pat_type_2_pte_flags(unsigned char pat_type);
extern int hold_mtrr_updates_on_aps;
extern void mtrr_aps_sync_begin(void);
extern void mtrr_aps_sync_end(void);
extern void mtrr_bp_restore(void);

extern bool_t mtrr_var_range_msr_set(struct domain *, struct mtrr_state *,
                                     uint32_t msr, uint64_t msr_content);
extern bool_t mtrr_fix_range_msr_set(struct domain *, struct mtrr_state *,
                                     uint32_t row, uint64_t msr_content);
extern bool_t mtrr_def_type_msr_set(struct domain *, struct mtrr_state *,
                                    uint64_t msr_content);
#ifdef CONFIG_HVM
extern void memory_type_changed(struct domain *);
#else
static inline void memory_type_changed(struct domain *d) {}
#endif

extern bool_t pat_msr_set(uint64_t *pat, uint64_t msr);

bool is_var_mtrr_overlapped(const struct mtrr_state *m);
bool mtrr_pat_not_equal(const struct vcpu *vd, const struct vcpu *vs);

#endif /* __ASM_X86_MTRR_H__ */
