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

Annotation of sys/arch/i386/stand/libsa/memprobe.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: memprobe.c,v 1.45 2006/09/18 21:14:15 mpf Exp $       */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1997-1999 Michael Shalayeff
        !             5:  * Copyright (c) 1997-1999 Tobias Weingartner
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            18:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            19:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            27:  * SUCH DAMAGE.
        !            28:  *
        !            29:  */
        !            30:
        !            31: #include <sys/param.h>
        !            32: #include <machine/biosvar.h>
        !            33: #include <dev/isa/isareg.h>
        !            34: #include <stand/boot/bootarg.h>
        !            35: #include "libsa.h"
        !            36:
        !            37: u_int cnvmem, extmem;          /* XXX - compatibility */
        !            38:
        !            39:
        !            40: /* Check gateA20
        !            41:  *
        !            42:  * A sanity check.
        !            43:  */
        !            44: static __inline int
        !            45: checkA20(void)
        !            46: {
        !            47:        register char *p = (char *)0x100000;
        !            48:        register char *q = (char *)0x000000;
        !            49:        int st;
        !            50:
        !            51:        /* Simple check */
        !            52:        if (*p != *q)
        !            53:                return 1;
        !            54:
        !            55:        /* Complex check */
        !            56:        *p = ~(*p);
        !            57:        st = (*p != *q);
        !            58:        *p = ~(*p);
        !            59:
        !            60:        return st;
        !            61: }
        !            62:
        !            63: /* BIOS int 15, AX=E820
        !            64:  *
        !            65:  * This is the "preferred" method.
        !            66:  */
        !            67: static __inline bios_memmap_t *
        !            68: bios_E820(bios_memmap_t *mp)
        !            69: {
        !            70:        int rc, off = 0, sig, gotcha = 0;
        !            71:
        !            72:        do {
        !            73:                BIOS_regs.biosr_es = ((u_int)(mp) >> 4);
        !            74:
        !            75:                __asm __volatile(DOINT(0x15) "; setc %b1"
        !            76:                    : "=a" (sig), "=d" (rc), "=b" (off)
        !            77:                    : "0" (0xE820), "1" (0x534d4150), "b" (off),
        !            78:                      "c" (sizeof(*mp)), "D" (((u_int)mp) & 0xF)
        !            79:                    : "cc", "memory");
        !            80:                off = BIOS_regs.biosr_bx;
        !            81:
        !            82:                if (rc & 0xff || sig != 0x534d4150)
        !            83:                        break;
        !            84:                gotcha++;
        !            85:                if (!mp->type)
        !            86:                        mp->type = BIOS_MAP_RES;
        !            87:                mp++;
        !            88:        } while (off);
        !            89:
        !            90:        if (!gotcha)
        !            91:                return NULL;
        !            92: #ifdef DEBUG
        !            93:        printf("0x15[E820] ");
        !            94: #endif
        !            95:        return mp;
        !            96: }
        !            97:
        !            98: #if 0
        !            99: /* BIOS int 15, AX=E801
        !           100:  *
        !           101:  * Only used if int 15, AX=E820 does not work.
        !           102:  * This should work for more than 64MB on most
        !           103:  * modern machines.  However, there is always
        !           104:  * an exception, the older IBM machine do not
        !           105:  * like this call.
        !           106:  */
        !           107: static __inline bios_memmap_t *
        !           108: bios_E801(bios_memmap_t *mp)
        !           109: {
        !           110:        int rc, m1, m2, m3, m4;
        !           111:        u_int8_t *info;
        !           112:
        !           113:        /* Test for possibility of 0xE801 */
        !           114:        info =  getSYSCONFaddr();
        !           115:        if (!info)
        !           116:                return NULL;
        !           117:        /* XXX - Should test model/submodel/rev here */
        !           118:        printf("model(%d,%d,%d)", info[2], info[3], info[4]);
        !           119:
        !           120:        /* Check for 94 or later bios */
        !           121:        info = (void *)0xFFFFB;
        !           122:        if (info[0] == '9' && info[1] <= '3')
        !           123:                return NULL;
        !           124:
        !           125:        /* We might have this call */
        !           126:        __asm __volatile(DOINT(0x15) "; mov %%ax, %%si; setc %b0"
        !           127:            : "=a" (rc), "=S" (m1), "=b" (m2), "=c" (m3), "=d" (m4)
        !           128:            : "0" (0xE801));
        !           129:
        !           130:        /* Test for failure */
        !           131:        if (rc & 0xff)
        !           132:                return NULL;
        !           133:
        !           134:        /* Fixup for screwed up machines */
        !           135:        if (m1 == 0) {
        !           136:                m1 = m3;
        !           137:                m2 = m4;
        !           138:        }
        !           139: #ifdef DEBUG
        !           140:        printf("0x15[E801] ");
        !           141: #endif
        !           142:        /* Fill out BIOS map */
        !           143:        mp->addr = (1024 * 1024);       /* 1MB */
        !           144:        mp->size = (m1 & 0xffff) * 1024;
        !           145:        mp->type = BIOS_MAP_FREE;
        !           146:
        !           147:        mp++;
        !           148:        mp->addr = (1024 * 1024) * 16;  /* 16MB */
        !           149:        mp->size = (m2 & 0xffff) * 64L * 1024;
        !           150:        mp->type = BIOS_MAP_FREE;
        !           151:
        !           152:        return ++mp;
        !           153: }
        !           154: #endif
        !           155:
        !           156: /* BIOS int 15, AX=8800
        !           157:  *
        !           158:  * Only used if int 15, AX=E801 does not work.
        !           159:  * Machines with this are restricted to 64MB.
        !           160:  */
        !           161: static __inline bios_memmap_t *
        !           162: bios_8800(bios_memmap_t *mp)
        !           163: {
        !           164:        int rc, mem;
        !           165:
        !           166:        __asm __volatile(DOINT(0x15) "; setc %b0"
        !           167:            : "=c" (rc), "=a" (mem) : "a" (0x8800));
        !           168:
        !           169:        if (rc & 0xff)
        !           170:                return NULL;
        !           171: #ifdef DEBUG
        !           172:        printf("0x15[8800] ");
        !           173: #endif
        !           174:        /* Fill out a BIOS_MAP */
        !           175:        mp->addr = 1024 * 1024;         /* 1MB */
        !           176:        mp->size = (mem & 0xffff) * 1024;
        !           177:        mp->type = BIOS_MAP_FREE;
        !           178:
        !           179:        return ++mp;
        !           180: }
        !           181:
        !           182: /* BIOS int 0x12 Get Conventional Memory
        !           183:  *
        !           184:  * Only used if int 15, AX=E820 does not work.
        !           185:  */
        !           186: static __inline bios_memmap_t *
        !           187: bios_int12(bios_memmap_t *mp)
        !           188: {
        !           189:        int mem;
        !           190: #ifdef DEBUG
        !           191:        printf("0x12 ");
        !           192: #endif
        !           193:        __asm __volatile(DOINT(0x12) : "=a" (mem) :: "%ecx", "%edx", "cc");
        !           194:
        !           195:        /* Fill out a bios_memmap_t */
        !           196:        mp->addr = 0;
        !           197:        mp->size = (mem & 0xffff) * 1024;
        !           198:        mp->type = BIOS_MAP_FREE;
        !           199:
        !           200:        return ++mp;
        !           201: }
        !           202:
        !           203:
        !           204: /* addrprobe(kloc): Probe memory at address kloc * 1024.
        !           205:  *
        !           206:  * This is a hack, but it seems to work ok.  Maybe this is
        !           207:  * the *real* way that you are supposed to do probing???
        !           208:  *
        !           209:  * Modify the original a bit.  We write everything first, and
        !           210:  * then test for the values.  This should croak on machines that
        !           211:  * return values just written on non-existent memory...
        !           212:  *
        !           213:  * BTW: These machines are pretty broken IMHO.
        !           214:  *
        !           215:  * XXX - Does not detect aliased memory.
        !           216:  */
        !           217: const u_int addrprobe_pat[] = {
        !           218:        0x00000000, 0xFFFFFFFF,
        !           219:        0x01010101, 0x10101010,
        !           220:        0x55555555, 0xCCCCCCCC
        !           221: };
        !           222: static int
        !           223: addrprobe(u_int kloc)
        !           224: {
        !           225:        __volatile u_int *loc;
        !           226:        register u_int i, ret = 0;
        !           227:        u_int save[NENTS(addrprobe_pat)];
        !           228:
        !           229:        /* Get location */
        !           230:        loc = (int *)(kloc * 1024);
        !           231:
        !           232:        save[0] = *loc;
        !           233:        /* Probe address */
        !           234:        for (i = 0; i < NENTS(addrprobe_pat); i++) {
        !           235:                *loc = addrprobe_pat[i];
        !           236:                if (*loc != addrprobe_pat[i])
        !           237:                        ret++;
        !           238:        }
        !           239:        *loc = save[0];
        !           240:
        !           241:        if (!ret) {
        !           242:                /* Write address */
        !           243:                for (i = 0; i < NENTS(addrprobe_pat); i++) {
        !           244:                        save[i] = loc[i];
        !           245:                        loc[i] = addrprobe_pat[i];
        !           246:                }
        !           247:
        !           248:                /* Read address */
        !           249:                for (i = 0; i < NENTS(addrprobe_pat); i++) {
        !           250:                        if (loc[i] != addrprobe_pat[i])
        !           251:                                ret++;
        !           252:                        loc[i] = save[i];
        !           253:                }
        !           254:        }
        !           255:
        !           256:        return ret;
        !           257: }
        !           258:
        !           259: /* Probe for all extended memory.
        !           260:  *
        !           261:  * This is only used as a last resort.  If we resort to this
        !           262:  * routine, we are getting pretty desperate.  Hopefully nobody
        !           263:  * has to rely on this after all the work above.
        !           264:  *
        !           265:  * XXX - Does not detect aliased memory.
        !           266:  * XXX - Could be destructive, as it does write.
        !           267:  */
        !           268: static __inline bios_memmap_t *
        !           269: badprobe(bios_memmap_t *mp)
        !           270: {
        !           271:        u_int64_t ram;
        !           272: #ifdef DEBUG
        !           273:        printf("scan ");
        !           274: #endif
        !           275:        /* probe extended memory
        !           276:         *
        !           277:         * There is no need to do this in assembly language.  This is
        !           278:         * much easier to debug in C anyways.
        !           279:         */
        !           280:        for (ram = 1024; ram < 512 * 1024; ram += 4)
        !           281:                if (addrprobe(ram))
        !           282:                        break;
        !           283:
        !           284:        mp->addr = 1024 * 1024;
        !           285:        mp->size = (ram - 1024) * 1024;
        !           286:        mp->type = BIOS_MAP_FREE;
        !           287:
        !           288:        return ++mp;
        !           289: }
        !           290:
        !           291: bios_memmap_t bios_memmap[32]; /* This is easier */
        !           292: #ifndef _TEST
        !           293: void
        !           294: memprobe(void)
        !           295: {
        !           296:        bios_memmap_t *pm = bios_memmap, *im;
        !           297:
        !           298: #ifdef DEBUG
        !           299:        printf(" mem(");
        !           300: #else
        !           301:        printf(" mem[");
        !           302: #endif
        !           303:
        !           304:        if ((pm = bios_E820(bios_memmap)) == NULL) {
        !           305:                im = bios_int12(bios_memmap);
        !           306: #if 0
        !           307:                pm = bios_E801(im);
        !           308:                if (pm == NULL)
        !           309: #endif
        !           310:                        pm = bios_8800(im);
        !           311:                if (pm == NULL)
        !           312:                        pm = badprobe(im);
        !           313:                if (pm == NULL) {
        !           314:                        printf(" No Extended memory detected.");
        !           315:                        pm = im;
        !           316:                }
        !           317:        }
        !           318:        pm->type = BIOS_MAP_END;
        !           319:
        !           320:        /* XXX - gotta peephole optimize the list */
        !           321:
        !           322:        /* Remove APM needed RAM */
        !           323:        apmfixmem();
        !           324:
        !           325: #ifdef DEBUG
        !           326:        printf(")[");
        !           327: #endif
        !           328:
        !           329:        /* XXX - Compatibility, remove later (smpprobe() relies on it) */
        !           330:        extmem = cnvmem = 0;
        !           331:        for (im = bios_memmap; im->type != BIOS_MAP_END; im++) {
        !           332:                /* Count only "good" memory chunks 12K and up in size */
        !           333:                if ((im->type == BIOS_MAP_FREE) && (im->size >= 12*1024)) {
        !           334:                        if (im->size > 1024 * 1024)
        !           335:                                printf("%uM ", (u_int)(im->size /
        !           336:                                    (1024 * 1024)));
        !           337:                        else
        !           338:                                printf("%uK ", (u_int)im->size / 1024);
        !           339:
        !           340:                        /*
        !           341:                         * Compute compatibility values:
        !           342:                         * cnvmem -- is the upper boundary of conventional
        !           343:                         *      memory (below IOM_BEGIN (=640k))
        !           344:                         * extmem -- is the size of the contignous extended
        !           345:                         *      memory segment starting at 1M
        !           346:                         *
        !           347:                         * We ignore "good" memory in the 640K-1M hole.
        !           348:                         * We drop "machine {cnvmem,extmem}" commands.
        !           349:                         */
        !           350:                        if (im->addr < IOM_BEGIN)
        !           351:                                cnvmem = max(cnvmem,
        !           352:                                    im->addr + im->size) / 1024;
        !           353:                        if (im->addr >= IOM_END)
        !           354:                                extmem += im->size / 1024;
        !           355:                }
        !           356:        }
        !           357:
        !           358:        /* Check if gate A20 is on */
        !           359:        printf("a20=o%s] ", checkA20()? "n" : "ff!");
        !           360: }
        !           361: #endif
        !           362:
        !           363: void
        !           364: dump_biosmem(bios_memmap_t *tm)
        !           365: {
        !           366:        register bios_memmap_t *p;
        !           367:        register u_int total = 0;
        !           368:
        !           369:        if (tm == NULL)
        !           370:                tm = bios_memmap;
        !           371:
        !           372:        for (p = tm; p->type != BIOS_MAP_END; p++) {
        !           373:                printf("Region %ld: type %u at 0x%llx for %uKB\n",
        !           374:                    (long)(p - tm), p->type, p->addr,
        !           375:                    (u_int)(p->size / 1024));
        !           376:
        !           377:                if (p->type == BIOS_MAP_FREE)
        !           378:                        total += p->size / 1024;
        !           379:        }
        !           380:
        !           381:        printf("Low ram: %dKB  High ram: %dKB\n", cnvmem, extmem);
        !           382:        printf("Total free memory: %uKB\n", total);
        !           383: }
        !           384:
        !           385: int
        !           386: mem_delete(long long sa, long long ea)
        !           387: {
        !           388:        register bios_memmap_t *p;
        !           389:
        !           390:        for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
        !           391:                if (p->type == BIOS_MAP_FREE) {
        !           392:                        register int64_t sp = p->addr, ep = p->addr + p->size;
        !           393:
        !           394:                        /* can we eat it as a whole? */
        !           395:                        if ((sa - sp) <= NBPG && (ep - ea) <= NBPG) {
        !           396:                                bcopy(p + 1, p, (char *)bios_memmap +
        !           397:                                    sizeof(bios_memmap) - (char *)p);
        !           398:                                break;
        !           399:                        /* eat head or legs */
        !           400:                        } else if (sa <= sp && sp < ea) {
        !           401:                                p->addr = ea;
        !           402:                                p->size = ep - ea;
        !           403:                                break;
        !           404:                        } else if (sa < ep && ep <= ea) {
        !           405:                                p->size = sa - sp;
        !           406:                                break;
        !           407:                        } else if (sp < sa && ea < ep) {
        !           408:                                /* bite in half */
        !           409:                                bcopy(p, p + 1, (char *)bios_memmap +
        !           410:                                    sizeof(bios_memmap) - (char *)p -
        !           411:                                    sizeof(bios_memmap[0]));
        !           412:                                p[1].addr = ea;
        !           413:                                p[1].size = ep - ea;
        !           414:                                p->size = sa - sp;
        !           415:                                break;
        !           416:                        }
        !           417:                }
        !           418:        }
        !           419:        return 0;
        !           420: }
        !           421:
        !           422: int
        !           423: mem_add(long long sa, long long ea)
        !           424: {
        !           425:        register bios_memmap_t *p;
        !           426:
        !           427:        for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
        !           428:                if (p->type == BIOS_MAP_FREE) {
        !           429:                        register int64_t sp = p->addr, ep = p->addr + p->size;
        !           430:
        !           431:                        /* is it already there? */
        !           432:                        if (sp <= sa && ea <= ep) {
        !           433:                                break;
        !           434:                        /* join head or legs */
        !           435:                        } else if (sa < sp && sp <= ea) {
        !           436:                                p->addr = sa;
        !           437:                                p->size = ep - sa;
        !           438:                                break;
        !           439:                        } else if (sa <= ep && ep < ea) {
        !           440:                                p->size = ea - sp;
        !           441:                                break;
        !           442:                        } else if (ea < sp) {
        !           443:                                /* insert before */
        !           444:                                bcopy(p, p + 1, (char *)bios_memmap +
        !           445:                                    sizeof(bios_memmap) - (char *)(p - 1));
        !           446:                                p->addr = sa;
        !           447:                                p->size = ea - sa;
        !           448:                                break;
        !           449:                        }
        !           450:                }
        !           451:        }
        !           452:
        !           453:        /* meaning add new item at the end of the list */
        !           454:        if (p->type == BIOS_MAP_END) {
        !           455:                p[1] = p[0];
        !           456:                p->type = BIOS_MAP_FREE;
        !           457:                p->addr = sa;
        !           458:                p->size = ea - sa;
        !           459:        }
        !           460:
        !           461:        return 0;
        !           462: }
        !           463:
        !           464: void
        !           465: mem_pass(void)
        !           466: {
        !           467:        bios_memmap_t *p;
        !           468:
        !           469:        for (p = bios_memmap; p->type != BIOS_MAP_END; p++)
        !           470:                ;
        !           471:        addbootarg(BOOTARG_MEMMAP, (p - bios_memmap + 1) * sizeof *bios_memmap,
        !           472:            bios_memmap);
        !           473: }

CVSweb