WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

Re: [Xen-devel] [PATCH] hvm bios: add PMM (a memory manager during POST)

To: Keir Fraser <keir.fraser@xxxxxxxxxxxxx>
Subject: Re: [Xen-devel] [PATCH] hvm bios: add PMM (a memory manager during POST)
From: Kouya Shimura <kouya@xxxxxxxxxxxxxx>
Date: Fri, 23 Jan 2009 19:23:58 +0900
Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: Fri, 23 Jan 2009 02:24:38 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <C59E0B2F.1AF2%keir.fraser@xxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <7kr62v8ui1.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx> <C59E0B2F.1AF2%keir.fraser@xxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
Hi Keir,

Thanks for your review.
Here is an updated patch using new 32-bit gateway interface.

Thanks,
Kouya

Keir Fraser writes:
> On 22/01/2009 11:12, "Kouya Shimura" <kouya@xxxxxxxxxxxxxx> wrote:
> 
> > The PMM (POST Memory Manager) offers malloc/free functionality
> > for PCI option ROMs during POST (Power On Self Test).
> > 
> > This patch adds a PMM functionality to the guest BIOS.
> 
> Hardcoding the entry point and setting up $PMM in hvmloader is not very
> nice. I think you should define the $PMM struct as data in rombios.c, and
> then you can directly reference pmm_entry_point without needing a .org
> directive. The only difficulty then is the checksum, which I think you
> should calculate in rombios.c rather than doing it in hvmloader. It's a tiny
> bit of C or pretty trivial asm to do it that way. Overall this avoids
> further tying together hvmloader and rombios unnecessarily.
> 
> Beyond that, the allocator looks pretty complicated, but as long as it works
> I suppose that is fine. It would be nice if you could add a top-of-file
> comment explaining the allocator algorithm, where it allocates memory from
> (scavenging from rombios's e820 perhaps), and other details like that.
> Otherwise it's rather unnecessarily opaque new code. A few more comments
> scattered through (especially at tops of functions) would be nice too!

Signed-off-by: Kouya Shimura <kouya@xxxxxxxxxxxxxx>
Signed-off-by: Akio Takebe <takebe_akio@xxxxxxxxxxxxxx>

diff -r 9b0289a165eb tools/firmware/rombios/32bit/Makefile
--- a/tools/firmware/rombios/32bit/Makefile     Thu Jan 22 18:00:48 2009 +0000
+++ b/tools/firmware/rombios/32bit/Makefile     Fri Jan 23 19:16:05 2009 +0900
@@ -18,7 +18,7 @@
 clean: subdirs-clean
        rm -rf *.o $(TARGET) $(DEPS)
 
-$(TARGET): 32bitbios.o $(MODULES) util.o
+$(TARGET): 32bitbios.o $(MODULES) util.o pmm.o
        $(LD) $(LDFLAGS_DIRECT) -s -r $^ -o 32bitbios_all.o
        @nm 32bitbios_all.o |                                \
          egrep '^ +U ' >/dev/null && {                      \
diff -r 9b0289a165eb tools/firmware/rombios/32bit/pmm.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/rombios/32bit/pmm.c        Fri Jan 23 19:16:05 2009 +0900
@@ -0,0 +1,530 @@
+/*
+ *  pmm.c - POST(Power On Self Test) Memory Manager
+ *  according to the specification described in
+ *  
http://www.phoenix.com/NR/rdonlyres/873A00CF-33AC-4775-B77E-08E7B9754993/0/specspmm101.pdf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ *  Copyright (C) 2009 FUJITSU LIMITED
+ *
+ *  Author: Kouya Shimura <kouya@xxxxxxxxxxxxxx>
+ *
+ */
+
+/*
+ * Algorithm:
+ *
+ * This is not a fast storage allocator but simple one.  There is no
+ * segregated management by block size and it does nothing special for
+ * avoiding the fragmentation.
+ *
+ * The allocation algorithm is a first-fit. All memory blocks are
+ * managed by linear single linked list in order of the address.
+ * (i.e. There is no backward pointer) It searches the first available
+ * equal or larger block from the head (lowest address) of memory
+ * heap. The larger block is splitted into two blocks unless one side
+ * becomes too small.
+ * 
+ * For de-allocation, the specified block is just marked as available
+ * and it does nothing else. Thus, the fragmentation will occur. The
+ * collection of continuous available blocks are done on the search
+ * phase of another block allocation.
+ *
+ * The following is an abstract of this algorithm. The actual code
+ * looks complicated on account of alignment and checking the handle.
+ *
+ *     static memblk_t *
+ *     alloc(heap_t *heap, uint32_t size)
+ *     {
+ *         static memblk_t *mb;
+ *         for_each_memblk(heap, mb) // search memory blocks
+ *             if (memblk_is_avail(mb))
+ *             {
+ *                 collect_avail_memblks(heap, mb);
+ *                 if (size <= memblk_bufsize(mb))
+ *                 {
+ *                     split_memblk(mb, size);
+ *                     set_inuse(mb);
+ *                     return mb;
+ *                 }
+ *             }
+ *         return NULL;
+ *     }
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <../hvmloader/config.h>
+#include <../hvmloader/e820.h>
+#include "util.h"
+
+#define DEBUG_PMM 0
+
+#define ASSERT(_expr, _action)                                  \
+    if (!(_expr)) {                                             \
+        printf("ASSERTION FAIL: %s %s:%d %s()\n",               \
+               __STRING(_expr), __FILE__, __LINE__, __func__);  \
+        _action;                                                \
+    } else
+
+#if DEBUG_PMM
+# define PMM_DEBUG(format, p...) printf("PMM " format, ##p)
+#else
+# define PMM_DEBUG(format, p...)
+#endif
+
+struct pmmAllocArgs {
+    uint16_t function;
+    uint32_t length;
+    uint32_t handle;
+    uint16_t flags;
+} __attribute__ ((packed));
+
+struct pmmFindArgs {
+    uint16_t function;
+    uint32_t handle;
+} __attribute__ ((packed));
+
+struct pmmDeallocateArgs {
+    uint16_t function;
+    uint32_t buffer;
+} __attribute__ ((packed));
+
+#define PMM_FUNCTION_ALLOCATE   0
+#define PMM_FUNCTION_FIND       1         
+#define PMM_FUNCTION_DEALLOC    2
+
+#define PARAGRAPH_LENGTH        16  // unit of length
+
+#define PMM_HANDLE_ANONYMOUS    0xffffffff
+
+#define PMM_FLAGS_MEMORY_TYPE_MASK      0x0003
+#define PMM_FLAGS_MEMORY_INVALID        0
+#define PMM_FLAGS_MEMORY_CONVENTIONAL   1  // 0 to 1MB
+#define PMM_FLAGS_MEMORY_EXTENDED       2  // 1MB to 4GB
+#define PMM_FLAGS_MEMORY_ANY            3  // whichever is available
+#define PMM_FLAGS_ALIGINMENT            0x0004
+
+/* Error code */
+#define PMM_ENOMEM      (0)     // Out of memory, duplicate handle
+#define PMM_EINVAL      (-1)    // Invalid argument
+
+#define ALIGN_UP(addr, size)    (((addr)+((size)-1))&(~((size)-1)))
+#define ALIGN_DOWN(addr, size)  ((addr)&(~((size)-1)))
+
+typedef struct memblk {
+    uint32_t magic;      // inuse or available
+    struct memblk *next; // points the very next of this memblk
+    uint32_t handle;     // identifier of this block
+    uint32_t __fill;     // for 16byte alignment, not used
+    uint8_t buffer[0];
+} memblk_t;
+
+typedef struct heap {
+    memblk_t *head;     // start address of heap
+    memblk_t *end;      // end address of heap
+} heap_t;
+
+#define HEAP_NOT_INITIALIZED    (memblk_t *)-1
+#define HEAP_ALIGNMENT          16
+
+/*
+ * PMM handles two memory heaps, the caller chooses either.
+ *
+ * - conventional memroy (below 1MB)
+ *    In HVM, the area is fixed. 0x00010000-0x0007FFFF
+ *    (from SCRATCH_PHYSICAL_ADDRESS to HYPERCALL_PHYSICAL_ADDRESS)
+ *
+ * - extended memory (start at 1MB, below 4GB)
+ *    In HVM, the area starts at memory address 0x00100000.
+ *    The end address is variable. We read low RAM address from e820 table.
+ *
+ * The following struct must be located in the data segment since bss
+ * in 32bitbios doesn't be relocated.
+ */
+static struct {
+    heap_t heap;     // conventional memory
+    heap_t ext_heap; // extended memory
+} pmm_data = { {HEAP_NOT_INITIALIZED, NULL}, {NULL, NULL} };
+
+/* These values are private use, not a spec in PMM */
+#define MEMBLK_MAGIC_INUSE   0x2A4D4D50  // 'PMM*'
+#define MEMBLK_MAGIC_AVAIL   0x5F4D4D50  // 'PMM_'
+
+#define memblk_is_inuse(_mb)  ((_mb)->magic == MEMBLK_MAGIC_INUSE)
+#define memblk_is_avail(_mb)  ((_mb)->magic == MEMBLK_MAGIC_AVAIL)
+
+static void set_inuse(memblk_t *mb, uint32_t handle)
+{
+    mb->magic = MEMBLK_MAGIC_INUSE;
+    mb->handle = handle;
+}
+
+static void set_avail(memblk_t *mb)
+{
+    mb->magic = MEMBLK_MAGIC_AVAIL;
+    mb->handle = PMM_HANDLE_ANONYMOUS;
+}
+
+#define MEMBLK_HEADER_SIZE   ((int)(&((memblk_t *)0)->buffer))
+#define MIN_MEMBLK_SIZE      (MEMBLK_HEADER_SIZE + PARAGRAPH_LENGTH)
+
+#define memblk_size(_mb)     ((void *)((_mb)->next) - (void *)(_mb))
+#define memblk_buffer(_mb)   ((uint32_t)(&(_mb)->buffer))
+#define memblk_bufsize(_mb)  (memblk_size(_mb) - MEMBLK_HEADER_SIZE)
+
+#define buffer_memblk(_buf)  (memblk_t *)((_buf) - MEMBLK_HEADER_SIZE)
+
+#define memblk_loop_mbondition(_h, _mb) \
+    (((_mb) < (_h)->end) && (/* avoid infinite loop */ (_mb) < (_mb)->next))
+
+#define for_each_memblk(_h, _mb)        \
+    for ((_mb) = (_h)->head;            \
+         memblk_loop_mbondition(_h, _mb);   \
+         (_mb) = (_mb)->next)
+
+#define for_remain_memblk(_h, _mb)      \
+    for (;                                      \
+         memblk_loop_mbondition(_h, _mb);   \
+         (_mb) = (_mb)->next)
+
+/*
+ *                                       <-size->
+ *    +==================+======+       +========+========+======+
+ *    |      avail       |      |       | avail  | avail  |      |
+ *    |      memblk      |memblk|...    | memblk | memblk |memblk|...
+ *    +==================+======+   =>  +========+========+======+
+ *    ^ |                ^ |    ^         |      ^ |      ^ |    ^
+ *    | |next            | |next|         |next  | |next  | |next|
+ *    | \________________/ \____/         \______/ \______/ \____/
+ *    |                                          ^
+ *    |                                          |
+ *    mb                                         +- sb(return value)
+ */
+static memblk_t *
+split_memblk(memblk_t *mb, uint32_t size)
+{
+    memblk_t *sb = (void *)memblk_buffer(mb) + size;
+
+    if (memblk_bufsize(mb) - size < MIN_MEMBLK_SIZE) // one side is too small
+        return mb;
+
+    sb->next = mb->next;
+    set_avail(sb);
+
+    mb->next = sb;
+    return sb;
+}
+
+/*
+ *    +======+======+======+======+       +=================+======+
+ *    |avail |avail |avail |inuse |       |      avail      |inuse |   
+ *    |memblk|memblk|memblk|memblk|...    |      memblk     |memblk|...
+ *    +======+======+======+======+   =>  +=================+======+
+ *    ^ |    ^ |    ^ |    ^ |    ^         |               ^ |    ^
+ *    | |next| |next| |next| |next|         |next           | |next|
+ *    | \____/ \____/ \____/ \____/         \_______________/ \____/
+ *    |
+ *    mb
+ */
+static void
+collect_avail_memblks(heap_t *heap, memblk_t *mb)
+{
+    memblk_t *nb = mb->next;
+
+    for_remain_memblk(heap, nb)
+        if (memblk_is_inuse(nb))
+            break;
+    mb->next = nb;
+}
+
+static void
+pmm_init_heap(heap_t *heap, uint32_t from_addr, uint32_t to_addr)
+{
+    memblk_t *mb = (memblk_t *)ALIGN_UP(from_addr, HEAP_ALIGNMENT);
+
+    mb->next = (memblk_t *)ALIGN_DOWN(to_addr, HEAP_ALIGNMENT);
+    set_avail(mb);
+
+    heap->head = mb;
+    heap->end = mb->next;
+}
+
+static void
+pmm_initalize(void)
+{
+    int i, e820_nr = *E820_NR;
+    struct e820entry *e820 = E820;
+
+    /* extended memory: RAM below 4GB, 0x100000-0xXXXXXXXX */
+    for (i = 0; i < e820_nr; i++)
+    {
+        if (e820[i].type == E820_RAM && e820[i].addr == 0x00100000)
+        {
+            pmm_init_heap(&pmm_data.ext_heap, e820[i].addr, 
+                          e820[i].addr + e820[i].size);
+            break;
+        }
+    }
+
+    /* convectional memory: RAM below 1MB, 0x10000-0x7FFFF */
+    pmm_init_heap(&pmm_data.heap, SCRATCH_PHYSICAL_ADDRESS,
+                  HYPERCALL_PHYSICAL_ADDRESS);
+}
+
+static uint32_t
+pmm_max_avail_length(heap_t *heap)
+{
+    memblk_t *mb;
+    uint32_t size, max = 0;
+
+    for_each_memblk(heap, mb)
+    {
+        if (memblk_is_avail(mb))
+        {
+            collect_avail_memblks(heap, mb);
+            size = memblk_bufsize(mb);
+            if (size > max)
+                max = size;
+        }
+    }
+    return (max / PARAGRAPH_LENGTH);
+}
+
+static memblk_t *
+first_fit(heap_t *heap, uint32_t size, uint32_t handle, uint32_t flags)
+{
+    memblk_t *mb;
+    int32_t align = 0;
+
+    if (flags & PMM_FLAGS_ALIGINMENT)
+        align = ((size ^ (size - 1)) >> 1) + 1;
+
+    for_each_memblk(heap, mb)
+    {
+        if (memblk_is_avail(mb))
+        {
+            collect_avail_memblks(heap, mb);
+
+            if (align)
+            {
+                uint32_t addr = memblk_buffer(mb);
+                uint32_t offset = ALIGN_UP(addr, align) - addr;
+
+                if (offset > 0)
+                {
+                    ASSERT(offset >= MEMBLK_HEADER_SIZE, continue);
+
+                    if (offset + size > memblk_bufsize(mb)) // not enough
+                        continue;
+
+                    mb = split_memblk(mb, offset - MEMBLK_HEADER_SIZE);
+                    return mb;
+                }
+            }
+
+            if (size <= memblk_bufsize(mb)) // large enough ?
+                return mb;
+        }
+        else
+        {
+            ASSERT(memblk_is_inuse(mb), return NULL);
+
+            /* duplication check for handle */
+            if (handle != PMM_HANDLE_ANONYMOUS && mb->handle == handle)
+                return NULL;
+        }
+    }
+
+    return NULL;
+}
+
+static memblk_t *
+pmm_find_handle(heap_t *heap, uint32_t handle)
+{
+    memblk_t *mb;
+
+    if (handle == PMM_HANDLE_ANONYMOUS)
+        return NULL;
+
+    for_each_memblk(heap, mb)
+        if (mb->handle == handle)
+            return mb;
+    return NULL;
+}
+
+/*
+ * allocate a memory block of the specified type and size, and returns
+ * the address of the memory block.
+ *
+ * A client-specified identifier to be associated with the allocated
+ * memory block. A handle of 0xFFFFFFFF indicates that no identifier
+ * should be associated with the block. Such a memory block is known
+ * as an "anonymous" memory block and cannot be found using the
+ * pmmFind function. If a specified handle for a requested memory
+ * block is already used in a currently allocated memory block, the
+ * error value of 0x00000000 is returned
+ *
+ * If length is 0x00000000, no memory is allocated and the value
+ * returned is the size of the largest memory block available for the
+ * memory type specified in the flags parameter. The alignment bit in
+ * the flags register is ignored when calculating the largest memory
+ * block available.
+ *
+ * If a specified handle for a requested memory block is already used
+ * in a currently allocated memory block, the error value of
+ * 0x00000000 is returned.
+ * 
+ * A return value of 0x00000000 indicates that an error occurred and
+ * no memory has been allocated. 
+ */
+static uint32_t
+pmmAllocate(uint32_t length, uint32_t handle, uint16_t flags)
+{
+    heap_t *heap;
+    memblk_t *mb;
+    uint32_t size;
+
+    switch(flags & PMM_FLAGS_MEMORY_TYPE_MASK)
+    {
+    case PMM_FLAGS_MEMORY_CONVENTIONAL:
+        heap = &pmm_data.heap;
+        break;
+
+    case PMM_FLAGS_MEMORY_EXTENDED:
+    case PMM_FLAGS_MEMORY_ANY: // XXX: ignore conventional memory for now
+        heap = &pmm_data.ext_heap;
+        break;
+
+    default:
+        return PMM_EINVAL;
+    }
+
+    /* return the largest memory block available */
+    if (length == 0)
+        return pmm_max_avail_length(heap);
+
+    size = length * PARAGRAPH_LENGTH;
+    mb = first_fit(heap, size, handle, flags);
+
+    if (mb == NULL)
+        return PMM_ENOMEM;
+
+    /* duplication check for handle */
+    if (handle != PMM_HANDLE_ANONYMOUS)
+    {
+        memblk_t *nb = mb->next;
+
+        for_remain_memblk(heap, nb)
+            if (nb->handle == handle)
+                return PMM_ENOMEM;
+    }
+
+    split_memblk(mb, size);
+    set_inuse(mb, handle);
+
+    return memblk_buffer(mb);
+}
+
+/*
+ * returns the address of the memory block associated with the
+ * specified handle.  
+ *
+ * A return value of 0x00000000 indicates that the handle does not
+ * correspond to a currently allocated memory block.
+ */
+static uint32_t
+pmmFind(uint32_t handle)
+{
+    memblk_t *mb;
+
+    if (handle == PMM_HANDLE_ANONYMOUS)
+        return 0;
+
+    mb = pmm_find_handle(&pmm_data.heap, handle);
+    if (mb != NULL)
+        return memblk_buffer(mb);
+    mb = pmm_find_handle(&pmm_data.ext_heap, handle);
+    if (mb != NULL)
+        return memblk_buffer(mb);
+    return 0;
+}
+
+/* 
+ * frees the specified memory block that was previously allocated by
+ * pmmAllocate.
+ *
+ * If the memory block was deallocated correctly, the return value is
+ * 0x00000000. If there was an error, the return value is non-zero.
+ */
+static uint32_t
+pmmDeallocate(uint32_t buffer)
+{
+    memblk_t *mb = buffer_memblk(buffer);
+
+    if (!memblk_is_inuse(mb))
+        return PMM_EINVAL;
+
+    set_avail(mb);
+    return 0;
+}
+
+
+union pmm_args {
+    uint16_t function;
+    struct pmmAllocArgs alloc;
+    struct pmmFindArgs find;
+    struct pmmDeallocateArgs dealloc;
+} __attribute__ ((packed));
+
+/*
+ * entry function of all PMM services.
+ *
+ * Values returned to the caller are placed in the DX:AX register
+ * pair. The flags and all registers, other than DX and AX, are
+ * preserved across calls to PMM services.
+ */
+uint32_t
+pmm(void *argp)
+{
+    union pmm_args *ap = argp;
+    uint32_t ret = PMM_EINVAL;
+
+    if (pmm_data.heap.head == HEAP_NOT_INITIALIZED)
+        pmm_initalize();
+
+    switch(ap->function) {
+    case PMM_FUNCTION_ALLOCATE:
+        ret = pmmAllocate(ap->alloc.length, ap->alloc.handle, ap->alloc.flags);
+        PMM_DEBUG("Alloc length=%x handle=%x flags=%x ret=%x\n", 
+               ap->alloc.length, ap->alloc.handle, ap->alloc.flags, ret);
+        break;
+
+    case PMM_FUNCTION_FIND:
+        ret = pmmFind(ap->find.handle);
+        PMM_DEBUG("Find handle=%x ret=%x\n", ap->find.handle, ret);
+        break;
+
+    case PMM_FUNCTION_DEALLOC:
+        ret = pmmDeallocate(ap->dealloc.buffer);
+        PMM_DEBUG("Dealloc buffer=%x ret=%x\n", ap->dealloc.buffer, ret);
+        break;
+
+    default:
+        PMM_DEBUG("Invalid function:%d\n", ap->function);
+    }
+
+    return ret;
+}
diff -r 9b0289a165eb tools/firmware/rombios/32bitprotos.h
--- a/tools/firmware/rombios/32bitprotos.h      Thu Jan 22 18:00:48 2009 +0000
+++ b/tools/firmware/rombios/32bitprotos.h      Fri Jan 23 19:16:05 2009 +0900
@@ -13,3 +13,4 @@
 X(11, void,   tcpa_measure_post, Bit32u from, Bit32u to)
 X(12, Bit32u, tcpa_initialize_tpm, Bit32u physpres)
 X(13, Bit32u, get_s3_waking_vector, void)
+X(14, Bit32u, pmm, void *argp)
diff -r 9b0289a165eb tools/firmware/rombios/rombios.c
--- a/tools/firmware/rombios/rombios.c  Thu Jan 22 18:00:48 2009 +0000
+++ b/tools/firmware/rombios/rombios.c  Fri Jan 23 19:16:05 2009 +0900
@@ -160,6 +160,8 @@
 #define BX_ELTORITO_BOOT 1
 
 #define BX_TCGBIOS       0   /* main switch for TCG BIOS ext. */
+
+#define BX_PMM           1   /* POST Memory Manager */
 
 #define BX_MAX_ATA_INTERFACES   4
 #define BX_MAX_ATA_DEVICES      (BX_MAX_ATA_INTERFACES*2)
@@ -2054,7 +2056,10 @@
   "rombios32 "
 #endif
 #if BX_TCGBIOS
-  "TCG-enabled"
+  "TCG-enabled "
+#endif
+#if BX_PMM
+  "PMM "
 #endif
   "\n\n");
 }
@@ -10356,6 +10361,32 @@
   dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
 #endif // BX_ROMBIOS32
 
+#if BX_PMM
+; according to POST Memory Manager Specification Version 1.01
+.align 16
+pmm_structure:
+  db 0x24,0x50,0x4d,0x4d ;; "$PMM" signature
+  db 0x01 ;; revision
+  db 16 ;; length
+  db (-((pmm_entry_point>>8)+pmm_entry_point+0x20f))&0xff;; checksum
+  dw pmm_entry_point,0xf000 ;; far call entrypoint
+  db 0,0,0,0,0 ;; reserved
+
+pmm_entry_point:
+  pushad
+  mov   eax, esp
+  add   eax, #(8*4+2+2) ;; skip regs of pushad, ip, cs
+  push  eax ;; pointer to PMM function args
+  call _pmm
+  mov   bx, sp
+SEG SS
+  mov   [bx+(4+7*4)], ax
+SEG SS
+  mov   [bx+(4+5*4)], dx
+  pop   eax
+  popad
+  db 0xcb ;; lret
+#endif // BX_PMM
 
 ; parallel port detection: base address in DX, index in BX, timeout in CL
 detect_parport:
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel