📄 memory.c
字号:
//
// Permedia3 Sample Display Driver
// memory.c
//
// Copyright (c) 2000 Microsoft Corporation. All rights reserved.
//
// This module contains all of the code for mainupulating dynamic memory, both
// system and video. This includes allocation services. The initialization
// tasks for memory are split in two becuase we need system memory services
// before we are prepared to initialize video memory.
//
// Main areas of improvement: allow allocated to be aligned to particular
// boundaries. Implement buddy system to allow free blocks to be coalesced
// to fight fragmentation. Figure out if there is a good way of determining
// the amount of RAM installed at run-time.
#include "pch.h" // Precompiled header support.
#include "const.h"
#include "debug.h"
#include "struct.h"
#include "global.h"
#include "proto.h"
#include "register.h"
// This structure is used to track allocations. The heap uses a hash table for
// recording allocated nodes (the hashing function is based on address,) and
// a segmented fits scheme for free nodes. The free nodes are kept in bins.
// Each bins stores nodes of a specified size range. If there is no node in a
// bin, a node is taken from the bin containing the next largest size and
// split. The bins themselves are organized in an array (the number of bins is
// constant.)
// These sturcts are private to this module, and are used for the video memory
// heap.
typedef struct t_VID_NODE {
LPVOID Memory;
ULONG Size;
// This is the alignment that this node was restricted to. This tells us how
// many bytes before the Memory pointer are actually part of this block
// that are not reflected in the Memory/Size members.
ULONG Alignment;
struct t_VID_NODE * Next;
} VID_NODE;
// This is the handle to our private system memory heap.
static HANDLE l_Heap;
// These are the virtual addresses of the video memory apertures.
static LPVOID l_Aperture1;
static LPVOID l_Aperture2;
// This is the hash table where records of allocated blocks of video memory are
// kept.
static VID_NODE * l_VidHash[VID_HASH_ENTRIES];
// This is the segregated fits array. Each entry in the array has a max size
// associated with it, stored in the companion array. Note, that the
// construction of the heap procludes allocations of greater than 32 MBytes.
// Also note that the fact the bin sizes are sorted is important and assumed
// by the code below.
static const ULONG l_VidBinsSizes[VID_BIN_COUNT] =
{ 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 33554432 };
static VID_NODE * l_VidBins[VID_BIN_COUNT];
// Some general stats about the heap.
static ULONG l_TotalVidMemory;
static ULONG l_FreeVidMemory;
// Internal prototypes. These functions are not exposed outside this module.
static BOOL
FindFreeNode(
ULONG Bytes,
VID_NODE ** CurrentNodeIndirect,
VID_NODE *** PreviousNextIndirect
);
static BOOL
FindAllocatedNode(
LPVOID Pointer,
VID_NODE ** CurrentNodeIndirect,
VID_NODE *** PreviousNextIndirect
);
static void
InsertAllocatedNode(
VID_NODE * Node
);
static void
InsertFreeNode(
VID_NODE * Node
);
static __inline ULONG
Hash(
LPVOID Pointer
);
BOOL
InitializeSystemMem()
{
// InitializeSystemMem
// This function initializes our access to dynamic system memory services.
// In practice, this means that we create a private heap for the driver's
// use. The GWES process heap is littered with many allocations that make it
// slower and possibly less useable than a private heap.
// Local variables.
BOOL FnRetVal = FALSE; // Return value for this function.
Enter(L"InitializeSystemMem");
// Because all driver access is serialezed through the GWES lock, we do not
// need to serialize access to our private heap. The size specified is the
// initial size : all CE heaps grow if needed.
l_Heap = HeapCreate(HEAP_NO_SERIALIZE,
SYSTEM_MEM_HEAP_SIZE,
0); // Maximum size is unsupported
if (l_Heap != NULL) {
FnRetVal = TRUE;
}
else {
Error(L"Unable to create private system memory heap!\n");
}
Exit(L"InitializeSystemMem");
return FnRetVal;
}
LPVOID
SystemAlloc(
ULONG Bytes
)
{
// SystemAlloc
// This function allocates a certian number of bytes of system memory.
// Local variables.
LPVOID Pointer = NULL; // Return value for this function.
// No parameter check - Bytes can be anything.
Enter(L"SystemAlloc");
Pointer = HeapAlloc(l_Heap,
0, // No flags (flags inherited from heap itself.)
Bytes);
Exit(L"SystemAlloc");
return Pointer;
}
LPVOID
SystemReAlloc(
LPVOID Pointer,
ULONG Bytes
)
{
// SystemReAlloc
// This method resizes a given allocation to the new given size, while
// maintaining the contents of the origianl allocation. Returns the new
// pointer to the resized block.
// Local variables.
LPVOID NewPointer = NULL;
// Check parameters.
// !TODO!
Enter(L"SystemReAlloc");
NewPointer = HeapReAlloc(l_Heap,
0, // No flags (flags inherited from heap itself.)
Pointer,
Bytes);
Exit(L"SystemReAlloc");
return NewPointer;
}
void
SystemFree(
LPVOID Pointer
)
{
// SystemFree
// This method releases an allocation issued by SystemAlloc.
// Check parameters. !TODO! What to do about Pointer? Anything?
Enter(L"SystemFree");
HeapFree(l_Heap,
0, // No flags (flags inherited from heap itself.)
Pointer);
Exit(L"SystemFree");
}
BOOL
InitializeVideoMem()
{
// InitializeVideoMem
// This function mpas the Permedia3's video memory into our virtual address
// space and initializes our local video memory heap.
// !TODO! Figure out something to do with Aperture2?
// Local variables.
BOOL FnRetVal = FALSE; // Return value for this function.
PHYSICAL_ADDRESS ApertureBus;
PHYSICAL_ADDRESS Aperture1Physical, Aperture2Physical;
ULONG AddressSpace;
BOOL RetVal1, RetVal2;
ULONG i;
VID_NODE * FirstNode = NULL;
Enter(L"InitializeVideoMem");
// Map the two video memory apertures to virtual address space.
l_Aperture1 = VirtualAlloc(NULL, // System locates virtual space
APERTURE_SIZE,
MEM_RESERVE,
PAGE_NOACCESS);
l_Aperture2 = VirtualAlloc(NULL, // System locates virtual space
APERTURE_SIZE,
MEM_RESERVE,
PAGE_NOACCESS);
if (l_Aperture1 != NULL && l_Aperture2 != NULL) {
// Use HalTranslateBusAddress to turn the PCI address into a physical
// address. Essentially, this is finding out what physical address the
// processor needs to issue to the PCI bus to get to the given PCI address.
AddressSpace = 0; // Memory mapped, not port mapped
Aperture1Physical.QuadPart = 0;
ApertureBus.LowPart = g_Config.PciCommonConfig.u.type0.BaseAddresses[1];
ApertureBus.HighPart = 0;
RetVal1 = HalTranslateBusAddress(PCIBus,
g_Config.PciBusNumber,
ApertureBus,
&AddressSpace,
&Aperture1Physical);
AddressSpace = 0; // Memory mapped, not port mapped
Aperture2Physical.QuadPart = 0;
ApertureBus.LowPart = g_Config.PciCommonConfig.u.type0.BaseAddresses[2];
ApertureBus.HighPart = 0;
RetVal2 = HalTranslateBusAddress(PCIBus,
g_Config.PciBusNumber,
ApertureBus,
&AddressSpace,
&Aperture2Physical);
if (RetVal1 && RetVal2) {
// Now, actually map the physical address to a virtual address. We need
// to shift the physcial address right because when PAGE_PHYSICAL is
// specified, VirtualCopy expects the high 32 bits of a 40 bit
// address. The shift essentially sets those high 8 bits to 0.
// !BUGBUG! Windows CE restricts us to calling VirtualCopy with no
// more than 32 Megabytes at a time. For the time being, we get around
// this by calling VirtualCopy twice per aperture. If you have memory
// apertures of less than 32 megabytes in size, then you don't need to
// worry about this.
#if APERTURE_SIZE < 33554432
RetVal1 = VirtualCopy(l_Aperture1,
(LPVOID)(Aperture1Physical.LowPart >> 8),
APERTURE_SIZE,
PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL);
RetVal2 = VirtualCopy(l_Aperture2,
(LPVOID)(Aperture2Physical.LowPart >> 8),
APERTURE_SIZE,
PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL);
#else
// Our bugbug code only handles aperture sizes of 64 MBytes.
#if APERTURE_SIZE != 67108864
#error APERTURE_SIZE problem! APERTURE_SIZE > 32 MBytes but not 64 MBytes!
#else
RetVal1 = (VirtualCopy(l_Aperture1,
(LPVOID)(Aperture1Physical.LowPart >> 8),
33554432,
PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
&
(VirtualCopy(((LPBYTE)l_Aperture1 + 33554432),
(LPVOID)((Aperture1Physical.LowPart + 33554432) >> 8),
33554432,
PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL));
RetVal2 = (VirtualCopy(l_Aperture2,
(LPVOID)(Aperture2Physical.LowPart >> 8),
33554432,
PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
&
(VirtualCopy(((LPBYTE)l_Aperture2 + 33554432),
(LPVOID)((Aperture2Physical.LowPart + 33554432) >> 8),
33554432,
PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL));
#endif
#endif
if (RetVal1 && RetVal2) {
WaitForInputFIFO(2);
// Setup both apertures as normal apertures : no SVGA subsystem, no
// ROM access.
WriteRegUlong(r_ApertureOne, 0);
WriteRegUlong(r_ApertureTwo, 0);
Message(L"Video memory access enabled. Initializing vidmem heap.\n");
// !BUGBUG! There is no good way to determine the amount of video
// RAM installed on the board and available to the Permedia3. So, we
// just hard-code it to 32 Megs. You MUST change this if your card has
// a different amount.
l_TotalVidMemory = 33554432;
l_FreeVidMemory = l_TotalVidMemory;
FirstNode = SystemAlloc(sizeof(VID_NODE));
if (FirstNode) {
// Initialize the allocated table.
for (i = 0; i < VID_HASH_ENTRIES; i++) {
l_VidHash[i] = NULL;
}
// Initialize the free bins, including our first node.
for (i = 0; i < VID_BIN_COUNT; i++) {
l_VidBins[i] = NULL;
}
FirstNode->Memory = l_Aperture1;
FirstNode->Size = l_TotalVidMemory;
FirstNode->Alignment = 0;
InsertFreeNode(FirstNode);
FnRetVal = TRUE;
}
else {
Error(L"System memory allocation failure!\n");
}
}
else {
Error(L"Unable to map physical address to virtual address!\n");
}
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -