/* * This file is part of the Palacios Virtual Machine Monitor developed * by the V3VEE Project with funding from the United States National * Science Foundation and the Department of Energy. * * The V3VEE Project is a joint project between Northwestern University * and the University of New Mexico. You can find out more at * http://www.v3vee.org * * Copyright (c) 2008, Jack Lange * Copyright (c) 2008, The V3VEE Project * All rights reserved. * * Author: Jack Lange * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ #include #include #include #define MTRR_CAP 0xfe #define MTRR_PHYS_BASE_0 0x200 #define MTRR_PHYS_MASK_0 0x201 #define MTRR_PHYS_BASE_1 0x202 #define MTRR_PHYS_MASK_1 0x203 #define MTRR_PHYS_BASE_2 0x204 #define MTRR_PHYS_MASK_2 0x205 #define MTRR_PHYS_BASE_3 0x206 #define MTRR_PHYS_MASK_3 0x207 #define MTRR_PHYS_BASE_4 0x208 #define MTRR_PHYS_MASK_4 0x209 #define MTRR_PHYS_BASE_5 0x20a #define MTRR_PHYS_MASK_5 0x20b #define MTRR_PHYS_BASE_6 0x20c #define MTRR_PHYS_MASK_6 0x20d #define MTRR_PHYS_BASE_7 0x20e #define MTRR_PHYS_MASK_7 0x20f #define MTRR_FIX_64K_00000 0x250 #define MTRR_FIX_16K_80000 0x258 #define MTRR_FIX_16K_A0000 0x259 #define MTRR_FIX_4K_C0000 0x268 #define MTRR_FIX_4K_C8000 0x269 #define MTRR_FIX_4K_D0000 0x26a #define MTRR_FIX_4K_D8000 0x26b #define MTRR_FIX_4K_E0000 0x26c #define MTRR_FIX_4K_E8000 0x26d #define MTRR_FIX_4K_F0000 0x26e #define MTRR_FIX_4K_F8000 0x26f #define PAT 0x277 #define MTRR_DEF_TYPE 0x2ff struct ia32_pat { union { uint64_t value; struct { uint64_t pa_0 : 3; uint64_t rsvd0 : 5; uint64_t pa_1 : 3; uint64_t rsvd1 : 5; uint64_t pa_2 : 3; uint64_t rsvd2 : 5; uint64_t pa_3 : 3; uint64_t rsvd3 : 5; uint64_t pa_4 : 3; uint64_t rsvd4 : 5; uint64_t pa_5 : 3; uint64_t rsvd5 : 5; uint64_t pa_6 : 3; uint64_t rsvd6 : 5; uint64_t pa_7 : 3; uint64_t rsvd7 : 5; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct mtrr_cap { union { uint64_t value; struct { uint64_t var_reg_cnt : 8; uint64_t fix : 1; uint64_t rsvd0 : 1; uint64_t wr_combine : 1; uint64_t rsvd1 : 53; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct mtrr_def_type { union { uint64_t value; struct { uint64_t def_type : 8; uint64_t rsvd0 : 2; uint64_t fixed_enable : 1; uint64_t mtrr_emable : 1; uint64_t rsvd1 : 52; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct mtrr_phys_base { union { uint64_t value; struct { uint64_t type : 8; uint64_t rsvd0 : 4; uint64_t base : 40; uint64_t rsvd1 : 12; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct mtrr_phys_mask { union { uint64_t value; struct { uint64_t rsvd0 : 11; uint64_t valid : 1; uint64_t mask : 40; uint64_t rsvd1 : 12; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct mtrr_fixed { union { uint64_t value; uint8_t types[8]; } __attribute__((packed)); } __attribute__((packed)); /* AMD Specific Registers */ #define SYSCONFIG 0xc0010010 #define TOP_MEM 0xc001001a #define TOP_MEM2 0xc001001d #define IORR_BASE0 0xc0010016 #define IORR_MASK0 0xc0010017 #define IORR_BASE1 0xc0010018 #define IORR_MASK1 0xc0010019 struct syscfg_reg { union { uint64_t value; struct { uint64_t rsvd0 : 18; uint64_t mfde : 1; // 1 = enables RdMem and WrMem bits in fixed-range MTRRs uint64_t mfdm : 1; // 1 = software can modify RdMem and WrMem bits uint64_t mvdm : 1; // 1 = enables TOP_MEM reg and var range MTRRs uint64_t tom2 : 1; // 1 = enables TOP_MEM2 reg uint64_t tom2_force_wb : 1; // 1 = enables default mem type for 4GB-TOP_MEM2 range uint64_t rsvd1 : 41; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct top_of_mem_reg { union { uint64_t value; struct { uint64_t rsvd0 : 23; uint64_t phys_addr : 29; uint64_t rsvd1 : 12; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct iorr_base { union { uint64_t value; struct { uint64_t rsvd0 : 3; uint64_t wrmem : 1; // 1 = writes go to memory, 0 = writes go to mmap IO uint64_t rdmem : 1; // 1 = reads go to memory, 0 = reads go to mmap IO uint64_t rsvd1 : 7; uint64_t base : 40; uint64_t rsvd2 : 12; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct iorr_mask { union { uint64_t value; struct { uint64_t rsvd0 : 11; uint64_t valid : 1; uint64_t mask : 40; uint64_t rsvd1 : 12; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); /* Intel Specific Registers */ #define SMRR_PHYS_BASE 0x1f2 #define SMRR_PHYS_MASK 0x1f3 struct smrr_phys_base { union { uint64_t value; struct { uint64_t type : 8; uint64_t rsvd0 : 4; uint64_t base : 20; uint64_t rsvd1 : 32; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct smrr_phys_mask { union { uint64_t value; struct { uint64_t rsvd0 : 11; uint64_t valid : 1; uint64_t mask : 20; uint64_t rsvd1 : 32; } __attribute__((packed)); } __attribute__((packed)); } __attribute__((packed)); struct mtrr_state { struct ia32_pat pat; struct mtrr_cap cap; struct mtrr_def_type def_type; struct mtrr_phys_base bases[8]; struct mtrr_phys_mask masks[8]; struct mtrr_fixed fixed_64k; struct mtrr_fixed fixed_16k[2]; struct mtrr_fixed fixed_4k[8]; /* AMD specific registers */ struct syscfg_reg amd_syscfg; struct top_of_mem_reg amd_tom; struct top_of_mem_reg amd_tom2; struct iorr_base iorr_bases[2]; struct iorr_mask iorr_masks[2]; /* Intel Specific registers */ struct smrr_phys_base intel_smrr_base; struct smrr_phys_mask intel_smrr_mask; }; static void init_state(struct mtrr_state * state) { state->pat.value = 0x0007040600070406LL; state->cap.value = 0x0000000000000508LL; state->amd_syscfg.value = 0x0000000000020601LL; state->amd_tom.value = 0x0000000004000000LL; return; } static int mtrr_cap_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; dst->value = state->cap.value; return 0; } static int mtrr_cap_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; state->cap.value = src.value; return 0; } static int pat_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; dst->value = state->pat.value; return 0; } static int pat_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; state->pat.value = src.value; return 0; } static int def_type_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; dst->value = state->def_type.value; return 0; } static int def_type_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; state->def_type.value = src.value; return 0; } static int mtrr_phys_base_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int base_index = (msr - MTRR_PHYS_BASE_0) / 2; dst->value = state->bases[base_index].value; return 0; } static int mtrr_phys_base_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int base_index = (msr - MTRR_PHYS_BASE_0) / 2; state->bases[base_index].value = src.value; return 0; } static int mtrr_phys_mask_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int mask_index = (msr - MTRR_PHYS_MASK_0) / 2; dst->value = state->masks[mask_index].value; return 0; } static int mtrr_phys_mask_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int mask_index = (msr - MTRR_PHYS_MASK_0) / 2; state->masks[mask_index].value = src.value; return 0; } static int mtrr_fix_64k_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; dst->value = state->fixed_64k.value; return 0; } static int mtrr_fix_64k_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; state->fixed_64k.value = src.value; return 0; } static int mtrr_fix_16k_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int index = msr - MTRR_FIX_16K_80000; dst->value = state->fixed_16k[index].value; return 0; } static int mtrr_fix_16k_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int index = msr - MTRR_FIX_16K_80000; state->fixed_16k[index].value = src.value; return 0; } static int mtrr_fix_4k_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int index = msr - MTRR_FIX_4K_C0000; dst->value = state->fixed_4k[index].value; return 0; } static int mtrr_fix_4k_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int index = msr - MTRR_FIX_4K_C0000; state->fixed_4k[index].value = src.value; return 0; } /* AMD specific registers */ static int amd_syscfg_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; dst->value = state->amd_syscfg.value; return 0; } static int amd_syscfg_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; state->amd_syscfg.value = src.value; return 0; } static int amd_top_mem_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; if (msr == TOP_MEM) { dst->value = state->amd_tom.value; } else if (msr == TOP_MEM2) { dst->value = state->amd_tom2.value; } return 0; } static int amd_top_mem_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; if (msr == TOP_MEM) { state->amd_tom.value = src.value; } else if (msr == TOP_MEM2) { state->amd_tom2.value = src.value; } return 0; } static int amd_iorr_base_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int base_index = (msr - IORR_BASE0) / 2; dst->value = state->iorr_bases[base_index].value; return 0; } static int amd_iorr_base_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int base_index = (msr - IORR_BASE0) / 2; state->iorr_bases[base_index].value = src.value; return 0; } static int amd_iorr_mask_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int mask_index = (msr - IORR_MASK0) / 2; dst->value = state->iorr_masks[mask_index].value; return 0; } static int amd_iorr_mask_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; int mask_index = (msr - IORR_MASK0) / 2; state->iorr_masks[mask_index].value = src.value; return 0; } static int intel_smrr_base_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; dst->value = state->intel_smrr_base.value; return 0; } static int intel_smrr_base_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; state->intel_smrr_base.value = src.value; return 0; } static int intel_smrr_mask_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; dst->value = state->intel_smrr_mask.value; return 0; } static int intel_smrr_mask_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; state->intel_smrr_mask.value = src.value; return 0; } static int deinit_mtrrs(struct v3_vm_info * vm, void * priv_data) { struct mtrr_state * state = (struct mtrr_state *)priv_data; v3_unhook_msr(vm, MTRR_CAP); v3_unhook_msr(vm, PAT); v3_unhook_msr(vm, MTRR_DEF_TYPE); v3_unhook_msr(vm, MTRR_PHYS_BASE_0); v3_unhook_msr(vm, MTRR_PHYS_BASE_1); v3_unhook_msr(vm, MTRR_PHYS_BASE_2); v3_unhook_msr(vm, MTRR_PHYS_BASE_3); v3_unhook_msr(vm, MTRR_PHYS_BASE_4); v3_unhook_msr(vm, MTRR_PHYS_BASE_5); v3_unhook_msr(vm, MTRR_PHYS_BASE_6); v3_unhook_msr(vm, MTRR_PHYS_BASE_7); v3_unhook_msr(vm, MTRR_PHYS_MASK_0); v3_unhook_msr(vm, MTRR_PHYS_MASK_1); v3_unhook_msr(vm, MTRR_PHYS_MASK_2); v3_unhook_msr(vm, MTRR_PHYS_MASK_3); v3_unhook_msr(vm, MTRR_PHYS_MASK_4); v3_unhook_msr(vm, MTRR_PHYS_MASK_5); v3_unhook_msr(vm, MTRR_PHYS_MASK_6); v3_unhook_msr(vm, MTRR_PHYS_MASK_7); v3_unhook_msr(vm, MTRR_FIX_64K_00000); v3_unhook_msr(vm, MTRR_FIX_16K_80000); v3_unhook_msr(vm, MTRR_FIX_16K_A0000); v3_unhook_msr(vm, MTRR_FIX_4K_C0000); v3_unhook_msr(vm, MTRR_FIX_4K_C8000); v3_unhook_msr(vm, MTRR_FIX_4K_D0000); v3_unhook_msr(vm, MTRR_FIX_4K_D8000); v3_unhook_msr(vm, MTRR_FIX_4K_E0000); v3_unhook_msr(vm, MTRR_FIX_4K_E8000); v3_unhook_msr(vm, MTRR_FIX_4K_F0000); v3_unhook_msr(vm, MTRR_FIX_4K_F8000); /* AMD specific */ v3_unhook_msr(vm, SYSCONFIG); v3_unhook_msr(vm, TOP_MEM); v3_unhook_msr(vm, TOP_MEM2); v3_unhook_msr(vm, IORR_BASE0); v3_unhook_msr(vm, IORR_BASE1); v3_unhook_msr(vm, IORR_MASK0); v3_unhook_msr(vm, IORR_MASK1); /* Intel Specfic */ v3_unhook_msr(vm, SMRR_PHYS_BASE); v3_unhook_msr(vm, SMRR_PHYS_MASK); V3_Free(state); return 0; } static int init_mtrrs(struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) { struct mtrr_state * state = NULL; int ret = 0; state = V3_Malloc(sizeof(struct mtrr_state)); memset(state, 0, sizeof(struct mtrr_state)); *priv_data = state; init_state(state); // hook MSRs ret |= v3_hook_msr(vm, MTRR_CAP, mtrr_cap_read, mtrr_cap_write, state); ret |= v3_hook_msr(vm, PAT, pat_read, pat_write, state); ret |= v3_hook_msr(vm, MTRR_DEF_TYPE, def_type_read, def_type_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_0, mtrr_phys_base_read, mtrr_phys_base_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_1, mtrr_phys_base_read, mtrr_phys_base_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_2, mtrr_phys_base_read, mtrr_phys_base_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_3, mtrr_phys_base_read, mtrr_phys_base_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_4, mtrr_phys_base_read, mtrr_phys_base_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_5, mtrr_phys_base_read, mtrr_phys_base_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_6, mtrr_phys_base_read, mtrr_phys_base_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_7, mtrr_phys_base_read, mtrr_phys_base_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_0, mtrr_phys_mask_read, mtrr_phys_mask_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_1, mtrr_phys_mask_read, mtrr_phys_mask_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_2, mtrr_phys_mask_read, mtrr_phys_mask_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_3, mtrr_phys_mask_read, mtrr_phys_mask_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_4, mtrr_phys_mask_read, mtrr_phys_mask_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_5, mtrr_phys_mask_read, mtrr_phys_mask_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_6, mtrr_phys_mask_read, mtrr_phys_mask_write, state); ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_7, mtrr_phys_mask_read, mtrr_phys_mask_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_64K_00000, mtrr_fix_64k_read, mtrr_fix_64k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_16K_80000, mtrr_fix_16k_read, mtrr_fix_16k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_16K_A0000, mtrr_fix_16k_read, mtrr_fix_16k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_4K_C0000, mtrr_fix_4k_read, mtrr_fix_4k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_4K_C8000, mtrr_fix_4k_read, mtrr_fix_4k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_4K_D0000, mtrr_fix_4k_read, mtrr_fix_4k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_4K_D8000, mtrr_fix_4k_read, mtrr_fix_4k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_4K_E0000, mtrr_fix_4k_read, mtrr_fix_4k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_4K_E8000, mtrr_fix_4k_read, mtrr_fix_4k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_4K_F0000, mtrr_fix_4k_read, mtrr_fix_4k_write, state); ret |= v3_hook_msr(vm, MTRR_FIX_4K_F8000, mtrr_fix_4k_read, mtrr_fix_4k_write, state); /* AMD Specific */ ret |= v3_hook_msr(vm, SYSCONFIG, amd_syscfg_read, amd_syscfg_write, state); ret |= v3_hook_msr(vm, TOP_MEM, amd_top_mem_read, amd_top_mem_write, state); ret |= v3_hook_msr(vm, TOP_MEM2, amd_top_mem_read, amd_top_mem_write, state); ret |= v3_hook_msr(vm, IORR_BASE0, amd_iorr_base_read, amd_iorr_base_write, state); ret |= v3_hook_msr(vm, IORR_BASE1, amd_iorr_base_read, amd_iorr_base_write, state); ret |= v3_hook_msr(vm, IORR_MASK0, amd_iorr_mask_read, amd_iorr_mask_write, state); ret |= v3_hook_msr(vm, IORR_MASK1, amd_iorr_mask_read, amd_iorr_mask_write, state); /* INTEL specific */ ret |= v3_hook_msr(vm, SMRR_PHYS_BASE, intel_smrr_base_read, intel_smrr_base_write, state); ret |= v3_hook_msr(vm, SMRR_PHYS_MASK, intel_smrr_mask_read, intel_smrr_mask_write, state); if (ret != 0) { PrintError("Failed to hook all MTRR MSRs. Aborting...\n"); deinit_mtrrs(vm, state); return -1; } return 0; } static struct v3_extension_impl mtrr_impl = { .name = "MTRRS", .init = init_mtrrs, .deinit = deinit_mtrrs, .core_init = NULL, .core_deinit = NULL, .on_entry = NULL, .on_exit = NULL }; register_extension(&mtrr_impl);