Subject: [PATCH] YABEL: add PMM functionality.
Signed-off-by: Pattrick Hueper <phueper@hueper.net> Acked-by: Myles Watson <mylesgw@gmail.com> git-svn-id: svn://coreboot.org/repository/coreboot-v3@1086 f3766cd6-281f-0410-b1cd-43a5c92072e9
This commit is contained in:
parent
a492ff7cc9
commit
54f58ebae7
5 changed files with 508 additions and 3 deletions
|
|
@ -29,6 +29,7 @@ ifeq ($(CONFIG_PCI_OPTION_ROM_RUN_YABEL),y)
|
|||
BIOSEMU_SRC = biosemu.c debug.c device.c mem.c io.c interrupt.c
|
||||
#TODO: add vbe.c, currently not needed...
|
||||
#BIOSEMU_SRC +=vbe.c
|
||||
BIOSEMU_SRC +=pmm.c
|
||||
#PH: TODO: remove the compat files??
|
||||
BIOSEMU_SRC += compat/functions.c
|
||||
X86EMU_INCLUDE += -I $(src)/util/x86emu/yabel
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "mem.h"
|
||||
#include "interrupt.h"
|
||||
#include "device.h"
|
||||
#include "pmm.h"
|
||||
|
||||
#include <rtas.h>
|
||||
|
||||
|
|
@ -56,7 +57,9 @@ biosemu(u8 *biosmem, u32 biosmem_size, struct device * dev, unsigned long rom_ad
|
|||
u8 *rom_image;
|
||||
int i = 0;
|
||||
#ifdef DEBUG
|
||||
debug_flags = DEBUG_PRINT_INT10 | DEBUG_PNP | DEBUG_PMM | DEBUG_INTR;// | DEBUG_CHECK_VMEM_ACCESS | DEBUG_MEM | DEBUG_IO;// | DEBUG_TRACE_X86EMU | DEBUG_JMP;
|
||||
debug_flags = DEBUG_PRINT_INT10 | DEBUG_PNP | DEBUG_PMM | DEBUG_INTR;
|
||||
// | DEBUG_CHECK_VMEM_ACCESS | DEBUG_MEM | DEBUG_IO;
|
||||
// | DEBUG_TRACE_X86EMU | DEBUG_JMP;
|
||||
#endif
|
||||
if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) {
|
||||
printf("Error: Not enough virtual memory: %x, required: %x!\n",
|
||||
|
|
@ -209,6 +212,20 @@ biosemu(u8 *biosmem, u32 biosmem_size, struct device * dev, unsigned long rom_ad
|
|||
X86EMU_setupPioFuncs(&my_pio_funcs);
|
||||
X86EMU_setupMemFuncs(&my_mem_funcs);
|
||||
|
||||
//setup PMM struct in BIOS_DATA_SEGMENT, offset 0x0
|
||||
u8 pmm_length = pmm_setup(BIOS_DATA_SEGMENT, 0x0);
|
||||
if (pmm_length <= 0) {
|
||||
printf ("\nYABEL: Warning: PMM Area could not be setup. PMM not available (%x)\n",
|
||||
pmm_length);
|
||||
return 0;
|
||||
} else {
|
||||
CHECK_DBG(DEBUG_PMM) {
|
||||
/* test the PMM */
|
||||
pmm_test();
|
||||
/* and clean it again by calling pmm_setup... */
|
||||
pmm_length = pmm_setup(BIOS_DATA_SEGMENT, 0x0);
|
||||
}
|
||||
}
|
||||
// setup the CPU
|
||||
M.x86.R_AH = bios_device.bus;
|
||||
M.x86.R_AL = bios_device.devfn;
|
||||
|
|
@ -248,8 +265,9 @@ biosemu(u8 *biosmem, u32 biosmem_size, struct device * dev, unsigned long rom_ad
|
|||
X86EMU_exec();
|
||||
DEBUG_PRINTF("done\n");
|
||||
|
||||
// according to PNP BIOS Spec, Option ROMs should upon exit, return some boot device status in
|
||||
// AX (see PNP BIOS Spec Section 3.3
|
||||
/* According to the PNP BIOS Spec, Option ROMs should upon exit, return
|
||||
* some boot device status in AX (see PNP BIOS Spec Section 3.3
|
||||
*/
|
||||
DEBUG_PRINTF_CS_IP("Option ROM Exit Status: %04x\n", M.x86.R_AX);
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF("Exit Status Decode:\n");
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "mem.h"
|
||||
#include "device.h"
|
||||
#include "debug.h"
|
||||
#include "pmm.h"
|
||||
|
||||
#include <x86emu/x86emu.h>
|
||||
#include <x86emu/prim_ops.h>
|
||||
|
|
@ -540,6 +541,13 @@ handleInterrupt(int intNum)
|
|||
handleInt1a();
|
||||
int_handled = 1;
|
||||
break;
|
||||
case PMM_INT_NUM:
|
||||
/* the selfdefined PMM INT number, this is called by the code in PMM struct, it
|
||||
* is handled by pmm_handleInt()
|
||||
*/
|
||||
pmm_handleInt();
|
||||
int_handled = 1;
|
||||
break;
|
||||
default:
|
||||
printf("Interrupt %#x (Vector: %x) not implemented\n", intNum,
|
||||
my_rdl(intNum * 4));
|
||||
|
|
|
|||
437
util/x86emu/yabel/pmm.c
Normal file
437
util/x86emu/yabel/pmm.c
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
/****************************************************************************
|
||||
* YABEL BIOS Emulator
|
||||
*
|
||||
* Copyright 2008 Pattrick Hueper <phueper@hueper.net>
|
||||
****************************************************************************/
|
||||
|
||||
#include <x86emu/x86emu.h>
|
||||
#include <x86emu/prim_ops.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "biosemu.h"
|
||||
#include "pmm.h"
|
||||
#include "debug.h"
|
||||
#include "device.h"
|
||||
|
||||
/* this struct is used to remember which PMM spaces
|
||||
* have been assigned. MAX_PMM_AREAS defines how many
|
||||
* PMM areas we can assign.
|
||||
* All areas are assigned in PMM_CONV_SEGMENT
|
||||
*/
|
||||
typedef struct {
|
||||
u32 handle; /* handle that is returned to PMM caller */
|
||||
u32 offset; /* in PMM_CONV_SEGMENT */
|
||||
u32 length; /* length of this area */
|
||||
} pmm_allocation_t;
|
||||
|
||||
#define MAX_PMM_AREAS 10
|
||||
|
||||
/* array to store the above structs */
|
||||
static pmm_allocation_t pmm_allocation_array[MAX_PMM_AREAS];
|
||||
|
||||
/* index into pmm_allocation_array */
|
||||
static u32 curr_pmm_allocation_index = 0;
|
||||
|
||||
/* This function is used to setup the PMM struct in virtual memory
|
||||
* at a certain offset, the length of the PMM struct is returned */
|
||||
u8 pmm_setup(u16 segment, u16 offset)
|
||||
{
|
||||
/* setup the PMM structure */
|
||||
pmm_information_t *pis =
|
||||
(pmm_information_t *) (M.mem_base + (((u32) segment) << 4) +
|
||||
offset);
|
||||
memset(pis, 0, sizeof(pmm_information_t));
|
||||
/* set signature to $PMM */
|
||||
pis->signature[0] = '$';
|
||||
pis->signature[1] = 'P';
|
||||
pis->signature[2] = 'M';
|
||||
pis->signature[3] = 'M';
|
||||
/* revision as specified */
|
||||
pis->struct_rev = 0x01;
|
||||
/* internal length, excluding code */
|
||||
pis->length = ((void *)&(pis->code) - (void *)&(pis->signature));
|
||||
/* the code to be executed, pointed to by entry_point_offset */
|
||||
pis->code[0] = 0xCD; /* INT */
|
||||
pis->code[1] = PMM_INT_NUM; /* my selfdefined PMM INT number */
|
||||
pis->code[2] = 0xCB; /* RETF */
|
||||
/* set the entry_point_offset, it should point to pis->code, segment is the segment of
|
||||
* this struct. Since pis->length is the length of the struct excluding code, offset+pis->length
|
||||
* points to the code... it's that simple ;-)
|
||||
*/
|
||||
out32le(&(pis->entry_point_offset),
|
||||
(u32) segment << 16 | (u32) (offset + pis->length));
|
||||
/* checksum calculation */
|
||||
u8 i;
|
||||
u8 checksum = 0;
|
||||
for (i = 0; i < pis->length; i++) {
|
||||
checksum += *(((u8 *) pis) + i);
|
||||
}
|
||||
pis->checksum = ((u8) 0) - checksum;
|
||||
CHECK_DBG(DEBUG_PMM) {
|
||||
DEBUG_PRINTF_PMM("PMM Structure:\n");
|
||||
dump((void *)pis, sizeof(pmm_information_t));
|
||||
}
|
||||
return sizeof(pmm_information_t);
|
||||
}
|
||||
|
||||
/* handle the selfdefined interrupt, this is executed, when the PMM Entry Point
|
||||
* is executed, it must handle all PMM requests
|
||||
*/
|
||||
void pmm_handleInt()
|
||||
{
|
||||
u32 rval = 0;
|
||||
u16 function, flags;
|
||||
u32 handle, length;
|
||||
u32 i, j;
|
||||
u32 buffer;
|
||||
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* according to the PMM Spec "the flags and all registers, except DX and AX
|
||||
* are preserved across calls to PMM"
|
||||
* so we save M.x86 and in :exit label we restore it, however, this means that no
|
||||
* returns must be used in this function, any exit must use goto exit!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*/
|
||||
X86EMU_regs backup_regs = M.x86;
|
||||
pop_long(); /* pop the return address, this is already saved in INT handler, we don't need
|
||||
to remember this. */
|
||||
function = pop_word();
|
||||
switch (function) {
|
||||
case 0:
|
||||
/* function pmmAllocate */
|
||||
length = pop_long();
|
||||
length *= 16; /* length is passed in "paragraphs" of 16 bytes each */
|
||||
handle = pop_long();
|
||||
flags = pop_word();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmAllocate: Length: %x, Handle: %x, Flags: %x\n",
|
||||
__FUNCTION__, length, handle, flags);
|
||||
if ((flags & 0x1) != 0) {
|
||||
/* request to allocate in conventional memory */
|
||||
if (curr_pmm_allocation_index >= MAX_PMM_AREAS) {
|
||||
printf
|
||||
("%s: pmmAllocate: Maximum Number of allocatable areas reached (%d), cannot allocate more memory!\n",
|
||||
__FUNCTION__, MAX_PMM_AREAS);
|
||||
rval = 0;
|
||||
goto exit;
|
||||
}
|
||||
/* some ROMs seem to be confused by offset 0, so lets start at 0x100 */
|
||||
u32 next_offset = 0x100;
|
||||
pmm_allocation_t *pmm_alloc =
|
||||
&(pmm_allocation_array[curr_pmm_allocation_index]);
|
||||
if (curr_pmm_allocation_index != 0) {
|
||||
/* we have already allocated... get the new next_offset
|
||||
* from the previous pmm_allocation_t */
|
||||
next_offset =
|
||||
pmm_allocation_array
|
||||
[curr_pmm_allocation_index - 1].offset +
|
||||
pmm_allocation_array
|
||||
[curr_pmm_allocation_index - 1].length;
|
||||
}
|
||||
DEBUG_PRINTF_PMM("%s: next_offset: 0x%x\n",
|
||||
__FUNCTION__, next_offset);
|
||||
if (length == 0) {
|
||||
/* largest possible block size requested, we have on segment
|
||||
* to allocate, so largest possible is segment size (0xFFFF)
|
||||
* minus next_offset
|
||||
*/
|
||||
rval = 0xFFFF - next_offset;
|
||||
goto exit;
|
||||
}
|
||||
u32 align = 0;
|
||||
if (((flags & 0x4) != 0) && (length > 0)) {
|
||||
/* align to least significant bit set in length param */
|
||||
u8 lsb = 0;
|
||||
while (((length >> lsb) & 0x1) == 0) {
|
||||
lsb++;
|
||||
}
|
||||
align = 1 << lsb;
|
||||
}
|
||||
/* always align at least to paragraph (16byte) boundary
|
||||
* hm... since the length is always in paragraphs, we cannot
|
||||
* align outside of paragraphs anyway... so this check might
|
||||
* be unnecessary...*/
|
||||
if (align < 0x10) {
|
||||
align = 0x10;
|
||||
}
|
||||
DEBUG_PRINTF_PMM("%s: align: 0x%x\n", __FUNCTION__,
|
||||
align);
|
||||
if ((next_offset & (align - 1)) != 0) {
|
||||
/* not yet aligned... align! */
|
||||
next_offset += align;
|
||||
next_offset &= ~(align - 1);
|
||||
}
|
||||
if ((next_offset + length) > 0xFFFF) {
|
||||
rval = 0;
|
||||
printf
|
||||
("%s: pmmAllocate: Not enough memory available for allocation!\n",
|
||||
__FUNCTION__);
|
||||
goto exit;
|
||||
}
|
||||
curr_pmm_allocation_index++;
|
||||
/* remember the values in pmm_allocation_array */
|
||||
pmm_alloc->handle = handle;
|
||||
pmm_alloc->offset = next_offset;
|
||||
pmm_alloc->length = length;
|
||||
/* return the 32bit "physical" address, i.e. combination of segment and offset */
|
||||
rval = ((u32) (PMM_CONV_SEGMENT << 16)) | next_offset;
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmAllocate: allocated memory at %x\n",
|
||||
__FUNCTION__, rval);
|
||||
} else {
|
||||
rval = 0;
|
||||
printf
|
||||
("%s: pmmAllocate: allocation in extended memory not supported!\n",
|
||||
__FUNCTION__);
|
||||
}
|
||||
goto exit;
|
||||
case 1:
|
||||
/* function pmmFind */
|
||||
handle = pop_long(); /* the handle to lookup */
|
||||
DEBUG_PRINTF_PMM("%s: pmmFind: Handle: %x\n", __FUNCTION__,
|
||||
handle);
|
||||
i = 0;
|
||||
for (i = 0; i < curr_pmm_allocation_index; i++) {
|
||||
if (pmm_allocation_array[i].handle == handle) {
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmFind: found allocated memory at %x\n",
|
||||
__FUNCTION__, rval);
|
||||
/* return the 32bit "physical" address, i.e. combination of segment and offset */
|
||||
rval =
|
||||
((u32) (PMM_CONV_SEGMENT << 16)) |
|
||||
pmm_allocation_array[i].offset;
|
||||
}
|
||||
}
|
||||
if (rval == 0) {
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmFind: handle (%x) not found!\n",
|
||||
__FUNCTION__, handle);
|
||||
}
|
||||
goto exit;
|
||||
case 2:
|
||||
/* function pmmDeallocate */
|
||||
buffer = pop_long();
|
||||
/* since argument is the address of the PMM block (including the segment,
|
||||
* we need to remove the segment to get the offset
|
||||
*/
|
||||
buffer = buffer ^ ((u32) PMM_CONV_SEGMENT << 16);
|
||||
DEBUG_PRINTF_PMM("%s: pmmDeallocate: PMM segment offset: %x\n",
|
||||
__FUNCTION__, buffer);
|
||||
i = 0;
|
||||
/* rval = 0 means we deallocated the buffer, so set it to 1 in case we dont find it and
|
||||
* thus cannot deallocate
|
||||
*/
|
||||
rval = 1;
|
||||
for (i = 0; i < curr_pmm_allocation_index; i++) {
|
||||
DEBUG_PRINTF_PMM("%d: %x\n", i,
|
||||
pmm_allocation_array[i].handle);
|
||||
if (pmm_allocation_array[i].offset == buffer) {
|
||||
/* we found the requested buffer, rval = 0 */
|
||||
rval = 0;
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmDeallocate: found allocated memory at index: %d\n",
|
||||
__FUNCTION__, i);
|
||||
/* copy the remaining elements in pmm_allocation_array one position up */
|
||||
j = i;
|
||||
for (; j < curr_pmm_allocation_index; j++) {
|
||||
pmm_allocation_array[j] =
|
||||
pmm_allocation_array[j + 1];
|
||||
}
|
||||
/* move curr_pmm_allocation_index one up, too */
|
||||
curr_pmm_allocation_index--;
|
||||
/* finally clean last element */
|
||||
pmm_allocation_array[curr_pmm_allocation_index].
|
||||
handle = 0;
|
||||
pmm_allocation_array[curr_pmm_allocation_index].
|
||||
offset = 0;
|
||||
pmm_allocation_array[curr_pmm_allocation_index].
|
||||
length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rval != 0) {
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmDeallocate: offset (%x) not found, cannot deallocate!\n",
|
||||
__FUNCTION__, buffer);
|
||||
}
|
||||
goto exit;
|
||||
default:
|
||||
/* invalid/unimplemented function */
|
||||
printf("%s: invalid PMM function (0x%04x) called!\n",
|
||||
__FUNCTION__, function);
|
||||
/* PMM spec says if function is invalid, return 0xFFFFFFFF */
|
||||
rval = 0xFFFFFFFF;
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
/* exit handler of this function, restore registers, put return value in DX:AX */
|
||||
M.x86 = backup_regs;
|
||||
M.x86.R_DX = (u16) ((rval >> 16) & 0xFFFF);
|
||||
M.x86.R_AX = (u16) (rval & 0xFFFF);
|
||||
CHECK_DBG(DEBUG_PMM) {
|
||||
DEBUG_PRINTF_PMM("%s: dump of pmm_allocation_array:\n",
|
||||
__FUNCTION__);
|
||||
for (i = 0; i < MAX_PMM_AREAS; i++) {
|
||||
DEBUG_PRINTF_PMM
|
||||
("%d:\n\thandle: %x\n\toffset: %x\n\tlength: %x\n",
|
||||
i, pmm_allocation_array[i].handle,
|
||||
pmm_allocation_array[i].offset,
|
||||
pmm_allocation_array[i].length);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* This function tests the pmm_handleInt() function above. */
|
||||
void pmm_test(void)
|
||||
{
|
||||
u32 handle, length, addr;
|
||||
u16 function, flags;
|
||||
/*-------------------- Test simple allocation/find/deallocation ----------------------------- */
|
||||
function = 0; /* pmmAllocate */
|
||||
handle = 0xdeadbeef;
|
||||
length = 16; /* in 16byte paragraphs, so we allocate 256 bytes... */
|
||||
flags = 0x1; /* conventional memory, unaligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __FUNCTION__,
|
||||
M.x86.R_DX, M.x86.R_AX);
|
||||
function = 1; /* pmmFind */
|
||||
push_long(handle);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM("%s: found memory at: %04x:%04x (expected: %08x)\n",
|
||||
__FUNCTION__, M.x86.R_DX, M.x86.R_AX, addr);
|
||||
function = 2; /* pmmDeallocate */
|
||||
push_long(addr);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n",
|
||||
__FUNCTION__, M.x86.R_DX, M.x86.R_AX);
|
||||
/*-------------------- Test aligned allocation/deallocation ----------------------------- */
|
||||
function = 0; /* pmmAllocate */
|
||||
handle = 0xdeadbeef;
|
||||
length = 257; /* in 16byte paragraphs, so we allocate 4KB + 16 bytes... */
|
||||
flags = 0x1; /* conventional memory, unaligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __FUNCTION__,
|
||||
M.x86.R_DX, M.x86.R_AX);
|
||||
function = 0; /* pmmAllocate */
|
||||
handle = 0xf00d4b0b;
|
||||
length = 128; /* in 16byte paragraphs, so we allocate 2KB... */
|
||||
flags = 0x5; /* conventional memory, aligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
/* the address should be aligned to 0x800, so probably it is at offset 0x1800... */
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __FUNCTION__,
|
||||
M.x86.R_DX, M.x86.R_AX);
|
||||
function = 1; /* pmmFind */
|
||||
push_long(handle);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
function = 2; /* pmmDeallocate */
|
||||
push_long(addr);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n",
|
||||
__FUNCTION__, M.x86.R_DX, M.x86.R_AX);
|
||||
handle = 0xdeadbeef;
|
||||
function = 1; /* pmmFind */
|
||||
push_long(handle);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
function = 2; /* pmmDeallocate */
|
||||
push_long(addr);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n",
|
||||
__FUNCTION__, M.x86.R_DX, M.x86.R_AX);
|
||||
/*-------------------- Test out of memory allocation ----------------------------- */
|
||||
function = 0; /* pmmAllocate */
|
||||
handle = 0xdeadbeef;
|
||||
length = 0; /* length zero means, give me the largest possible block */
|
||||
flags = 0x1; /* conventional memory, unaligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
length = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
length /= 16; /* length in paragraphs */
|
||||
DEBUG_PRINTF_PMM("%s: largest possible length: %08x\n", __FUNCTION__,
|
||||
length);
|
||||
function = 0; /* pmmAllocate */
|
||||
flags = 0x1; /* conventional memory, aligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __FUNCTION__,
|
||||
M.x86.R_DX, M.x86.R_AX);
|
||||
function = 0; /* pmmAllocate */
|
||||
length = 1;
|
||||
handle = 0xf00d4b0b;
|
||||
flags = 0x1; /* conventional memory, aligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
/* this should fail, so 0x0 should be returned */
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: allocated memory at: %04x:%04x expected: 0000:0000\n",
|
||||
__FUNCTION__, M.x86.R_DX, M.x86.R_AX);
|
||||
handle = 0xdeadbeef;
|
||||
function = 1; /* pmmFind */
|
||||
push_long(handle);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
function = 2; /* pmmDeallocate */
|
||||
push_long(addr);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n",
|
||||
__FUNCTION__, M.x86.R_DX, M.x86.R_AX);
|
||||
}
|
||||
41
util/x86emu/yabel/pmm.h
Normal file
41
util/x86emu/yabel/pmm.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/****************************************************************************
|
||||
* YABEL BIOS Emulator
|
||||
*
|
||||
* Copyright 2008 Pattrick Hueper <phueper@hueper.net>
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _YABEL_PMM_H_
|
||||
#define _YABEL_PMM_H_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/* PMM Structure see PMM Spec Version 1.01 Chapter 3.1.1
|
||||
* (search web for specspmm101.pdf)
|
||||
*/
|
||||
typedef struct {
|
||||
u8 signature[4];
|
||||
u8 struct_rev;
|
||||
u8 length;
|
||||
u8 checksum;
|
||||
u32 entry_point_offset;
|
||||
u8 reserved[5];
|
||||
/* Code is not part of the speced PMM struct, however, since I cannot
|
||||
* put the handling of PMM in the virtual memory (I dont want to hack it
|
||||
* together in x86 assembly ;-)) this code array is pointed to by
|
||||
* entry_point_offset, in code there is only a INT call and a RETF,
|
||||
* thus every PMM call will issue a PMM INT (only defined in YABEL,
|
||||
* see interrupt.c) and the INT Handler will do the actual PMM work.
|
||||
*/
|
||||
u8 code[3];
|
||||
} __attribute__ ((__packed__)) pmm_information_t;
|
||||
|
||||
/* This function is used to setup the PMM struct in virtual memory
|
||||
* at a certain offset */
|
||||
u8 pmm_setup(u16 segment, u16 offset);
|
||||
|
||||
/* This is the INT Handler mentioned above, called by my special PMM INT. */
|
||||
void pmm_handleInt(void);
|
||||
|
||||
void pmm_test(void);
|
||||
|
||||
#endif // _YABEL_PMM_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue