X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6601e61aa18bf4f09af135ff61fc7f4771d23b06..4d15aeb193b2c68f1d38666c317f8d3734f5f083:/osfmk/i386/mtrr.c diff --git a/osfmk/i386/mtrr.c b/osfmk/i386/mtrr.c index fe718c39d..30df3db47 100644 --- a/osfmk/i386/mtrr.c +++ b/osfmk/i386/mtrr.c @@ -1,33 +1,40 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2011 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include #include #include #include -#include #include +#include #include #include +#include struct mtrr_var_range { uint64_t base; /* in IA32_MTRR_PHYSBASE format */ @@ -56,6 +63,7 @@ decl_simple_lock_data(static, mtrr_lock); #define MTRR_LOCK() simple_lock(&mtrr_lock); #define MTRR_UNLOCK() simple_unlock(&mtrr_lock); +//#define MTRR_DEBUG 1 #if MTRR_DEBUG #define DBG(x...) kprintf(x) #else @@ -100,7 +108,7 @@ static int var_range_overlap(mtrr_var_range_t * range, addr64_t address, static uint64_t mtrr_phys_mask = PHYS_BITS_TO_MASK(36); #define IA32_MTRR_PHYMASK_VALID 0x0000000000000800ULL -#define IA32_MTRR_PHYSBASE_MASK (mtrr_phys_mask & ~0xFFF) +#define IA32_MTRR_PHYSBASE_MASK (mtrr_phys_mask & ~0x0000000000000FFFULL) #define IA32_MTRR_PHYSBASE_TYPE 0x00000000000000FFULL /* @@ -180,6 +188,42 @@ mtrr_set_fix_ranges(const struct mtrr_fix_range * range) wrmsr64(MSR_IA32_MTRR_FIX4K_C0000 + i, range[3 + i].types); } +static boolean_t +mtrr_check_fix_ranges(const struct mtrr_fix_range * range) +{ + int i; + boolean_t match = TRUE; + + DBG("CPU%d: %s\n", get_cpu_number(), __FUNCTION__); + + /* assume 11 fix range registers */ + match = range[0].types == rdmsr64(MSR_IA32_MTRR_FIX64K_00000) && + range[1].types == rdmsr64(MSR_IA32_MTRR_FIX16K_80000) && + range[2].types == rdmsr64(MSR_IA32_MTRR_FIX16K_A0000); + for (i = 0; match && i < 8; i++) { + match = range[3 + i].types == + rdmsr64(MSR_IA32_MTRR_FIX4K_C0000 + i); + } + + return match; +} + +static boolean_t +mtrr_check_var_ranges(mtrr_var_range_t * range, int count) +{ + int i; + boolean_t match = TRUE; + + DBG("CPU%d: %s\n", get_cpu_number(), __FUNCTION__); + + for (i = 0; match && i < count; i++) { + match = range[i].base == rdmsr64(MSR_IA32_MTRR_PHYSBASE(i)) && + range[i].mask == rdmsr64(MSR_IA32_MTRR_PHYSMASK(i)); + } + + return match; +} + #if MTRR_DEBUG static void mtrr_msr_dump(void) @@ -221,8 +265,6 @@ mtrr_msr_dump(void) void mtrr_init(void) { - i386_cpu_info_t * infop = cpuid_info(); - /* no reason to init more than once */ if (mtrr_initialized == TRUE) return; @@ -231,48 +273,13 @@ mtrr_init(void) if ((cpuid_features() & CPUID_FEATURE_MTRR) == 0) return; /* no MTRR feature */ - /* cpu vendor/model specific handling */ - if (!strncmp(infop->cpuid_vendor, CPUID_VID_AMD, sizeof(CPUID_VID_AMD))) - { - /* Check for AMD Athlon 64 and Opteron */ - if (cpuid_family() == 0xF) - { - uint32_t cpuid_result[4]; - - /* check if cpu support Address Sizes function */ - do_cpuid(0x80000000, cpuid_result); - if (cpuid_result[0] >= 0x80000008) - { - int bits; - - do_cpuid(0x80000008, cpuid_result); - DBG("MTRR: AMD 8000_0008 EAX = %08x\n", - cpuid_result[0]); - - /* - * Function 8000_0008 (Address Sizes) EAX - * Bits 7-0 : phys address size - * Bits 15-8 : virt address size - */ - bits = cpuid_result[0] & 0xFF; - if ((bits < 36) || (bits > 64)) - { - printf("MTRR: bad address size\n"); - return; /* bogus size */ - } - - mtrr_phys_mask = PHYS_BITS_TO_MASK(bits); - } - } - } - /* use a lock to serialize MTRR changes */ bzero((void *)&mtrr_state, sizeof(mtrr_state)); simple_lock_init(&mtrr_lock, 0); mtrr_state.MTRRcap = rdmsr64(MSR_IA32_MTRRCAP); mtrr_state.MTRRdefType = rdmsr64(MSR_IA32_MTRR_DEF_TYPE); - mtrr_state.var_count = mtrr_state.MTRRcap & IA32_MTRRCAP_VCNT; + mtrr_state.var_count = (unsigned int)(mtrr_state.MTRRcap & IA32_MTRRCAP_VCNT); /* allocate storage for variable ranges (can block?) */ if (mtrr_state.var_count) { @@ -297,6 +304,7 @@ mtrr_init(void) #if MTRR_DEBUG mtrr_msr_dump(); /* dump firmware settings */ #endif + } /* @@ -308,8 +316,8 @@ mtrr_init(void) static void mtrr_update_action(void * cache_control_type) { - uint32_t cr0, cr4; - uint32_t tmp; + uintptr_t cr0, cr4; + uintptr_t tmp; cr0 = get_cr0(); cr4 = get_cr4(); @@ -327,7 +335,7 @@ mtrr_update_action(void * cache_control_type) set_cr4(cr4 & ~CR4_PGE); /* flush TLBs */ - flush_tlb(); + flush_tlb_raw(); if (CACHE_CONTROL_PAT == cache_control_type) { /* Change PA6 attribute field to WC */ @@ -359,7 +367,7 @@ mtrr_update_action(void * cache_control_type) /* flush all caches and TLBs a second time */ wbinvd(); - flush_tlb(); + flush_tlb_raw(); /* restore normal cache mode */ set_cr0(cr0); @@ -406,20 +414,55 @@ mtrr_update_all_cpus(void) } /* - * Update a single CPU with the current MTRR settings. Can be called - * during slave processor initialization to mirror the MTRR settings + * Verify that a processor has been set with the BSP's MTRR settings. Called + * during slave processor initialization to check and set MTRR settings * discovered on the boot processor by mtrr_init(). */ kern_return_t mtrr_update_cpu(void) { + boolean_t match = TRUE; + if (mtrr_initialized == FALSE) return KERN_NOT_SUPPORTED; + DBG("CPU%d: %s\n", get_cpu_number(), __FUNCTION__); + MTRR_LOCK(); - mtrr_update_setup(NULL); - mtrr_update_action(NULL); - mtrr_update_teardown(NULL); + + /* Check MSR_IA32_MTRR_DEF_TYPE MSR */ + match = mtrr_state.MTRRdefType == rdmsr64(MSR_IA32_MTRR_DEF_TYPE); + + /* Check MSR_IA32_MTRRCAP MSR */ + if (match) { + match = mtrr_state.MTRRcap == rdmsr64(MSR_IA32_MTRRCAP); + } + + /* Check variable ranges */ + if (match && mtrr_state.var_count) { + match = mtrr_check_var_ranges(mtrr_state.var_range, + mtrr_state.var_count); + } + + /* Check fixed ranges */ + if (match && (mtrr_state.MTRRcap & IA32_MTRRCAP_FIX)) { + match = mtrr_check_fix_ranges(mtrr_state.fix_range); + } + +#if MTRR_DEBUG + if (!match) + mtrr_msr_dump(); +#endif + if (!match) { + DBG("mtrr_update_cpu() setting MTRR for cpu %d\n", + get_cpu_number()); + mtrr_update_action(NULL); + } +#if MTRR_DEBUG + if (!match) + mtrr_msr_dump(); +#endif + MTRR_UNLOCK(); return KERN_SUCCESS; @@ -585,7 +628,7 @@ var_range_encode(mtrr_var_range_t * range, addr64_t address, uint64_t length, uint32_t type, int valid) { range->base = (address & IA32_MTRR_PHYSBASE_MASK) | - (type & IA32_MTRR_PHYSBASE_TYPE); + (type & (uint32_t)IA32_MTRR_PHYSBASE_TYPE); range->mask = LEN_TO_MASK(length) | (valid ? IA32_MTRR_PHYMASK_VALID : 0); @@ -600,7 +643,7 @@ var_range_overlap(mtrr_var_range_t * range, addr64_t address, int result = 0; /* no overlap, or overlap ok */ v_address = range->base & IA32_MTRR_PHYSBASE_MASK; - v_type = range->base & IA32_MTRR_PHYSBASE_TYPE; + v_type = (uint32_t)(range->base & IA32_MTRR_PHYSBASE_TYPE); v_length = MASK_TO_LEN(range->mask); /* detect range overlap */ @@ -634,10 +677,20 @@ var_range_overlap(mtrr_var_range_t * range, addr64_t address, void pat_init(void) { - if (cpuid_features() & CPUID_FEATURE_PAT) - { - boolean_t istate = ml_set_interrupts_enabled(FALSE); + boolean_t istate; + uint64_t pat; + + if (!(cpuid_features() & CPUID_FEATURE_PAT)) + return; + + istate = ml_set_interrupts_enabled(FALSE); + + pat = rdmsr64(MSR_IA32_CR_PAT); + DBG("CPU%d PAT: was 0x%016llx\n", get_cpu_number(), pat); + + /* Change PA6 attribute field to WC if required */ + if ((pat & ~(0x0FULL << 48)) != (0x01ULL << 48)) { mtrr_update_action(CACHE_CONTROL_PAT); - ml_set_interrupts_enabled(istate); } + ml_set_interrupts_enabled(istate); }