2 * Copyright (c) 2000-2011 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach/kern_return.h>
30 #include <kern/zalloc.h>
31 #include <kern/cpu_number.h>
32 #include <kern/cpu_data.h>
33 #include <i386/cpuid.h>
35 #include <i386/proc_reg.h>
36 #include <i386/mtrr.h>
37 #include <i386/machine_check.h>
39 struct mtrr_var_range
{
40 uint64_t base
; /* in IA32_MTRR_PHYSBASE format */
41 uint64_t mask
; /* in IA32_MTRR_PHYSMASK format */
42 uint32_t refcnt
; /* var ranges reference count */
45 struct mtrr_fix_range
{
46 uint64_t types
; /* fixed-range type octet */
49 typedef struct mtrr_var_range mtrr_var_range_t
;
50 typedef struct mtrr_fix_range mtrr_fix_range_t
;
55 mtrr_var_range_t
* var_range
;
56 unsigned int var_count
;
57 mtrr_fix_range_t fix_range
[11];
60 static boolean_t mtrr_initialized
= FALSE
;
62 decl_simple_lock_data(static, mtrr_lock
);
63 #define MTRR_LOCK() simple_lock(&mtrr_lock, LCK_GRP_NULL);
64 #define MTRR_UNLOCK() simple_unlock(&mtrr_lock);
66 //#define MTRR_DEBUG 1
68 #define DBG(x...) kprintf(x)
73 /* Private functions */
74 static void mtrr_get_var_ranges(mtrr_var_range_t
* range
, int count
);
75 static void mtrr_set_var_ranges(const mtrr_var_range_t
* range
, int count
);
76 static void mtrr_get_fix_ranges(mtrr_fix_range_t
* range
);
77 static void mtrr_set_fix_ranges(const mtrr_fix_range_t
* range
);
78 static void mtrr_update_setup(void * param
);
79 static void mtrr_update_teardown(void * param
);
80 static void mtrr_update_action(void * param
);
81 static void var_range_encode(mtrr_var_range_t
* range
, addr64_t address
,
82 uint64_t length
, uint32_t type
, int valid
);
83 static int var_range_overlap(mtrr_var_range_t
* range
, addr64_t address
,
84 uint64_t length
, uint32_t type
);
86 #define CACHE_CONTROL_MTRR (NULL)
87 #define CACHE_CONTROL_PAT ((void *)1)
90 * MTRR MSR bit fields.
92 #define IA32_MTRR_DEF_TYPE_MT 0x000000ff
93 #define IA32_MTRR_DEF_TYPE_FE 0x00000400
94 #define IA32_MTRR_DEF_TYPE_E 0x00000800
96 #define IA32_MTRRCAP_VCNT 0x000000ff
97 #define IA32_MTRRCAP_FIX 0x00000100
98 #define IA32_MTRRCAP_WC 0x00000400
101 #define PHYS_BITS_TO_MASK(bits) \
102 ((((1ULL << (bits-1)) - 1) << 1) | 1)
105 * Default mask for 36 physical address bits, this can
106 * change depending on the cpu model.
108 static uint64_t mtrr_phys_mask
= PHYS_BITS_TO_MASK(36);
110 #define IA32_MTRR_PHYMASK_VALID 0x0000000000000800ULL
111 #define IA32_MTRR_PHYSBASE_MASK (mtrr_phys_mask & ~0x0000000000000FFFULL)
112 #define IA32_MTRR_PHYSBASE_TYPE 0x00000000000000FFULL
115 * Variable-range mask to/from length conversions.
117 #define MASK_TO_LEN(mask) \
118 ((~((mask) & IA32_MTRR_PHYSBASE_MASK) & mtrr_phys_mask) + 1)
120 #define LEN_TO_MASK(len) \
121 (~((len) - 1) & IA32_MTRR_PHYSBASE_MASK)
123 #define LSB(x) ((x) & (~((x) - 1)))
126 * Fetch variable-range MTRR register pairs.
129 mtrr_get_var_ranges(mtrr_var_range_t
* range
, int count
)
133 for (i
= 0; i
< count
; i
++) {
134 range
[i
].base
= rdmsr64(MSR_IA32_MTRR_PHYSBASE(i
));
135 range
[i
].mask
= rdmsr64(MSR_IA32_MTRR_PHYSMASK(i
));
137 /* bump ref count for firmware configured ranges */
138 if (range
[i
].mask
& IA32_MTRR_PHYMASK_VALID
) {
147 * Update variable-range MTRR register pairs.
150 mtrr_set_var_ranges(const mtrr_var_range_t
* range
, int count
)
154 for (i
= 0; i
< count
; i
++) {
155 wrmsr64(MSR_IA32_MTRR_PHYSBASE(i
), range
[i
].base
);
156 wrmsr64(MSR_IA32_MTRR_PHYSMASK(i
), range
[i
].mask
);
161 * Fetch all fixed-range MTRR's. Note MSR offsets are not consecutive.
164 mtrr_get_fix_ranges(mtrr_fix_range_t
* range
)
168 /* assume 11 fix range registers */
169 range
[0].types
= rdmsr64(MSR_IA32_MTRR_FIX64K_00000
);
170 range
[1].types
= rdmsr64(MSR_IA32_MTRR_FIX16K_80000
);
171 range
[2].types
= rdmsr64(MSR_IA32_MTRR_FIX16K_A0000
);
172 for (i
= 0; i
< 8; i
++) {
173 range
[3 + i
].types
= rdmsr64(MSR_IA32_MTRR_FIX4K_C0000
+ i
);
178 * Update all fixed-range MTRR's.
181 mtrr_set_fix_ranges(const struct mtrr_fix_range
* range
)
185 /* assume 11 fix range registers */
186 wrmsr64(MSR_IA32_MTRR_FIX64K_00000
, range
[0].types
);
187 wrmsr64(MSR_IA32_MTRR_FIX16K_80000
, range
[1].types
);
188 wrmsr64(MSR_IA32_MTRR_FIX16K_A0000
, range
[2].types
);
189 for (i
= 0; i
< 8; i
++) {
190 wrmsr64(MSR_IA32_MTRR_FIX4K_C0000
+ i
, range
[3 + i
].types
);
195 mtrr_check_fix_ranges(const struct mtrr_fix_range
* range
)
198 boolean_t match
= TRUE
;
200 DBG("CPU%d: %s\n", get_cpu_number(), __FUNCTION__
);
202 /* assume 11 fix range registers */
203 match
= range
[0].types
== rdmsr64(MSR_IA32_MTRR_FIX64K_00000
) &&
204 range
[1].types
== rdmsr64(MSR_IA32_MTRR_FIX16K_80000
) &&
205 range
[2].types
== rdmsr64(MSR_IA32_MTRR_FIX16K_A0000
);
206 for (i
= 0; match
&& i
< 8; i
++) {
207 match
= range
[3 + i
].types
==
208 rdmsr64(MSR_IA32_MTRR_FIX4K_C0000
+ i
);
215 mtrr_check_var_ranges(mtrr_var_range_t
* range
, int count
)
218 boolean_t match
= TRUE
;
220 DBG("CPU%d: %s\n", get_cpu_number(), __FUNCTION__
);
222 for (i
= 0; match
&& i
< count
; i
++) {
223 match
= range
[i
].base
== rdmsr64(MSR_IA32_MTRR_PHYSBASE(i
)) &&
224 range
[i
].mask
== rdmsr64(MSR_IA32_MTRR_PHYSMASK(i
));
235 int count
= rdmsr64(MSR_IA32_MTRRCAP
) & IA32_MTRRCAP_VCNT
;
237 DBG("VAR -- BASE -------------- MASK -------------- SIZE\n");
238 for (i
= 0; i
< count
; i
++) {
239 DBG(" %02x 0x%016llx 0x%016llx 0x%llx\n", i
,
240 rdmsr64(MSR_IA32_MTRR_PHYSBASE(i
)),
241 rdmsr64(MSR_IA32_MTRR_PHYSMASK(i
)),
242 MASK_TO_LEN(rdmsr64(MSR_IA32_MTRR_PHYSMASK(i
))));
246 DBG("FIX64K_00000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX64K_00000
));
247 DBG("FIX16K_80000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX16K_80000
));
248 DBG("FIX16K_A0000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX16K_A0000
));
249 DBG(" FIX4K_C0000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX4K_C0000
));
250 DBG(" FIX4K_C8000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX4K_C8000
));
251 DBG(" FIX4K_D0000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX4K_D0000
));
252 DBG(" FIX4K_D8000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX4K_D8000
));
253 DBG(" FIX4K_E0000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX4K_E0000
));
254 DBG(" FIX4K_E8000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX4K_E8000
));
255 DBG(" FIX4K_F0000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX4K_F0000
));
256 DBG(" FIX4K_F8000: 0x%016llx\n", rdmsr64(MSR_IA32_MTRR_FIX4K_F8000
));
258 DBG("\nMTRRcap = 0x%llx MTRRdefType = 0x%llx\n",
259 rdmsr64(MSR_IA32_MTRRCAP
), rdmsr64(MSR_IA32_MTRR_DEF_TYPE
));
261 #endif /* MTRR_DEBUG */
264 * Called by the boot processor (BP) early during boot to initialize MTRR
265 * support. The MTRR state on the BP is saved, any additional processors
266 * will have the same settings applied to ensure MTRR consistency.
271 /* no reason to init more than once */
272 if (mtrr_initialized
== TRUE
) {
276 /* check for presence of MTRR feature on the processor */
277 if ((cpuid_features() & CPUID_FEATURE_MTRR
) == 0) {
278 return; /* no MTRR feature */
280 /* use a lock to serialize MTRR changes */
281 bzero((void *)&mtrr_state
, sizeof(mtrr_state
));
282 simple_lock_init(&mtrr_lock
, 0);
284 mtrr_state
.MTRRcap
= rdmsr64(MSR_IA32_MTRRCAP
);
285 mtrr_state
.MTRRdefType
= rdmsr64(MSR_IA32_MTRR_DEF_TYPE
);
286 mtrr_state
.var_count
= (unsigned int)(mtrr_state
.MTRRcap
& IA32_MTRRCAP_VCNT
);
288 /* allocate storage for variable ranges (can block?) */
289 if (mtrr_state
.var_count
) {
290 mtrr_state
.var_range
= (mtrr_var_range_t
*)
291 zalloc_permanent(sizeof(mtrr_var_range_t
) *
292 mtrr_state
.var_count
, ZALIGN(mtrr_var_range_t
));
293 if (mtrr_state
.var_range
== NULL
) {
294 mtrr_state
.var_count
= 0;
298 /* fetch the initial firmware configured variable ranges */
299 if (mtrr_state
.var_count
) {
300 mtrr_get_var_ranges(mtrr_state
.var_range
,
301 mtrr_state
.var_count
);
304 /* fetch the initial firmware configured fixed ranges */
305 if (mtrr_state
.MTRRcap
& IA32_MTRRCAP_FIX
) {
306 mtrr_get_fix_ranges(mtrr_state
.fix_range
);
309 mtrr_initialized
= TRUE
;
312 mtrr_msr_dump(); /* dump firmware settings */
317 * Performs the Intel recommended procedure for changing the MTRR
318 * in a MP system. Leverage rendezvous mechanism for the required
319 * barrier synchronization among all processors. This function is
320 * called from the rendezvous IPI handler, and mtrr_update_cpu().
323 mtrr_update_action(void * cache_control_type
)
331 /* enter no-fill cache mode */
339 /* clear the PGE flag in CR4 */
341 set_cr4(cr4
& ~CR4_PGE
);
343 set_cr3_raw(get_cr3_raw());
346 if (CACHE_CONTROL_PAT
== cache_control_type
) {
347 /* Change PA6 attribute field to WC */
348 uint64_t pat
= rdmsr64(MSR_IA32_CR_PAT
);
349 DBG("CPU%d PAT: was 0x%016llx\n", get_cpu_number(), pat
);
352 * "The IA32_PAT MSR contains eight page attribute fields: PA0 through PA7.
353 * The three low-order bits of each field are used to specify a memory type.
354 * The five high-order bits of each field are reserved, and must be set to all 0s."
355 * So, we zero-out the high 5 bits of the PA6 entry here:
357 pat
&= ~(0xFFULL
<< 48);
358 pat
|= (0x01ULL
<< 48);
359 wrmsr64(MSR_IA32_CR_PAT
, pat
);
360 DBG("CPU%d PAT: is 0x%016llx\n",
361 get_cpu_number(), rdmsr64(MSR_IA32_CR_PAT
));
363 /* disable all MTRR ranges */
364 wrmsr64(MSR_IA32_MTRR_DEF_TYPE
,
365 mtrr_state
.MTRRdefType
& ~IA32_MTRR_DEF_TYPE_E
);
367 /* apply MTRR settings */
368 if (mtrr_state
.var_count
) {
369 mtrr_set_var_ranges(mtrr_state
.var_range
,
370 mtrr_state
.var_count
);
373 if (mtrr_state
.MTRRcap
& IA32_MTRRCAP_FIX
) {
374 mtrr_set_fix_ranges(mtrr_state
.fix_range
);
377 /* enable all MTRR range registers (what if E was not set?) */
378 wrmsr64(MSR_IA32_MTRR_DEF_TYPE
,
379 mtrr_state
.MTRRdefType
| IA32_MTRR_DEF_TYPE_E
);
382 /* flush all caches and TLBs a second time */
384 set_cr3_raw(get_cr3_raw());
385 /* restore normal cache mode */
388 /* restore PGE flag */
393 DBG("CPU%d: %s\n", get_cpu_number(), __FUNCTION__
);
397 mtrr_update_setup(__unused
void * param_not_used
)
399 /* disable interrupts before the first barrier */
400 current_cpu_datap()->cpu_iflag
= ml_set_interrupts_enabled(FALSE
);
401 DBG("CPU%d: %s\n", get_cpu_number(), __FUNCTION__
);
405 mtrr_update_teardown(__unused
void * param_not_used
)
407 /* restore interrupt flag following MTRR changes */
408 ml_set_interrupts_enabled(current_cpu_datap()->cpu_iflag
);
409 DBG("CPU%d: %s\n", get_cpu_number(), __FUNCTION__
);
413 * Update MTRR settings on all processors.
416 mtrr_update_all_cpus(void)
418 if (mtrr_initialized
== FALSE
) {
419 return KERN_NOT_SUPPORTED
;
423 mp_rendezvous(mtrr_update_setup
,
425 mtrr_update_teardown
, NULL
);
432 * Verify that a processor has been set with the BSP's MTRR settings. Called
433 * during slave processor initialization to check and set MTRR settings
434 * discovered on the boot processor by mtrr_init().
437 mtrr_update_cpu(void)
439 boolean_t match
= TRUE
;
441 if (mtrr_initialized
== FALSE
) {
442 return KERN_NOT_SUPPORTED
;
445 DBG("CPU%d: %s\n", get_cpu_number(), __FUNCTION__
);
449 /* Check MSR_IA32_MTRR_DEF_TYPE MSR */
450 match
= mtrr_state
.MTRRdefType
== rdmsr64(MSR_IA32_MTRR_DEF_TYPE
);
452 /* Check MSR_IA32_MTRRCAP MSR */
454 match
= mtrr_state
.MTRRcap
== rdmsr64(MSR_IA32_MTRRCAP
);
457 /* Check variable ranges */
458 if (match
&& mtrr_state
.var_count
) {
459 match
= mtrr_check_var_ranges(mtrr_state
.var_range
,
460 mtrr_state
.var_count
);
463 /* Check fixed ranges */
464 if (match
&& (mtrr_state
.MTRRcap
& IA32_MTRRCAP_FIX
)) {
465 match
= mtrr_check_fix_ranges(mtrr_state
.fix_range
);
474 DBG("mtrr_update_cpu() setting MTRR for cpu %d\n",
476 mtrr_update_action(NULL
);
490 * Add a MTRR range to associate the physical memory range specified
491 * with a given memory caching type.
494 mtrr_range_add(addr64_t address
, uint64_t length
, uint32_t type
)
496 mtrr_var_range_t
* vr
;
497 mtrr_var_range_t
* free_range
;
498 kern_return_t ret
= KERN_NO_SPACE
;
502 DBG("mtrr_range_add base = 0x%llx, size = 0x%llx, type = %d\n",
503 address
, length
, type
);
505 if (mtrr_initialized
== FALSE
) {
506 return KERN_NOT_SUPPORTED
;
509 /* check memory type (GPF exception for undefined types) */
510 if ((type
!= MTRR_TYPE_UNCACHEABLE
) &&
511 (type
!= MTRR_TYPE_WRITECOMBINE
) &&
512 (type
!= MTRR_TYPE_WRITETHROUGH
) &&
513 (type
!= MTRR_TYPE_WRITEPROTECT
) &&
514 (type
!= MTRR_TYPE_WRITEBACK
)) {
515 return KERN_INVALID_ARGUMENT
;
518 /* check WC support if requested */
519 if ((type
== MTRR_TYPE_WRITECOMBINE
) &&
520 (mtrr_state
.MTRRcap
& IA32_MTRRCAP_WC
) == 0) {
521 return KERN_NOT_SUPPORTED
;
524 /* leave the fix range area below 1MB alone */
525 if (address
< 0x100000 || mtrr_state
.var_count
== 0) {
526 return KERN_NOT_SUPPORTED
;
530 * Length must be a power of 2 given by 2^n, where n >= 12.
531 * Base address alignment must be larger than or equal to length.
533 if ((length
< 0x1000) ||
534 (LSB(length
) != length
) ||
535 (address
&& (length
> LSB(address
)))) {
536 return KERN_INVALID_ARGUMENT
;
542 * Check for overlap and locate a free range.
544 for (i
= 0, free_range
= NULL
; i
< mtrr_state
.var_count
; i
++) {
545 vr
= &mtrr_state
.var_range
[i
];
547 if (vr
->refcnt
== 0) {
548 /* free range candidate if no overlaps are found */
553 overlap
= var_range_overlap(vr
, address
, length
, type
);
556 * identical overlap permitted, increment ref count.
557 * no hardware update required.
563 /* unsupported overlapping of memory types */
570 if (free_range
->refcnt
++ == 0) {
571 var_range_encode(free_range
, address
, length
, type
, 1);
572 mp_rendezvous(mtrr_update_setup
,
574 mtrr_update_teardown
, NULL
);
589 * Remove a previously added MTRR range. The same arguments used for adding
590 * the memory range must be supplied again.
593 mtrr_range_remove(addr64_t address
, uint64_t length
, uint32_t type
)
595 mtrr_var_range_t
* vr
;
596 int result
= KERN_FAILURE
;
600 DBG("mtrr_range_remove base = 0x%llx, size = 0x%llx, type = %d\n",
601 address
, length
, type
);
603 if (mtrr_initialized
== FALSE
) {
604 return KERN_NOT_SUPPORTED
;
609 for (i
= 0; i
< mtrr_state
.var_count
; i
++) {
610 vr
= &mtrr_state
.var_range
[i
];
613 var_range_overlap(vr
, address
, length
, type
) > 0) {
614 /* found specified variable range */
615 if (--mtrr_state
.var_range
[i
].refcnt
== 0) {
616 var_range_encode(vr
, address
, length
, type
, 0);
619 result
= KERN_SUCCESS
;
625 mp_rendezvous(mtrr_update_setup
,
627 mtrr_update_teardown
, NULL
);
628 result
= KERN_SUCCESS
;
641 * Variable range helper routines
644 var_range_encode(mtrr_var_range_t
* range
, addr64_t address
,
645 uint64_t length
, uint32_t type
, int valid
)
647 range
->base
= (address
& IA32_MTRR_PHYSBASE_MASK
) |
648 (type
& (uint32_t)IA32_MTRR_PHYSBASE_TYPE
);
650 range
->mask
= LEN_TO_MASK(length
) |
651 (valid
? IA32_MTRR_PHYMASK_VALID
: 0);
655 var_range_overlap(mtrr_var_range_t
* range
, addr64_t address
,
656 uint64_t length
, uint32_t type
)
658 uint64_t v_address
, v_length
;
660 int result
= 0; /* no overlap, or overlap ok */
662 v_address
= range
->base
& IA32_MTRR_PHYSBASE_MASK
;
663 v_type
= (uint32_t)(range
->base
& IA32_MTRR_PHYSBASE_TYPE
);
664 v_length
= MASK_TO_LEN(range
->mask
);
666 /* detect range overlap */
667 if ((v_address
>= address
&& v_address
< (address
+ length
)) ||
668 (address
>= v_address
&& address
< (v_address
+ v_length
))) {
669 if (v_address
== address
&& v_length
== length
&& v_type
== type
) {
670 result
= 1; /* identical overlap ok */
671 } else if (v_type
== MTRR_TYPE_UNCACHEABLE
&&
672 type
== MTRR_TYPE_UNCACHEABLE
) {
673 /* UC ranges can overlap */
674 } else if ((v_type
== MTRR_TYPE_UNCACHEABLE
&&
675 type
== MTRR_TYPE_WRITEBACK
) ||
676 (v_type
== MTRR_TYPE_WRITEBACK
&&
677 type
== MTRR_TYPE_UNCACHEABLE
)) {
678 /* UC/WB can overlap - effective type becomes UC */
680 /* anything else may cause undefined behavior */
689 * Initialize PAT (Page Attribute Table)
697 if (!(cpuid_features() & CPUID_FEATURE_PAT
)) {
701 istate
= ml_set_interrupts_enabled(FALSE
);
703 pat
= rdmsr64(MSR_IA32_CR_PAT
);
704 DBG("CPU%d PAT: was 0x%016llx\n", get_cpu_number(), pat
);
706 /* Change PA6 attribute field to WC if required */
707 if ((pat
& (0x07ULL
<< 48)) != (0x01ULL
<< 48)) {
708 mtrr_update_action(CACHE_CONTROL_PAT
);
710 ml_set_interrupts_enabled(istate
);