mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
481 lines
12 KiB
481 lines
12 KiB
/*
|
|
*
|
|
* 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);
|
|
}
|
|
}
|