Annotation of sys/arch/i386/i386/i686_mem.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: i686_mem.c,v 1.9 2006/09/19 11:06:33 jsg 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/kernel.h>
! 32: #include <sys/systm.h>
! 33: #include <sys/malloc.h>
! 34: #include <sys/memrange.h>
! 35:
! 36: #include <machine/cpufunc.h>
! 37: #include <machine/specialreg.h>
! 38:
! 39: /*
! 40: * i686 memory range operations
! 41: *
! 42: * This code will probably be impenetrable without reference to the
! 43: * Intel Pentium Pro documentation.
! 44: */
! 45:
! 46: char *mem_owner_bios = "BIOS";
! 47:
! 48: #define MR686_FIXMTRR (1<<0)
! 49:
! 50: #define mrwithin(mr, a) \
! 51: (((a) >= (mr)->mr_base) && ((a) < ((mr)->mr_base + (mr)->mr_len)))
! 52: #define mroverlap(mra, mrb) \
! 53: (mrwithin(mra, mrb->mr_base) || mrwithin(mrb, mra->mr_base))
! 54:
! 55: #define mrvalid(base, len) \
! 56: ((!(base & ((1 << 12) - 1))) && /* base is multiple of 4k */ \
! 57: ((len) >= (1 << 12)) && /* length is >= 4k */ \
! 58: powerof2((len)) && /* ... and power of two */ \
! 59: !((base) & ((len) - 1))) /* range is not discontiuous */
! 60:
! 61: #define mrcopyflags(curr, new) (((curr) & ~MDF_ATTRMASK) | ((new) & MDF_ATTRMASK))
! 62:
! 63: void i686_mrinit(struct mem_range_softc *sc);
! 64: int i686_mrset(struct mem_range_softc *sc,
! 65: struct mem_range_desc *mrd,
! 66: int *arg);
! 67: void i686_mrAPinit(struct mem_range_softc *sc);
! 68:
! 69: struct mem_range_ops i686_mrops = {
! 70: i686_mrinit,
! 71: i686_mrset,
! 72: i686_mrAPinit
! 73: };
! 74:
! 75: /* XXX for AP startup hook */
! 76: u_int64_t mtrrcap, mtrrdef;
! 77:
! 78: struct mem_range_desc *mem_range_match(struct mem_range_softc *sc,
! 79: struct mem_range_desc *mrd);
! 80: void i686_mrfetch(struct mem_range_softc *sc);
! 81: int i686_mtrrtype(int flags);
! 82: int i686_mrt2mtrr(int flags, int oldval);
! 83: int i686_mtrr2mrt(int val);
! 84: int i686_mtrrconflict(int flag1, int flag2);
! 85: void i686_mrstore(struct mem_range_softc *sc);
! 86: void i686_mrstoreone(void *arg);
! 87: struct mem_range_desc *i686_mtrrfixsearch(struct mem_range_softc *sc,
! 88: u_int64_t addr);
! 89: int i686_mrsetlow(struct mem_range_softc *sc,
! 90: struct mem_range_desc *mrd,
! 91: int *arg);
! 92: int i686_mrsetvariable(struct mem_range_softc *sc,
! 93: struct mem_range_desc *mrd,
! 94: int *arg);
! 95:
! 96: /* i686 MTRR type to memory range type conversion */
! 97: int i686_mtrrtomrt[] = {
! 98: MDF_UNCACHEABLE,
! 99: MDF_WRITECOMBINE,
! 100: MDF_UNKNOWN,
! 101: MDF_UNKNOWN,
! 102: MDF_WRITETHROUGH,
! 103: MDF_WRITEPROTECT,
! 104: MDF_WRITEBACK
! 105: };
! 106:
! 107: #define MTRRTOMRTLEN (sizeof(i686_mtrrtomrt) / sizeof(i686_mtrrtomrt[0]))
! 108:
! 109: int
! 110: i686_mtrr2mrt(int val)
! 111: {
! 112: if (val < 0 || val >= MTRRTOMRTLEN)
! 113: return MDF_UNKNOWN;
! 114: return i686_mtrrtomrt[val];
! 115: }
! 116:
! 117: /*
! 118: * i686 MTRR conflicts. Writeback and uncachable may overlap.
! 119: */
! 120: int
! 121: i686_mtrrconflict(int flag1, int flag2)
! 122: {
! 123:
! 124: flag1 &= MDF_ATTRMASK;
! 125: flag2 &= MDF_ATTRMASK;
! 126: if (flag1 == flag2 ||
! 127: (flag1 == MDF_WRITEBACK && flag2 == MDF_UNCACHEABLE) ||
! 128: (flag2 == MDF_WRITEBACK && flag1 == MDF_UNCACHEABLE))
! 129: return 0;
! 130: return 1;
! 131: }
! 132:
! 133: /*
! 134: * Look for an exactly-matching range.
! 135: */
! 136: struct mem_range_desc *
! 137: mem_range_match(struct mem_range_softc *sc, struct mem_range_desc *mrd)
! 138: {
! 139: struct mem_range_desc *cand;
! 140: int i;
! 141:
! 142: for (i = 0, cand = sc->mr_desc; i < sc->mr_ndesc; i++, cand++)
! 143: if ((cand->mr_base == mrd->mr_base) &&
! 144: (cand->mr_len == mrd->mr_len))
! 145: return(cand);
! 146: return(NULL);
! 147: }
! 148:
! 149: /*
! 150: * Fetch the current mtrr settings from the current CPU (assumed to all
! 151: * be in sync in the SMP case). Note that if we are here, we assume
! 152: * that MTRRs are enabled, and we may or may not have fixed MTRRs.
! 153: */
! 154: void
! 155: i686_mrfetch(struct mem_range_softc *sc)
! 156: {
! 157: struct mem_range_desc *mrd;
! 158: u_int64_t msrv;
! 159: int i, j, msr;
! 160:
! 161: mrd = sc->mr_desc;
! 162:
! 163: /* Get fixed-range MTRRs */
! 164: if (sc->mr_cap & MR686_FIXMTRR) {
! 165: msr = MSR_MTRR64kBase;
! 166: for (i = 0; i < (MTRR_N64K / 8); i++, msr++) {
! 167: msrv = rdmsr(msr);
! 168: for (j = 0; j < 8; j++, mrd++) {
! 169: mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
! 170: i686_mtrr2mrt(msrv & 0xff) |
! 171: MDF_ACTIVE;
! 172: if (mrd->mr_owner[0] == 0)
! 173: strlcpy(mrd->mr_owner, mem_owner_bios,
! 174: sizeof(mrd->mr_owner));
! 175: msrv = msrv >> 8;
! 176: }
! 177: }
! 178: msr = MSR_MTRR16kBase;
! 179: for (i = 0; i < (MTRR_N16K / 8); i++, msr++) {
! 180: msrv = rdmsr(msr);
! 181: for (j = 0; j < 8; j++, mrd++) {
! 182: mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
! 183: i686_mtrr2mrt(msrv & 0xff) |
! 184: MDF_ACTIVE;
! 185: if (mrd->mr_owner[0] == 0)
! 186: strlcpy(mrd->mr_owner, mem_owner_bios,
! 187: sizeof(mrd->mr_owner));
! 188: msrv = msrv >> 8;
! 189: }
! 190: }
! 191: msr = MSR_MTRR4kBase;
! 192: for (i = 0; i < (MTRR_N4K / 8); i++, msr++) {
! 193: msrv = rdmsr(msr);
! 194: for (j = 0; j < 8; j++, mrd++) {
! 195: mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
! 196: i686_mtrr2mrt(msrv & 0xff) |
! 197: MDF_ACTIVE;
! 198: if (mrd->mr_owner[0] == 0)
! 199: strlcpy(mrd->mr_owner, mem_owner_bios,
! 200: sizeof(mrd->mr_owner));
! 201: msrv = msrv >> 8;
! 202: }
! 203: }
! 204: }
! 205:
! 206: /* Get remainder which must be variable MTRRs */
! 207: msr = MSR_MTRRVarBase;
! 208: for (; (mrd - sc->mr_desc) < sc->mr_ndesc; msr += 2, mrd++) {
! 209: msrv = rdmsr(msr);
! 210: mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) |
! 211: i686_mtrr2mrt(msrv & 0xff);
! 212: mrd->mr_base = msrv & 0x0000000ffffff000LL;
! 213: msrv = rdmsr(msr + 1);
! 214: mrd->mr_flags = (msrv & 0x800) ?
! 215: (mrd->mr_flags | MDF_ACTIVE) :
! 216: (mrd->mr_flags & ~MDF_ACTIVE);
! 217: /* Compute the range from the mask. Ick. */
! 218: mrd->mr_len = (~(msrv & 0x0000000ffffff000LL) & 0x0000000fffffffffLL) + 1;
! 219: if (!mrvalid(mrd->mr_base, mrd->mr_len))
! 220: mrd->mr_flags |= MDF_BOGUS;
! 221: /* If unclaimed and active, must be the BIOS */
! 222: if ((mrd->mr_flags & MDF_ACTIVE) && (mrd->mr_owner[0] == 0))
! 223: strlcpy(mrd->mr_owner, mem_owner_bios,
! 224: sizeof(mrd->mr_owner));
! 225: }
! 226: }
! 227:
! 228: /*
! 229: * Return the MTRR memory type matching a region's flags
! 230: */
! 231: int
! 232: i686_mtrrtype(int flags)
! 233: {
! 234: int i;
! 235:
! 236: flags &= MDF_ATTRMASK;
! 237:
! 238: for (i = 0; i < MTRRTOMRTLEN; i++) {
! 239: if (i686_mtrrtomrt[i] == MDF_UNKNOWN)
! 240: continue;
! 241: if (flags == i686_mtrrtomrt[i])
! 242: return(i);
! 243: }
! 244: return(-1);
! 245: }
! 246:
! 247: int
! 248: i686_mrt2mtrr(int flags, int oldval)
! 249: {
! 250: int val;
! 251:
! 252: if ((val = i686_mtrrtype(flags)) == -1)
! 253: return oldval & 0xff;
! 254: return val & 0xff;
! 255: }
! 256:
! 257: /*
! 258: * Update running CPU(s) MTRRs to match the ranges in the descriptor
! 259: * list.
! 260: *
! 261: * XXX Must be called with interrupts enabled.
! 262: */
! 263: void
! 264: i686_mrstore(struct mem_range_softc *sc)
! 265: {
! 266: disable_intr(); /* disable interrupts */
! 267: i686_mrstoreone((void *)sc);
! 268: enable_intr();
! 269: }
! 270:
! 271: /*
! 272: * Update the current CPU's MTRRs with those represented in the
! 273: * descriptor list. Note that we do this wholesale rather than
! 274: * just stuffing one entry; this is simpler (but slower, of course).
! 275: */
! 276: void
! 277: i686_mrstoreone(void *arg)
! 278: {
! 279: struct mem_range_softc *sc = (struct mem_range_softc *)arg;
! 280: struct mem_range_desc *mrd;
! 281: u_int64_t omsrv, msrv;
! 282: int i, j, msr;
! 283: u_int cr4save;
! 284:
! 285: mrd = sc->mr_desc;
! 286:
! 287: cr4save = rcr4(); /* save cr4 */
! 288: if (cr4save & CR4_PGE)
! 289: lcr4(cr4save & ~CR4_PGE);
! 290: lcr0((rcr0() & ~CR0_NW) | CR0_CD); /* disable caches (CD = 1, NW = 0) */
! 291: wbinvd(); /* flush caches, TLBs */
! 292: wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) & ~0x800); /* disable MTRRs (E = 0) */
! 293:
! 294: /* Set fixed-range MTRRs */
! 295: if (sc->mr_cap & MR686_FIXMTRR) {
! 296: msr = MSR_MTRR64kBase;
! 297: for (i = 0; i < (MTRR_N64K / 8); i++, msr++) {
! 298: msrv = 0;
! 299: omsrv = rdmsr(msr);
! 300: for (j = 7; j >= 0; j--) {
! 301: msrv = msrv << 8;
! 302: msrv |= i686_mrt2mtrr((mrd + j)->mr_flags,
! 303: omsrv >> (j*8));
! 304: }
! 305: wrmsr(msr, msrv);
! 306: mrd += 8;
! 307: }
! 308: msr = MSR_MTRR16kBase;
! 309: for (i = 0; i < (MTRR_N16K / 8); i++, msr++) {
! 310: msrv = 0;
! 311: omsrv = rdmsr(msr);
! 312: for (j = 7; j >= 0; j--) {
! 313: msrv = msrv << 8;
! 314: msrv |= i686_mrt2mtrr((mrd + j)->mr_flags,
! 315: omsrv >> (j*8));
! 316: }
! 317: wrmsr(msr, msrv);
! 318: mrd += 8;
! 319: }
! 320: msr = MSR_MTRR4kBase;
! 321: for (i = 0; i < (MTRR_N4K / 8); i++, msr++) {
! 322: msrv = 0;
! 323: omsrv = rdmsr(msr);
! 324: for (j = 7; j >= 0; j--) {
! 325: msrv = msrv << 8;
! 326: msrv |= i686_mrt2mtrr((mrd + j)->mr_flags,
! 327: omsrv >> (j*8));
! 328: }
! 329: wrmsr(msr, msrv);
! 330: mrd += 8;
! 331: }
! 332: }
! 333:
! 334: /* Set remainder which must be variable MTRRs */
! 335: msr = MSR_MTRRVarBase;
! 336: for (; (mrd - sc->mr_desc) < sc->mr_ndesc; msr += 2, mrd++) {
! 337: /* base/type register */
! 338: omsrv = rdmsr(msr);
! 339: if (mrd->mr_flags & MDF_ACTIVE) {
! 340: msrv = mrd->mr_base & 0x0000000ffffff000LL;
! 341: msrv |= i686_mrt2mtrr(mrd->mr_flags, omsrv);
! 342: } else {
! 343: msrv = 0;
! 344: }
! 345: wrmsr(msr, msrv);
! 346:
! 347: /* mask/active register */
! 348: if (mrd->mr_flags & MDF_ACTIVE) {
! 349: msrv = 0x800 | (~(mrd->mr_len - 1) & 0x0000000ffffff000LL);
! 350: } else {
! 351: msrv = 0;
! 352: }
! 353: wrmsr(msr + 1, msrv);
! 354: }
! 355: wbinvd(); /* flush caches, TLBs */
! 356: wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) | 0x800); /* restore MTRR state */
! 357: lcr0(rcr0() & ~(CR0_CD | CR0_NW)); /* enable caches CD = 0 and NW = 0 */
! 358: lcr4(cr4save); /* restore cr4 */
! 359: }
! 360:
! 361: /*
! 362: * Hunt for the fixed MTRR referencing (addr)
! 363: */
! 364: struct mem_range_desc *
! 365: i686_mtrrfixsearch(struct mem_range_softc *sc, u_int64_t addr)
! 366: {
! 367: struct mem_range_desc *mrd;
! 368: int i;
! 369:
! 370: for (i = 0, mrd = sc->mr_desc; i < (MTRR_N64K + MTRR_N16K + MTRR_N4K); i++, mrd++)
! 371: if ((addr >= mrd->mr_base) && (addr < (mrd->mr_base + mrd->mr_len)))
! 372: return(mrd);
! 373: return(NULL);
! 374: }
! 375:
! 376: /*
! 377: * Try to satisfy the given range request by manipulating the fixed MTRRs that
! 378: * cover low memory.
! 379: *
! 380: * Note that we try to be generous here; we'll bloat the range out to the
! 381: * next higher/lower boundary to avoid the consumer having to know too much
! 382: * about the mechanisms here.
! 383: *
! 384: * XXX note that this will have to be updated when we start supporting "busy" ranges.
! 385: */
! 386: int
! 387: i686_mrsetlow(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg)
! 388: {
! 389: struct mem_range_desc *first_md, *last_md, *curr_md;
! 390:
! 391: /* range check */
! 392: if (((first_md = i686_mtrrfixsearch(sc, mrd->mr_base)) == NULL) ||
! 393: ((last_md = i686_mtrrfixsearch(sc, mrd->mr_base + mrd->mr_len - 1)) == NULL))
! 394: return(EINVAL);
! 395:
! 396: /* check we aren't doing something risky */
! 397: if (!(mrd->mr_flags & MDF_FORCE))
! 398: for (curr_md = first_md; curr_md <= last_md; curr_md++) {
! 399: if ((curr_md->mr_flags & MDF_ATTRMASK) == MDF_UNKNOWN)
! 400: return (EACCES);
! 401: }
! 402:
! 403: /* set flags, clear set-by-firmware flag */
! 404: for (curr_md = first_md; curr_md <= last_md; curr_md++) {
! 405: curr_md->mr_flags = mrcopyflags(curr_md->mr_flags & ~MDF_FIRMWARE, mrd->mr_flags);
! 406: bcopy(mrd->mr_owner, curr_md->mr_owner, sizeof(mrd->mr_owner));
! 407: }
! 408:
! 409: return(0);
! 410: }
! 411:
! 412:
! 413: /*
! 414: * Modify/add a variable MTRR to satisfy the request.
! 415: *
! 416: * XXX needs to be updated to properly support "busy" ranges.
! 417: */
! 418: int
! 419: i686_mrsetvariable(struct mem_range_softc *sc, struct mem_range_desc *mrd,
! 420: int *arg)
! 421: {
! 422: struct mem_range_desc *curr_md, *free_md;
! 423: int i;
! 424:
! 425: /*
! 426: * Scan the currently active variable descriptors, look for
! 427: * one we exactly match (straight takeover) and for possible
! 428: * accidental overlaps.
! 429: * Keep track of the first empty variable descriptor in case we
! 430: * can't perform a takeover.
! 431: */
! 432: i = (sc->mr_cap & MR686_FIXMTRR) ? MTRR_N64K + MTRR_N16K + MTRR_N4K : 0;
! 433: curr_md = sc->mr_desc + i;
! 434: free_md = NULL;
! 435: for (; i < sc->mr_ndesc; i++, curr_md++) {
! 436: if (curr_md->mr_flags & MDF_ACTIVE) {
! 437: /* exact match? */
! 438: if ((curr_md->mr_base == mrd->mr_base) &&
! 439: (curr_md->mr_len == mrd->mr_len)) {
! 440: /* whoops, owned by someone */
! 441: if (curr_md->mr_flags & MDF_BUSY)
! 442: return(EBUSY);
! 443: /* check we aren't doing something risky */
! 444: if (!(mrd->mr_flags & MDF_FORCE) &&
! 445: ((curr_md->mr_flags & MDF_ATTRMASK)
! 446: == MDF_UNKNOWN))
! 447: return (EACCES);
! 448: /* Ok, just hijack this entry */
! 449: free_md = curr_md;
! 450: break;
! 451: }
! 452: /* non-exact overlap ? */
! 453: if (mroverlap(curr_md, mrd)) {
! 454: /* between conflicting region types? */
! 455: if (i686_mtrrconflict(curr_md->mr_flags,
! 456: mrd->mr_flags))
! 457: return(EINVAL);
! 458: }
! 459: } else if (free_md == NULL) {
! 460: free_md = curr_md;
! 461: }
! 462: }
! 463: /* got somewhere to put it? */
! 464: if (free_md == NULL)
! 465: return(ENOSPC);
! 466:
! 467: /* Set up new descriptor */
! 468: free_md->mr_base = mrd->mr_base;
! 469: free_md->mr_len = mrd->mr_len;
! 470: free_md->mr_flags = mrcopyflags(MDF_ACTIVE, mrd->mr_flags);
! 471: bcopy(mrd->mr_owner, free_md->mr_owner, sizeof(mrd->mr_owner));
! 472: return(0);
! 473: }
! 474:
! 475: /*
! 476: * Handle requests to set memory range attributes by manipulating MTRRs.
! 477: *
! 478: */
! 479: int
! 480: i686_mrset(struct mem_range_softc *sc, struct mem_range_desc *mrd, int *arg)
! 481: {
! 482: struct mem_range_desc *targ;
! 483: int error = 0;
! 484:
! 485: switch(*arg) {
! 486: case MEMRANGE_SET_UPDATE:
! 487: /* make sure that what's being asked for is even possible at all */
! 488: if (!mrvalid(mrd->mr_base, mrd->mr_len) ||
! 489: i686_mtrrtype(mrd->mr_flags) == -1)
! 490: return(EINVAL);
! 491:
! 492: #define FIXTOP ((MTRR_N64K * 0x10000) + (MTRR_N16K * 0x4000) + (MTRR_N4K * 0x1000))
! 493:
! 494: /* are the "low memory" conditions applicable? */
! 495: if ((sc->mr_cap & MR686_FIXMTRR) &&
! 496: ((mrd->mr_base + mrd->mr_len) <= FIXTOP)) {
! 497: if ((error = i686_mrsetlow(sc, mrd, arg)) != 0)
! 498: return(error);
! 499: } else {
! 500: /* it's time to play with variable MTRRs */
! 501: if ((error = i686_mrsetvariable(sc, mrd, arg)) != 0)
! 502: return(error);
! 503: }
! 504: break;
! 505:
! 506: case MEMRANGE_SET_REMOVE:
! 507: if ((targ = mem_range_match(sc, mrd)) == NULL)
! 508: return(ENOENT);
! 509: if (targ->mr_flags & MDF_FIXACTIVE)
! 510: return(EPERM);
! 511: if (targ->mr_flags & MDF_BUSY)
! 512: return(EBUSY);
! 513: targ->mr_flags &= ~MDF_ACTIVE;
! 514: targ->mr_owner[0] = 0;
! 515: break;
! 516:
! 517: default:
! 518: return(EOPNOTSUPP);
! 519: }
! 520:
! 521: /* update the hardware */
! 522: i686_mrstore(sc);
! 523: i686_mrfetch(sc); /* refetch to see where we're at */
! 524: return(0);
! 525: }
! 526:
! 527: /*
! 528: * Work out how many ranges we support, initialise storage for them,
! 529: * fetch the initial settings.
! 530: */
! 531: void
! 532: i686_mrinit(struct mem_range_softc *sc)
! 533: {
! 534: struct mem_range_desc *mrd;
! 535: int nmdesc = 0;
! 536: int i;
! 537:
! 538: mtrrcap = rdmsr(MSR_MTRRcap);
! 539: mtrrdef = rdmsr(MSR_MTRRdefType);
! 540:
! 541: /* For now, bail out if MTRRs are not enabled */
! 542: if (!(mtrrdef & 0x800)) {
! 543: printf("mtrr: CPU supports MTRRs but not enabled\n");
! 544: return;
! 545: }
! 546: nmdesc = mtrrcap & 0xff;
! 547: printf("mtrr: Pentium Pro MTRR support\n");
! 548:
! 549: /* If fixed MTRRs supported and enabled */
! 550: if ((mtrrcap & 0x100) && (mtrrdef & 0x400)) {
! 551: sc->mr_cap = MR686_FIXMTRR;
! 552: nmdesc += MTRR_N64K + MTRR_N16K + MTRR_N4K;
! 553: }
! 554:
! 555: sc->mr_desc = malloc(nmdesc * sizeof(struct mem_range_desc),
! 556: M_MEMDESC, M_WAITOK);
! 557: bzero(sc->mr_desc, nmdesc * sizeof(struct mem_range_desc));
! 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 & MR686_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: for (i = 0; i < MTRR_N16K; i++, mrd++) {
! 570: mrd->mr_base = i * 0x4000 + 0x80000;
! 571: mrd->mr_len = 0x4000;
! 572: mrd->mr_flags = MDF_FIXBASE | MDF_FIXLEN | MDF_FIXACTIVE;
! 573: }
! 574: for (i = 0; i < MTRR_N4K; i++, mrd++) {
! 575: mrd->mr_base = i * 0x1000 + 0xc0000;
! 576: mrd->mr_len = 0x1000;
! 577: mrd->mr_flags = MDF_FIXBASE | MDF_FIXLEN | MDF_FIXACTIVE;
! 578: }
! 579: }
! 580:
! 581: /*
! 582: * Get current settings, anything set now is considered to have
! 583: * been set by the firmware. (XXX has something already played here?)
! 584: */
! 585: i686_mrfetch(sc);
! 586: mrd = sc->mr_desc;
! 587: for (i = 0; i < sc->mr_ndesc; i++, mrd++) {
! 588: if (mrd->mr_flags & MDF_ACTIVE)
! 589: mrd->mr_flags |= MDF_FIRMWARE;
! 590: }
! 591: }
! 592:
! 593: /*
! 594: * Initialise MTRRs on an AP after the BSP has run the init code.
! 595: */
! 596: void
! 597: i686_mrAPinit(struct mem_range_softc *sc)
! 598: {
! 599: i686_mrstoreone((void *)sc); /* set MTRRs to match BSP */
! 600: wrmsr(MSR_MTRRdefType, mtrrdef); /* set MTRR behaviour to match BSP */
! 601: }
! 602:
CVSweb