Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / src / pmm.c
diff --git a/qemu/roms/seabios/src/pmm.c b/qemu/roms/seabios/src/pmm.c
new file mode 100644 (file)
index 0000000..304faab
--- /dev/null
@@ -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;
+}