📄 memory.c
字号:
Error(L"Unable to translate bus address to physical address!\n");
}
}
else {
Error(L"Unable to allocate virtual address for memory region 0!\n");
}
Exit(L"InitializeVideoMem");
return FnRetVal;
}
LPVOID
VideoAlloc(
ULONG Bytes,
ULONG Alignment
)
{
// VideoAlloc
// This function allocates video memory. It does so by locating a free node
// of the appropriate size and turning it into an allocated node. It will
// split the remaining piece of the free node into a new free node.
// Local variables.
LPVOID ReturnPointer = NULL; // Return value for this function.
VID_NODE * CurrentNode = NULL;
VID_NODE ** PreviousNext = NULL;
VID_NODE * LeftoverNode = NULL;
// Check parameters. - Bytes can be anything. !TODO! Alignment.
Enter(L"VideoAlloc");
// !TODO! Alignment
if (FindFreeNode(Bytes, &CurrentNode, &PreviousNext)) {
// Work on the free node bins. We may need to split off a new node and
// re-insert it into the free bins.
if (CurrentNode->Size - Bytes != 0) {
LeftoverNode = SystemAlloc(sizeof(VID_NODE));
if (LeftoverNode) {
LeftoverNode->Memory = (LPVOID)((BYTE *)CurrentNode->Memory + Bytes);
LeftoverNode->Size = CurrentNode->Size - Bytes;
// Leftovers are not aligned to anything.
LeftoverNode->Alignment = 0;
// Fixup the CurrentNode.
CurrentNode->Size = Bytes;
// !TODO! Alignemnt?
}
else {
Error(L"System memory allocation failure!\n");
// This call does not return.
}
}
// Remove the current node by making the next pointer in the node before
// us (could be a pointer to the l_FreeBin array,) point to the node
// that's next to the current one (Could be NULL.)
*PreviousNext = CurrentNode->Next;
CurrentNode->Next = NULL;
// Add the leftover node to the bin structure. This must happen AFTER the
// current node has been removed to insure the pointers we got back from
// FindFreeNode are still valid.
if (LeftoverNode) {
InsertFreeNode(LeftoverNode);
}
// Add the current node to the free node hash table.
InsertAllocatedNode(CurrentNode);
// Done.
ReturnPointer = CurrentNode->Memory;
l_FreeVidMemory -= Bytes;
}
Exit(L"VideoAlloc");
return ReturnPointer;
}
void
VideoFree(
LPVOID Pointer
)
{
// VideoFree
// This function frees video memory allocations made with VideoAlloc. It
// moves the allocated node into the correct bin in the free nodes
// structure. Someday, we should probably attempt to compact memory
// at this point. !TODO! (Buddy system?)
// Local variables.
VID_NODE * CurrentNode = NULL;
VID_NODE ** PreviousNext = NULL;
// Check parameters. Pointer can be anything (if we don't find the node,
// we handle it below.)
Enter(L"VideoFree");
if (FindAllocatedNode(Pointer, &CurrentNode, &PreviousNext)) {
// We need to remove the node from the allocated hash table.
*PreviousNext = CurrentNode->Next;
CurrentNode->Next = NULL;
// !TODO! Buddy system coalesce?
// !TODO! Alignment?
// Add the node back into the free bins.
InsertFreeNode(CurrentNode);
// Done.
l_FreeVidMemory += CurrentNode->Size;
}
else {
Message(L"Unable to locate pointer in allocated hash table.\n");
}
Exit(L"VideoFree");
}
ULONG
GetTotalVideoMem()
{
// GetTotalVideoMem
// Returns the total amount of video memory avialable to the Permedia3 in
// bytes. Inlined, so there is no Enter/Exit semantics.
return (l_TotalVidMemory);
}
ULONG
GetFreeVideoMem()
{
// GetFreeVideoMem
// Returns the total amount of unallocated video memory, in bytes. Inlined,
// so there is no Enter or Exit.
return (l_FreeVidMemory);
}
BOOL
FindFreeNode(
ULONG Bytes,
VID_NODE ** CurrentNodeIndirect,
VID_NODE *** PreviousNextIndirect
)
{
// FindFreeNode
// This function searches the free node bin structure for a node just
// larger than the size passed in. It returns the pointer to that node in
// CurrentNodeIndirect and a pointer to the pointer to the current node in
// the bin list in PreviousNextIndirect this allows us to treat head nodes
// the same as Next pointers in VID_NODE structures.
// Local variables.
BOOL GotNode = FALSE; // Return value for this function.
ULONG BinIndex;
// Check parameters.
// Bytes can be anything.
AssertWritePtr(CurrentNodeIndirect, sizeof(VID_NODE*));
AssertWritePtr(PreviousNextIndirect, sizeof(VID_NODE**));
Enter(L"FindFreeNode");
// Simple check. Do we have the memory to do this? (Fragmentation is not
// considered, the call still may fail.)
if (Bytes < l_FreeVidMemory) {
// Find the appropriate bin.
BinIndex = 0;
while (Bytes > l_VidBinsSizes[++BinIndex]);
// Work the bins. If we can find an appropriate node in this bin, use
// it. If not, step up to the next larger bin.
while (!GotNode &&
BinIndex < VID_BIN_COUNT) {
// Search this bin for a node big enough to fit this allocation (first
// fit policy.)
*CurrentNodeIndirect = l_VidBins[BinIndex];
*PreviousNextIndirect = &l_VidBins[BinIndex];
while (*CurrentNodeIndirect != NULL &&
(*CurrentNodeIndirect)->Size < Bytes) {
*PreviousNextIndirect = &((*CurrentNodeIndirect)->Next);
*CurrentNodeIndirect = (*CurrentNodeIndirect)->Next;
}
// Check the search results.
if (*CurrentNodeIndirect != NULL) {
GotNode = TRUE;
}
else {
// Step up to the next biggest bin.
BinIndex++;
}
}
}
else {
Message(L"Not enough memory to satisfy request.\n");
}
Exit(L"FindFreeNode");
return GotNode;
}
BOOL
FindAllocatedNode(
LPVOID Pointer,
VID_NODE ** CurrentNodeIndirect,
VID_NODE *** PreviousNextIndirect
)
{
// FindAllocatedNode
// This function uses the Hash function to attempt to locate an allocated
// node in the table. It returns a pointer to that node through
// CurrentNodeIndirect and pointer to the pointer to that node through
// PreviousNextIndirect. The function returns TRUE if it finds the
// allocation, FALSE if not.
// Local variables.
BOOL GotNode; // Return value for this function.
ULONG PointerHash;
// Check parameters.
// Pointer can be anything - If we don't find it, we fail the call.
AssertWritePtr(CurrentNodeIndirect, sizeof(VID_NODE*));
AssertWritePtr(PreviousNextIndirect, sizeof(VID_NODE**));
Enter(L"FindAllocatedNode");
// Get the hash table entry where this pointer's node would live.
PointerHash = Hash(Pointer);
// Search the list in that entry for the node.
*CurrentNodeIndirect = l_VidHash[PointerHash];
*PreviousNextIndirect = &l_VidHash[PointerHash];
while (*CurrentNodeIndirect != NULL &&
(*CurrentNodeIndirect)->Memory != Pointer) {
*PreviousNextIndirect = &((*CurrentNodeIndirect)->Next);
*CurrentNodeIndirect = (*CurrentNodeIndirect)->Next;
}
// Did we get it?
GotNode = (*CurrentNodeIndirect != NULL);
Exit(L"FindAllocatedNode");
return GotNode;
}
void
InsertAllocatedNode(
VID_NODE * Node
)
{
// InsertAllocatedNode
// This function takes a VID_NODE and inserts it into the allocated node
// table. It cannot fail. The process is simple: figure out which hash
// table entry the node needs to go into and insert it into the list
// at that node.
// Local variables.
ULONG PointerHash;
// Check parameters.
AssertReadPtr(Node, sizeof(VID_NODE));
Enter(L"InsertAllocatedNode");
// Get the hash table entry where this pointer's node would live.
PointerHash = Hash(Node->Memory);
// Insert the new node as the head of the list in that entry.
Node->Next = l_VidHash[PointerHash];
l_VidHash[PointerHash] = Node;
Exit(L"InsertAllocatedNode");
}
void
InsertFreeNode(
VID_NODE * Node
)
{
// InsertFreeNode
// This function takes a VID_NODE and inserts it into the appropriate free
// bin, based on size. It is not allowed to fail. The process is quite
// simple. Locate the appropriate bin and insert the node into the list as
// the new head node, making the old head node our Next.
// Local variables.
ULONG BinIndex = 0;
// Check parameters.
AssertReadPtr(Node, sizeof(VID_NODE));
Enter(L"InsertFreeNode");
// Locate the correct bin.
while (Node->Size > l_VidBinsSizes[++BinIndex]);
// Insert the node into the bin we have located as it's new head.
Node->Next = l_VidBins[BinIndex];
l_VidBins[BinIndex] = Node;
Exit(L"InsertFreeNode");
}
__inline ULONG
Hash(
LPVOID Pointer
)
{
// Hash
// This function turns a pointer to video memory into a suitable hash value
// for the allopcated node table. It does not use the Enter/Exit semantics
// because it's inline, and not really a function.
// Check parameters - Pointer can be anything.
return ((ULONG)(Pointer) % VID_HASH_ENTRIES);
}
ULONG
VirtualToOffset(
LPVOID Pointer
)
{
// VirtualToOffset
// Given a virtual address of video memory location, this function returns
// the offset of that memory location in the memory (from 0.) No Enter/Exit
// semantics becuase this should be inlined.
// !TODO! This code will change if we ever use Aperture2.
// Check parameters.
AssertVideoPtr(Pointer);
return ((ULONG)Pointer - (ULONG)l_Aperture1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -