The Pedigree Project 0.1
DebugAllocator.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#if SLAM_USE_DEBUG_ALLOCATOR
21
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"
29
30#if THREADS
31#include "pedigree/kernel/process/Process.h"
32#include "pedigree/kernel/process/Thread.h"
33#endif
34
35SlamAllocator SlamAllocator::m_Instance;
36
37inline uintptr_t getHeapBase() {
39}
40
41inline uintptr_t getHeapEnd() {
43}
44
45inline size_t getPageSize() {
47}
48
49inline void allocateAndMapAt(void* addr) {
51
52 static physical_uintptr_t physZero = 0;
53
54 physical_uintptr_t phys = PhysicalMemoryManager::instance().allocatePage();
55
57 if (!va.map(phys, addr, standardFlags)) {
58 FATAL("SlamAllocator: failed to allocate and map at " << addr);
59 }
60}
61
62inline void unmap(void* addr) {
64 if (!va.isMapped(addr))
65 return;
66
67 physical_uintptr_t phys;
68 size_t flags;
69 va.getMapping(addr, phys, flags);
70 va.unmap(addr);
71
73}
74
75inline bool isMapped(void* addr) {
77 return va.isMapped(addr);
78}
79
80inline void markReadOnly(void* addr) {
83}
84
86 : m_PartialLists(),
87 m_ObjectSize(0),
88 m_SlabSize(0),
89 m_FirstSlab(),
90 m_RecoveryLock(false, true),
91 m_EmptyNode() {}
92
94
95void SlamCache::initialise(SlamAllocator* parent, size_t objectSize) {
96 // no-op for debug allocator
97}
98
99size_t SlamCache::currentList() const {
100 return 0;
101}
102
103#if defined(PEDIGREE_BUILDUTILS)
104void SlamCache::setListForTest(size_t list) {
105 m_TestList = list;
106}
107#endif
108
109SlamCache::Node* SlamCache::pop(SlamCache::alignedNode* head) {
110 // no-op for debug allocator
111 return nullptr;
112}
113
114void SlamCache::push(SlamCache::alignedNode* head, SlamCache::Node* newTail,
115 SlamCache::Node* newHead) {
116 // no-op for debug allocator
117}
118
119uintptr_t SlamCache::allocate() {
120 // no-op for debug allocator
121 return 0;
122}
123
124void SlamCache::free(uintptr_t object) {
125 // no-op for debug allocator
126}
127
128bool SlamCache::isPointerValid(uintptr_t object) const {
129 // no-op for debug allocator
130 return false;
131}
132
133uintptr_t SlamCache::getSlab() {
134 // no-op for debug allocator
135 return 0;
136}
137
138void SlamCache::freeSlab(uintptr_t slab) {
139 // no-op for debug allocator
140}
141
142size_t SlamCache::recovery(size_t maxSlabs) {
143 // no-op for debug allocator
144 return 0;
145}
146
147SlamCache::Node* SlamCache::initialiseSlab(uintptr_t slab) {
148 // no-op for debug allocator
149 return nullptr;
150}
151
152#if CRIPPLINGLY_VIGILANT
153void SlamCache::check() {
154 // no-op for debug allocator
155}
156
157void SlamCache::trackSlab(uintptr_t slab) {
158 // no-op for debug allocator
159}
160#endif
161
162SlamAllocator::SlamAllocator()
163 : m_bInitialised(false),
164 m_bVigilant(false),
165 m_SlabRegionLock(false, true),
166 m_HeapPageCount(0),
167 m_SlabRegionBitmap(),
168 m_SlabRegionBitmapEntries(0),
169 m_SlabRegionPages(0),
170 m_Base(0) {}
171
172SlamAllocator::~SlamAllocator() {
173 if (m_bInitialised) {
174 wipe();
175 }
176}
177
178void SlamAllocator::initialise() {
179 RecursingLockGuard<Spinlock> guard(m_Lock);
180
181 if (m_bInitialised) {
182 return;
183 }
184
185 m_Base = getHeapBase();
186 m_bInitialised = true;
187}
188
189void SlamAllocator::wipe() {
190 // no-op for debug allocator
191}
192
193uintptr_t SlamAllocator::getSlab(size_t fullSize) {
194 // no-op for debug allocator
195 return 0;
196}
197
198void SlamAllocator::freeSlab(uintptr_t address, size_t length) {
199 // no-op for debug allocator
200}
201
202void SlamAllocator::markSlabReady(uintptr_t address, size_t length) {
203 // no-op for debug allocator
204}
205
206#if defined(PEDIGREE_BUILDUTILS)
207void SlamAllocator::setSlabTransitionHookForTest(SlabTransitionHookForTest hook, void* context) {
208 m_SlabTransitionHook = hook;
209 m_SlabTransitionHookContext = context;
210}
211#endif
212
213size_t SlamAllocator::recovery(size_t maxSlabs) {
214 // no-op for debug allocator
215 return 0;
216}
217
218uintptr_t SlamAllocator::allocate(size_t nBytes) {
219 if (!Processor::guardDeviceHardIrqOperation(DeviceHardIrqOperation::HeapAllocate)) {
220 return 0;
221 }
222
223 if (!m_bInitialised) {
224 initialise();
225 }
226
227 if (!nBytes) {
228 return 0;
229 }
230
231 uintptr_t mapStart = 0, mapEnd = 0, result = 0;
232 size_t nTotalBytes = 0, numPages = 0;
233
234 numPages = nBytes / getPageSize();
235 if (nBytes % getPageSize()) {
236 ++numPages;
237 }
238 if (!numPages) {
239 ++numPages;
240 }
241 nTotalBytes = numPages * getPageSize();
242
243 {
244 RecursingLockGuard<Spinlock> guard(m_Lock);
245
246 m_Base += getPageSize(); // gap between allocations
247 mapStart = m_Base;
248 m_Base += getPageSize(); // page for the allocation header (readonly once
249 // it's written to)
250 result = m_Base;
251 m_Base += numPages * getPageSize();
252 mapEnd = m_Base;
253 }
254
255 for (uintptr_t addr = mapStart; addr < mapEnd; addr += getPageSize()) {
256 allocateAndMapAt(reinterpret_cast<void*>(addr));
257
258 ++m_HeapPageCount;
259 }
260
261 *((size_t*)(result - sizeof(size_t))) = numPages;
262
263 // now that the size is written we can mark the header section readonly
264 markReadOnly(reinterpret_cast<void*>(mapStart));
265
266#if THREADS
267 if (Processor::m_Initialised == 2) {
268 Thread* pThread = Processor::information().getCurrentThread();
269 if (pThread) {
270 pThread->getParent()->trackHeap(nTotalBytes);
271 }
272 }
273#endif
274
275#if MEMORY_TRACING
276 traceAllocation(reinterpret_cast<void*>(result), MemoryTracing::Allocation, nTotalBytes);
277#endif
278
279 return result;
280}
281
282#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
283uintptr_t SlamAllocator::guardedAllocateForTest(size_t nBytes) {
284 return instance().allocate(nBytes);
285}
286
287void SlamAllocator::guardedFreeForTest(uintptr_t mem) {
288 instance().free(mem);
289}
290#endif
291
292size_t SlamAllocator::allocSize(uintptr_t mem) {
293 if (!m_bInitialised) {
294 return 0;
295 }
296
297 if (!mem) {
298 return 0;
299 }
300
301 return *((size_t*)(mem - sizeof(size_t))) * getPageSize();
302}
303
304SlamAllocator& SlamAllocator::instance() {
305 EMIT_IF(PEDIGREE_BENCHMARK) {
306 static SlamAllocator instance;
307 return instance;
308 }
309 else {
310 return m_Instance;
311 }
312}
313
314void SlamAllocator::free(uintptr_t mem) {
315 if (!Processor::guardDeviceHardIrqOperation(DeviceHardIrqOperation::HeapFree)) {
316 return;
317 }
318
319 assert(m_bInitialised);
320
321 if (!mem) {
322 return;
323 }
324
325#if MEMORY_TRACING
326 // do this first so we can detect double frees before the asserts/memory
327 // accesses below - this just helps a lot with tracing these issues after
328 // the fact
329 traceAllocation(reinterpret_cast<void*>(mem), MemoryTracing::Free, 0);
330#endif
331
332 assert(isMapped(reinterpret_cast<void*>(mem)));
333
334 if (!isPointerValid(mem)) {
335 return;
336 }
337
338 size_t numPages = *((size_t*)(mem - sizeof(size_t)));
339 size_t nBytes = numPages * getPageSize();
340
341 uintptr_t unmapStart = mem - getPageSize();
342 uintptr_t unmapEnd = mem + nBytes;
343
344 for (uintptr_t addr = unmapStart; addr < unmapEnd; addr += getPageSize()) {
345 unmap(reinterpret_cast<void*>(addr));
346
347 --m_HeapPageCount;
348 }
349
350#if THREADS
351 if (Processor::m_Initialised == 2) {
352 Thread* pThread = Processor::information().getCurrentThread();
353 if (pThread) {
354 pThread->getParent()->trackHeap(-nBytes);
355 }
356 }
357#endif
358
359#if MEMORY_TRACING
360 traceAllocation(reinterpret_cast<void*>(mem), MemoryTracing::Free, 0);
361#endif
362}
363
364bool SlamAllocator::isPointerValid(uintptr_t mem)
365#if !SLAM_LOCKED
366 const
367#endif
368{
369 if (!m_bInitialised) {
370 return false;
371 }
372
373 // On the heap?
374 if (!Processor::information().getVirtualAddressSpace().memIsInKernelHeap(
375 reinterpret_cast<void*>(mem))) {
376#if VERBOSE_ISPOINTERVALID
377 WARNING("SlamAllocator::isPointerValid: memory " << Hex << mem
378 << " is not in the heap region.");
379#endif
380 return false;
381 }
382
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 << "].");
387#endif
388 if (mem >= m_Base) {
389#if VERBOSE_ISPOINTERVALID
390 WARNING(
391 " (pointer being deleted is beyond the end of the heap "
392 "somehow)");
393#endif
394 }
395 return false;
396 }
397
398 return true;
399}
400
401bool SlamAllocator::isWithinHeap(uintptr_t mem) const {
402 if (!Processor::information().getVirtualAddressSpace().memIsInKernelHeap(
403 reinterpret_cast<void*>(mem))) {
404#if VERBOSE_ISPOINTERVALID
405 WARNING("SlamAllocator::isWithinHeap: memory " << Hex << mem << " is not in the heap region.");
406#endif
407 return false;
408 }
409
410 return true;
411}
412
413bool _assert_ptr_valid(uintptr_t ptr) {
414 return SlamAllocator::instance().isPointerValid(ptr);
415}
416
417#endif // SLAM_USE_DEBUG_ALLOCATOR
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
static PhysicalMemoryManager & instance()
virtual void freePage(physical_uintptr_t page)=0
static ProcessorInformation & information()
static size_t m_Initialised
Definition Processor.h:483
static bool guardDeviceHardIrqOperation(DeviceHardIrqOperation operation)
Definition Processor.h:585
void markSlabReady(uintptr_t address, size_t length)
uintptr_t allocate(size_t nBytes)
void free(uintptr_t object)
virtual ~SlamCache()
bool isPointerValid(uintptr_t object) const
void initialise(SlamAllocator *parent, size_t objectSize)
size_t recovery(size_t maxSlabs)
uintptr_t allocate()
Process * getParent() const
Definition Thread.h:340
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
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual uintptr_t getKernelHeapEnd() const =0
virtual void unmap(void *virtualAddress)=0
@ Hex
Definition Log.h:124
Definition mem.c:283