/*
*
* Copyright (c) 1994 FirePower Systems, Inc.
* Copyright (c) 1995 FirePower Systems, Inc.
*
* $RCSfile: vrmemory.c $
* $Revision: 1.19 $
* $Date: 1996/06/17 02:55:43 $
* $Locker: $
*
* Module Name:
* vrmemory.c
*
* Authour:
* Shin Iwamoto at FirePower Systems, Inc.
*
* History:
* 10-Sep-94 Shin Iwamoto at FirePower Systems, Inc.
* Added for ExecuteProg. Added comments.
* 07-Sep-94 Shin Iwamoto at FirePower Systems, Inc.
* Recreated.
*/
#include "veneer.h"
//
// Define memory allocation structure.
//
typedef struct _VR_MEMORY_DESCRIPTOR {
struct _VR_MEMORY_DESCRIPTOR *NextEntry;
MEMORY_DESCRIPTOR MemoryEntry;
} VR_MEMORY_DESCRIPTOR, *PVR_MEMORY_DESCRIPTOR;
PVR_MEMORY_DESCRIPTOR VrMemoryListOrig = (PVR_MEMORY_DESCRIPTOR) NULL;
//
// Function declaration
//
STATIC PVR_MEMORY_DESCRIPTOR SearchMemoryList(ULONG, ULONG);
STATIC VOID SplitDesc(PVR_MEMORY_DESCRIPTOR, ULONG, ULONG, MEMORY_TYPE);
STATIC PCHAR
MemoryTypeTable[] = {
"MemoryExceptionBlock",
"MemorySystemBlock",
"MemoryFree",
"MemoryBad",
"MemoryLoadedProgram",
"MemoryFirmwareTemporary",
"MemoryFirmwarePermanent",
"MemoryFreeContiguous",
"MemorySpecialMemory"
};
/*
* Name: VrGetmemoryDescriptor
*
* Description:
* This routine returns a pointer to the next memory descriptor. If
* the specified memory descriptor is NULL, then a pointer to the
* first memory descriptor is returned. If there are no more memory
* descriptors, then NULL is returned.
*
* Arguments:
* MemoryDescriptor - Supplies a optional pointer to a memory descriptor.
*
* Return Value:
* If there are any more entries in the memory descriptor list, the
* address of the next descriptor is returned. Otherwise, NULL is
* returned.
*
*/
PMEMORY_DESCRIPTOR
VrGetMemoryDescriptor(
IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
)
{
PMEMORY_DESCRIPTOR P;
PVR_MEMORY_DESCRIPTOR Entry;
debug(VRDBG_MEM, "VrGetMemoryDescriptor(%x): ", MemoryDescriptor);
if (MemoryDescriptor == (PMEMORY_DESCRIPTOR) NULL) {
P = &(VrMemoryListOrig->MemoryEntry);
debug(VRDBG_MEM, "%x (%s %x %x)\n", P, MemoryTypeTable[P->MemoryType],
P->BasePage, P->PageCount);
return (P);
}
for (Entry = VrMemoryListOrig; Entry; Entry = Entry->NextEntry) {
if (&Entry->MemoryEntry == MemoryDescriptor) {
break;
}
}
if (Entry->NextEntry == NULL) {
debug(VRDBG_MEM, "NULL\n");
return ((PMEMORY_DESCRIPTOR) NULL);
} else {
P = &(Entry->NextEntry->MemoryEntry);
debug(VRDBG_MEM, "%x (%s %x %x)\n", P, MemoryTypeTable[P->MemoryType],
P->BasePage, P->PageCount);
return (P);
}
}
/*
* Name: VrCreateMemoryDescriptor
*
* Description:
* This function creates the list of memory descriptors.
*
*/
VOID
VrCreateMemoryDescriptors(
VOID
)
{
phandle ph;
char *regp;
reg *cur_reg;
int addr_cells, size_cells, regsize;
PVR_MEMORY_DESCRIPTOR pre_desc, cur_desc;
PVR_MEMORY_DESCRIPTOR FoundDesc;
ULONG proplen, cur_basepage, cur_pagecount;
ULONG i;
debug(VRDBG_MEM|VRDBG_ENTRY,
"VrCreateMemoryDescriptors:____________________BEGIN...\n");
//
// Get phandle for /memory.
//
ph = OFFinddevice("/chosen");
if (ph == -1) {
fatal("Cannot access /chosen node.\n");
}
ph = OFInstanceToPackage(get_int_prop(ph, "memory"));
if (ph == -1) {
fatal("Cannot access /memory node.\n");
}
//
// Get information of installed memory from OpenFirmware.
//
if ((proplen = OFGetproplen(ph, "reg")) <= 0) {
fatal("No memory reg structs. proplen = %d\n", proplen);
}
regp = malloc(proplen);
if (OFGetprop(ph, "reg", regp, proplen) != (long) proplen) {
warn("Getprop(memory.reg) return != %d\n", proplen);
}
//
// How big are the descriptors? How many "cells" are required to
// represent addresses.
//
addr_cells = get_int_prop(OFParent(ph), "#address-cells");
if (addr_cells == -1) {
addr_cells = 2;
}
//
// How many ints is an address cell?
//
size_cells = get_int_prop(OFParent(ph), "#size-cells");
if (size_cells == -1) {
size_cells = 1;
}
regsize = (addr_cells + size_cells) * sizeof(int);
debug(VRDBG_MEM, "regsize: %x, proplen: %x\n",regsize, proplen);
//
// Look at the "reg" property list for the /memory node. This list
// shows what memory the firmware has already "claimed" for any reason.
//
pre_desc = (PVR_MEMORY_DESCRIPTOR) &VrMemoryListOrig;
debug(VRDBG_MEM, "VrCreateMemoryDescriptors: Base Page Page Count\n");
for (i = 0; i < proplen/regsize; i++) {
cur_desc = new(VR_MEMORY_DESCRIPTOR);
cur_desc->NextEntry = NULL;
pre_desc->NextEntry = cur_desc;
cur_desc->MemoryEntry.MemoryType = MemoryFirmwareTemporary;
cur_reg = decode_reg( regp + (i * regsize),
regsize,
addr_cells,
size_cells
);
cur_desc->MemoryEntry.BasePage =
(cur_reg->lo >> PAGE_SHIFT) + (cur_reg->hi << (32-PAGE_SHIFT));
cur_desc->MemoryEntry.PageCount = cur_reg->size >> PAGE_SHIFT;
debug(VRDBG_MEM, "\t\t\t\t\t0x%x\t0x%x\n",
cur_desc->MemoryEntry.BasePage,cur_desc->MemoryEntry.PageCount);
pre_desc = cur_desc;
}
//
// Release the area for "reg" property
//
free(regp);
//
// Get information of available memory from OpenFirmware.
//
if ((proplen = OFGetproplen(ph, "available")) <= 0) {
fatal("No memory available structs. proplen = %d\n", proplen);
}
regp = malloc(proplen);
if (OFGetprop(ph, "available", regp, proplen) != (long) proplen) {
warn("Getprop(memory.available) return != %d\n", proplen);
}
//
// Search the chunk specified by each "available" memory
// in the installed memory. Then make the chunk MemoryFree.
//
for (i = 0; i < proplen/regsize; i++) {
cur_reg = decode_reg(regp + (i * regsize), regsize, 1, 1);
cur_basepage =
(cur_reg->lo >> PAGE_SHIFT) + (cur_reg->hi << (32-PAGE_SHIFT));
cur_pagecount = cur_reg->size >> PAGE_SHIFT;
FoundDesc = SearchMemoryList(cur_basepage, cur_pagecount);
if (FoundDesc == NULL) {
fatal("Available memory (0x%x, 0x%x) is not in installed memory",
cur_basepage, cur_pagecount);
}
if ((FoundDesc->MemoryEntry.BasePage == cur_basepage) &&
(FoundDesc->MemoryEntry.PageCount == cur_pagecount)) {
FoundDesc->MemoryEntry.MemoryType = MemoryFree;
} else {
SplitDesc(FoundDesc, cur_basepage, cur_pagecount, MemoryFree);
}
debug(VRDBG_MEM, "\t\t\t\t\t0x%x\t0x%x\n",
FoundDesc->MemoryEntry.BasePage, FoundDesc->MemoryEntry.PageCount);
}
//
// Release the area for "available" property
//
free(regp);
//
// For some memory chunks, mark specific attributes.
//
cur_desc = VrMemoryListOrig;
while (cur_desc != NULL) {
PMEMORY_DESCRIPTOR cur_mem;
cur_mem = &cur_desc->MemoryEntry;
//
// The loaded program must be MemoryLoadedProgram.
//
if ( cur_mem->BasePage == 0x600) {
cur_mem->MemoryType = MemoryLoadedProgram;
}
//
// The first N pages are marked Permanent.
//
if ( cur_mem->BasePage == 0x0) {
cur_mem->MemoryType = MemoryFirmwarePermanent;
}
//
// If a descriptor crosses the 8MB line, split it.
//
if (cur_mem->BasePage < 0x800 &&
(cur_mem->BasePage + cur_mem->PageCount > 0x800)) {
SplitDesc(cur_desc, cur_mem->BasePage,
0x800 - cur_mem->BasePage, MemoryFree);
}
//
// Descriptors > 8MB are marked FirmwareTemporary.
//
if (cur_mem->MemoryType == MemoryFree && cur_mem->BasePage >= 0x800) {
cur_mem->MemoryType = MemoryFirmwareTemporary;
}
cur_desc = cur_desc->NextEntry;
}
debug(VRDBG_MEM|VRDBG_ENTRY,
"VrCreateMemoryDescriptors:____________________...END\n");
}
/*
* Name: VrMemoryInitialize
*
* Description:
* This function initializes the Memory entry points in the firmware
* transfer vector and the file table.
*
* Arguments:
* None.
*
* Return Value:
* None.
*
*/
VOID
VrMemoryInitialize(
VOID
)
{
//
// Initialize the I/O entry points in the firmware transfer vector.
//
debug(VRDBG_ENTRY, "VrMemoryInitialize: BEGIN....\n");
(PARC_MEMORY_ROUTINE) SYSTEM_BLOCK->FirmwareVector[MemoryRoutine] =
VrGetMemoryDescriptor;
debug(VRDBG_ENTRY, "VrMemoryInitialize: ....END\n");
}
STATIC
PVR_MEMORY_DESCRIPTOR
SearchMemoryList(
ULONG CurBasePage,
ULONG CurPageCount
)
{
PVR_MEMORY_DESCRIPTOR search_desc;
search_desc = VrMemoryListOrig;
while(search_desc != NULL) {
if (search_desc->MemoryEntry.BasePage <= CurBasePage
&& search_desc->MemoryEntry.BasePage +
search_desc->MemoryEntry.PageCount >= CurBasePage+CurPageCount) {
return search_desc;
}
search_desc = search_desc->NextEntry;
}
return (PVR_MEMORY_DESCRIPTOR) NULL;
}
/*
*
* Routine: VOID SplitDesc(PVR_MEMORY_DESCRIPTOR, ULONG, ULONG, MEMORY_TYPE)
*
*
* Description:
* This routine is called to split a memory descriptor into two
pieces. The only issue is whether the left over piece is the
first or the second of the two pieces.
The original descriptor looks like.....
CurBasePage
|-----------------------PageCount-------------->|
________________________________________________
| |
| Original Type (OType) |
| |
| |
------------------------------------------------
The new arrangement will have pieces that are either
CurBasePage
|---------CurPageCount-------->|
________________________________________________
| | |
| Original Piece, | New Piece |
| MemType passed in | OType |
| | |
------------------------------------------------
OR it will look like:.....
CurBasePage
| |--CurPageCount->|
________________________________________________
| | |
| OType, Original Descript. | New Piece |
| | MemType |
| | |
------------------------------------------------
*
*/
STATIC
VOID
SplitDesc(
PVR_MEMORY_DESCRIPTOR MemDesc,
ULONG CurBasePage,
ULONG CurPageCount,
MEMORY_TYPE MemType
)
{
PVR_MEMORY_DESCRIPTOR new_desc;
//
// If the descriptor passed in points the the base page passed in,
// then take the current descriptor and retype it the MemType, size
// it as CurPageCount, and then create a new descriptor to describe
// what's left over maintaining the original mem type.
//
if (MemDesc->MemoryEntry.BasePage == CurBasePage) {
new_desc = new(VR_MEMORY_DESCRIPTOR);
new_desc->NextEntry = MemDesc->NextEntry;
MemDesc->NextEntry = new_desc;
new_desc->MemoryEntry.MemoryType = MemDesc->MemoryEntry.MemoryType;
new_desc->MemoryEntry.BasePage =
MemDesc->MemoryEntry.BasePage + CurPageCount;
new_desc->MemoryEntry.PageCount =
MemDesc->MemoryEntry.PageCount - CurPageCount;
MemDesc->MemoryEntry.MemoryType = MemType;
MemDesc->MemoryEntry.BasePage = CurBasePage;
MemDesc->MemoryEntry.PageCount = CurPageCount;
return;
}
//
// If the base page value passed in is not the base page of the
// descriptor passed in, then the size and type refer to a region to
// carve out of the end of this descriptor rather than the beginning.
//
new_desc = new(VR_MEMORY_DESCRIPTOR);
new_desc->NextEntry = MemDesc->NextEntry;
MemDesc->NextEntry = new_desc;
new_desc->MemoryEntry.MemoryType = MemType;
new_desc->MemoryEntry.BasePage = CurBasePage;
new_desc->MemoryEntry.PageCount = CurPageCount;
MemDesc->MemoryEntry.PageCount -= CurPageCount;
if (MemDesc->MemoryEntry.BasePage + MemDesc->MemoryEntry.PageCount
!= new_desc->MemoryEntry.BasePage) {
ULONG old_size = MemDesc->MemoryEntry.PageCount;
new_desc = new(VR_MEMORY_DESCRIPTOR);
new_desc->NextEntry = MemDesc->NextEntry->NextEntry;
MemDesc->NextEntry->NextEntry = new_desc;
MemDesc->MemoryEntry.PageCount =
MemDesc->NextEntry->MemoryEntry.BasePage -
MemDesc->MemoryEntry.BasePage;
new_desc->MemoryEntry.MemoryType = MemDesc->MemoryEntry.MemoryType;
new_desc->MemoryEntry.BasePage =
MemDesc->NextEntry->MemoryEntry.BasePage +
MemDesc->NextEntry->MemoryEntry.PageCount;
new_desc->MemoryEntry.PageCount =
old_size - MemDesc->MemoryEntry.PageCount;
}
return;
}
VOID
DisplayMemory(VOID)
{
PMEMORY_DESCRIPTOR P = NULL;
while ((P = VrGetMemoryDescriptor(P)) != NULL) {
debug(VRDBG_MEM, "MemoryType=%s, BasePage=0x%x, PageCount=0x%x\n",
MemoryTypeTable[P->MemoryType], P->BasePage, P->PageCount);
}
}