AllocatePool

This commit is contained in:
ergo720 2018-04-27 23:22:18 +02:00
parent 125bc23d4f
commit e14b775b7e
6 changed files with 202 additions and 19 deletions

View File

@ -363,22 +363,24 @@ LIST_ENTRY, *PLIST_ENTRY;
#define LIST_ENTRY_ACCESS_RECORD(address, type, field) \
((type*)((UCHAR*)(address) - (ULONG)(&((type*)0)->field)))
#define IS_LIST_EMPTY(ListHead) ((ListHead)->Flink == (ListHead))
#define LIST_ENTRY_INSERT_HEAD(ListHead, Entry) {\
xboxkrnl::PLIST_ENTRY Flink;\
Flink = ListHead->Flink;\
Flink = (ListHead)->Flink;\
(Entry)->Flink = Flink;\
(Entry)->Blink = ListHead;\
Flink->Blink = Entry;\
ListHead->Flink = Entry;\
(Entry)->Blink = (ListHead);\
(Flink)->Blink = Entry;\
(ListHead)->Flink = Entry;\
}
#define LIST_ENTRY_INSERT_TAIL(ListHead, Entry) {\
xboxkrnl::PLIST_ENTRY Blink;\
Blink = ListHead->Blink;\
Blink = (ListHead)->Blink;\
(Entry)->Flink = ListHead;\
(Entry)->Blink = Blink;\
Blink->Flink = Entry;\
ListHead->Blink = Entry;\
(Blink)->Flink = Entry;\
(ListHead)->Blink = Entry;\
}
#define LIST_ENTRY_REMOVE(Entry) {\
@ -386,14 +388,18 @@ xboxkrnl::PLIST_ENTRY ExFlink;\
xboxkrnl::PLIST_ENTRY ExBlink;\
ExFlink = (Entry)->Flink;\
ExBlink = (Entry)->Blink;\
ExFlink->Blink = ExBlink;\
ExBlink->Flink = ExFlink;\
(ExFlink)->Blink = ExBlink;\
(ExBlink)->Flink = ExFlink;\
}
#define LIST_ENTRY_REMOVE_AT_HEAD(ListHead) \
(ListHead)->Flink;\
LIST_ENTRY_REMOVE((ListHead)->Flink)
#define REMOVE_HEAD_LIST(ListHead) \
(ListHead)->Flink;\
{LIST_ENTRY_REMOVE((ListHead)->Flink)}
// ******************************************************************
// * SLIST_ENTRY
// ******************************************************************

View File

@ -47,12 +47,12 @@ namespace xboxkrnl
#include "Logging.h" // For LOG_FUNC()
#include "EmuEEPROM.h" // For EmuFindEEPROMInfo, EEPROM, XboxFactoryGameRegion
#include "EmuKrnlLogging.h"
#include "VMManager.h"
#include "PoolManager.h"
// prevent name collisions
namespace NtDll
{
#include "EmuNtDll.h" // For NtDelayExecution(), etc.
#include "EmuNtDll.h" // For NtDelayExecution(), etc.
};
#include "CxbxKrnl.h" // For CxbxKrnlCleanup
@ -212,11 +212,9 @@ XBSYSAPI EXPORTNUM(15) xboxkrnl::PVOID NTAPI xboxkrnl::ExAllocatePoolWithTag
LOG_FUNC_BEGIN
LOG_FUNC_ARG(NumberOfBytes)
LOG_FUNC_ARG(Tag)
LOG_FUNC_END;
LOG_FUNC_END;
PVOID pRet = (xboxkrnl::PVOID)g_VMManager.AllocateZeroed(NumberOfBytes); // Clear, to prevent side-effects on random contents
LOG_INCOMPLETE(); // TODO : Actually implement ExAllocatePoolWithTag
PVOID pRet = g_PoolManager.AllocatePool(NumberOfBytes, Tag);
RETURN(pRet);
}
@ -245,7 +243,7 @@ XBSYSAPI EXPORTNUM(17) xboxkrnl::VOID NTAPI xboxkrnl::ExFreePool
{
LOG_FUNC_ONE_ARG(P);
g_VMManager.Deallocate((VAddr)P);
g_PoolManager.DeallocatePool(P);
}
// ******************************************************************
@ -371,8 +369,7 @@ XBSYSAPI EXPORTNUM(23) xboxkrnl::ULONG NTAPI xboxkrnl::ExQueryPoolBlockSize
{
LOG_FUNC_ONE_ARG(PoolBlock);
// Not strictly correct, but it will do for now
ULONG ret = g_VMManager.QuerySize((VAddr)PoolBlock);
ULONG ret = g_PoolManager.QueryPoolSize(PoolBlock);
RETURN(ret);
}

View File

