[BACK]Return to i686_mem.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / i386

Annotation of sys/arch/i386/i386/i686_mem.c, Revision 1.1.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