20#if SLAM_USE_DEBUG_ALLOCATOR
22#include "pedigree/kernel/LockGuard.h"
23#include "pedigree/kernel/core/SlamAllocator.h"
24#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
25#include "pedigree/kernel/processor/Processor.h"
26#include "pedigree/kernel/processor/VirtualAddressSpace.h"
27#include "pedigree/kernel/utilities/MemoryTracing.h"
28#include "pedigree/kernel/utilities/assert.h"
31#include "pedigree/kernel/process/Process.h"
32#include "pedigree/kernel/process/Thread.h"
37inline uintptr_t getHeapBase() {
41inline uintptr_t getHeapEnd() {
45inline size_t getPageSize() {
49inline void allocateAndMapAt(
void* addr) {
52 static physical_uintptr_t physZero = 0;
57 if (!va.
map(phys, addr, standardFlags)) {
58 FATAL(
"SlamAllocator: failed to allocate and map at " << addr);
62inline void unmap(
void* addr) {
67 physical_uintptr_t phys;
75inline bool isMapped(
void* addr) {
80inline void markReadOnly(
void* addr) {
90 m_RecoveryLock(false, true),
99size_t SlamCache::currentList()
const {
103#if defined(PEDIGREE_BUILDUTILS)
104void SlamCache::setListForTest(
size_t list) {
114void SlamCache::push(SlamCache::alignedNode* head,
SlamCache::Node* newTail,
133uintptr_t SlamCache::getSlab() {
138void SlamCache::freeSlab(uintptr_t slab) {
152#if CRIPPLINGLY_VIGILANT
153void SlamCache::check() {
157void SlamCache::trackSlab(uintptr_t slab) {
162SlamAllocator::SlamAllocator()
163 : m_bInitialised(false),
165 m_SlabRegionLock(false, true),
167 m_SlabRegionBitmap(),
168 m_SlabRegionBitmapEntries(0),
169 m_SlabRegionPages(0),
172SlamAllocator::~SlamAllocator() {
173 if (m_bInitialised) {
178void SlamAllocator::initialise() {
181 if (m_bInitialised) {
185 m_Base = getHeapBase();
186 m_bInitialised =
true;
193uintptr_t SlamAllocator::getSlab(
size_t fullSize) {
198void SlamAllocator::freeSlab(uintptr_t address,
size_t length) {
206#if defined(PEDIGREE_BUILDUTILS)
207void SlamAllocator::setSlabTransitionHookForTest(SlabTransitionHookForTest hook,
void* context) {
208 m_SlabTransitionHook = hook;
209 m_SlabTransitionHookContext = context;
213size_t SlamAllocator::recovery(
size_t maxSlabs) {
223 if (!m_bInitialised) {
231 uintptr_t mapStart = 0, mapEnd = 0, result = 0;
232 size_t nTotalBytes = 0, numPages = 0;
234 numPages = nBytes / getPageSize();
235 if (nBytes % getPageSize()) {
241 nTotalBytes = numPages * getPageSize();
246 m_Base += getPageSize();
248 m_Base += getPageSize();
251 m_Base += numPages * getPageSize();
255 for (uintptr_t addr = mapStart; addr < mapEnd; addr += getPageSize()) {
256 allocateAndMapAt(
reinterpret_cast<void*
>(addr));
261 *((
size_t*)(result -
sizeof(
size_t))) = numPages;
264 markReadOnly(
reinterpret_cast<void*
>(mapStart));
270 pThread->
getParent()->trackHeap(nTotalBytes);
276 traceAllocation(
reinterpret_cast<void*
>(result), MemoryTracing::Allocation, nTotalBytes);
282#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
283uintptr_t SlamAllocator::guardedAllocateForTest(
size_t nBytes) {
287void SlamAllocator::guardedFreeForTest(uintptr_t
mem) {
288 instance().free(
mem);
292size_t SlamAllocator::allocSize(uintptr_t
mem) {
293 if (!m_bInitialised) {
301 return *((
size_t*)(
mem -
sizeof(
size_t))) * getPageSize();
314void SlamAllocator::free(uintptr_t
mem) {
319 assert(m_bInitialised);
329 traceAllocation(
reinterpret_cast<void*
>(
mem), MemoryTracing::Free, 0);
332 assert(isMapped(
reinterpret_cast<void*
>(
mem)));
334 if (!isPointerValid(
mem)) {
338 size_t numPages = *((
size_t*)(
mem -
sizeof(
size_t)));
339 size_t nBytes = numPages * getPageSize();
341 uintptr_t unmapStart =
mem - getPageSize();
342 uintptr_t unmapEnd =
mem + nBytes;
344 for (uintptr_t addr = unmapStart; addr < unmapEnd; addr += getPageSize()) {
345 unmap(
reinterpret_cast<void*
>(addr));
354 pThread->
getParent()->trackHeap(-nBytes);
360 traceAllocation(
reinterpret_cast<void*
>(
mem), MemoryTracing::Free, 0);
364bool SlamAllocator::isPointerValid(uintptr_t
mem)
369 if (!m_bInitialised) {
375 reinterpret_cast<void*
>(
mem))) {
376#if VERBOSE_ISPOINTERVALID
377 WARNING(
"SlamAllocator::isPointerValid: memory " <<
Hex <<
mem
378 <<
" is not in the heap region.");
383 if (!isMapped(
reinterpret_cast<void*
>(
mem))) {
384#if VERBOSE_ISPOINTERVALID
385 WARNING(
"SlamAllocator::isPointerValid: memory "
386 <<
Hex <<
mem <<
" is not mapped [current base = " <<
Hex << m_Base <<
"].");
389#if VERBOSE_ISPOINTERVALID
391 " (pointer being deleted is beyond the end of the heap "
401bool SlamAllocator::isWithinHeap(uintptr_t
mem)
const {
403 reinterpret_cast<void*
>(
mem))) {
404#if VERBOSE_ISPOINTERVALID
405 WARNING(
"SlamAllocator::isWithinHeap: memory " <<
Hex <<
mem <<
" is not in the heap region.");
413bool _assert_ptr_valid(uintptr_t ptr) {
414 return SlamAllocator::instance().isPointerValid(ptr);
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
virtual void freePage(physical_uintptr_t page)=0
static ProcessorInformation & information()
static size_t m_Initialised
static bool guardDeviceHardIrqOperation(DeviceHardIrqOperation operation)
void markSlabReady(uintptr_t address, size_t length)
uintptr_t allocate(size_t nBytes)
void free(uintptr_t object)
bool isPointerValid(uintptr_t object) const
void initialise(SlamAllocator *parent, size_t objectSize)
size_t recovery(size_t maxSlabs)
Process * getParent() const
virtual void setFlags(void *virtualAddress, size_t newFlags)=0
virtual uintptr_t getKernelHeapStart() const =0
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
virtual bool isMapped(void *virtualAddress)=0
static const size_t KernelMode
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
static const size_t Write
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual uintptr_t getKernelHeapEnd() const =0
virtual void unmap(void *virtualAddress)=0