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

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

unix.superglobalmegacorp.com

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