blob: e87cfd1eebd39f3352f1e28977ca649e206d8d75 [file] [log] [blame]
// 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 "farptr.h" // struct segoff_s
#include "malloc.h" // _malloc
#include "output.h" // dprintf
#include "string.h" // checksum
#include "util.h" // pmm_init
#include "x86.h" // __ffs
struct pmmheader {
u32 signature;
u8 version;
u8 length;
u8 checksum;
struct segoff_s entry;
u8 reserved[5];
} PACKED;
extern struct pmmheader PMMHEADER;
#define PMM_SIGNATURE 0x4d4d5024 // $PMM
#if CONFIG_PMM
struct pmmheader PMMHEADER __aligned(16) VARFSEG = {
.signature = PMM_SIGNATURE,
.version = 0x01,
.length = sizeof(PMMHEADER),
};
#endif
#define PMM_FUNCTION_NOT_SUPPORTED 0xffffffff
// 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;
}
switch (flags & 3) {
default:
case 0:
return 0;
case 1:
return (u32)_malloc(lowzone, handle, size, align);
case 2:
return (u32)_malloc(highzone, handle, size, align);
case 3: {
void *data = _malloc(lowzone, handle, size, align);
if (data)
return (u32)data;
return (u32)_malloc(highzone, handle, size, align);
}
}
}
// 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_find(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;
}