Annotation of qemu/roms/seabios/src/pmm.c, revision 1.1

1.1     ! root        1: // Post memory manager (PMM) calls
        !             2: //
        !             3: // Copyright (C) 2009  Kevin O'Connor <[email protected]>
        !             4: //
        !             5: // This file may be distributed under the terms of the GNU LGPLv3 license.
        !             6: 
        !             7: #include "util.h" // checksum
        !             8: #include "config.h" // BUILD_BIOS_ADDR
        !             9: #include "memmap.h" // find_high_area
        !            10: #include "farptr.h" // GET_FARVAR
        !            11: #include "biosvar.h" // GET_BDA
        !            12: 
        !            13: 
        !            14: #if MODE16
        !            15: // The 16bit pmm entry points runs in "big real" mode, and can
        !            16: // therefore read/write to the 32bit malloc variables.
        !            17: #define GET_PMMVAR(var) GET_FARVAR(0, (var))
        !            18: #define SET_PMMVAR(var, val) SET_FARVAR(0, (var), (val))
        !            19: #else
        !            20: #define GET_PMMVAR(var) (var)
        !            21: #define SET_PMMVAR(var, val) do { (var) = (val); } while (0)
        !            22: #endif
        !            23: 
        !            24: // Zone definitions
        !            25: struct zone_s {
        !            26:     u32 top, bottom, cur;
        !            27: };
        !            28: 
        !            29: struct zone_s ZoneLow VAR32VISIBLE, ZoneHigh VAR32VISIBLE;
        !            30: struct zone_s ZoneFSeg VAR32VISIBLE;
        !            31: struct zone_s ZoneTmpLow VAR32VISIBLE, ZoneTmpHigh VAR32VISIBLE;
        !            32: 
        !            33: struct zone_s *Zones[] VAR32VISIBLE = {
        !            34:     &ZoneTmpLow, &ZoneLow, &ZoneFSeg, &ZoneTmpHigh, &ZoneHigh
        !            35: };
        !            36: 
        !            37: 
        !            38: /****************************************************************
        !            39:  * ebda movement
        !            40:  ****************************************************************/
        !            41: 
        !            42: // Move ebda
        !            43: static int
        !            44: relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size)
        !            45: {
        !            46:     u32 lowram = GET_BDA(mem_size_kb) * 1024;
        !            47:     if (oldebda != lowram)
        !            48:         // EBDA isn't at end of ram - give up.
        !            49:         return -1;
        !            50: 
        !            51:     // Do copy
        !            52:     if (MODE16)
        !            53:         memcpy_far(FLATPTR_TO_SEG(newebda)
        !            54:                    , (void*)FLATPTR_TO_OFFSET(newebda)
        !            55:                    , FLATPTR_TO_SEG(oldebda)
        !            56:                    , (void*)FLATPTR_TO_OFFSET(oldebda)
        !            57:                    , ebda_size * 1024);
        !            58:     else
        !            59:         memmove((void*)newebda, (void*)oldebda, ebda_size * 1024);
        !            60: 
        !            61:     // Update indexes
        !            62:     dprintf(1, "ebda moved from %x to %x\n", oldebda, newebda);
        !            63:     SET_BDA(mem_size_kb, newebda / 1024);
        !            64:     SET_BDA(ebda_seg, FLATPTR_TO_SEG(newebda));
        !            65:     return 0;
        !            66: }
        !            67: 
        !            68: // Support expanding the ZoneLow dynamically.
        !            69: static void
        !            70: zonelow_expand(u32 size, u32 align)
        !            71: {
        !            72:     u32 oldpos = GET_PMMVAR(ZoneLow.cur);
        !            73:     u32 newpos = ALIGN_DOWN(oldpos - size, align);
        !            74:     u32 bottom = GET_PMMVAR(ZoneLow.bottom);
        !            75:     if (newpos >= bottom && newpos <= oldpos)
        !            76:         // Space already present.
        !            77:         return;
        !            78:     u16 ebda_seg = get_ebda_seg();
        !            79:     u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0);
        !            80:     u8 ebda_size = GET_EBDA2(ebda_seg, size);
        !            81:     u32 ebda_end = ebda_pos + ebda_size * 1024;
        !            82:     if (ebda_end != bottom) {
        !            83:         // Something else is after ebda - can't use any existing space.
        !            84:         oldpos = ebda_end;
        !            85:         newpos = ALIGN_DOWN(oldpos - size, align);
        !            86:     }
        !            87:     u32 newbottom = ALIGN_DOWN(newpos, 1024);
        !            88:     u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024);
        !            89:     if (newebda < BUILD_EBDA_MINIMUM)
        !            90:         // Not enough space.
        !            91:         return;
        !            92: 
        !            93:     // Move ebda
        !            94:     int ret = relocate_ebda(newebda, ebda_pos, ebda_size);
        !            95:     if (ret)
        !            96:         return;
        !            97: 
        !            98:     // Update zone
        !            99:     SET_PMMVAR(ZoneLow.cur, oldpos);
        !           100:     SET_PMMVAR(ZoneLow.bottom, newbottom);
        !           101: }
        !           102: 
        !           103: 
        !           104: /****************************************************************
        !           105:  * zone allocations
        !           106:  ****************************************************************/
        !           107: 
        !           108: // Obtain memory from a given zone.
        !           109: static void *
        !           110: zone_malloc(struct zone_s *zone, u32 size, u32 align)
        !           111: {
        !           112:     u32 oldpos = GET_PMMVAR(zone->cur);
        !           113:     u32 newpos = ALIGN_DOWN(oldpos - size, align);
        !           114:     if (newpos < GET_PMMVAR(zone->bottom) || newpos > oldpos)
        !           115:         // No space
        !           116:         return NULL;
        !           117:     SET_PMMVAR(zone->cur, newpos);
        !           118:     return (void*)newpos;
        !           119: }
        !           120: 
        !           121: // Find the zone that contains the given data block.
        !           122: static struct zone_s *
        !           123: zone_find(void *data)
        !           124: {
        !           125:     int i;
        !           126:     for (i=0; i<ARRAY_SIZE(Zones); i++) {
        !           127:         struct zone_s *zone = GET_PMMVAR(Zones[i]);
        !           128:         if ((u32)data >= GET_PMMVAR(zone->cur)
        !           129:             && (u32)data < GET_PMMVAR(zone->top))
        !           130:             return zone;
        !           131:     }
        !           132:     return NULL;
        !           133: }
        !           134: 
        !           135: // Return memory to a zone (if it was the last to be allocated).
        !           136: static int
        !           137: zone_free(void *data, u32 olddata)
        !           138: {
        !           139:     struct zone_s *zone = zone_find(data);
        !           140:     if (!zone || !data || GET_PMMVAR(zone->cur) != (u32)data)
        !           141:         return -1;
        !           142:     SET_PMMVAR(zone->cur, olddata);
        !           143:     return 0;
        !           144: }
        !           145: 
        !           146: // Report the status of all the zones.
        !           147: static void
        !           148: dumpZones()
        !           149: {
        !           150:     int i;
        !           151:     for (i=0; i<ARRAY_SIZE(Zones); i++) {
        !           152:         struct zone_s *zone = Zones[i];
        !           153:         u32 used = zone->top - zone->cur;
        !           154:         u32 avail = zone->top - zone->bottom;
        !           155:         u32 pct = avail ? ((100 * used) / avail) : 0;
        !           156:         dprintf(2, "zone %d: %08x-%08x used=%d (%d%%)\n"
        !           157:                 , i, zone->bottom, zone->top, used, pct);
        !           158:     }
        !           159: }
        !           160: 
        !           161: 
        !           162: /****************************************************************
        !           163:  * tracked memory allocations
        !           164:  ****************************************************************/
        !           165: 
        !           166: // Information on PMM tracked allocations
        !           167: struct pmmalloc_s {
        !           168:     void *data;
        !           169:     u32 olddata;
        !           170:     u32 handle;
        !           171:     u32 oldallocdata;
        !           172:     struct pmmalloc_s *next;
        !           173: };
        !           174: 
        !           175: struct pmmalloc_s *PMMAllocs VAR32VISIBLE;
        !           176: 
        !           177: // Allocate memory from the given zone and track it as a PMM allocation
        !           178: void *
        !           179: pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align)
        !           180: {
        !           181:     u32 oldallocdata = GET_PMMVAR(ZoneTmpHigh.cur);
        !           182:     struct pmmalloc_s *info = zone_malloc(&ZoneTmpHigh, sizeof(*info)
        !           183:                                           , MALLOC_MIN_ALIGN);
        !           184:     if (!info) {
        !           185:         oldallocdata = GET_PMMVAR(ZoneTmpLow.cur);
        !           186:         info = zone_malloc(&ZoneTmpLow, sizeof(*info), MALLOC_MIN_ALIGN);
        !           187:         if (!info)
        !           188:             return NULL;
        !           189:     }
        !           190:     if (zone == &ZoneLow)
        !           191:         zonelow_expand(size, align);
        !           192:     u32 olddata = GET_PMMVAR(zone->cur);
        !           193:     void *data = zone_malloc(zone, size, align);
        !           194:     if (! data) {
        !           195:         zone_free(info, oldallocdata);
        !           196:         return NULL;
        !           197:     }
        !           198:     dprintf(8, "pmm_malloc zone=%p handle=%x size=%d align=%x"
        !           199:             " ret=%p (info=%p)\n"
        !           200:             , zone, handle, size, align
        !           201:             , data, info);
        !           202:     SET_PMMVAR(info->data, data);
        !           203:     SET_PMMVAR(info->olddata, olddata);
        !           204:     SET_PMMVAR(info->handle, handle);
        !           205:     SET_PMMVAR(info->oldallocdata, oldallocdata);
        !           206:     SET_PMMVAR(info->next, GET_PMMVAR(PMMAllocs));
        !           207:     SET_PMMVAR(PMMAllocs, info);
        !           208:     return data;
        !           209: }
        !           210: 
        !           211: // Free a raw data block (either from a zone or from pmm alloc list).
        !           212: static void
        !           213: pmm_free_data(void *data, u32 olddata)
        !           214: {
        !           215:     int ret = zone_free(data, olddata);
        !           216:     if (!ret)
        !           217:         // Success - done.
        !           218:         return;
        !           219:     struct pmmalloc_s *info;
        !           220:     for (info=GET_PMMVAR(PMMAllocs); info; info = GET_PMMVAR(info->next))
        !           221:         if (GET_PMMVAR(info->olddata) == (u32)data) {
        !           222:             SET_PMMVAR(info->olddata, olddata);
        !           223:             return;
        !           224:         } else if (GET_PMMVAR(info->oldallocdata) == (u32)data) {
        !           225:             SET_PMMVAR(info->oldallocdata, olddata);
        !           226:             return;
        !           227:         }
        !           228: }
        !           229: 
        !           230: // Free a data block allocated with pmm_malloc
        !           231: int
        !           232: pmm_free(void *data)
        !           233: {
        !           234:     struct pmmalloc_s **pinfo = &PMMAllocs;
        !           235:     for (;;) {
        !           236:         struct pmmalloc_s *info = GET_PMMVAR(*pinfo);
        !           237:         if (!info)
        !           238:             return -1;
        !           239:         if (GET_PMMVAR(info->data) == data) {
        !           240:             SET_PMMVAR(*pinfo, GET_PMMVAR(info->next));
        !           241:             u32 oldallocdata = GET_PMMVAR(info->oldallocdata);
        !           242:             u32 olddata = GET_PMMVAR(info->olddata);
        !           243:             pmm_free_data(data, olddata);
        !           244:             pmm_free_data(info, oldallocdata);
        !           245:             dprintf(8, "pmm_free data=%p olddata=%p oldallocdata=%p info=%p\n"
        !           246:                     , data, (void*)olddata, (void*)oldallocdata, info);
        !           247:             return 0;
        !           248:         }
        !           249:         pinfo = &info->next;
        !           250:     }
        !           251: }
        !           252: 
        !           253: // Find the amount of free space in a given zone.
        !           254: static u32
        !           255: pmm_getspace(struct zone_s *zone)
        !           256: {
        !           257:     // XXX - doesn't account for ZoneLow being able to grow.
        !           258:     u32 space = GET_PMMVAR(zone->cur) - GET_PMMVAR(zone->bottom);
        !           259:     if (zone != &ZoneTmpHigh && zone != &ZoneTmpLow)
        !           260:         return space;
        !           261:     // Account for space needed for PMM tracking.
        !           262:     u32 reserve = ALIGN(sizeof(struct pmmalloc_s), MALLOC_MIN_ALIGN);
        !           263:     if (space <= reserve)
        !           264:         return 0;
        !           265:     return space - reserve;
        !           266: }
        !           267: 
        !           268: // Find the data block allocated with pmm_malloc with a given handle.
        !           269: static void *
        !           270: pmm_find(u32 handle)
        !           271: {
        !           272:     struct pmmalloc_s *info;
        !           273:     for (info=GET_PMMVAR(PMMAllocs); info; info = GET_PMMVAR(info->next))
        !           274:         if (GET_PMMVAR(info->handle) == handle)
        !           275:             return GET_PMMVAR(info->data);
        !           276:     return NULL;
        !           277: }
        !           278: 
        !           279: void
        !           280: malloc_setup()
        !           281: {
        !           282:     ASSERT32();
        !           283:     dprintf(3, "malloc setup\n");
        !           284: 
        !           285:     PMMAllocs = NULL;
        !           286: 
        !           287:     // Memory in 0xf0000 area.
        !           288:     extern u8 code32_start[];
        !           289:     if ((u32)code32_start > BUILD_BIOS_ADDR)
        !           290:         // Clear unused parts of f-segment
        !           291:         memset((void*)BUILD_BIOS_ADDR, 0, (u32)code32_start - BUILD_BIOS_ADDR);
        !           292:     memset(BiosTableSpace, 0, CONFIG_MAX_BIOSTABLE);
        !           293:     ZoneFSeg.bottom = (u32)BiosTableSpace;
        !           294:     ZoneFSeg.top = ZoneFSeg.cur = ZoneFSeg.bottom + CONFIG_MAX_BIOSTABLE;
        !           295: 
        !           296:     // Memory under 1Meg.
        !           297:     ZoneTmpLow.bottom = BUILD_STACK_ADDR;
        !           298:     ZoneTmpLow.top = ZoneTmpLow.cur = BUILD_EBDA_MINIMUM;
        !           299: 
        !           300:     // Permanent memory under 1Meg.
        !           301:     ZoneLow.bottom = ZoneLow.top = ZoneLow.cur = BUILD_LOWRAM_END;
        !           302: 
        !           303:     // Find memory at the top of ram.
        !           304:     struct e820entry *e = find_high_area(CONFIG_MAX_HIGHTABLE+MALLOC_MIN_ALIGN);
        !           305:     if (!e) {
        !           306:         // No memory above 1Meg
        !           307:         memset(&ZoneHigh, 0, sizeof(ZoneHigh));
        !           308:         memset(&ZoneTmpHigh, 0, sizeof(ZoneTmpHigh));
        !           309:         return;
        !           310:     }
        !           311:     u32 top = e->start + e->size, bottom = e->start;
        !           312: 
        !           313:     // Memory at top of ram.
        !           314:     ZoneHigh.bottom = ALIGN(top - CONFIG_MAX_HIGHTABLE, MALLOC_MIN_ALIGN);
        !           315:     ZoneHigh.top = ZoneHigh.cur = ZoneHigh.bottom + CONFIG_MAX_HIGHTABLE;
        !           316:     add_e820(ZoneHigh.bottom, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
        !           317: 
        !           318:     // Memory above 1Meg
        !           319:     ZoneTmpHigh.bottom = ALIGN(bottom, MALLOC_MIN_ALIGN);
        !           320:     ZoneTmpHigh.top = ZoneTmpHigh.cur = ZoneHigh.bottom;
        !           321: }
        !           322: 
        !           323: void
        !           324: malloc_finalize()
        !           325: {
        !           326:     dprintf(3, "malloc finalize\n");
        !           327: 
        !           328:     dumpZones();
        !           329: 
        !           330:     // Reserve more low-mem if needed.
        !           331:     u32 endlow = GET_BDA(mem_size_kb)*1024;
        !           332:     add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
        !           333: 
        !           334:     // Give back unused high ram.
        !           335:     u32 giveback = ALIGN_DOWN(ZoneHigh.cur - ZoneHigh.bottom, PAGE_SIZE);
        !           336:     add_e820(ZoneHigh.bottom, giveback, E820_RAM);
        !           337:     dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
        !           338: 
        !           339:     // Clear low-memory allocations.
        !           340:     memset((void*)ZoneTmpLow.bottom, 0, ZoneTmpLow.top - ZoneTmpLow.bottom);
        !           341: }
        !           342: 
        !           343: 
        !           344: /****************************************************************
        !           345:  * pmm interface
        !           346:  ****************************************************************/
        !           347: 
        !           348: struct pmmheader {
        !           349:     u32 signature;
        !           350:     u8 version;
        !           351:     u8 length;
        !           352:     u8 checksum;
        !           353:     u16 entry_offset;
        !           354:     u16 entry_seg;
        !           355:     u8 reserved[5];
        !           356: } PACKED;
        !           357: 
        !           358: extern struct pmmheader PMMHEADER;
        !           359: 
        !           360: #define PMM_SIGNATURE 0x4d4d5024 // $PMM
        !           361: 
        !           362: #if CONFIG_PMM
        !           363: struct pmmheader PMMHEADER __aligned(16) VAR16EXPORT = {
        !           364:     .version = 0x01,
        !           365:     .length = sizeof(PMMHEADER),
        !           366:     .entry_seg = SEG_BIOS,
        !           367: };
        !           368: #endif
        !           369: 
        !           370: #define PMM_FUNCTION_NOT_SUPPORTED 0xffffffff
        !           371: 
        !           372: // PMM - allocate
        !           373: static u32
        !           374: handle_pmm00(u16 *args)
        !           375: {
        !           376:     u32 length = *(u32*)&args[1], handle = *(u32*)&args[3];
        !           377:     u16 flags = args[5];
        !           378:     dprintf(3, "pmm00: length=%x handle=%x flags=%x\n"
        !           379:             , length, handle, flags);
        !           380:     struct zone_s *lowzone = &ZoneTmpLow, *highzone = &ZoneTmpHigh;
        !           381:     if (flags & 8) {
        !           382:         // Permanent memory request.
        !           383:         lowzone = &ZoneLow;
        !           384:         highzone = &ZoneHigh;
        !           385:     }
        !           386:     if (!length) {
        !           387:         // Memory size request
        !           388:         switch (flags & 3) {
        !           389:         default:
        !           390:         case 0:
        !           391:             return 0;
        !           392:         case 1:
        !           393:             return pmm_getspace(lowzone);
        !           394:         case 2:
        !           395:             return pmm_getspace(highzone);
        !           396:         case 3: {
        !           397:             u32 spacelow = pmm_getspace(lowzone);
        !           398:             u32 spacehigh = pmm_getspace(highzone);
        !           399:             if (spacelow > spacehigh)
        !           400:                 return spacelow;
        !           401:             return spacehigh;
        !           402:         }
        !           403:         }
        !           404:     }
        !           405:     u32 size = length * 16;
        !           406:     if ((s32)size <= 0)
        !           407:         return 0;
        !           408:     u32 align = MALLOC_MIN_ALIGN;
        !           409:     if (flags & 4) {
        !           410:         align = 1<<__ffs(size);
        !           411:         if (align < MALLOC_MIN_ALIGN)
        !           412:             align = MALLOC_MIN_ALIGN;
        !           413:     }
        !           414:     switch (flags & 3) {
        !           415:     default:
        !           416:     case 0:
        !           417:         return 0;
        !           418:     case 1:
        !           419:         return (u32)pmm_malloc(lowzone, handle, size, align);
        !           420:     case 2:
        !           421:         return (u32)pmm_malloc(highzone, handle, size, align);
        !           422:     case 3: {
        !           423:         void *data = pmm_malloc(lowzone, handle, size, align);
        !           424:         if (data)
        !           425:             return (u32)data;
        !           426:         return (u32)pmm_malloc(highzone, handle, size, align);
        !           427:     }
        !           428:     }
        !           429: }
        !           430: 
        !           431: // PMM - find
        !           432: static u32
        !           433: handle_pmm01(u16 *args)
        !           434: {
        !           435:     u32 handle = *(u32*)&args[1];
        !           436:     dprintf(3, "pmm01: handle=%x\n", handle);
        !           437:     if (handle == PMM_DEFAULT_HANDLE)
        !           438:         return 0;
        !           439:     return (u32)pmm_find(handle);
        !           440: }
        !           441: 
        !           442: // PMM - deallocate
        !           443: static u32
        !           444: handle_pmm02(u16 *args)
        !           445: {
        !           446:     u32 buffer = *(u32*)&args[1];
        !           447:     dprintf(3, "pmm02: buffer=%x\n", buffer);
        !           448:     int ret = pmm_free((void*)buffer);
        !           449:     if (ret)
        !           450:         // Error
        !           451:         return 1;
        !           452:     return 0;
        !           453: }
        !           454: 
        !           455: static u32
        !           456: handle_pmmXX(u16 *args)
        !           457: {
        !           458:     return PMM_FUNCTION_NOT_SUPPORTED;
        !           459: }
        !           460: 
        !           461: u32 VISIBLE16
        !           462: handle_pmm(u16 *args)
        !           463: {
        !           464:     if (! CONFIG_PMM)
        !           465:         return PMM_FUNCTION_NOT_SUPPORTED;
        !           466: 
        !           467:     u16 arg1 = args[0];
        !           468:     dprintf(DEBUG_HDL_pmm, "pmm call arg1=%x\n", arg1);
        !           469: 
        !           470:     switch (arg1) {
        !           471:     case 0x00: return handle_pmm00(args);
        !           472:     case 0x01: return handle_pmm01(args);
        !           473:     case 0x02: return handle_pmm02(args);
        !           474:     default:   return handle_pmmXX(args);
        !           475:     }
        !           476: }
        !           477: 
        !           478: // romlayout.S
        !           479: extern void entry_pmm();
        !           480: 
        !           481: void
        !           482: pmm_setup()
        !           483: {
        !           484:     if (! CONFIG_PMM)
        !           485:         return;
        !           486: 
        !           487:     dprintf(3, "init PMM\n");
        !           488: 
        !           489:     PMMHEADER.signature = PMM_SIGNATURE;
        !           490:     PMMHEADER.entry_offset = (u32)entry_pmm - BUILD_BIOS_ADDR;
        !           491:     PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER));
        !           492: }
        !           493: 
        !           494: void
        !           495: pmm_finalize()
        !           496: {
        !           497:     if (! CONFIG_PMM)
        !           498:         return;
        !           499: 
        !           500:     dprintf(3, "finalize PMM\n");
        !           501: 
        !           502:     PMMHEADER.signature = 0;
        !           503:     PMMHEADER.entry_offset = 0;
        !           504: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.