Annotation of qemu/roms/seabios/src/pmm.c, revision 1.1.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.