// 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 "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; } void *data; switch (flags & 3) { default: case 0: return 0; case 1: data = _malloc(lowzone, size, align); break; case 2: data = _malloc(highzone, size, align); break; case 3: { data = _malloc(lowzone, size, align); if (!data) data = _malloc(highzone, size, align); } } if (data && handle != MALLOC_DEFAULT_HANDLE) malloc_sethandle(data, handle); return (u32)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 (u32)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 = _free((void*)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; }