@ -199,6 +199,7 @@ typedef enum _PageType
#define PAGES_SPANNED_LARGE(Va, Size) ((ULONG)((((VAddr)(Va) & (PAGE_SIZE_LARGE - 1)) + (Size) + (PAGE_SIZE_LARGE - 1)) >> PAGE_SHIFT_LARGE))
#define BYTE_OFFSET(Va) ((ULONG)((VAddr)(Va) & (PAGE_SIZE - 1)))
#define BYTE_OFFSET_LARGE(Va) ((ULONG)((VAddr)(Va) & (PAGE_SIZE_LARGE - 1)))
#define PAGE_END(Va) (((ULONG_PTR)(Va) & (PAGE_SIZE - 1)) == 0)
/* These macros check if the supplied address is inside a known range */

View File

@ -35,6 +35,7 @@
// ******************************************************************
#include "PoolManager.h"
#include <assert.h>
#define LOG_PREFIX "PMEM"
@ -76,6 +77,151 @@ void PoolManager::InitializePool()
printf(LOG_PREFIX " Pool manager initialized!\n");
}
void* PoolManager::AllocatePool(size_t Size, uint32_t Tag)
{
PVOID Block;
PPOOL_HEADER Entry;
PPOOL_LOOKASIDE_LIST LookasideList;
PPOOL_HEADER NextEntry;
PPOOL_HEADER SplitEntry;
PPOOL_DESCRIPTOR PoolDesc = &m_NonPagedPoolDescriptor;
ULONG Index;
ULONG ListNumber;
ULONG NeededSize;
xboxkrnl::PLIST_ENTRY ListHead;
ULONG NumberOfPages;
assert(Size);
if (Size > POOL_BUDDY_MAX) {
Lock();
PoolDesc->RunningAllocs += 1;
Entry = reinterpret_cast<PPOOL_HEADER>(g_VMManager.AllocateSystemMemory(PoolType, XBOX_PAGE_READWRITE, Size, false));
if (Entry != nullptr) {
NumberOfPages = ROUND_UP_4K(Size) >> PAGE_SHIFT;
PoolDesc->TotalBigPages += NumberOfPages;
Unlock();
}
else {
EmuWarning("AllocatePool returns nullptr");
Unlock();
}
return Entry;
}
ListNumber = ((Size + POOL_OVERHEAD + (POOL_SMALLEST_BLOCK - 1)) >> POOL_BLOCK_SHIFT);
NeededSize = ListNumber;
if (NeededSize <= POOL_SMALL_LISTS) {
LookasideList = &m_ExpSmallNPagedPoolLookasideLists[NeededSize - 1];
LookasideList->TotalAllocates += 1;
Entry = reinterpret_cast<PPOOL_HEADER>(xboxkrnl::KRNL(InterlockedPopEntrySList(&LookasideList->ListHead)));
if (Entry != nullptr) {
Entry -= 1;
LookasideList->AllocateHits += 1;
Entry->PoolType = static_cast<UCHAR>(1);
MARK_POOL_HEADER_ALLOCATED(Entry);
Entry->PoolTag = Tag;
(reinterpret_cast<PULONG>((reinterpret_cast<PCHAR>(Entry) + POOL_OVERHEAD)))[0] = 0;
return reinterpret_cast<PUCHAR>(Entry) + POOL_OVERHEAD;
}
}
Lock();
PoolDesc->RunningAllocs += 1;
ListHead = &PoolDesc->ListHeads[ListNumber];
do {
do {
if (IS_LIST_EMPTY(ListHead) == false) {
Block = REMOVE_HEAD_LIST(ListHead);
Entry = reinterpret_cast<PPOOL_HEADER>((static_cast<PCHAR>(Block) - POOL_OVERHEAD));
assert(Entry->BlockSize >= NeededSize);
assert(Entry->PoolType == 0);
if (Entry->BlockSize != NeededSize) {
if (Entry->PreviousSize == 0) {
SplitEntry = reinterpret_cast<PPOOL_HEADER>((reinterpret_cast<PPOOL_BLOCK>(Entry) + NeededSize));
SplitEntry->BlockSize = Entry->BlockSize - static_cast<UCHAR>(NeededSize);
SplitEntry->PreviousSize = static_cast<UCHAR>(NeededSize);
NextEntry = reinterpret_cast<PPOOL_HEADER>((reinterpret_cast<PPOOL_BLOCK>(SplitEntry) + SplitEntry->BlockSize));
if (PAGE_END(NextEntry) == false) {
NextEntry->PreviousSize = SplitEntry->BlockSize;
}
}
else {
SplitEntry = Entry;
Entry->BlockSize -= static_cast<UCHAR>(NeededSize);
Entry = reinterpret_cast<PPOOL_HEADER>(reinterpret_cast<PPOOL_BLOCK>(Entry) + Entry->BlockSize);
Entry->PreviousSize = SplitEntry->BlockSize;
NextEntry = reinterpret_cast<PPOOL_HEADER>(reinterpret_cast<PPOOL_BLOCK>(Entry) + NeededSize);
if (PAGE_END(NextEntry) == false) {
NextEntry->PreviousSize = static_cast<UCHAR>(NeededSize);
}
}
Entry->BlockSize = static_cast<UCHAR>(NeededSize);
SplitEntry->PoolType = 0;
Index = SplitEntry->BlockSize;
LIST_ENTRY_INSERT_TAIL(&PoolDesc->ListHeads[Index - 1], (reinterpret_cast<xboxkrnl::PLIST_ENTRY>((reinterpret_cast<PCHAR>(SplitEntry)
+ POOL_OVERHEAD))));
}
Entry->PoolType = static_cast<UCHAR>(1);
MARK_POOL_HEADER_ALLOCATED(Entry);
Unlock();
Entry->PoolTag = Tag;
(reinterpret_cast<PULONGLONG>((reinterpret_cast<PCHAR>(Entry) + POOL_OVERHEAD)))[0] = 0;
return reinterpret_cast<PCHAR>(Entry) + POOL_OVERHEAD;
}
ListHead += 1;
} while (ListHead != &PoolDesc->ListHeads[POOL_LIST_HEADS]);
Entry = reinterpret_cast<PPOOL_HEADER>(g_VMManager.AllocateSystemMemory(PoolType, XBOX_PAGE_READWRITE, PAGE_SIZE, false));
if (Entry == nullptr) {
EmuWarning("AllocatePool returns nullptr");
Unlock();
return Entry;
}
PoolDesc->TotalPages += 1;
Entry->PoolType = 0;
if ((PAGE_SIZE / POOL_SMALLEST_BLOCK) > 255) {
Entry->BlockSize = 255;
}
else {
Entry->BlockSize = static_cast<UCHAR>((PAGE_SIZE / POOL_SMALLEST_BLOCK));
}
Entry->PreviousSize = 0;
ListHead = &PoolDesc->ListHeads[POOL_LIST_HEADS - 1];
LIST_ENTRY_INSERT_HEAD(ListHead, (reinterpret_cast<xboxkrnl::PLIST_ENTRY>((reinterpret_cast<UCHAR>(Entry) + POOL_OVERHEAD))));
} while (true);
}
void PoolManager::Lock()
{
EnterCriticalSection(&m_CriticalSection);

View File

@ -53,6 +53,7 @@ typedef struct _POOL_DESCRIPTOR {
xboxkrnl::LIST_ENTRY ListHeads[POOL_LIST_HEADS];
} POOL_DESCRIPTOR, *PPOOL_DESCRIPTOR;
typedef struct _POOL_LOOKASIDE_LIST {
xboxkrnl::SLIST_HEADER ListHead;
USHORT Depth;
@ -62,6 +63,32 @@ typedef struct _POOL_LOOKASIDE_LIST {
} POOL_LOOKASIDE_LIST, *PPOOL_LOOKASIDE_LIST;
typedef struct _POOL_HEADER {
union {
struct {
UCHAR PreviousSize;
UCHAR PoolIndex;
UCHAR PoolType;
UCHAR BlockSize;
};
ULONG Ulong1;
};
ULONG PoolTag;
} POOL_HEADER, *PPOOL_HEADER;
typedef struct _POOL_BLOCK {
UCHAR Fill[1 << POOL_BLOCK_SHIFT];
} POOL_BLOCK, *PPOOL_BLOCK;
#define POOL_OVERHEAD ((LONG)sizeof(POOL_HEADER))
#define POOL_SMALLEST_BLOCK (sizeof(POOL_BLOCK))
#define POOL_BUDDY_MAX \
(PAGE_SIZE - (POOL_OVERHEAD + POOL_SMALLEST_BLOCK ))
/* PoolManager class */
class PoolManager
{
public:
@ -71,6 +98,13 @@ class PoolManager
~PoolManager() { DeleteCriticalSection(&m_CriticalSection); }
// initializes the pool manager to the default configuration
void InitializePool();
// allocates pool memory
void* AllocatePool(size_t Size, uint32_t Tag);
// deallocates pool memory
void DeallocatePool(void* addr);
// queries the pool block size
size_t QueryPoolSize(void* addr);
private:
// main (and only) pool type available on the Xbox

View File

@ -42,7 +42,6 @@
#define LOG_PREFIX "VMEM"
#include "VMManager.h"
#include "PoolManager.h"
#include "Logging.h"
#include "EmuShared.h"