1/* $OpenBSD: amd64_mem.c,v 1.14 2018/07/27 21:11:31 kettenis Exp $ */
2/*
3 * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: src/sys/i386/i386/i686_mem.c,v 1.8 1999/10/12 22:53:05 green Exp $
28 */
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/malloc.h>
33#include <sys/memrange.h>
34
35#include <machine/cpufunc.h>
36#include <machine/intr.h>
37#include <machine/specialreg.h>
38
39/*
40 * This code implements a set of MSRs known as MTRR which define caching
41 * modes/behavior for various memory ranges.
42 */
43
44char *mem_owner_bios = "BIOS";
45
46#define MR_FIXMTRR	(1<<0)
47
48#define mrwithin(mr, a) \
49    (((a) >= (mr)->mr_base) && ((a) < ((mr)->mr_base + (mr)->mr_len)))
50#define mroverlap(mra, mrb) \
51    (mrwithin(mra, mrb->mr_base) || mrwithin(mrb, mra->mr_base))
52
53#define mrvalid(base, len) 						\
54    ((!(base & ((1 << 12) - 1))) && 	/* base is multiple of 4k */	\
55     ((len) >= (1 << 12)) && 		/* length is >= 4k */		\
56     powerof2((len)) && 		/* ... and power of two */	\
57     !((base) & ((len) - 1)))		/* range is not discontiuous */
58
59#define mrcopyflags(curr, new) (((curr) & ~MDF_ATTRMASK) | \
60	((new) & MDF_ATTRMASK))
61
62#define FIXTOP	((MTRR_N64K * 0x10000) + (MTRR_N16K * 0x4000) + \
63	(MTRR_N4K * 0x1000))
64
65void	mrinit(struct mem_range_softc *sc);
66int	mrset(struct mem_range_softc *sc,
67	    struct mem_range_desc *mrd, int *arg);
68void	mrinit_cpu(struct mem_range_softc *sc);
69void	mrreload_cpu(struct mem_range_softc *sc);
70
71struct mem_range_ops mrops = {
72	mrinit,
73	mrset,
74	mrinit_cpu,
75	mrreload_cpu
76};
77
78u_int64_t	mtrrcap, mtrrdef;
79u_int64_t	mtrrmask = 0x0000000ffffff000ULL;
80
81struct mem_range_desc	*mem_range_match(struct mem_range_softc *sc,
82			     struct mem_range_desc *mrd);
83void			 mrfetch(struct mem_range_softc *sc);
84int			 mtrrtype(u_int64_t flags);
85int			 mrt2mtrr(u_int64_t flags);
86int			 mtrr2mrt(int val);
87int			 mtrrconflict(u_int64_t flag1, u_int64_t flag2);
88void			 mrstore(struct mem_range_softc *sc);
89void			 mrstoreone(struct mem_range_softc *sc);
90struct mem_range_desc	*mtrrfixsearch(struct mem_range_softc *sc,
91			     u_int64_t addr);
92int			 mrsetlow(struct mem_range_softc *sc,
93			     struct mem_range_desc *mrd, int *arg);
94int			 mrsetvariable(struct mem_range_softc *sc,
95			     struct mem_range_desc *mrd, int *arg);
96
97/* MTRR type to memory range type conversion */
98int mtrrtomrt[] = {
99	MDF_UNCACHEABLE,
100	MDF_WRITECOMBINE,
101	MDF_UNKNOWN,
102	MDF_UNKNOWN,
103	MDF_WRITETHROUGH,
104	MDF_WRITEPROTECT,
105	MDF_WRITEBACK
106};
107
108int
109mtrr2mrt(int val)
110{
111	if (val < 0 || val >= nitems(mtrrtomrt))
112		return MDF_UNKNOWN;
113	return mtrrtomrt[val];
114}
115
116/*
117 * MTRR conflicts. Writeback and uncachable may overlap.
118 */
119int
120mtrrconflict(u_int64_t flag1, u_int64_t flag2)
121{
122	flag1 &= MDF_ATTRMASK;
123	flag2 &= MDF_ATTRMASK;
124	if (flag1 == flag2 ||
125	    (flag1 == MDF_WRITEBACK && flag2 == MDF_UNCACHEABLE) ||
126	    (flag2 == MDF_WRITEBACK && flag1 == MDF_UNCACHEABLE))
127		return 0;
128	return 1;
129}
130
131/*
132 * Look for an exactly-matching range.
133 */
134struct mem_range_desc *
135mem_range_match(struct mem_range_softc *sc, struct mem_range_desc *mrd)
136{
137	struct mem_range_desc	*cand;
138	int			 i;
139
140	for (i = 0, cand = sc->mr_desc; i < sc->mr_ndesc; i++, cand++)
141		if ((cand->mr_base == mrd->mr_base) &&
142		    (cand->mr_len == mrd->mr_len))
143			return(cand);
144	return(NULL);
145}
146
147/*
148 * Fetch the current mtrr settings from the current CPU (assumed to all
149 * be in sync in the SMP case).  Note that if we are here, we assume
150 * that MTRRs are enabled, and we may or may not have fixed MTRRs.
151 */
152void
153mrfetch(struct mem_range_softc *sc)
154{
155	struct mem_range_desc	*mrd;
156	u_int64_t		 msrv;
157	int			 i, j, msr, mrt;
158
159	mrd = sc->mr_desc;
160
161	/* We should never be fetching MTRRs from an AP */
162	KASSERT(CPU_IS_PRIMARY(curcpu()));
163
164	/* Get fixed-range MTRRs, if the CPU supports them */
165	if (sc->mr_cap & MR_FIXMTRR) {
166		msr = MSR_MTRRfix64K_00000;
167		for (i = 0; i < (MTRR_N64K / 8); i++, msr++) {
168			msrv = rdmsr(msr);
169			for (j = 0; j < 8; j++, mrd++) {
170				mrt = mtrr2mrt(msrv & 0xff);
171				if (mrt == MDF_UNKNOWN)
172					mrt = MDF_UNCACHEABLE;
173				mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
174					mrt | MDF_ACTIVE;
175				if (mrd->mr_owner[0] == 0)
176					strlcpy(mrd->mr_owner, mem_owner_bios,
177					    sizeof(mrd->mr_owner));
178				msrv = msrv >> 8;
179			}
180		}
181
182		msr = MSR_MTRRfix16K_80000;
183		for (i = 0; i < (MTRR_N16K / 8); i++, msr++) {
184			msrv = rdmsr(msr);
185			for (j = 0; j < 8; j++, mrd++) {
186				mrt = mtrr2mrt(msrv & 0xff);
187				if (mrt == MDF_UNKNOWN)
188					mrt = MDF_UNCACHEABLE;
189				mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
190					mrt | MDF_ACTIVE;
191				if (mrd->mr_owner[0] == 0)
192					strlcpy(mrd->mr_owner, mem_owner_bios,
193					    sizeof(mrd->mr_owner));
194				msrv = msrv >> 8;
195			}
196		}
197
198		msr = MSR_MTRRfix4K_C0000;
199		for (i = 0; i < (MTRR_N4K / 8); i++, msr++) {
200			msrv = rdmsr(msr);
201			for (j = 0; j < 8; j++, mrd++) {
202				mrt = mtrr2mrt(msrv & 0xff);
203				if (mrt == MDF_UNKNOWN)
204					mrt = MDF_UNCACHEABLE;
205				mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
206					mrt | MDF_ACTIVE;
207				if (mrd->mr_owner[0] == 0)
208					strlcpy(mrd->mr_owner, mem_owner_bios,
209					    sizeof(mrd->mr_owner));
210				msrv = msrv >> 8;
211			}
212		}
213	}
214
215	/* Get remainder which must be variable MTRRs */
216	msr = MSR_MTRRvarBase;
217	for (; (mrd - sc->mr_desc) < sc->mr_ndesc; msr += 2, mrd++) {
218		msrv = rdmsr(msr);
219		mrt = mtrr2mrt(msrv & 0xff);
220		if (mrt == MDF_UNKNOWN)
221			mrt = MDF_UNCACHEABLE;
222		mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) | mrt;
223		mrd->mr_base = msrv & mtrrmask;
224		msrv = rdmsr(msr + 1);
225		mrd->mr_flags = (msrv & 0x800) ?
226			(mrd->mr_flags | MDF_ACTIVE) :
227			(mrd->mr_flags & ~MDF_ACTIVE);
228		/* Compute the range from the mask. Ick. */
229		mrd->mr_len = (~(msrv & mtrrmask) & mtrrmask) + 0x1000;
230		if (!mrvalid(mrd->mr_base, mrd->mr_len))
231			mrd->mr_flags |= MDF_BOGUS;
232		/* If unclaimed and active, must be the BIOS */
233		if ((mrd->mr_flags & MDF_ACTIVE) && (mrd->mr_owner[0] == 0))
234			strlcpy(mrd->mr_owner, mem_owner_bios,
235			    sizeof(mrd->mr_owner));
236	}
237}
238
239/*
240 * Return the MTRR memory type matching a region's flags
241 */
242int
243mtrrtype(u_int64_t flags)
244{
245	int i;
246
247	flags &= MDF_ATTRMASK;
248
249	for (i = 0; i < nitems(mtrrtomrt); i++) {
250		if (mtrrtomrt[i] == MDF_UNKNOWN)
251			continue;
252		if (flags == mtrrtomrt[i])
253			return(i);
254	}
255	return MDF_UNCACHEABLE;
256}
257
258int
259mrt2mtrr(u_int64_t flags)
260{
261	int val;
262
263	val = mtrrtype(flags);
264
265	return val & 0xff;
266}
267
268/*
269 * Update running CPU(s) MTRRs to match the ranges in the descriptor
270 * list.
271 *
272 * XXX Must be called with interrupts enabled.
273 */
274void
275mrstore(struct mem_range_softc *sc)
276{
277	u_long s;
278
279	s = intr_disable();
280#ifdef MULTIPROCESSOR
281	x86_broadcast_ipi(X86_IPI_MTRR);
282#endif
283	mrstoreone(sc);
284	intr_restore(s);
285}
286
287/*
288 * Update the current CPU's MTRRs with those represented in the
289 * descriptor list.  Note that we do this wholesale rather than
290 * just stuffing one entry; this is simpler (but slower, of course).
291 */
292void
293mrstoreone(struct mem_range_softc *sc)
294{
295	struct mem_range_desc	*mrd;
296	u_int64_t		 msrv;
297	int			 i, j, msr;
298	u_int			 cr4save;
299
300	mrd = sc->mr_desc;
301
302	cr4save = rcr4();	/* save cr4 */
303	if (cr4save & CR4_PGE)
304		lcr4(cr4save & ~CR4_PGE);
305
306	/* Flush caches, then disable caches, then disable MTRRs */
307	wbinvd();
308	lcr0((rcr0() & ~CR0_NW) | CR0_CD);
309	wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) & ~0x800);
310
311	/* Set fixed-range MTRRs */
312	if (sc->mr_cap & MR_FIXMTRR) {
313		msr = MSR_MTRRfix64K_00000;
314		for (i = 0; i < (MTRR_N64K / 8); i++, msr++) {
315			msrv = 0;
316			for (j = 7; j >= 0; j--) {
317				msrv = msrv << 8;
318				msrv |= mrt2mtrr((mrd + j)->mr_flags);
319			}
320			wrmsr(msr, msrv);
321			mrd += 8;
322		}
323
324		msr = MSR_MTRRfix16K_80000;
325		for (i = 0, msrv = 0; i < (MTRR_N16K / 8); i++, msr++) {
326			for (j = 7; j >= 0; j--) {
327				msrv = msrv << 8;
328				msrv |= mrt2mtrr((mrd + j)->mr_flags);
329			}
330			wrmsr(msr, msrv);
331			mrd += 8;
332		}
333
334		msr = MSR_MTRRfix4K_C0000;
335		for (i = 0, msrv = 0; i < (MTRR_N4K / 8); i++, msr++) {
336			for (j = 7; j >= 0; j--) {
337				msrv = msrv << 8;
338				msrv |= mrt2mtrr((mrd + j)->mr_flags);
339			}
340			wrmsr(msr, msrv);
341			mrd += 8;
342		}
343	}
344
345	/* Set remainder which must be variable MTRRs */
346	msr = MSR_MTRRvarBase;
347	for (; (mrd - sc->mr_desc) < sc->mr_ndesc; msr += 2, mrd++) {
348		if (mrd->mr_flags & MDF_ACTIVE) {
349			msrv = mrd->mr_base & mtrrmask;
350			msrv |= mrt2mtrr(mrd->mr_flags);
351		} else
352			msrv = 0;
353
354		wrmsr(msr, msrv);
355
356		/* mask/active register */
357		if (mrd->mr_flags & MDF_ACTIVE) {
358			msrv = 0x800 | (~(mrd->mr_len - 1) & mtrrmask);
359		} else
360			msrv = 0;
361
362		wrmsr(msr + 1, msrv);
363	}
364
365	/* Re-enable caches and MTRRs */
366	wrmsr(MSR_MTRRdefType, mtrrdef | 0x800);
367	lcr0(rcr0() & ~(CR0_CD | CR0_NW));
368	lcr4(cr4save);
369}
370
371/*
372 * Hunt for the fixed MTRR referencing (addr)
373 */
374struct mem_range_desc *
375mtrrfixsearch(struct mem_range_softc *sc, u_int64_t addr)
376{
377	struct mem_range_desc *mrd;
378	int			i;
379
380	for (i = 0, mrd = sc->mr_desc; i < (MTRR_N64K + MTRR_N16K + MTRR_N4K); i++, mrd++)
381		if ((addr >= mrd->mr_base) && (addr < (mrd->mr_base + mrd->mr_len)))
382			return(mrd);
383	return(NULL);
384}
385
386/*
387 * Try to satisfy the given range request by manipulating the fixed MTRRs that
388 * cover low memory.
389 *
390 * Note that we try to be generous here; we'll bloat the range out to the
391 * next higher/lower boundary to avoid the consumer having to know too much
392 * about the mechanisms here.
393 */
394int
395mrsetlow(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg)
396{
397	struct mem_range_desc	*first_md, *last_md, *curr_md;
398
399	/* range check */
400	if (((first_md = mtrrfixsearch(sc, mrd->mr_base)) == NULL) ||
401	    ((last_md = mtrrfixsearch(sc, mrd->mr_base + mrd->mr_len - 1)) == NULL))
402		return(EINVAL);
403
404	/* check we aren't doing something risky */
405	if (!(mrd->mr_flags & MDF_FORCE))
406		for (curr_md = first_md; curr_md <= last_md; curr_md++) {
407			if ((curr_md->mr_flags & MDF_ATTRMASK) == MDF_UNKNOWN)
408				return (EACCES);
409		}
410
411	/* set flags, clear set-by-firmware flag */
412	for (curr_md = first_md; curr_md <= last_md; curr_md++) {
413		curr_md->mr_flags = mrcopyflags(curr_md->mr_flags & ~MDF_FIRMWARE, mrd->mr_flags);
414		memcpy(curr_md->mr_owner, mrd->mr_owner, sizeof(mrd->mr_owner));
415	}
416
417	return(0);
418}
419
420
421/*
422 * Modify/add a variable MTRR to satisfy the request.
423 */
424int
425mrsetvariable(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg)
426{
427	struct mem_range_desc	*curr_md, *free_md;
428	int			 i;
429
430	/*
431	 * Scan the currently active variable descriptors, look for
432	 * one we exactly match (straight takeover) and for possible
433	 * accidental overlaps.
434	 * Keep track of the first empty variable descriptor in case we
435	 * can't perform a takeover.
436	 */
437	i = (sc->mr_cap & MR_FIXMTRR) ? MTRR_N64K + MTRR_N16K + MTRR_N4K : 0;
438	curr_md = sc->mr_desc + i;
439	free_md = NULL;
440	for (; i < sc->mr_ndesc; i++, curr_md++) {
441		if (curr_md->mr_flags & MDF_ACTIVE) {
442			/* exact match? */
443			if ((curr_md->mr_base == mrd->mr_base) &&
444			    (curr_md->mr_len == mrd->mr_len)) {
445				/* check we aren't doing something risky */
446				if (!(mrd->mr_flags & MDF_FORCE) &&
447				    ((curr_md->mr_flags & MDF_ATTRMASK)
448				    == MDF_UNKNOWN))
449					return (EACCES);
450				/* Ok, just hijack this entry */
451				free_md = curr_md;
452				break;
453			}
454			/* non-exact overlap ? */
455			if (mroverlap(curr_md, mrd)) {
456				/* between conflicting region types? */
457				if (mtrrconflict(curr_md->mr_flags,
458						      mrd->mr_flags))
459					return(EINVAL);
460			}
461		} else if (free_md == NULL) {
462			free_md = curr_md;
463		}
464	}
465	/* got somewhere to put it? */
466	if (free_md == NULL)
467		return(ENOSPC);
468
469	/* Set up new descriptor */
470	free_md->mr_base = mrd->mr_base;
471	free_md->mr_len = mrd->mr_len;
472	free_md->mr_flags = mrcopyflags(MDF_ACTIVE, mrd->mr_flags);
473	memcpy(free_md->mr_owner, mrd->mr_owner, sizeof(mrd->mr_owner));
474	return(0);
475}
476
477/*
478 * Handle requests to set memory range attributes by manipulating MTRRs.
479 */
480int
481mrset(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg)
482{
483	struct mem_range_desc	*targ;
484	int			 error = 0;
485
486	switch(*arg) {
487	case MEMRANGE_SET_UPDATE:
488		/* make sure that what's being asked for is possible */
489		if (!mrvalid(mrd->mr_base, mrd->mr_len) ||
490		    mtrrtype(mrd->mr_flags) == -1)
491			return(EINVAL);
492
493		/* are the "low memory" conditions applicable? */
494		if ((sc->mr_cap & MR_FIXMTRR) &&
495		    ((mrd->mr_base + mrd->mr_len) <= FIXTOP)) {
496			if ((error = mrsetlow(sc, mrd, arg)) != 0)
497				return(error);
498		} else {
499			/* it's time to play with variable MTRRs */
500			if ((error = mrsetvariable(sc, mrd, arg)) != 0)
501				return(error);
502		}
503		break;
504
505	case MEMRANGE_SET_REMOVE:
506		if ((targ = mem_range_match(sc, mrd)) == NULL)
507			return(ENOENT);
508		if (targ->mr_flags & MDF_FIXACTIVE)
509			return(EPERM);
510		targ->mr_flags &= ~MDF_ACTIVE;
511		targ->mr_owner[0] = 0;
512		break;
513
514	default:
515		return(EOPNOTSUPP);
516	}
517
518	/* update the hardware */
519	mrstore(sc);
520	return(0);
521}
522
523/*
524 * Work out how many ranges we support, initialise storage for them,
525 * fetch the initial settings.
526 */
527void
528mrinit(struct mem_range_softc *sc)
529{
530	struct mem_range_desc	*mrd;
531	uint32_t		 regs[4];
532	int			 nmdesc = 0;
533	int			 i;
534
535	mtrrcap = rdmsr(MSR_MTRRcap);
536	mtrrdef = rdmsr(MSR_MTRRdefType);
537
538	/* For now, bail out if MTRRs are not enabled */
539	if (!(mtrrdef & MTRRdefType_ENABLE)) {
540		printf("mtrr: CPU supports MTRRs but not enabled by BIOS\n");
541		return;
542	}
543	nmdesc = mtrrcap & 0xff;
544	printf("mtrr: Pentium Pro MTRR support, %d var ranges", nmdesc);
545
546	/* If fixed MTRRs supported and enabled */
547	if ((mtrrcap & MTRRcap_FIXED) &&
548	    (mtrrdef & MTRRdefType_FIXED_ENABLE)) {
549		sc->mr_cap = MR_FIXMTRR;
550		nmdesc += MTRR_N64K + MTRR_N16K + MTRR_N4K;
551		printf(", %d fixed ranges", MTRR_N64K + MTRR_N16K + MTRR_N4K);
552	}
553
554	printf("\n");
555
556	sc->mr_desc = mallocarray(nmdesc, sizeof(struct mem_range_desc),
557	     M_MEMDESC, M_WAITOK|M_ZERO);
558	sc->mr_ndesc = nmdesc;
559
560	mrd = sc->mr_desc;
561
562	/* Populate the fixed MTRR entries' base/length */
563	if (sc->mr_cap & MR_FIXMTRR) {
564		for (i = 0; i < MTRR_N64K; i++, mrd++) {
565			mrd->mr_base = i * 0x10000;
566			mrd->mr_len = 0x10000;
567			mrd->mr_flags = MDF_FIXBASE | MDF_FIXLEN | MDF_FIXACTIVE;
568		}
569
570		for (i = 0; i < MTRR_N16K; i++, mrd++) {
571			mrd->mr_base = i * 0x4000 + 0x80000;
572			mrd->mr_len = 0x4000;
573			mrd->mr_flags = MDF_FIXBASE | MDF_FIXLEN | MDF_FIXACTIVE;
574		}
575
576		for (i = 0; i < MTRR_N4K; i++, mrd++) {
577			mrd->mr_base = i * 0x1000 + 0xc0000;
578			mrd->mr_len = 0x1000;
579			mrd->mr_flags = MDF_FIXBASE | MDF_FIXLEN | MDF_FIXACTIVE;
580		}
581	}
582
583	/*
584	 * Fetch maximum physical address size supported by the
585	 * processor as supported by CPUID leaf function 0x80000008.
586	 * If CPUID does not support leaf function 0x80000008, use the
587	 * default 36-bit address size.
588	 */
589	if (curcpu()->ci_pnfeatset >= 0x80000008) {
590		CPUID(0x80000008, regs[0], regs[1], regs[2], regs[3]);
591		if (regs[0] & 0xff) {
592			mtrrmask = (1ULL << (regs[0] & 0xff)) - 1;
593			mtrrmask &= ~0x0000000000000fffULL;
594		}
595	}
596
597	/*
598	 * Get current settings, anything set now is considered to have
599	 * been set by the firmware.
600	 */
601	mrfetch(sc);
602	mrd = sc->mr_desc;
603	for (i = 0; i < sc->mr_ndesc; i++, mrd++) {
604		if (mrd->mr_flags & MDF_ACTIVE)
605			mrd->mr_flags |= MDF_FIRMWARE;
606	}
607}
608
609/*
610 * Initialise MTRRs on a cpu from the software state.
611 */
612void
613mrinit_cpu(struct mem_range_softc *sc)
614{
615	mrstoreone(sc); /* set MTRRs to match BSP */
616}
617
618void
619mrreload_cpu(struct mem_range_softc *sc)
620{
621	u_long s;
622
623	s = intr_disable();
624	mrstoreone(sc); /* set MTRRs to match BSP */
625	intr_restore(s);
626}
627