// Post memory manager (PMM) calls // // Copyright (C) 2009-2013 Kevin O'Connor // // This file may be distributed under the terms of the GNU LGPLv3 license. #include "biosvar.h" // FUNC16 #include "config.h" // CONFIG_* #include "malloc.h" // _malloc #include "output.h" // dprintf #include "e820map.h" // struct e820entry #include "std/pmm.h" // PMM_SIGNATURE #include "string.h" // checksum #include "util.h" // pmm_init #include "x86.h" // __ffs extern struct pmmheader PMMHEADER; #if CONFIG_PMM struct pmmheader PMMHEADER __aligned(16) VARFSEG = { .signature = PMM_SIGNATURE, .version = 0x01, .length = sizeof(PMMHEADER), }; #endif // PMM - allocate static u32 handle_pmm00(u16 *args) { u32 length = *(u32*)&args[1], handle = *(u32*)&args[3]; u16 flags = args[5]; dprintf(3, "pmm00: length=%x handle=%x flags=%x\n" , length, handle, flags); struct zone_s *lowzone = &ZoneTmpLow, *highzone = &ZoneTmpHigh; if (flags & 8) { // Permanent memory request. lowzone = &ZoneLow; highzone = &ZoneHigh; } if (!length) { // Memory size request switch (flags & 3) { default: case 0: return 0; case 1: return malloc_getspace(lowzone); case 2: return malloc_getspace(highzone); case 3: { u32 spacelow = malloc_getspace(lowzone); u32 spacehigh = malloc_getspace(highzone); if (spacelow > spacehigh) return spacelow; return spacehigh; } } } u32 size = length * 16; if ((s32)size <= 0) return 0; u32 align = MALLOC_MIN_ALIGN; if (flags & 4) { align = 1<<__ffs(size); if (align < MALLOC_MIN_ALIGN) align = MALLOC_MIN_ALIGN; } u32 data; switch (flags & 3) { default: case 0: return 0; case 1: data = malloc_palloc(lowzone, size, align); break; case 2: data = malloc_palloc(highzone, size, align); if (!data && (flags & 8)) { /* * We are out of meory. So go allocate from the (big) * ZoneTmpHigh instead and reserve the block in the e820 * map so the OS will not override it. That way we can * handle big permanent allocations without needing a big * ZoneHigh. */ data = malloc_palloc(&ZoneTmpHigh, size, align); if (data) e820_add(data, size, E820_RESERVED); } break; case 3: { data = malloc_palloc(lowzone, size, align); if (!data) data = malloc_palloc(highzone, size, align); } } if (data && handle != MALLOC_DEFAULT_HANDLE) malloc_sethandle(data, handle); return data; } // PMM - find static u32 handle_pmm01(u16 *args) { u32 handle = *(u32*)&args[1]; dprintf(3, "pmm01: handle=%x\n", handle); if (handle == MALLOC_DEFAULT_HANDLE) return 0; return malloc_findhandle(handle); } // PMM - deallocate static u32 handle_pmm02(u16 *args) { u32 buffer = *(u32*)&args[1]; dprintf(3, "pmm02: buffer=%x\n", buffer); int ret = malloc_pfree(buffer); if (ret) // Error return 1; return 0; } static u32 handle_pmmXX(u16 *args) { return PMM_FUNCTION_NOT_SUPPORTED; } u32 VISIBLE32INIT handle_pmm(u16 *args) { ASSERT32FLAT(); if (! CONFIG_PMM) return PMM_FUNCTION_NOT_SUPPORTED; u16 arg1 = args[0]; dprintf(DEBUG_HDL_pmm, "pmm call arg1=%x\n", arg1); u32 ret; switch (arg1) { case 0x00: ret = handle_pmm00(args); break; case 0x01: ret = handle_pmm01(args); break; case 0x02: ret = handle_pmm02(args); break; default: ret = handle_pmmXX(args); break; } return ret; } void pmm_init(void) { if (! CONFIG_PMM) return; dprintf(3, "init PMM\n"); PMMHEADER.entry = FUNC16(entry_pmm); PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER)); } void pmm_prepboot(void) { if (! CONFIG_PMM) return; dprintf(3, "finalize PMM\n"); PMMHEADER.signature = 0; PMMHEADER.entry.segoff = 0; }