mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-05-28 15:34:33 +00:00
Reimplemented Xalloc from scratch
This commit is contained in:
parent
62e9d7b9c9
commit
4519204580
@ -1,285 +0,0 @@
|
||||
#include "Xalloc.hpp"
|
||||
|
||||
namespace Xalloc
|
||||
{
|
||||
class XLockClass
|
||||
{
|
||||
struct SpinLockData
|
||||
{
|
||||
uintptr_t LockData = 0x0;
|
||||
const char *CurrentHolder = "(null)";
|
||||
const char *AttemptingToGet = "(null)";
|
||||
size_t Count = 0;
|
||||
};
|
||||
|
||||
void DeadLock(SpinLockData Lock)
|
||||
{
|
||||
Xalloc_warn("Potential deadlock in lock '%s' held by '%s'! %ld locks in queue.", Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count);
|
||||
}
|
||||
|
||||
private:
|
||||
SpinLockData LockData;
|
||||
bool IsLocked = false;
|
||||
|
||||
public:
|
||||
int Lock(const char *FunctionName)
|
||||
{
|
||||
LockData.AttemptingToGet = FunctionName;
|
||||
Retry:
|
||||
unsigned int i = 0;
|
||||
while (__atomic_exchange_n(&IsLocked, true, __ATOMIC_ACQUIRE) && ++i < 0x10000000)
|
||||
;
|
||||
if (i >= 0x10000000)
|
||||
{
|
||||
DeadLock(LockData);
|
||||
goto Retry;
|
||||
}
|
||||
LockData.Count++;
|
||||
LockData.CurrentHolder = FunctionName;
|
||||
__sync_synchronize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Unlock()
|
||||
{
|
||||
__sync_synchronize();
|
||||
__atomic_store_n(&IsLocked, false, __ATOMIC_RELEASE);
|
||||
LockData.Count--;
|
||||
IsLocked = false;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class XSmartLock
|
||||
{
|
||||
private:
|
||||
XLockClass *LockPointer = nullptr;
|
||||
|
||||
public:
|
||||
XSmartLock(XLockClass &Lock, const char *FunctionName)
|
||||
{
|
||||
this->LockPointer = &Lock;
|
||||
this->LockPointer->Lock(FunctionName);
|
||||
}
|
||||
~XSmartLock() { this->LockPointer->Unlock(); }
|
||||
};
|
||||
|
||||
XLockClass XLock;
|
||||
|
||||
#define XSL XSmartLock CONCAT(lock##_, __COUNTER__)(XLock, __FUNCTION__)
|
||||
|
||||
class SmartSMAPClass
|
||||
{
|
||||
private:
|
||||
AllocatorV1 *allocator = nullptr;
|
||||
|
||||
public:
|
||||
SmartSMAPClass(AllocatorV1 *allocator)
|
||||
{
|
||||
this->allocator = allocator;
|
||||
this->allocator->Xstac();
|
||||
}
|
||||
~SmartSMAPClass() { this->allocator->Xclac(); }
|
||||
};
|
||||
#define SmartSMAP SmartSMAPClass XALLOC_CONCAT(SmartSMAP##_, __COUNTER__)(this)
|
||||
|
||||
AllocatorV1::AllocatorV1(void *Address, bool UserMode, bool SMAPEnabled)
|
||||
{
|
||||
SmartSMAP;
|
||||
XSL;
|
||||
void *Position = Address;
|
||||
UserMapping = UserMode;
|
||||
SMAPUsed = SMAPEnabled;
|
||||
for (Xuint64_t i = 0; i < 0x20; i++)
|
||||
{
|
||||
void *Page = Xalloc_REQUEST_PAGE();
|
||||
if (UserMapping)
|
||||
Xalloc_MAP_MEMORY(Position, Page, Xalloc_MAP_MEMORY_READ_WRITE | Xalloc_MAP_MEMORY_USER);
|
||||
else
|
||||
Xalloc_MAP_MEMORY(Position, Page, Xalloc_MAP_MEMORY_READ_WRITE);
|
||||
Xalloc_trace("Preallocate Heap Memory (%#llx-%#llx [%#llx])...", Position, (Xuint64_t)Position + Xalloc_PAGE_SIZE, Page);
|
||||
Position = (void *)((Xuint64_t)Position + Xalloc_PAGE_SIZE);
|
||||
}
|
||||
Xuint64_t HeapLength = 16 * Xalloc_PAGE_SIZE;
|
||||
this->HeapStart = Address;
|
||||
this->HeapEnd = (void *)((Xuint64_t)this->HeapStart + HeapLength);
|
||||
HeapSegment *StartSegment = (HeapSegment *)Address;
|
||||
StartSegment->Length = HeapLength - sizeof(HeapSegment);
|
||||
StartSegment->Next = nullptr;
|
||||
StartSegment->Last = nullptr;
|
||||
StartSegment->IsFree = true;
|
||||
this->LastSegment = StartSegment;
|
||||
}
|
||||
|
||||
AllocatorV1::~AllocatorV1()
|
||||
{
|
||||
SmartSMAP;
|
||||
XSL;
|
||||
Xalloc_trace("Destructor not implemented yet.");
|
||||
}
|
||||
|
||||
void AllocatorV1::ExpandHeap(Xuint64_t Length)
|
||||
{
|
||||
if (Length % Xalloc_PAGE_SIZE)
|
||||
{
|
||||
Length -= Length % Xalloc_PAGE_SIZE;
|
||||
Length += Xalloc_PAGE_SIZE;
|
||||
}
|
||||
Xuint64_t PageCount = Length / Xalloc_PAGE_SIZE;
|
||||
HeapSegment *NewSegment = (HeapSegment *)this->HeapEnd;
|
||||
for (Xuint64_t i = 0; i < PageCount; i++)
|
||||
{
|
||||
void *Page = Xalloc_REQUEST_PAGE();
|
||||
if (UserMapping)
|
||||
Xalloc_MAP_MEMORY(this->HeapEnd, Page, Xalloc_MAP_MEMORY_READ_WRITE | Xalloc_MAP_MEMORY_USER);
|
||||
else
|
||||
Xalloc_MAP_MEMORY(this->HeapEnd, Page, Xalloc_MAP_MEMORY_READ_WRITE);
|
||||
// Xalloc_trace("Expanding Heap Memory (%#llx-%#llx [%#llx])...", this->HeapEnd, (Xuint64_t)this->HeapEnd + Xalloc_PAGE_SIZE, Page);
|
||||
this->HeapEnd = (void *)((Xuint64_t)this->HeapEnd + Xalloc_PAGE_SIZE);
|
||||
}
|
||||
NewSegment->IsFree = true;
|
||||
NewSegment->Last = this->LastSegment;
|
||||
this->LastSegment->Next = NewSegment;
|
||||
this->LastSegment = NewSegment;
|
||||
NewSegment->Next = nullptr;
|
||||
NewSegment->Length = Length - sizeof(HeapSegment);
|
||||
NewSegment->CombineBackward(this->LastSegment);
|
||||
}
|
||||
|
||||
void *AllocatorV1::Malloc(Xuint64_t Size)
|
||||
{
|
||||
SmartSMAP;
|
||||
XSL;
|
||||
if (this->HeapStart == nullptr)
|
||||
{
|
||||
Xalloc_err("Memory allocation not initialized yet!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Size < 0x10)
|
||||
{
|
||||
// Xalloc_warn("Allocation size is too small, using 0x10 instead!");
|
||||
Size = 0x10;
|
||||
}
|
||||
|
||||
// #ifdef DEBUG
|
||||
// if (Size < 1024)
|
||||
// debug("Allocating %dB", Size);
|
||||
// else if (TO_KB(Size) < 1024)
|
||||
// debug("Allocating %dKB", TO_KB(Size));
|
||||
// else if (TO_MB(Size) < 1024)
|
||||
// debug("Allocating %dMB", TO_MB(Size));
|
||||
// else if (TO_GB(Size) < 1024)
|
||||
// debug("Allocating %dGB", TO_GB(Size));
|
||||
// #endif
|
||||
|
||||
if (Size % 0x10 > 0) // it is not a multiple of 0x10
|
||||
{
|
||||
Size -= (Size % 0x10);
|
||||
Size += 0x10;
|
||||
}
|
||||
if (Size == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HeapSegment *CurrentSegment = (HeapSegment *)this->HeapStart;
|
||||
while (true)
|
||||
{
|
||||
if (CurrentSegment->IsFree)
|
||||
{
|
||||
if (CurrentSegment->Length > Size)
|
||||
{
|
||||
CurrentSegment->Split(Size, this->LastSegment);
|
||||
CurrentSegment->IsFree = false;
|
||||
return (void *)((Xuint64_t)CurrentSegment + sizeof(HeapSegment));
|
||||
}
|
||||
if (CurrentSegment->Length == Size)
|
||||
{
|
||||
CurrentSegment->IsFree = false;
|
||||
return (void *)((Xuint64_t)CurrentSegment + sizeof(HeapSegment));
|
||||
}
|
||||
}
|
||||
if (CurrentSegment->Next == nullptr)
|
||||
break;
|
||||
CurrentSegment = CurrentSegment->Next;
|
||||
}
|
||||
ExpandHeap(Size);
|
||||
XLock.Unlock();
|
||||
return this->Malloc(Size);
|
||||
}
|
||||
|
||||
void AllocatorV1::Free(void *Address)
|
||||
{
|
||||
SmartSMAP;
|
||||
XSL;
|
||||
if (this->HeapStart == nullptr)
|
||||
{
|
||||
Xalloc_err("Memory allocation not initialized yet!");
|
||||
return;
|
||||
}
|
||||
HeapSegment *Segment = (HeapSegment *)Address - 1;
|
||||
Segment->IsFree = true;
|
||||
Segment->CombineForward(this->LastSegment);
|
||||
Segment->CombineBackward(this->LastSegment);
|
||||
}
|
||||
|
||||
void *AllocatorV1::Calloc(Xuint64_t NumberOfBlocks, Xuint64_t Size)
|
||||
{
|
||||
SmartSMAP;
|
||||
XSL;
|
||||
if (this->HeapStart == nullptr)
|
||||
{
|
||||
Xalloc_err("Memory allocation not initialized yet!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Size < 0x10)
|
||||
{
|
||||
// Xalloc_warn("Allocation size is too small, using 0x10 instead!");
|
||||
Size = 0x10;
|
||||
}
|
||||
|
||||
XLock.Unlock();
|
||||
void *Block = this->Malloc(NumberOfBlocks * Size);
|
||||
XLock.Lock(__FUNCTION__);
|
||||
|
||||
if (Block)
|
||||
Xmemset(Block, 0, NumberOfBlocks * Size);
|
||||
return Block;
|
||||
}
|
||||
|
||||
void *AllocatorV1::Realloc(void *Address, Xuint64_t Size)
|
||||
{
|
||||
SmartSMAP;
|
||||
XSL;
|
||||
if (this->HeapStart == nullptr)
|
||||
{
|
||||
Xalloc_err("Memory allocation not initialized yet!");
|
||||
return 0;
|
||||
}
|
||||
if (!Address && Size == 0)
|
||||
{
|
||||
XLock.Unlock();
|
||||
this->Free(Address);
|
||||
return nullptr;
|
||||
}
|
||||
else if (!Address)
|
||||
{
|
||||
XLock.Unlock();
|
||||
return this->Calloc(Size, sizeof(char));
|
||||
}
|
||||
|
||||
if (Size < 0x10)
|
||||
{
|
||||
// Xalloc_warn("Allocation size is too small, using 0x10 instead!");
|
||||
Size = 0x10;
|
||||
}
|
||||
|
||||
XLock.Unlock();
|
||||
void *newAddress = this->Calloc(Size, sizeof(char));
|
||||
XLock.Lock(__FUNCTION__);
|
||||
Xmemcpy(newAddress, Address, Size);
|
||||
return newAddress;
|
||||
}
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
#pragma once
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
// Functions defines
|
||||
|
||||
// Page allocation functions
|
||||
#define Xalloc_REQUEST_PAGE() KernelAllocator.RequestPage()
|
||||
#define Xalloc_REQUEST_PAGES(Pages) KernelAllocator.RequestPages(Pages)
|
||||
#define Xalloc_FREE_PAGE(Address) KernelAllocator.FreePage(Address)
|
||||
#define Xalloc_FREE_PAGES(Address, Pages) KernelAllocator.FreePages(Address, Pages)
|
||||
|
||||
#define Xalloc_MAP_MEMORY(VirtualAddress, PhysicalAddress, Flags) Memory::Virtual(KernelPageTable).Map(VirtualAddress, PhysicalAddress, Flags)
|
||||
#define Xalloc_UNMAP_MEMORY(VirtualAddress) Memory::Virtual(KernelPageTable).Unmap(VirtualAddress)
|
||||
#define Xalloc_MAP_MEMORY_READ_WRITE Memory::PTFlag::RW
|
||||
#define Xalloc_MAP_MEMORY_USER Memory::PTFlag::US
|
||||
|
||||
#define Xalloc_PAGE_SIZE PAGE_SIZE
|
||||
|
||||
#define Xalloc_trace(m, ...) trace(m, ##__VA_ARGS__)
|
||||
#define Xalloc_warn(m, ...) warn(m, ##__VA_ARGS__)
|
||||
#define Xalloc_err(m, ...) error(m, ##__VA_ARGS__)
|
||||
|
||||
#define XALLOC_CONCAT(x, y) x##y
|
||||
|
||||
typedef long unsigned Xuint64_t;
|
||||
|
||||
namespace Xalloc
|
||||
{
|
||||
class AllocatorV1
|
||||
{
|
||||
private:
|
||||
struct HeapSegment
|
||||
{
|
||||
Xuint64_t Length;
|
||||
HeapSegment *Next;
|
||||
HeapSegment *Last;
|
||||
bool IsFree;
|
||||
|
||||
HeapSegment *Split(Xuint64_t SplitLength, HeapSegment *LastSegment)
|
||||
{
|
||||
if (SplitLength < 0x10)
|
||||
return nullptr;
|
||||
int64_t SplitSegmentLength = Length - SplitLength - (sizeof(HeapSegment));
|
||||
if (SplitSegmentLength < 0x10)
|
||||
return nullptr;
|
||||
HeapSegment *NewSplitHdr = (HeapSegment *)((Xuint64_t)this + SplitLength + sizeof(HeapSegment));
|
||||
Next->Last = NewSplitHdr;
|
||||
NewSplitHdr->Next = Next;
|
||||
Next = NewSplitHdr;
|
||||
NewSplitHdr->Last = this;
|
||||
NewSplitHdr->Length = SplitSegmentLength;
|
||||
NewSplitHdr->IsFree = IsFree;
|
||||
Length = SplitLength;
|
||||
if (LastSegment == this)
|
||||
LastSegment = NewSplitHdr;
|
||||
return NewSplitHdr;
|
||||
}
|
||||
|
||||
void CombineForward(HeapSegment *LastSegment)
|
||||
{
|
||||
if (Next == nullptr)
|
||||
return;
|
||||
if (Next->IsFree == false)
|
||||
return;
|
||||
if (Next == LastSegment)
|
||||
LastSegment = this;
|
||||
if (Next->Next != nullptr)
|
||||
Next->Next->Last = this;
|
||||
|
||||
Length = Length + Next->Length + sizeof(HeapSegment);
|
||||
Next = Next->Next;
|
||||
}
|
||||
|
||||
void CombineBackward(HeapSegment *LastSegment)
|
||||
{
|
||||
if (Last != nullptr && Last->IsFree)
|
||||
Last->CombineForward(LastSegment);
|
||||
}
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
void *HeapStart = nullptr;
|
||||
void *HeapEnd = nullptr;
|
||||
HeapSegment *LastSegment = nullptr;
|
||||
bool UserMapping = false;
|
||||
bool SMAPUsed = false;
|
||||
|
||||
void ExpandHeap(Xuint64_t Length);
|
||||
|
||||
// TODO: Change memcpy with an optimized version
|
||||
static inline void *Xmemcpy(void *__restrict__ Destination, const void *__restrict__ Source, Xuint64_t Length)
|
||||
{
|
||||
unsigned char *dst = (unsigned char *)Destination;
|
||||
const unsigned char *src = (const unsigned char *)Source;
|
||||
for (Xuint64_t i = 0; i < Length; i++)
|
||||
dst[i] = src[i];
|
||||
return Destination;
|
||||
}
|
||||
|
||||
// TODO: Change memset with an optimized version
|
||||
static inline void *Xmemset(void *__restrict__ Destination, int Data, Xuint64_t Length)
|
||||
{
|
||||
unsigned char *Buffer = (unsigned char *)Destination;
|
||||
for (Xuint64_t i = 0; i < Length; i++)
|
||||
Buffer[i] = (unsigned char)Data;
|
||||
return Destination;
|
||||
}
|
||||
|
||||
public:
|
||||
inline void Xstac()
|
||||
{
|
||||
if (this->SMAPUsed)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
asm volatile("stac" ::
|
||||
: "cc");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline void Xclac()
|
||||
{
|
||||
if (this->SMAPUsed)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
asm volatile("clac" ::
|
||||
: "cc");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new Allocator V1 object
|
||||
*
|
||||
* @param Address Virtual address to allocate.
|
||||
* @param UserMode Map the new pages with USER flag?
|
||||
* @param SMAPEnabled Does the kernel has Supervisor Mode Access Prevention enabled?
|
||||
*/
|
||||
AllocatorV1(void *Address, bool UserMode, bool SMAPEnabled);
|
||||
|
||||
/**
|
||||
* @brief Destroy the Allocator V 1 object
|
||||
*
|
||||
*/
|
||||
~AllocatorV1();
|
||||
|
||||
/**
|
||||
* @brief Allocate a new memory block
|
||||
*
|
||||
* @param Size Size of the block to allocate.
|
||||
* @return void* Pointer to the allocated block.
|
||||
*/
|
||||
void *Malloc(Xuint64_t Size);
|
||||
|
||||
/**
|
||||
* @brief Free a previously allocated block
|
||||
*
|
||||
* @param Address Address of the block to free.
|
||||
*/
|
||||
void Free(void *Address);
|
||||
|
||||
/**
|
||||
* @brief Allocate a new memory block
|
||||
*
|
||||
* @param NumberOfBlocks Number of blocks to allocate.
|
||||
* @param Size Size of the block to allocate.
|
||||
* @return void* Pointer to the allocated block.
|
||||
*/
|
||||
void *Calloc(Xuint64_t NumberOfBlocks, Xuint64_t Size);
|
||||
|
||||
/**
|
||||
* @brief Reallocate a previously allocated block
|
||||
*
|
||||
* @param Address Address of the block to reallocate.
|
||||
* @param Size New size of the block.
|
||||
* @return void* Pointer to the reallocated block.
|
||||
*/
|
||||
void *Realloc(void *Address, Xuint64_t Size);
|
||||
};
|
||||
}
|
137
Core/Memory/HeapAllocators/Xalloc/README.md
Normal file
137
Core/Memory/HeapAllocators/Xalloc/README.md
Normal file
@ -0,0 +1,137 @@
|
||||
# Xalloc
|
||||
|
||||
Xalloc is a custom memory allocator designed for hobby operating systems. It is written in C++ and provides a simple and efficient way to manage memory in your hobby OS.
|
||||
|
||||
#### ❗ This project is still in development and is not ready for use in production environments. ❗
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Simple API** - Xalloc provides a simple API for allocating and freeing memory. It is designed to be easy to use and understand.
|
||||
|
||||
- [ ] todo complete this
|
||||
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Implementing missing functions
|
||||
|
||||
You will need to implement the following functions in your OS:
|
||||
|
||||
##### Wrapper.cpp
|
||||
```cpp
|
||||
extern "C" void *Xalloc_REQUEST_PAGES(Xsize_t Pages)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_FREE_PAGES(void *Address, Xsize_t Pages)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_MAP_MEMORY(void *VirtualAddress, void *PhysicalAddress, Xsize_t Flags)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_UNMAP_MEMORY(void *VirtualAddress)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
##### Xalloc.hpp
|
||||
```cpp
|
||||
#define Xalloc_PAGE_SIZE <page size> /* <-- Replace with your page size */
|
||||
#define Xalloc_trace(m, ...) <trace function>
|
||||
#define Xalloc_warn(m, ...) <warning function>
|
||||
#define Xalloc_err(m, ...) <error function>
|
||||
#define Xalloc_def <define a lock> /* eg. std::mutex Xalloc_lock; */
|
||||
#define Xalloc_lock <lock function>
|
||||
#define Xalloc_unlock <unlock function>
|
||||
```
|
||||
|
||||
### Typical usage
|
||||
|
||||
```cpp
|
||||
#include "Xalloc.hpp"
|
||||
|
||||
Xalloc::V1 *XallocV1Allocator = nullptr;
|
||||
|
||||
int main()
|
||||
{
|
||||
/* Virtual Base User SMAP */
|
||||
XallocV1Allocator = new Xalloc::V1((void *)0xFFFFA00000000000, false, false);
|
||||
|
||||
void *p = XallocV1Allocator->malloc(1234);
|
||||
/* ... */
|
||||
XallocV1Allocator->free(p);
|
||||
delete XallocV1Allocator;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```cpp
|
||||
#include "Xalloc.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
/* Virtual Base User SMAP */
|
||||
Xalloc::V1 XallocV1Allocator((void *)0xFFFFA00000000000, false, false);
|
||||
|
||||
void *p = XallocV1Allocator.malloc(1234);
|
||||
/* ... */
|
||||
XallocV1Allocator.free(p);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API
|
||||
|
||||
### Xalloc::V1
|
||||
|
||||
```cpp
|
||||
void *malloc(Xsize_t Size);
|
||||
```
|
||||
Allocates a block of memory of size `Size` bytes.
|
||||
If `Size` is 0, then `nullptr` is returned.
|
||||
- `Size` - The size of the block to allocate in bytes.
|
||||
|
||||
<br><br>
|
||||
|
||||
```cpp
|
||||
void free(void *Address);
|
||||
```
|
||||
Frees the memory block pointed to by `Address`.
|
||||
If `Address` is `nullptr`, then no operation is performed.
|
||||
- `Address` - The address of the memory block to free.
|
||||
|
||||
<br><br>
|
||||
|
||||
```cpp
|
||||
void *calloc(Xsize_t NumberOfBlocks, Xsize_t Size);
|
||||
```
|
||||
Allocates a block of memory for an array of `NumberOfBlocks` elements, each of them `Size` bytes long.
|
||||
If `NumberOfBlocks` or `Size` is 0, then `nullptr` is returned.
|
||||
- `NumberOfBlocks` - The number of elements to allocate.
|
||||
- `Size` - The size of each element in bytes.
|
||||
|
||||
<br><br>
|
||||
|
||||
```cpp
|
||||
void *realloc(void *Address, Xsize_t Size);
|
||||
```
|
||||
Changes the size of the memory block pointed to by `Address` to `Size` bytes.
|
||||
If `Address` is `nullptr`, then the call is equivalent to `malloc(Size)`.
|
||||
If `Size` is equal to zero, and `Address` is not `nullptr`, then the call is equivalent to `free(Address)`.
|
||||
- `Address` - The address of the memory block to resize.
|
||||
- `Size` - The new size of the memory block in bytes.
|
||||
|
||||
---
|
23
Core/Memory/HeapAllocators/Xalloc/Wrapper.cpp
Normal file
23
Core/Memory/HeapAllocators/Xalloc/Wrapper.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "Xalloc.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
|
||||
extern "C" void *Xalloc_REQUEST_PAGES(Xsize_t Pages)
|
||||
{
|
||||
return KernelAllocator.RequestPages(Pages);
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_FREE_PAGES(void *Address, Xsize_t Pages)
|
||||
{
|
||||
KernelAllocator.FreePages(Address, Pages);
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_MAP_MEMORY(void *VirtualAddress, void *PhysicalAddress, Xsize_t Flags)
|
||||
{
|
||||
Memory::Virtual(KernelPageTable).Map(VirtualAddress, PhysicalAddress, Flags);
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_UNMAP_MEMORY(void *VirtualAddress)
|
||||
{
|
||||
Memory::Virtual(KernelPageTable).Unmap(VirtualAddress);
|
||||
}
|
101
Core/Memory/HeapAllocators/Xalloc/Xalloc.hpp
Normal file
101
Core/Memory/HeapAllocators/Xalloc/Xalloc.hpp
Normal file
@ -0,0 +1,101 @@
|
||||
#ifndef __FENNIX_KERNEL_Xalloc_H__
|
||||
#define __FENNIX_KERNEL_Xalloc_H__
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
typedef long unsigned Xuint64_t;
|
||||
typedef long unsigned Xsize_t;
|
||||
|
||||
#define Xalloc_PAGE_SIZE PAGE_SIZE
|
||||
#define Xalloc_trace(m, ...) trace(m, ##__VA_ARGS__)
|
||||
#define Xalloc_warn(m, ...) warn(m, ##__VA_ARGS__)
|
||||
#define Xalloc_err(m, ...) error(m, ##__VA_ARGS__)
|
||||
#define Xalloc_def NewLock(XallocLock)
|
||||
#define Xalloc_lock XallocLock.Lock(__FUNCTION__)
|
||||
#define Xalloc_unlock XallocLock.Unlock()
|
||||
|
||||
namespace Xalloc
|
||||
{
|
||||
class V1
|
||||
{
|
||||
private:
|
||||
void *BaseVirtualAddress = nullptr;
|
||||
void *FirstBlock = nullptr;
|
||||
void *LastBlock = nullptr;
|
||||
|
||||
bool UserMapping = false;
|
||||
bool SMAPUsed = false;
|
||||
|
||||
public:
|
||||
/** @brief Execute "stac" instruction if the kernel has SMAP enabled */
|
||||
void Xstac();
|
||||
|
||||
/** @brief Execute "clac" instruction if the kernel has SMAP enabled */
|
||||
void Xclac();
|
||||
|
||||
/**
|
||||
* @brief Arrange the blocks to optimize the memory usage
|
||||
* The allocator is not arranged by default
|
||||
* to avoid performance issues.
|
||||
* This function will defragment the memory
|
||||
* and free the unused blocks.
|
||||
*
|
||||
* You should call this function when the
|
||||
* kernel is idle or when is not using
|
||||
* the allocator.
|
||||
*/
|
||||
void Arrange();
|
||||
|
||||
/**
|
||||
* @brief Allocate a new memory block
|
||||
*
|
||||
* @param Size Size of the block to allocate.
|
||||
* @return void* Pointer to the allocated block.
|
||||
*/
|
||||
void *malloc(Xsize_t Size);
|
||||
|
||||
/**
|
||||
* @brief Free a previously allocated block
|
||||
*
|
||||
* @param Address Address of the block to free.
|
||||
*/
|
||||
void free(void *Address);
|
||||
|
||||
/**
|
||||
* @brief Allocate a new memory block
|
||||
*
|
||||
* @param NumberOfBlocks Number of blocks to allocate.
|
||||
* @param Size Size of the block to allocate.
|
||||
* @return void* Pointer to the allocated block.
|
||||
*/
|
||||
void *calloc(Xsize_t NumberOfBlocks, Xsize_t Size);
|
||||
|
||||
/**
|
||||
* @brief Reallocate a previously allocated block
|
||||
*
|
||||
* @param Address Address of the block to reallocate.
|
||||
* @param Size New size of the block.
|
||||
* @return void* Pointer to the reallocated block.
|
||||
*/
|
||||
void *realloc(void *Address, Xsize_t Size);
|
||||
|
||||
/**
|
||||
* @brief Construct a new Allocator object
|
||||
*
|
||||
* @param BaseVirtualAddress Virtual address to map the pages.
|
||||
* @param UserMode Map the new pages with USER flag?
|
||||
* @param SMAPEnabled Does the kernel has Supervisor Mode Access Prevention enabled?
|
||||
*/
|
||||
V1(void *BaseVirtualAddress, bool UserMode, bool SMAPEnabled);
|
||||
|
||||
/**
|
||||
* @brief Destroy the Allocator object
|
||||
*
|
||||
*/
|
||||
~V1();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_Xalloc_H__
|
263
Core/Memory/HeapAllocators/Xalloc/XallocV1.cpp
Normal file
263
Core/Memory/HeapAllocators/Xalloc/XallocV1.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
#include "Xalloc.hpp"
|
||||
|
||||
Xalloc_def;
|
||||
|
||||
#define XALLOC_CONCAT(x, y) x##y
|
||||
#define XStoP(x) (x / Xalloc_PAGE_SIZE + 1)
|
||||
#define XPtoS(x) (x * Xalloc_PAGE_SIZE)
|
||||
#define Xalloc_BlockChecksum 0xA110C
|
||||
|
||||
extern "C" void *Xalloc_REQUEST_PAGES(Xsize_t Pages);
|
||||
extern "C" void Xalloc_FREE_PAGES(void *Address, Xsize_t Pages);
|
||||
extern "C" void Xalloc_MAP_MEMORY(void *VirtualAddress, void *PhysicalAddress, Xsize_t Flags);
|
||||
extern "C" void Xalloc_UNMAP_MEMORY(void *VirtualAddress);
|
||||
|
||||
// TODO: Change memcpy with an optimized version
|
||||
void *Xmemcpy(void *__restrict__ Destination, const void *__restrict__ Source, Xuint64_t Length)
|
||||
{
|
||||
unsigned char *dst = (unsigned char *)Destination;
|
||||
const unsigned char *src = (const unsigned char *)Source;
|
||||
for (Xuint64_t i = 0; i < Length; i++)
|
||||
dst[i] = src[i];
|
||||
return Destination;
|
||||
}
|
||||
|
||||
// TODO: Change memset with an optimized version
|
||||
void *Xmemset(void *__restrict__ Destination, int Data, Xuint64_t Length)
|
||||
{
|
||||
unsigned char *Buffer = (unsigned char *)Destination;
|
||||
for (Xuint64_t i = 0; i < Length; i++)
|
||||
Buffer[i] = (unsigned char)Data;
|
||||
return Destination;
|
||||
}
|
||||
|
||||
namespace Xalloc
|
||||
{
|
||||
class Block
|
||||
{
|
||||
public:
|
||||
void *Address = nullptr;
|
||||
|
||||
int Checksum = Xalloc_BlockChecksum;
|
||||
Xsize_t Size = 0;
|
||||
Block *Next = nullptr;
|
||||
Block *Last = nullptr;
|
||||
bool IsFree = true;
|
||||
|
||||
bool Check()
|
||||
{
|
||||
if (this->Checksum != Xalloc_BlockChecksum)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Block(Xsize_t Size)
|
||||
{
|
||||
this->Size = Size;
|
||||
this->Address = Xalloc_REQUEST_PAGES(XStoP(Size));
|
||||
}
|
||||
|
||||
~Block()
|
||||
{
|
||||
Xalloc_FREE_PAGES(this->Address, XStoP(this->Size));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Overload new operator to allocate memory from the heap
|
||||
* @param Size Unused
|
||||
* @return void* Pointer to the allocated memory
|
||||
*/
|
||||
void *operator new(Xsize_t Size)
|
||||
{
|
||||
void *ptr = Xalloc_REQUEST_PAGES(XStoP(sizeof(Block)));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Overload delete operator to free memory from the heap
|
||||
* @param Address Pointer to the memory to free
|
||||
*/
|
||||
void operator delete(void *Address)
|
||||
{
|
||||
Xalloc_FREE_PAGES(Address, XStoP(sizeof(Block)));
|
||||
}
|
||||
} __attribute__((packed, aligned((16))));
|
||||
|
||||
class SmartSMAPClass
|
||||
{
|
||||
private:
|
||||
V1 *allocator = nullptr;
|
||||
|
||||
public:
|
||||
SmartSMAPClass(V1 *allocator)
|
||||
{
|
||||
this->allocator = allocator;
|
||||
this->allocator->Xstac();
|
||||
}
|
||||
~SmartSMAPClass() { this->allocator->Xclac(); }
|
||||
};
|
||||
#define SmartSMAP SmartSMAPClass XALLOC_CONCAT(SmartSMAP##_, __COUNTER__)(this)
|
||||
|
||||
void V1::Xstac()
|
||||
{
|
||||
if (this->SMAPUsed)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
asm volatile("stac" ::
|
||||
: "cc");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void V1::Xclac()
|
||||
{
|
||||
if (this->SMAPUsed)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
asm volatile("clac" ::
|
||||
: "cc");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void V1::Arrange()
|
||||
{
|
||||
Xalloc_err("Arrange() is not implemented yet!");
|
||||
}
|
||||
|
||||
void *V1::malloc(Xsize_t Size)
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
Xalloc_warn("Attempted to allocate 0 bytes!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SmartSMAP;
|
||||
Xalloc_lock;
|
||||
|
||||
if (this->FirstBlock == nullptr)
|
||||
{
|
||||
this->FirstBlock = new Block(Size);
|
||||
((Block *)this->FirstBlock)->IsFree = false;
|
||||
((Block *)this->FirstBlock)->Checksum = Xalloc_BlockChecksum;
|
||||
Xmemset(((Block *)this->FirstBlock)->Address, 0, Size);
|
||||
Xalloc_unlock;
|
||||
return ((Block *)this->FirstBlock)->Address;
|
||||
}
|
||||
|
||||
Block *CurrentBlock = ((Block *)this->FirstBlock);
|
||||
while (CurrentBlock != nullptr)
|
||||
{
|
||||
if (CurrentBlock->IsFree && CurrentBlock->Size >= Size)
|
||||
{
|
||||
CurrentBlock->IsFree = false;
|
||||
CurrentBlock->Checksum = Xalloc_BlockChecksum;
|
||||
Xmemset(CurrentBlock->Address, 0, Size);
|
||||
Xalloc_unlock;
|
||||
return CurrentBlock->Address;
|
||||
}
|
||||
CurrentBlock = CurrentBlock->Next;
|
||||
}
|
||||
|
||||
CurrentBlock = ((Block *)this->FirstBlock);
|
||||
while (CurrentBlock->Next != nullptr)
|
||||
CurrentBlock = CurrentBlock->Next;
|
||||
|
||||
CurrentBlock->Next = new Block(Size);
|
||||
((Block *)CurrentBlock->Next)->Last = CurrentBlock;
|
||||
((Block *)CurrentBlock->Next)->IsFree = false;
|
||||
((Block *)CurrentBlock->Next)->Checksum = Xalloc_BlockChecksum;
|
||||
Xmemset(((Block *)CurrentBlock->Next)->Address, 0, Size);
|
||||
Xalloc_unlock;
|
||||
return ((Block *)CurrentBlock->Next)->Address;
|
||||
}
|
||||
|
||||
void V1::free(void *Address)
|
||||
{
|
||||
if (Address == nullptr)
|
||||
{
|
||||
Xalloc_warn("Attempted to free a null pointer!");
|
||||
return;
|
||||
}
|
||||
|
||||
SmartSMAP;
|
||||
Xalloc_lock;
|
||||
|
||||
Block *CurrentBlock = ((Block *)this->FirstBlock);
|
||||
while (CurrentBlock != nullptr)
|
||||
{
|
||||
if (CurrentBlock->Address == Address)
|
||||
{
|
||||
if (CurrentBlock->IsFree)
|
||||
{
|
||||
Xalloc_warn("Attempted to free an already freed pointer!");
|
||||
Xalloc_unlock;
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentBlock->IsFree = true;
|
||||
CurrentBlock->Checksum = Xalloc_BlockChecksum;
|
||||
Xalloc_unlock;
|
||||
return;
|
||||
}
|
||||
CurrentBlock = CurrentBlock->Next;
|
||||
}
|
||||
|
||||
Xalloc_err("Invalid address.");
|
||||
Xalloc_unlock;
|
||||
}
|
||||
|
||||
void *V1::calloc(Xsize_t NumberOfBlocks, Xsize_t Size)
|
||||
{
|
||||
if (NumberOfBlocks == 0 || Size == 0)
|
||||
{
|
||||
Xalloc_warn("The %s%s%s is 0!",
|
||||
NumberOfBlocks == 0 ? "NumberOfBlocks" : "",
|
||||
NumberOfBlocks == 0 && Size == 0 ? " and " : "",
|
||||
Size == 0 ? "Size" : "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return this->malloc(NumberOfBlocks * Size);
|
||||
}
|
||||
|
||||
void *V1::realloc(void *Address, Xsize_t Size)
|
||||
{
|
||||
if (Address == nullptr)
|
||||
return this->malloc(Size);
|
||||
|
||||
if (Size == 0)
|
||||
{
|
||||
this->free(Address);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// SmartSMAP;
|
||||
// Xalloc_lock;
|
||||
// ...
|
||||
// Xalloc_unlock;
|
||||
|
||||
// TODO: Implement realloc
|
||||
this->free(Address);
|
||||
return this->malloc(Size);
|
||||
}
|
||||
|
||||
V1::V1(void *BaseVirtualAddress, bool UserMode, bool SMAPEnabled)
|
||||
{
|
||||
SmartSMAP;
|
||||
Xalloc_lock;
|
||||
this->SMAPUsed = SMAPEnabled;
|
||||
this->UserMapping = UserMode;
|
||||
this->BaseVirtualAddress = BaseVirtualAddress;
|
||||
Xalloc_unlock;
|
||||
}
|
||||
|
||||
V1::~V1()
|
||||
{
|
||||
SmartSMAP;
|
||||
Xalloc_lock;
|
||||
Xalloc_trace("Destructor not implemented yet.");
|
||||
Xalloc_unlock;
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
#include <lock.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
#include "HeapAllocators/Xalloc.hpp"
|
||||
#include "HeapAllocators/Xalloc/Xalloc.hpp"
|
||||
#include "../Library/liballoc_1_1.h"
|
||||
#include "../../kernel.h"
|
||||
|
||||
@ -32,7 +32,7 @@ PageTable4 *UserspaceKernelOnlyPageTable = nullptr;
|
||||
void *KPT = nullptr;
|
||||
|
||||
static MemoryAllocatorType AllocatorType = MemoryAllocatorType::None;
|
||||
Xalloc::AllocatorV1 *XallocV1Allocator = nullptr;
|
||||
Xalloc::V1 *XallocV1Allocator = nullptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
__no_instrument_function void tracepagetable(PageTable4 *pt)
|
||||
@ -241,7 +241,7 @@ __no_instrument_function void InitializeMemoryManagement(BootInfo *Info)
|
||||
debug("Page table updated.");
|
||||
if (strstr(Info->Kernel.CommandLine, "xallocv1"))
|
||||
{
|
||||
XallocV1Allocator = new Xalloc::AllocatorV1((void *)KERNEL_HEAP_BASE, false, false);
|
||||
XallocV1Allocator = new Xalloc::V1((void *)KERNEL_HEAP_BASE, false, false);
|
||||
AllocatorType = MemoryAllocatorType::XallocV1;
|
||||
trace("XallocV1 Allocator initialized (%p)", XallocV1Allocator);
|
||||
}
|
||||
@ -262,11 +262,7 @@ void *HeapMalloc(size_t Size)
|
||||
case unlikely(MemoryAllocatorType::Pages):
|
||||
return KernelAllocator.RequestPages(TO_PAGES(Size));
|
||||
case MemoryAllocatorType::XallocV1:
|
||||
{
|
||||
void *ret = XallocV1Allocator->Malloc(Size);
|
||||
memset(ret, 0, Size);
|
||||
return ret;
|
||||
}
|
||||
return XallocV1Allocator->malloc(Size);
|
||||
case MemoryAllocatorType::liballoc11:
|
||||
{
|
||||
void *ret = PREFIX(malloc)(Size);
|
||||
@ -289,11 +285,7 @@ void *HeapCalloc(size_t n, size_t Size)
|
||||
case unlikely(MemoryAllocatorType::Pages):
|
||||
return KernelAllocator.RequestPages(TO_PAGES(n * Size));
|
||||
case MemoryAllocatorType::XallocV1:
|
||||
{
|
||||
void *ret = XallocV1Allocator->Calloc(n, Size);
|
||||
memset(ret, 0, n * Size);
|
||||
return ret;
|
||||
}
|
||||
return XallocV1Allocator->calloc(n, Size);
|
||||
case MemoryAllocatorType::liballoc11:
|
||||
{
|
||||
void *ret = PREFIX(calloc)(n, Size);
|
||||
@ -311,22 +303,12 @@ void *HeapRealloc(void *Address, size_t Size)
|
||||
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("realloc(%#lx, %d)->[%s]", Address, Size, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
if (unlikely(!Address))
|
||||
{
|
||||
error("Attempt to realloc a null pointer");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (AllocatorType)
|
||||
{
|
||||
case unlikely(MemoryAllocatorType::Pages):
|
||||
return KernelAllocator.RequestPages(TO_PAGES(Size)); // WARNING: Potential memory leak
|
||||
case MemoryAllocatorType::XallocV1:
|
||||
{
|
||||
void *ret = XallocV1Allocator->Realloc(Address, Size);
|
||||
memset(ret, 0, Size);
|
||||
return ret;
|
||||
}
|
||||
return XallocV1Allocator->realloc(Address, Size);
|
||||
case MemoryAllocatorType::liballoc11:
|
||||
{
|
||||
void *ret = PREFIX(realloc)(Address, Size);
|
||||
@ -344,20 +326,13 @@ void HeapFree(void *Address)
|
||||
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("free(%#lx)->[%s]", Address, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
if (unlikely(!Address))
|
||||
{
|
||||
warn("Attempt to free a null pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (AllocatorType)
|
||||
{
|
||||
case unlikely(MemoryAllocatorType::Pages):
|
||||
KernelAllocator.FreePage(Address); // WARNING: Potential memory leak
|
||||
break;
|
||||
case MemoryAllocatorType::XallocV1:
|
||||
if (XallocV1Allocator)
|
||||
XallocV1Allocator->Free(Address);
|
||||
XallocV1Allocator->free(Address);
|
||||
break;
|
||||
case MemoryAllocatorType::liballoc11:
|
||||
PREFIX(free)
|
||||
|
@ -32,6 +32,7 @@ void TreeFS(Node *node, int Depth)
|
||||
{
|
||||
printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->Name);
|
||||
Display->SetBuffer(0);
|
||||
TaskManager->Sleep(100);
|
||||
TreeFS(Chld, Depth + 1);
|
||||
}
|
||||
}
|
||||
@ -137,6 +138,8 @@ void KernelMainThread()
|
||||
/* TODO: This should not be enabled because it may cause a deadlock. Not sure where or how. */
|
||||
// Tasking::PCB *tskMgr = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), "Debug Task Manager", Tasking::TaskTrustLevel::Kernel);
|
||||
// TaskManager->CreateThread(tskMgr, (Tasking::IP)TaskMgr)->SetPriority(Tasking::High);
|
||||
|
||||
TreeFS(vfs->GetRootNode(), 0);
|
||||
#endif
|
||||
|
||||
KPrint("Kernel Compiled at: %s %s with C++ Standard: %d", __DATE__, __TIME__, CPP_LANGUAGE_STANDARD);
|
||||
@ -163,10 +166,6 @@ void KernelMainThread()
|
||||
KPrint("Starting Network Interface Manager...");
|
||||
NIManager->StartService();
|
||||
|
||||
#ifdef DEBUG
|
||||
TreeFS(vfs->GetRootNode(), 0);
|
||||
#endif
|
||||
|
||||
Time::Clock tm = Time::ReadClock();
|
||||
printf("\eCCCCCC[\e00AEFF%02d:%02d:%02d\eCCCCCC] ", tm.Hour, tm.Minute, tm.Second);
|
||||
const char *USpace_msg = "Setting up userspace";
|
||||
|
@ -340,6 +340,7 @@ EXTERNC __no_stack_protector __no_instrument_function void Entry(BootInfo *Info)
|
||||
#ifdef DEBUG
|
||||
// Running tests
|
||||
TestString();
|
||||
TestMemoryAllocation();
|
||||
#endif
|
||||
|
||||
EnableProfiler = true;
|
||||
|
224
Tests/MemoryAllocation.cpp
Normal file
224
Tests/MemoryAllocation.cpp
Normal file
@ -0,0 +1,224 @@
|
||||
#ifdef DEBUG
|
||||
|
||||
#include <string.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
/* Originally from: https://github.com/EnderIce2/FennixProject/blob/main/kernel/test.cpp */
|
||||
|
||||
#define MEMTEST_ITERATIONS 1024
|
||||
|
||||
class test_mem_new_delete
|
||||
{
|
||||
public:
|
||||
test_mem_new_delete();
|
||||
~test_mem_new_delete();
|
||||
};
|
||||
|
||||
test_mem_new_delete::test_mem_new_delete()
|
||||
{
|
||||
for (char i = 0; i < 2; i++)
|
||||
;
|
||||
}
|
||||
|
||||
test_mem_new_delete::~test_mem_new_delete()
|
||||
{
|
||||
for (char i = 0; i < 2; i++)
|
||||
;
|
||||
}
|
||||
|
||||
void TestMemoryAllocation()
|
||||
{
|
||||
void *tmpAlloc1 = kmalloc(176);
|
||||
void *tmpAlloc2 = kmalloc(511);
|
||||
void *tmpAlloc3 = kmalloc(1027);
|
||||
void *tmpAlloc4 = kmalloc(1569);
|
||||
for (int repeat = 0; repeat < 4; repeat++)
|
||||
{
|
||||
debug("---------------[TEST %d]---------------\n", repeat);
|
||||
|
||||
debug("Single Page Request Test");
|
||||
{
|
||||
uint64_t prq1 = (uint64_t)KernelAllocator.RequestPage();
|
||||
KernelAllocator.FreePage((void *)prq1);
|
||||
|
||||
for (uint64_t i = 0; i < MEMTEST_ITERATIONS; i++)
|
||||
KernelAllocator.FreePage(KernelAllocator.RequestPage());
|
||||
|
||||
uint64_t prq2 = (uint64_t)KernelAllocator.RequestPage();
|
||||
KernelAllocator.FreePage((void *)prq2);
|
||||
|
||||
debug(" Result:\t\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2);
|
||||
assert(prq1 == prq2);
|
||||
}
|
||||
|
||||
debug("Multiple Page Request Test");
|
||||
{
|
||||
uint64_t prq1 = (uint64_t)KernelAllocator.RequestPages(10);
|
||||
KernelAllocator.FreePages((void *)prq1, 10);
|
||||
|
||||
for (uint64_t i = 0; i < MEMTEST_ITERATIONS; i++)
|
||||
KernelAllocator.FreePages(KernelAllocator.RequestPages(20), 20);
|
||||
|
||||
uint64_t prq2 = (uint64_t)KernelAllocator.RequestPages(10);
|
||||
KernelAllocator.FreePages((void *)prq2, 10);
|
||||
|
||||
debug(" Result:\t\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2);
|
||||
assert(prq1 == prq2);
|
||||
}
|
||||
|
||||
debug("Multiple Fixed Malloc Test");
|
||||
{
|
||||
uint64_t prq1 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq1);
|
||||
|
||||
for (uint64_t i = 0; i < MEMTEST_ITERATIONS; i++)
|
||||
kfree(kmalloc(0x10000));
|
||||
|
||||
uint64_t prq2 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq2);
|
||||
|
||||
debug(" Result:\t\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2);
|
||||
assert(prq1 == prq2);
|
||||
}
|
||||
|
||||
debug("Multiple Dynamic Malloc Test");
|
||||
{
|
||||
uint64_t prq1 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq1);
|
||||
|
||||
for (uint64_t i = 0; i < MEMTEST_ITERATIONS; i++)
|
||||
kfree(kmalloc(i));
|
||||
|
||||
uint64_t prq2 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq2);
|
||||
|
||||
debug(" Result:\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2);
|
||||
assert(prq1 == prq2);
|
||||
}
|
||||
|
||||
debug("New/Delete Test");
|
||||
{
|
||||
uint64_t prq1 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq1);
|
||||
|
||||
for (uint64_t i = 0; i < MEMTEST_ITERATIONS; i++)
|
||||
{
|
||||
test_mem_new_delete *t = new test_mem_new_delete();
|
||||
delete t;
|
||||
}
|
||||
|
||||
uint64_t prq2 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq2);
|
||||
|
||||
debug(" Result: \t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2);
|
||||
assert(prq1 == prq2);
|
||||
}
|
||||
|
||||
debug("New/Delete Fixed Array Test");
|
||||
{
|
||||
uint64_t prq1 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq1);
|
||||
|
||||
for (uint64_t i = 0; i < MEMTEST_ITERATIONS; i++)
|
||||
{
|
||||
char *t = new char[128];
|
||||
delete[] t;
|
||||
}
|
||||
|
||||
uint64_t prq2 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq2);
|
||||
|
||||
debug(" Result: \t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2);
|
||||
assert(prq1 == prq2);
|
||||
}
|
||||
|
||||
debug("New/Delete Dynamic Array Test");
|
||||
{
|
||||
uint64_t prq1 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq1);
|
||||
|
||||
for (uint64_t i = 0; i < MEMTEST_ITERATIONS; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
continue;
|
||||
char *t = new char[i];
|
||||
delete[] t;
|
||||
}
|
||||
|
||||
uint64_t prq2 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq2);
|
||||
|
||||
debug(" Result:\t1-[%#lx]; 2-[%#lx]\n", (void *)prq1, (void *)prq2);
|
||||
assert(prq1 == prq2);
|
||||
}
|
||||
|
||||
debug("calloc Test");
|
||||
{
|
||||
uint64_t prq1 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq1);
|
||||
|
||||
for (uint64_t i = 0; i < MEMTEST_ITERATIONS; i++)
|
||||
{
|
||||
char *t = (char *)kcalloc(128, 1);
|
||||
kfree(t);
|
||||
}
|
||||
|
||||
uint64_t prq2 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq2);
|
||||
|
||||
debug(" Result:\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2);
|
||||
assert(prq1 == prq2);
|
||||
}
|
||||
|
||||
debug("realloc Test");
|
||||
{
|
||||
uint64_t prq1 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq1);
|
||||
|
||||
for (uint64_t i = 0; i < MEMTEST_ITERATIONS; i++)
|
||||
{
|
||||
char *t = (char *)kmalloc(128);
|
||||
t = (char *)krealloc(t, 256);
|
||||
kfree(t);
|
||||
}
|
||||
|
||||
uint64_t prq2 = (uint64_t)kmalloc(0x1000);
|
||||
kfree((void *)prq2);
|
||||
|
||||
debug(" Result:\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2);
|
||||
assert(prq1 == prq2);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(tmpAlloc1);
|
||||
kfree(tmpAlloc2);
|
||||
kfree(tmpAlloc3);
|
||||
kfree(tmpAlloc4);
|
||||
|
||||
debug("Memory Stress Test");
|
||||
for (size_t i = 0; i < 0x1000; i++)
|
||||
kfree(kmalloc(i));
|
||||
|
||||
debug("Invalid Usage Test");
|
||||
kfree(tmpAlloc1);
|
||||
kfree(tmpAlloc2);
|
||||
kfree(tmpAlloc3);
|
||||
kfree(tmpAlloc4);
|
||||
|
||||
void *InvMlc = kmalloc(0);
|
||||
assert(InvMlc == nullptr);
|
||||
krealloc(InvMlc, 0);
|
||||
assert(InvMlc == nullptr);
|
||||
kcalloc(0, 0);
|
||||
assert(InvMlc == nullptr);
|
||||
kcalloc(1, 0);
|
||||
assert(InvMlc == nullptr);
|
||||
kcalloc(0, 1);
|
||||
assert(InvMlc == nullptr);
|
||||
kfree(InvMlc);
|
||||
|
||||
debug("Memory Test Complete\n");
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
Loading…
x
Reference in New Issue
Block a user