Home | History | Annotate | Line # | Download | only in x86
      1 /*	$NetBSD: mtrr_i686.c,v 1.32 2021/10/07 12:52:27 msaitoh Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2000, 2011 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Bill Sommerfeld.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: mtrr_i686.c,v 1.32 2021/10/07 12:52:27 msaitoh Exp $");
     34 
     35 #include "opt_multiprocessor.h"
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 
     40 #include <sys/atomic.h>
     41 #include <sys/cpu.h>
     42 #include <sys/kmem.h>
     43 #include <sys/proc.h>
     44 
     45 #include <uvm/uvm_extern.h>
     46 
     47 #include <machine/specialreg.h>
     48 #include <machine/cpuvar.h>
     49 #include <machine/cpufunc.h>
     50 #include <machine/mtrr.h>
     51 
     52 extern paddr_t avail_end;
     53 
     54 static void i686_mtrr_reload(int);
     55 static void i686_mtrr_init_cpu(struct cpu_info *);
     56 static void i686_mtrr_reload_cpu(struct cpu_info *);
     57 static void i686_mtrr_clean(struct proc *p);
     58 static int i686_mtrr_set(struct mtrr *, int *n, struct proc *p, int flags);
     59 static int i686_mtrr_get(struct mtrr *, int *n, struct proc *p, int flags);
     60 static void i686_mtrr_dump(const char *tag);
     61 
     62 static int i686_mtrr_validate(struct mtrr *, struct proc *p);
     63 static void i686_soft2raw(void);
     64 static void i686_raw2soft(void);
     65 static void i686_mtrr_commit(void);
     66 static int i686_mtrr_setone(struct mtrr *, struct proc *p);
     67 static int i686_mtrr_conflict(uint8_t, uint8_t);
     68 
     69 static struct mtrr_state
     70 mtrr_raw[] = {
     71 	{ MSR_MTRRphysBase0, 0 },
     72 	{ MSR_MTRRphysMask0, 0 },
     73 	{ MSR_MTRRphysBase1, 0 },
     74 	{ MSR_MTRRphysMask1, 0 },
     75 	{ MSR_MTRRphysBase2, 0 },
     76 	{ MSR_MTRRphysMask2, 0 },
     77 	{ MSR_MTRRphysBase3, 0 },
     78 	{ MSR_MTRRphysMask3, 0 },
     79 	{ MSR_MTRRphysBase4, 0 },
     80 	{ MSR_MTRRphysMask4, 0 },
     81 	{ MSR_MTRRphysBase5, 0 },
     82 	{ MSR_MTRRphysMask5, 0 },
     83 	{ MSR_MTRRphysBase6, 0 },
     84 	{ MSR_MTRRphysMask6, 0 },
     85 	{ MSR_MTRRphysBase7, 0 },
     86 	{ MSR_MTRRphysMask7, 0 },
     87 	{ MSR_MTRRphysBase8, 0 },
     88 	{ MSR_MTRRphysMask8, 0 },
     89 	{ MSR_MTRRphysBase9, 0 },
     90 	{ MSR_MTRRphysMask9, 0 },
     91 	{ MSR_MTRRphysBase10, 0 },
     92 	{ MSR_MTRRphysMask10, 0 },
     93 	{ MSR_MTRRphysBase11, 0 },
     94 	{ MSR_MTRRphysMask11, 0 },
     95 	{ MSR_MTRRphysBase12, 0 },
     96 	{ MSR_MTRRphysMask12, 0 },
     97 	{ MSR_MTRRphysBase13, 0 },
     98 	{ MSR_MTRRphysMask13, 0 },
     99 	{ MSR_MTRRphysBase14, 0 },
    100 	{ MSR_MTRRphysMask14, 0 },
    101 	{ MSR_MTRRphysBase15, 0 },
    102 	{ MSR_MTRRphysMask15, 0 },
    103 	{ MSR_MTRRfix64K_00000, 0 },
    104 	{ MSR_MTRRfix16K_80000, 0 },
    105 	{ MSR_MTRRfix16K_A0000, 0 },
    106 	{ MSR_MTRRfix4K_C0000, 0 },
    107 	{ MSR_MTRRfix4K_C8000, 0 },
    108 	{ MSR_MTRRfix4K_D0000, 0 },
    109 	{ MSR_MTRRfix4K_D8000, 0 },
    110 	{ MSR_MTRRfix4K_E0000, 0 },
    111 	{ MSR_MTRRfix4K_E8000, 0 },
    112 	{ MSR_MTRRfix4K_F0000, 0 },
    113 	{ MSR_MTRRfix4K_F8000, 0 },
    114 	{ MSR_MTRRdefType, 0 },
    115 
    116 };
    117 
    118 static const int nmtrr_raw = __arraycount(mtrr_raw);
    119 static int i686_mtrr_vcnt = 0;
    120 
    121 static struct mtrr_state *mtrr_var_raw;
    122 static struct mtrr_state *mtrr_fixed_raw;
    123 
    124 static struct mtrr *mtrr_fixed;
    125 static struct mtrr *mtrr_var;
    126 
    127 const struct mtrr_funcs i686_mtrr_funcs = {
    128 	i686_mtrr_init_cpu,
    129 	i686_mtrr_reload_cpu,
    130 	i686_mtrr_clean,
    131 	i686_mtrr_set,
    132 	i686_mtrr_get,
    133 	i686_mtrr_commit,
    134 	i686_mtrr_dump
    135 };
    136 
    137 static kcpuset_t *		mtrr_waiting;
    138 
    139 static uint64_t			i686_mtrr_cap;
    140 
    141 static void
    142 i686_mtrr_dump(const char *tag)
    143 {
    144 	int i;
    145 
    146 	for (i = 0; i < nmtrr_raw; i++)
    147 		printf("%s: %x: %016llx\n",
    148 		    tag, mtrr_raw[i].msraddr,
    149 		    (unsigned long long)rdmsr(mtrr_raw[i].msraddr));
    150 }
    151 
    152 /*
    153  * The Intel Archicture Software Developer's Manual volume 3 (systems
    154  * programming) section 9.12.8 describes a simple 15-step process for
    155  * updating the MTRR's on all processors on a multiprocessor system.
    156  * If synch is nonzero, assume we're being called from an IPI handler,
    157  * and synchronize with all running processors.
    158  */
    159 
    160 /*
    161  * 1. Broadcast to all processor to execute the following code sequence.
    162  */
    163 
    164 static void
    165 i686_mtrr_reload(int synch)
    166 {
    167 	int i;
    168 	/* XXX cr0 is 64-bit on amd64 too, but the upper bits are
    169 	 * unused and must be zero so it does not matter too
    170 	 * much. Need to change the prototypes of l/rcr0 too if you
    171 	 * want to correct it. */
    172 	uint32_t cr0;
    173 	vaddr_t cr4;
    174 	uint32_t origcr0;
    175 	vaddr_t origcr4;
    176 
    177 	/*
    178 	 * 2. Disable interrupts
    179 	 */
    180 	x86_disable_intr();
    181 
    182 #ifdef MULTIPROCESSOR
    183 	if (synch) {
    184 		/*
    185 		 * 3. Wait for all processors to reach this point.
    186 		 */
    187 		kcpuset_atomic_set(mtrr_waiting, cpu_index(curcpu()));
    188 		while (!kcpuset_match(mtrr_waiting, kcpuset_running)) {
    189 			DELAY(10);
    190 		}
    191 	}
    192 #endif
    193 
    194 	/*
    195 	 * 4. Enter the no-fill cache mode (set the CD flag in CR0 to 1 and
    196 	 * the NW flag to 0)
    197 	 */
    198 
    199 	origcr0 = cr0 = rcr0();
    200 	cr0 |= CR0_CD;
    201 	cr0 &= ~CR0_NW;
    202 	lcr0(cr0);
    203 
    204 	/*
    205 	 * 5. Flush all caches using the WBINVD instruction.
    206 	 */
    207 
    208 	wbinvd();
    209 
    210 	/*
    211 	 * 6. Clear the PGE flag in control register CR4 (if set).
    212 	 */
    213 
    214 	origcr4 = cr4 = rcr4();
    215 	cr4 &= ~CR4_PGE;
    216 	lcr4(cr4);
    217 
    218 	/*
    219 	 * 7. Flush all TLBs (execute a MOV from control register CR3
    220 	 * to another register and then a move from that register back
    221 	 * to CR3)
    222 	 */
    223 
    224 	tlbflush();
    225 
    226 	/*
    227 	 * 8. Disable all range registers (by clearing the E flag in
    228 	 * register MTRRdefType.  If only variable ranges are being
    229 	 * modified, software may clear the valid bits for the
    230 	 * affected register pairs instead.
    231 	 */
    232 	/* disable MTRRs (E = 0) */
    233 	wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) & ~MTRR_I686_ENABLE_MASK);
    234 
    235 	/*
    236 	 * 9. Update the MTRR's
    237 	 */
    238 
    239 	for (i = 0; i < nmtrr_raw; i++) {
    240 		uint64_t val = mtrr_raw[i].msrval;
    241 		uint32_t addr = mtrr_raw[i].msraddr;
    242 		if (addr == 0)
    243 			continue;
    244 		if (addr == MSR_MTRRdefType)
    245 			val &= ~MTRR_I686_ENABLE_MASK;
    246 		wrmsr(addr, val);
    247 	}
    248 
    249 	/*
    250 	 * 10. Enable all range registers (by setting the E flag in
    251 	 * register MTRRdefType).  If only variable-range registers
    252 	 * were modified and their individual valid bits were cleared,
    253 	 * then set the valid bits for the affected ranges instead.
    254 	 */
    255 
    256 	wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) | MTRR_I686_ENABLE_MASK);
    257 
    258 	/*
    259 	 * 11. Flush all caches and all TLB's a second time. (repeat
    260 	 * steps 5, 7)
    261 	 */
    262 
    263 	wbinvd();
    264 	tlbflush();
    265 
    266 	/*
    267 	 * 12. Enter the normal cache mode to reenable caching (set the CD and
    268 	 * NW flags in CR0 to 0)
    269 	 */
    270 
    271 	lcr0(origcr0);
    272 
    273 	/*
    274 	 * 13. Set the PGE flag in control register CR4, if previously
    275 	 * cleared.
    276 	 */
    277 
    278 	lcr4(origcr4);
    279 
    280 #ifdef MULTIPROCESSOR
    281 	if (synch) {
    282 		/*
    283 		 * 14. Wait for all processors to reach this point.
    284 		 */
    285 		kcpuset_atomic_clear(mtrr_waiting, cpu_index(curcpu()));
    286 		while (!kcpuset_iszero(mtrr_waiting)) {
    287 			DELAY(10);
    288 		}
    289 	}
    290 #endif
    291 
    292 	/*
    293 	 * 15. Enable interrupts.
    294 	 */
    295 	x86_enable_intr();
    296 }
    297 
    298 static void
    299 i686_mtrr_reload_cpu(struct cpu_info *ci)
    300 {
    301 	i686_mtrr_reload(1);
    302 }
    303 
    304 void
    305 i686_mtrr_init_first(void)
    306 {
    307 	int i;
    308 
    309 	i686_mtrr_cap = rdmsr(MSR_MTRRcap);
    310 	i686_mtrr_vcnt = i686_mtrr_cap & MTRR_I686_CAP_VCNT_MASK;
    311 
    312 	if (i686_mtrr_vcnt > MTRR_I686_NVAR_MAX)
    313 		printf("%s: FIXME: more than %d MTRRs (%d)\n", __FILE__,
    314 		    MTRR_I686_NVAR_MAX, i686_mtrr_vcnt);
    315 	else if (i686_mtrr_vcnt < MTRR_I686_NVAR_MAX) {
    316 		for (i = MTRR_I686_NVAR_MAX - i686_mtrr_vcnt; i; i--) {
    317 			mtrr_raw[(MTRR_I686_NVAR_MAX - i) * 2].msraddr = 0;
    318 			mtrr_raw[(MTRR_I686_NVAR_MAX - i) * 2 + 1].msraddr = 0;
    319 		}
    320 	}
    321 
    322 	for (i = 0; i < nmtrr_raw; i++) {
    323 		if (mtrr_raw[i].msraddr)
    324 			mtrr_raw[i].msrval = rdmsr(mtrr_raw[i].msraddr);
    325 		else
    326 			mtrr_raw[i].msrval = 0;
    327 	}
    328 #if 0
    329 	mtrr_dump("init mtrr");
    330 #endif
    331 
    332 	kcpuset_create(&mtrr_waiting, true);
    333 
    334 	mtrr_fixed =
    335 	    kmem_zalloc(MTRR_I686_NFIXED_SOFT * sizeof(struct mtrr), KM_SLEEP);
    336 
    337 	if (i686_mtrr_vcnt) {
    338 		mtrr_var =
    339 		    kmem_zalloc(i686_mtrr_vcnt * sizeof(struct mtrr), KM_SLEEP);
    340 	}
    341 
    342 	mtrr_var_raw = &mtrr_raw[0];
    343 	mtrr_fixed_raw = &mtrr_raw[MTRR_I686_NVAR_MAX * 2];
    344 	mtrr_funcs = &i686_mtrr_funcs;
    345 
    346 	i686_raw2soft();
    347 }
    348 
    349 static void
    350 i686_raw2soft(void)
    351 {
    352 	int i, j, idx;
    353 	struct mtrr *mtrrp;
    354 	uint64_t base, mask;
    355 
    356 	for (i = 0; i < i686_mtrr_vcnt; i++) {
    357 		mtrrp = &mtrr_var[i];
    358 		memset(mtrrp, 0, sizeof *mtrrp);
    359 		mask = mtrr_var_raw[i * 2 + 1].msrval;
    360 		if (!mtrr_valid(mask))
    361 			continue;
    362 		base = mtrr_var_raw[i * 2].msrval;
    363 		mtrrp->base = mtrr_base(base);
    364 		mtrrp->type = mtrr_type(base);
    365 		mtrrp->len = mtrr_len(mask);
    366 		mtrrp->flags |= MTRR_VALID;
    367 	}
    368 
    369 	idx = 0;
    370 	base = 0;
    371 	for (i = 0; i < MTRR_I686_NFIXED_64K; i++, idx++) {
    372 		mask = mtrr_fixed_raw[idx].msrval;
    373 		for (j = 0; j < 8; j++) {
    374 			mtrrp = &mtrr_fixed[idx * 8 + j];
    375 			mtrrp->owner = 0;
    376 			mtrrp->flags = MTRR_FIXED | MTRR_VALID;
    377 			mtrrp->base = base;
    378 			mtrrp->len = 65536;
    379 			mtrrp->type = mask & 0xff;
    380 			mask >>= 8;
    381 			base += 65536;
    382 		}
    383 	}
    384 
    385 	for (i = 0; i < MTRR_I686_NFIXED_16K; i++, idx++) {
    386 		mask = mtrr_fixed_raw[idx].msrval;
    387 		for (j = 0; j < 8; j++) {
    388 			mtrrp = &mtrr_fixed[idx * 8 + j];
    389 			mtrrp->owner = 0;
    390 			mtrrp->flags = MTRR_FIXED | MTRR_VALID;
    391 			mtrrp->base = base;
    392 			mtrrp->len = 16384;
    393 			mtrrp->type = mask & 0xff;
    394 			mask >>= 8;
    395 			base += 16384;
    396 		}
    397 	}
    398 
    399 	for (i = 0; i < MTRR_I686_NFIXED_4K; i++, idx++) {
    400 		mask = mtrr_fixed_raw[idx].msrval;
    401 		for (j = 0; j < 8; j++) {
    402 			mtrrp = &mtrr_fixed[idx * 8 + j];
    403 			mtrrp->owner = 0;
    404 			mtrrp->flags = MTRR_FIXED | MTRR_VALID;
    405 			mtrrp->base = base;
    406 			mtrrp->len = 4096;
    407 			mtrrp->type = mask & 0xff;
    408 			mask >>= 8;
    409 			base += 4096;
    410 		}
    411 	}
    412 }
    413 
    414 static void
    415 i686_soft2raw(void)
    416 {
    417 	int i, idx, j;
    418 	uint64_t val;
    419 	struct mtrr *mtrrp;
    420 
    421 	for (i = 0; i < i686_mtrr_vcnt; i++) {
    422 		mtrrp = &mtrr_var[i];
    423 		mtrr_var_raw[i * 2].msrval = mtrr_base_value(mtrrp);
    424 		mtrr_var_raw[i * 2 + 1].msrval = mtrr_mask_value(mtrrp);
    425 		if (mtrrp->flags & MTRR_VALID)
    426 			mtrr_var_raw[i * 2 + 1].msrval |= MTRR_I686_MASK_VALID;
    427 	}
    428 
    429 	idx = 0;
    430 	for (i = 0; i < MTRR_I686_NFIXED_64K; i++, idx++) {
    431 		val = 0;
    432 		for (j = 0; j < 8; j++) {
    433 			mtrrp = &mtrr_fixed[idx * 8 + j];
    434 			val |= ((uint64_t)mtrrp->type << (j << 3));
    435 		}
    436 		mtrr_fixed_raw[idx].msrval = val;
    437 	}
    438 
    439 	for (i = 0; i < MTRR_I686_NFIXED_16K; i++, idx++) {
    440 		val = 0;
    441 		for (j = 0; j < 8; j++) {
    442 			mtrrp = &mtrr_fixed[idx * 8 + j];
    443 			val |= ((uint64_t)mtrrp->type << (j << 3));
    444 		}
    445 		mtrr_fixed_raw[idx].msrval = val;
    446 	}
    447 
    448 	for (i = 0; i < MTRR_I686_NFIXED_4K; i++, idx++) {
    449 		val = 0;
    450 		for (j = 0; j < 8; j++) {
    451 			mtrrp = &mtrr_fixed[idx * 8 + j];
    452 			val |= ((uint64_t)mtrrp->type << (j << 3));
    453 		}
    454 		mtrr_fixed_raw[idx].msrval = val;
    455 	}
    456 }
    457 
    458 static void
    459 i686_mtrr_init_cpu(struct cpu_info *ci)
    460 {
    461 	i686_mtrr_reload(0);
    462 #if 0
    463 	mtrr_dump(device_xname(ci->ci_dev));
    464 #endif
    465 }
    466 
    467 static int
    468 i686_mtrr_validate(struct mtrr *mtrrp, struct proc *p)
    469 {
    470 	uint64_t high;
    471 
    472 	/*
    473 	 * Must be at least page-aligned.
    474 	 */
    475 	if (mtrrp->base & 0xfff || mtrrp->len & 0xfff || mtrrp->len == 0)
    476 		return EINVAL;
    477 
    478 	/*
    479 	 * Private mappings are bound to a process.
    480 	 */
    481 	if (p == NULL && (mtrrp->flags & MTRR_PRIVATE))
    482 		return EINVAL;
    483 
    484 	high = mtrrp->base + mtrrp->len;
    485 
    486 	/*
    487 	 * Check for bad types.
    488 	 */
    489 	if ((mtrrp->type == MTRR_TYPE_UNDEF1 || mtrrp->type == MTRR_TYPE_UNDEF2
    490 	    || mtrrp->type > MTRR_TYPE_WB) && (mtrrp->flags & MTRR_VALID))
    491 		return EINVAL;
    492 
    493 	/*
    494 	 * If write-combining is requested, make sure that the WC feature
    495 	 * is supported by the processor.
    496 	 */
    497 	if (mtrrp->type == MTRR_TYPE_WC &&
    498 	    !(i686_mtrr_cap & MTRR_I686_CAP_WC_MASK))
    499 		return ENODEV;
    500 
    501 	/*
    502 	 * Only use fixed ranges < 1M.
    503 	 */
    504 	if ((mtrrp->flags & MTRR_FIXED) && high > 0x100000)
    505 		return EINVAL;
    506 
    507 	/*
    508 	 * Check for the right alignment and size for fixed ranges.
    509 	 * The requested range may span several actual MTRRs, but
    510 	 * it must be properly aligned.
    511 	 */
    512 	if (mtrrp->flags & MTRR_FIXED) {
    513 		if (mtrrp->base < MTRR_I686_16K_START) {
    514 			if ((mtrrp->base  & 0xffff) != 0)
    515 				return EINVAL;
    516 		} else if (mtrrp->base < MTRR_I686_4K_START) {
    517 			if ((mtrrp->base & 0x3fff) != 0)
    518 				return EINVAL;
    519 		} else {
    520 			if ((mtrrp->base  & 0xfff) != 0)
    521 				return EINVAL;
    522 		}
    523 
    524 		if (high < MTRR_I686_16K_START) {
    525 			if ((high  & 0xffff) != 0)
    526 				return EINVAL;
    527 		} else if (high < MTRR_I686_4K_START) {
    528 			if ((high & 0x3fff) != 0)
    529 				return EINVAL;
    530 		} else {
    531 			if ((high & 0xfff) != 0)
    532 				return EINVAL;
    533 		}
    534 	}
    535 
    536 	return 0;
    537 }
    538 
    539 /*
    540  * Try to find a non-conflicting match on physical MTRRs for the
    541  * requested range. For fixed ranges, more than one actual MTRR
    542  * may be used.
    543  */
    544 static int
    545 i686_mtrr_setone(struct mtrr *mtrrp, struct proc *p)
    546 {
    547 	int i, error;
    548 	struct mtrr *lowp, *highp, *mp, *freep;
    549 	uint64_t low, high, curlow, curhigh;
    550 
    551 	/*
    552 	 * If explicitly requested, or if the range lies below 1M,
    553 	 * try the fixed range MTRRs.
    554 	 */
    555 	if (mtrrp->flags & MTRR_FIXED ||
    556 	    (mtrrp->base + mtrrp->len) <= 0x100000) {
    557 		lowp = highp = NULL;
    558 		for (i = 0; i < MTRR_I686_NFIXED_SOFT; i++) {
    559 			if (mtrr_fixed[i].base == mtrrp->base + mtrrp->len) {
    560 				highp = &mtrr_fixed[i];
    561 				break;
    562 			}
    563 			if (mtrr_fixed[i].base == mtrrp->base) {
    564 				lowp = &mtrr_fixed[i];
    565 				/*
    566 				 * If the requested upper bound is the 1M
    567 				 * limit, search no further.
    568 				 */
    569 				if ((mtrrp->base + mtrrp->len) == 0x100000) {
    570 					highp =
    571 					    &mtrr_fixed[MTRR_I686_NFIXED_SOFT];
    572 					break;
    573 				} else {
    574 					highp = &mtrr_fixed[i + 1];
    575 					continue;
    576 				}
    577 			}
    578 		}
    579 		if (lowp == NULL || highp == NULL)
    580 			panic("mtrr: fixed register screwup");
    581 		error = 0;
    582 		for (mp = lowp; mp < highp; mp++) {
    583 			if ((mp->flags & MTRR_PRIVATE) && p != NULL
    584 			     && p->p_pid != mp->owner) {
    585 				error = EBUSY;
    586 				break;
    587 			}
    588 		}
    589 		if (error != 0) {
    590 			if (mtrrp->flags & MTRR_FIXED)
    591 				return error;
    592 		} else {
    593 			for (mp = lowp; mp < highp; mp++) {
    594 				/*
    595 				 * Can't invalidate fixed ranges, so
    596 				 * just reset the 'private' flag,
    597 				 * making the range available for
    598 				 * changing again.
    599 				 */
    600 				if (!(mtrrp->flags & MTRR_VALID)) {
    601 					mp->flags &= ~MTRR_PRIVATE;
    602 					continue;
    603 				}
    604 				mp->type = mtrrp->type;
    605 				if (mtrrp->flags & MTRR_PRIVATE) {
    606 					/*
    607 					 * Private mappings are bound to a
    608 					 * process. This has been checked in
    609 					 * i686_mtrr_validate()
    610 					 */
    611 					mp->flags |= MTRR_PRIVATE;
    612 					mp->owner = p->p_pid;
    613 				}
    614 			}
    615 			return 0;
    616 		}
    617 	}
    618 
    619 	/*
    620 	 * Try one of the variable range registers.
    621 	 * XXX could be more sophisticated here by merging ranges.
    622 	 */
    623 	low = mtrrp->base;
    624 	high = low + mtrrp->len - 1;
    625 	freep = NULL;
    626 	for (i = 0; i < i686_mtrr_vcnt; i++) {
    627 		if (!(mtrr_var[i].flags & MTRR_VALID)) {
    628 			freep = &mtrr_var[i];
    629 			continue;
    630 		}
    631 		curlow = mtrr_var[i].base;
    632 		curhigh = curlow + mtrr_var[i].len - 1;
    633 		if (low == curlow && high == curhigh &&
    634 		    (!(mtrr_var[i].flags & MTRR_PRIVATE) ||
    635 		     ((mtrrp->flags & MTRR_PRIVATE) && (p != NULL) &&
    636 		      (mtrr_var[i].owner == p->p_pid)))) {
    637 			freep = &mtrr_var[i];
    638 			break;
    639 		}
    640 		if (((high >= curlow && high < curhigh) ||
    641 		    (low >= curlow && low < curhigh)) &&
    642 		    (i686_mtrr_conflict(mtrr_var[i].type, mtrrp->type) ||
    643 		     ((mtrr_var[i].flags & MTRR_PRIVATE) &&
    644 		      (!(mtrrp->flags & MTRR_PRIVATE) || (p == NULL) ||
    645 		       (mtrr_var[i].owner != p->p_pid))))) {
    646 			return EBUSY;
    647 		}
    648 	}
    649 	if (freep == NULL)
    650 		return EBUSY;
    651 	mtrrp->flags &= ~MTRR_CANTSET;
    652 	*freep = *mtrrp;
    653 	freep->owner = (mtrrp->flags & MTRR_PRIVATE) ? p->p_pid : 0;
    654 
    655 	return 0;
    656 }
    657 
    658 static int
    659 i686_mtrr_conflict(uint8_t type1, uint8_t type2)
    660 {
    661 	if (type1 == MTRR_TYPE_UC || type2 == MTRR_TYPE_UC)
    662 		return 0;
    663 	if ((type1 == MTRR_TYPE_WT && type2 == MTRR_TYPE_WB) ||
    664 	    (type1 == MTRR_TYPE_WB && type2 == MTRR_TYPE_WT))
    665 		return 0;
    666 	return 1;
    667 }
    668 
    669 static void
    670 i686_mtrr_clean(struct proc *p)
    671 {
    672 	int i;
    673 
    674 	for (i = 0; i < MTRR_I686_NFIXED_SOFT; i++) {
    675 		if ((mtrr_fixed[i].flags & MTRR_PRIVATE) &&
    676 		    (mtrr_fixed[i].owner == p->p_pid))
    677 			mtrr_fixed[i].flags &= ~MTRR_PRIVATE;
    678 	}
    679 
    680 	for (i = 0; i < i686_mtrr_vcnt; i++) {
    681 		if ((mtrr_var[i].flags & MTRR_PRIVATE) &&
    682 		    (mtrr_var[i].owner == p->p_pid))
    683 			mtrr_var[i].flags &= ~(MTRR_PRIVATE | MTRR_VALID);
    684 	}
    685 
    686 	i686_mtrr_commit();
    687 }
    688 
    689 static int
    690 i686_mtrr_set(struct mtrr *mtrrp, int *n, struct proc *p, int flags)
    691 {
    692 	int i, error;
    693 	struct mtrr mtrr;
    694 
    695 	if (*n > (MTRR_I686_NFIXED_SOFT + MTRR_I686_NVAR_MAX)) {
    696 		*n = 0;
    697 		return EINVAL;
    698 	}
    699 
    700 	error = 0;
    701 	for (i = 0; i < *n; i++) {
    702 		if (flags & MTRR_GETSET_USER) {
    703 			error = copyin(&mtrrp[i], &mtrr, sizeof mtrr);
    704 			if (error != 0)
    705 				break;
    706 		} else
    707 			mtrr = mtrrp[i];
    708 		error = i686_mtrr_validate(&mtrr, p);
    709 		if (error != 0)
    710 			break;
    711 		error = i686_mtrr_setone(&mtrr, p);
    712 		if (error != 0)
    713 			break;
    714 		if (mtrr.flags & MTRR_PRIVATE)
    715 			p->p_md.md_flags |= MDP_USEDMTRR;
    716 	}
    717 	*n = i;
    718 	return error;
    719 }
    720 
    721 static int
    722 i686_mtrr_get(struct mtrr *mtrrp, int *n, struct proc *p, int flags)
    723 {
    724 	int idx, i, error;
    725 
    726 	if (mtrrp == NULL) {
    727 		*n = MTRR_I686_NFIXED_SOFT + MTRR_I686_NVAR_MAX;
    728 		return 0;
    729 	}
    730 
    731 	error = 0;
    732 
    733 	for (idx = i = 0; i < MTRR_I686_NFIXED_SOFT && idx < *n; idx++, i++) {
    734 		if (flags & MTRR_GETSET_USER) {
    735 			error = copyout(&mtrr_fixed[i], &mtrrp[idx],
    736 					sizeof *mtrrp);
    737 			if (error != 0)
    738 				break;
    739 		} else
    740 			memcpy(&mtrrp[idx], &mtrr_fixed[i], sizeof *mtrrp);
    741 	}
    742 	if (error != 0) {
    743 		*n = idx;
    744 		return error;
    745 	}
    746 
    747 	for (i = 0; i < i686_mtrr_vcnt && idx < *n; idx++, i++) {
    748 		if (flags & MTRR_GETSET_USER) {
    749 			error = copyout(&mtrr_var[i], &mtrrp[idx],
    750 					sizeof *mtrrp);
    751 			if (error != 0)
    752 				break;
    753 		} else
    754 			memcpy(&mtrrp[idx], &mtrr_var[i], sizeof *mtrrp);
    755 	}
    756 	*n = idx;
    757 	return error;
    758 }
    759 
    760 static void
    761 i686_mtrr_commit(void)
    762 {
    763 
    764 	i686_soft2raw();
    765 	kpreempt_disable();
    766 #ifdef MULTIPROCESSOR
    767 	x86_broadcast_ipi(X86_IPI_MTRR);
    768 #endif
    769 	i686_mtrr_reload(1);
    770 	kpreempt_enable();
    771 }
    772