diff options
Diffstat (limited to 'qemu/roms/seabios/src/pmm.c')
-rw-r--r-- | qemu/roms/seabios/src/pmm.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/qemu/roms/seabios/src/pmm.c b/qemu/roms/seabios/src/pmm.c new file mode 100644 index 000000000..304faab2c --- /dev/null +++ b/qemu/roms/seabios/src/pmm.c @@ -0,0 +1,163 @@ +// Post memory manager (PMM) calls +// +// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net> +// +// 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; +} |