a new allocator that doesn't yet fix msi

This commit is contained in:
maksw committed 2025-10-25 19:30:32 +02:00
1 parent 79906b4c2c
commit 23d7ff90f7
12 files changed
+133 -80

No files matched your search

-3
View File
@@ -1,3 +0,0 @@
{
"CurrentProjectSetting": "No Configurations"
}
-6
View File
@@ -1,6 +0,0 @@
{
"ExpandedNodes": [
""
],
"PreviewInSolutionExplorer": false
}
Binary file not shown.
Binary file not shown.
-23
View File
@@ -1,23 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\Administrator\\Documents\\binkx86\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": -1,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
}
]
}
]
}
]
}
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+7 -5
View File
@@ -165,6 +165,8 @@ typedef DWORD LCTYPE;
#pragma endregion #pragma endregion
extern int stricmp(const char *s1, const char *s2); extern int stricmp(const char *s1, const char *s2);
extern void* Malloc(size_t size);
extern void Free(void* ptr);
// --- Memory --- // --- Memory ---
HANDLE HeapCreate(DWORD, SIZE_T, SIZE_T) { HANDLE HeapCreate(DWORD, SIZE_T, SIZE_T) {
@@ -179,24 +181,24 @@ BOOL HeapDestroy(HANDLE) {
LPVOID HeapAlloc(HANDLE, DWORD, SIZE_T size) { LPVOID HeapAlloc(HANDLE, DWORD, SIZE_T size) {
PRINT(L"Called: HeapAlloc with size: %ull\n", size); PRINT(L"Called: HeapAlloc with size: %ull\n", size);
return AllocatePool(size); return Malloc(size);
} }
BOOL HeapFree(HANDLE, DWORD, LPVOID ptr) { BOOL HeapFree(HANDLE, DWORD, LPVOID ptr) {
PRINT(L"Called: HeapFree with ptr: %p\n", ptr); PRINT(L"Called: HeapFree with ptr: %p\n", ptr);
if (ptr) if (ptr)
FreePool(ptr); Free(ptr);
return TRUE; return TRUE;
} }
LPVOID HeapReAlloc(HANDLE, DWORD, LPVOID ptr, SIZE_T size) { LPVOID HeapReAlloc(HANDLE, DWORD, LPVOID ptr, SIZE_T size) {
PRINT(L"Called: HeapReAlloc with size: %ull and ptr: %p\n", size, ptr); PRINT(L"Called: HeapReAlloc with size: %ull and ptr: %p\n", size, ptr);
if (!ptr) return AllocatePool(size); if (!ptr) return Malloc(size);
LPVOID newPtr = AllocatePool(size); LPVOID newPtr = Malloc(size);
if (!newPtr) return nullptr; if (!newPtr) return nullptr;
// No original size info; can't fully emulate, user must handle // No original size info; can't fully emulate, user must handle
CopyMem(newPtr, ptr, size); CopyMem(newPtr, ptr, size);
FreePool(ptr); Free(ptr);
return newPtr; return newPtr;
} }
+126 -43
View File
@@ -1,8 +1,6 @@
#include <efi.h> #include <efi.h>
#include <efilib.h> #include <efilib.h>
#include <x86_64\pe.h> #include <x86_64\pe.h>
#define malloc AllocatePool
#define free FreePool
#include <immintrin.h> #include <immintrin.h>
#include <compiler_defines.h> #include <compiler_defines.h>
#include "bink.h" #include "bink.h"
@@ -78,63 +76,127 @@ EFI_GRAPHICS_OUTPUT_PROTOCOL* gop;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* framebuffer; EFI_GRAPHICS_OUTPUT_BLT_PIXEL* framebuffer;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* mode_info; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* mode_info;
#define SIMD_ALIGNMENT_BYTES 32 struct BlockHeader {
#define ALIGN_MASK (~(SIMD_ALIGNMENT_BYTES - 1)) uint32_t magic;
#define ALIGN_CAST(ptr) ((UINTN)(ptr)) size_t size;
bool free;
BlockHeader* next;
};
void* Malloc(size_t size) { constexpr uint32_t MAGIC_ALLOCATED = 0xCAFEBABE;
PRINT(L"Malloc called with size: %u\n", size); constexpr uint32_t MAGIC_FREED = 0xDEADBEEF;
VOID *OriginalPtr; static void* g_memoryPool = 0;
VOID **AlignedPtrLoc; static size_t g_poolSize = 0;
UINTN TotalSize; static struct BlockHeader* g_freeList = 0;
UINTN Addr;
// Calculate total size: #define AVX_ALIGN 32
// 1. User requested size #define ALIGN_UP(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
// 2. Maximum space for alignment padding (SIMD_ALIGNMENT_BYTES - 1)
// 3. Space to store the original pointer for freeing (sizeof(VOID*))
TotalSize = size + SIMD_ALIGNMENT_BYTES - 1 + sizeof(VOID*);
// 1. Allocate a larger block of memory using the UEFI Pool service. void InitAllocatorFromBuffer(void* buffer, size_t size) {
if (EFI_ERROR(gBS->AllocatePool(EfiLoaderData, TotalSize, &OriginalPtr))) { PRINT(L"Initializing custom allocator with buffer %p of size %ull\n", buffer, size);
return NULL; // Allocation failed if (!buffer || size <= sizeof(struct BlockHeader)) {
Print(L"Invalid buffer or size for allocator initialization\n");
gBS->Stall(5 * 1000000); // 5 seconds
gRT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
} }
// 2. Calculate the aligned address. g_memoryPool = buffer;
// Start the alignment calculation *after* the space reserved for the original pointer. g_poolSize = size;
Addr = ALIGN_CAST(OriginalPtr) + sizeof(VOID*);
// Align the address up to the nearest SIMD_ALIGNMENT_BYTES multiple: g_freeList = (struct BlockHeader*)buffer;
// (Addr + Alignment - 1) & ~(Alignment - 1) g_freeList->magic = MAGIC_ALLOCATED;
Addr = (Addr + SIMD_ALIGNMENT_BYTES - 1) & ALIGN_MASK; g_freeList->size = size - sizeof(struct BlockHeader);
g_freeList->free = true;
g_freeList->next = 0;
}
// 3. Store the original pointer (OriginalPtr) immediately before the aligned address (Addr). static bool IsPointerInPool(void* ptr) {
// The location is 8 bytes (sizeof(VOID*)) behind the start of the aligned block. return ptr >= g_memoryPool &&
AlignedPtrLoc = (VOID**)(Addr - sizeof(VOID*)); ptr < (void*)((uint8_t*)g_memoryPool + g_poolSize);
*AlignedPtrLoc = OriginalPtr; }
// 4. Return the aligned address to the caller. void* Malloc(size_t size) {
return (VOID*)Addr; PRINT(L"Allocating memory of size %ull\n", size);
size = ALIGN_UP(size, AVX_ALIGN); // ensure AVX alignment
struct BlockHeader* best = 0;
struct BlockHeader* bestPrev = 0;
struct BlockHeader* prev = 0;
struct BlockHeader* current = g_freeList;
while (current) {
if (current->free && current->size >= size) {
if (!best || current->size < best->size) {
best = current;
bestPrev = prev;
}
}
prev = current;
current = current->next;
}
if (!best) {
return 0;
}
uintptr_t payloadAddr = (uintptr_t)(best + 1);
uintptr_t alignedAddr = ALIGN_UP(payloadAddr, AVX_ALIGN);
size_t padding = alignedAddr - payloadAddr;
size_t totalNeeded = size + padding;
if (best->size < totalNeeded) {
return 0; // not enough space
}
size_t remaining = best->size - totalNeeded;
if (remaining > sizeof(struct BlockHeader)) {
struct BlockHeader* newBlock = (struct BlockHeader*)((uint8_t*)(best + 1) + totalNeeded);
newBlock->magic = MAGIC_ALLOCATED;
newBlock->size = remaining - sizeof(struct BlockHeader);
newBlock->free = true;
newBlock->next = best->next;
best->next = newBlock;
}
best->magic = MAGIC_ALLOCATED;
best->free = false;
best->size = totalNeeded;
return (void*)alignedAddr;
} }
void Free(void* ptr) { void Free(void* ptr) {
PRINT(L"Free called with ptr: %p\n", ptr); PRINT(L"Freeing memory at %p\n", ptr);
if (!ptr || !IsPointerInPool(ptr)) return;
VOID **OriginalPtrLoc; struct BlockHeader* block = (struct BlockHeader*)((uint8_t*)ptr - sizeof(struct BlockHeader));
VOID *OriginalPtr;
if (ptr == NULL) { while (block->magic != MAGIC_ALLOCATED && (uint8_t*)block > (uint8_t*)g_memoryPool) {
block = (struct BlockHeader*)((uint8_t*)block - 1); // backtrack if pointer was aligned forward
}
if (!IsPointerInPool(block) || block->magic != MAGIC_ALLOCATED) {
Print(L"Invalid pointer passed to Free: %p\n", ptr);
return; return;
} }
// 1. Calculate the address where the original pointer is stored. block->magic = MAGIC_FREED;
// It is located sizeof(VOID*) bytes immediately before the AlignedPtr. block->free = true;
OriginalPtrLoc = (VOID**)(ALIGN_CAST(ptr) - sizeof(VOID*));
OriginalPtr = *OriginalPtrLoc;
// 2. Use the UEFI Boot Service to free the original, unaligned block. // Coalesce
gBS->FreePool(OriginalPtr); struct BlockHeader* current = g_freeList;
while (current) {
if (current->free) {
struct BlockHeader* next = current->next;
while (next && next->free) {
current->size += sizeof(struct BlockHeader) + next->size;
current->next = next->next;
next = next->next;
}
}
current = current->next;
}
} }
EFI_STATUS InitializeGop() { EFI_STATUS InitializeGop() {
@@ -584,7 +646,7 @@ bool LoadBinkDLL(EFI_FILE_HANDLE volume) {
} }
#pragma endregion #pragma endregion
void Blit1280x720_AVX2_NT( void Blit_AVX2_NT(
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop, EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,
uint32_t *src, uint32_t *src,
UINTN src_width, UINTN src_height UINTN src_width, UINTN src_height
@@ -677,6 +739,27 @@ EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
SystemTable->BootServices->SetWatchdogTimer(0, 0, 0, NULL); SystemTable->BootServices->SetWatchdogTimer(0, 0, 0, NULL);
Print(L"Hello, World!\n"); Print(L"Hello, World!\n");
VOID* HeapMemory = NULL;
UINTN AllocationSize = 512 * 1024 * 1024; // 512 MB
UINTN Pages = AllocationSize / 4096; // UEFI page size is 4KB
EFI_STATUS Status = gBS->AllocatePages(
AllocateAnyPages,
EfiLoaderData,
Pages,
(EFI_PHYSICAL_ADDRESS*)&HeapMemory
);
if (EFI_ERROR(Status)) {
Print(L"Failed to allocate memory pool pages: %r\n", Status);
gBS->Stall(5 * 1000 * 1000);
gST->RuntimeServices->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
return Status;
}
InitAllocatorFromBuffer(HeapMemory, AllocationSize);
Print(L"Custom allocator initialized\n");
InitializeGop(); InitializeGop();
Print(L"GOP initialized\n"); Print(L"GOP initialized\n");
@@ -779,7 +862,7 @@ EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
pBinkNextFrame(bink); pBinkNextFrame(bink);
Blit1280x720_AVX2_NT(gop, framebuffer, width, height); Blit_AVX2_NT(gop, framebuffer, width, height);
Print(L"\rframe %d done", bink->FrameNum); Print(L"\rframe %d done", bink->FrameNum);
} }