1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: fnd_FrameHeap.h
4
5 Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Rev: 47798 $
14 *---------------------------------------------------------------------------*/
15
16 /* Please see man pages for details
17
18
19 */
20
21 #ifndef NN_FND_FND_FRAMEHEAP_H_
22 #define NN_FND_FND_FRAMEHEAP_H_
23
24 #include <nn/types.h>
25 #include <nn/fnd/fnd_Allocator.h>
26 #include <nn/fnd/fnd_HeapBase.h>
27 #include <nn/fnd/fnd_MemoryRange.h>
28 #include <nn/assert.h>
29 #include <nn/os.h>
30
31 #ifdef __cplusplus
32
33 #define NN_FND_FRAMEHEAP_FREE_HEAD 1
34 #define NN_FND_FRAMEHEAP_FREE_TAIL 2
35 #define NN_FND_FRAMEHEAP_FREE_ALL (NN_FND_FRAMEHEAP_FREE_HEAD | NN_FND_FRAMEHEAP_FREE_TAIL)
36
37 #define NN_FND_FRAMEHEAP_ADJUST_TAIL 1
38 #define NN_FND_FRAMEHEAP_ADJUST_HEAD -1
39
40 namespace nn { namespace fnd {
41
42 /* Please see man pages for details
43
44
45
46
47
48 */
49 class FrameHeapBase : public HeapBase
50 {
51 public:
52
53 class State;
54
55 protected:
56
FrameHeapBase()57 FrameHeapBase() : m_Addr(0) {}
58
59 FrameHeapBase(uptr addr, size_t size, bit32 option = 0) : m_Addr(0) { Initialize(addr, size, option); }
60
61 template <class MemoryBlock>
62 FrameHeapBase(const MemoryBlock& block, bit32 option = 0) : m_Addr(0) { Initialize(block.GetAddress(), block.GetSize(), option); }
63
64 void Initialize(uptr addr, size_t size, bit32 option = 0);
65
Finalize()66 void Finalize() { m_Addr = 0; }
67
~FrameHeapBase()68 virtual ~FrameHeapBase() { Finalize(); }
69
70 void* Allocate(size_t size, s32 alignment);
71
72 size_t ResizeBlock(void* p, size_t newSize);
73
74 void FreeAll(int mode);
75
FreeV(void *)76 virtual void FreeV(void*) {}
77
78 State SaveState();
79
80 void RestoreState(State state);
81
82 MemoryRange Adjust(int mode);
83
84 size_t GetAllocatableSize(s32 alignment) const;
85
GetStartAddress()86 virtual void* GetStartAddress() const { return reinterpret_cast<void*>(m_Addr); }
87
GetTotalSize()88 virtual size_t GetTotalSize() const { return m_Size; }
89
90 virtual void Dump() const;
91
92 virtual bool HasAddress(const void* addr) const;
93
94 private:
95 uptr m_Addr;
96 size_t m_Size;
97 uptr m_CurrentHead;
98 uptr m_CurrentTail;
99 };
100
101 /* Please see man pages for details
102
103 */
104 class FrameHeapBase::State
105 {
106 public:
107
108 /* Please see man pages for details
109
110
111
112 */
State(FrameHeapBase & heap)113 explicit State(FrameHeapBase& heap) : m_Head(heap.m_CurrentHead), m_Tail(heap.m_CurrentTail) {}
114
115 /* Please see man pages for details
116
117 */
State()118 State() : m_Head(0), m_Tail(0) {}
119
120 private:
121 uptr m_Head;
122 uptr m_Tail;
123
State(uptr head,uptr tail)124 explicit State(uptr head, uptr tail) : m_Head(head), m_Tail(tail) {}
125
126 friend class FrameHeapBase;
127 };
128
Allocate(size_t size,s32 alignment)129 inline void* FrameHeapBase::Allocate(size_t size, s32 alignment)
130 {
131 NN_TASSERT_(size > 0);
132 NN_TASSERT_(alignment != 0);
133 uptr ret;
134
135 if ( alignment == 0 )
136 {
137 NN_TPANIC_("invalid argument: alignment == 0");
138 }
139
140 if ( alignment > 0 ) {
141 ret = RoundUp(m_CurrentHead, alignment);
142 uptr current = ret + size;
143
144 if (current > m_CurrentTail)
145 {
146 return 0;
147 }
148
149 m_CurrentHead = current;
150 }
151 else
152 {
153 uptr current = ret = RoundDown(m_CurrentTail-size, -alignment);
154
155 if (current < m_CurrentHead)
156 {
157 return 0;
158 }
159
160 m_CurrentTail = current;
161 }
162
163
164 // File options
165 DebugFillMemory(ret, size, HEAP_FILL_TYPE_ALLOC);
166 FillMemoryZero(ret, size);
167
168 return reinterpret_cast<void*>(ret);
169 }
170
FreeAll(int mode)171 inline void FrameHeapBase::FreeAll(int mode)
172 {
173 NN_TASSERT_( mode == NN_FND_FRAMEHEAP_FREE_HEAD ||
174 mode == NN_FND_FRAMEHEAP_FREE_TAIL ||
175 mode == NN_FND_FRAMEHEAP_FREE_ALL);
176
177 if ( mode & NN_FND_FRAMEHEAP_FREE_HEAD )
178 {
179 DebugFillMemory(m_Addr, m_CurrentHead - m_Addr, HEAP_FILL_TYPE_FREE);
180 this->m_CurrentHead = this->m_Addr;
181 }
182
183 if ( mode & NN_FND_FRAMEHEAP_FREE_TAIL )
184 {
185 DebugFillMemory(m_CurrentTail, m_Addr + m_Size - m_CurrentTail, HEAP_FILL_TYPE_FREE);
186 this->m_CurrentTail = this->m_Addr + this->m_Size;
187 }
188 }
189
ResizeBlock(void * p,size_t newSize)190 inline size_t FrameHeapBase::ResizeBlock(void* p, size_t newSize)
191 {
192 // TODO: debug_fill
193 uptr& addr = reinterpret_cast<uptr&>(p);
194 NN_TASSERT_(m_Addr <= addr && addr < m_CurrentTail);
195 NN_TASSERT_(addr <= m_CurrentHead);
196 uptr current = addr + newSize;
197 if (current < m_CurrentTail)
198 {
199 if ( current < this->m_CurrentHead )
200 {
201 DebugFillMemory(current, this->m_CurrentHead - current, HEAP_FILL_TYPE_FREE);
202 }
203 if ( this->m_CurrentHead < current )
204 {
205 FillMemoryZero(this->m_CurrentHead, current - this->m_CurrentHead);
206 }
207 this->m_CurrentHead = current;
208 return newSize;
209 }
210 else
211 {
212 return 0;
213 }
214 }
215
Adjust(int mode)216 inline MemoryRange FrameHeapBase::Adjust(int mode)
217 {
218 // TODO: debug_fill
219 if ( mode == 0 )
220 {
221 NN_TPANIC_("invalid argument: mode == 0");
222 }
223
224 if ( mode > 0 )
225 {
226 if ( m_CurrentTail != m_Addr + m_Size )
227 {
228 NN_TPANIC_("invalid call: tail used");
229 }
230
231 DebugFillMemory(m_CurrentHead, m_Addr + m_Size - m_CurrentHead, HEAP_FILL_TYPE_FREE);
232
233 uptr oldtail = m_Addr + m_Size;
234 this->m_Size = m_CurrentHead - m_Addr;
235 this->m_CurrentTail = m_CurrentHead;
236 return MemoryRange(this->m_CurrentTail, oldtail);
237 }
238 else
239 {
240 if ( m_CurrentHead != m_Addr )
241 {
242 NN_TPANIC_("invalid call: head used");
243 }
244
245 DebugFillMemory(m_Addr, m_CurrentTail - m_Addr, HEAP_FILL_TYPE_FREE);
246
247 uptr oldhead = m_Addr;
248 this->m_Size = m_Addr + m_Size - m_CurrentTail;
249 this->m_CurrentHead = m_CurrentTail;
250 this->m_Addr = m_CurrentTail;
251 return MemoryRange(oldhead, m_Addr);
252 }
253 }
254
SaveState()255 inline FrameHeapBase::State FrameHeapBase::SaveState()
256 {
257 return State(m_CurrentHead, m_CurrentTail);
258 }
259
RestoreState(FrameHeapBase::State state)260 inline void FrameHeapBase::RestoreState(FrameHeapBase::State state)
261 {
262 NN_TASSERT_(this->m_Addr <= state.m_Head && state.m_Head <= this->m_Addr + this->m_Size);
263 NN_TASSERT_(this->m_Addr <= state.m_Tail && state.m_Tail <= this->m_Addr + this->m_Size);
264 NN_TASSERT_(state.m_Head <= this->m_CurrentHead);
265 NN_TASSERT_(state.m_Tail >= this->m_CurrentTail);
266
267 this->m_CurrentHead = state.m_Head;
268 this->m_CurrentTail = state.m_Tail;
269
270 DebugFillMemory(m_CurrentHead, m_CurrentTail - m_CurrentHead, HEAP_FILL_TYPE_FREE);
271 }
272
GetAllocatableSize(s32 alignment)273 inline size_t FrameHeapBase::GetAllocatableSize(s32 alignment) const
274 {
275 NN_TASSERT_(alignment != 0);
276
277 if ( alignment == 0 )
278 {
279 NN_TPANIC_("invalid argument: alignment == 0");
280 }
281
282 if ( alignment < 0 )
283 {
284 alignment = -alignment;
285 }
286
287 uptr addr = RoundUp(m_CurrentHead, alignment);
288 if (addr <= m_CurrentTail)
289 {
290 return m_CurrentTail - addr;
291 }
292 else
293 {
294 return 0;
295 }
296 }
297
HasAddress(const void * addr)298 inline bool FrameHeapBase::HasAddress(const void* addr) const
299 {
300 return m_Addr <= reinterpret_cast<uptr>(addr)
301 && reinterpret_cast<uptr>(addr) < (m_Addr+m_Size);
302 }
303
304 /* Please see man pages for details
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319 */
320 template <class LockPolicy>
321 class FrameHeapTemplate : public FrameHeapBase, private LockPolicy::LockObject
322 {
323 private:
324 typedef FrameHeapBase Base;
325 typedef typename LockPolicy::LockObject LockObject;
326 typedef typename LockPolicy::ScopedLock ScopedLock;
327 public:
328
329 /* Please see man pages for details
330
331 */
FrameHeapTemplate()332 FrameHeapTemplate() {}
333
334 /* Please see man pages for details
335
336
337
338
339
340 */
341 FrameHeapTemplate(uptr addr, size_t size, bit32 option = 0) { Initialize(addr, size, option); }
342
343 /* Please see man pages for details
344
345
346
347
348 */
349 template <class MemoryBlock>
350 FrameHeapTemplate(const MemoryBlock& block, bit32 option = 0) { Initialize(block.GetAddress(), block.GetSize(), option); }
351
352 /* Please see man pages for details
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372 */
373 static FrameHeapTemplate* Create(HeapBase* parent, void* addr, size_t size, bit32 option = 0, bit32 placement = HEAP_INFOPLACEMENT_HEAD);
374
375 /* Please see man pages for details
376
377
378
379
380
381
382
383 */
384 void Initialize(uptr addr, size_t size, bit32 option = 0)
385 {
386 Base::Initialize(addr, size, option);
387 LockObject::Initialize();
388 }
389
390 /* Please see man pages for details
391
392
393
394 */
Finalize()395 void Finalize()
396 {
397 LockObject::Finalize();
398 Base::Finalize();
399 }
400
401 /* Please see man pages for details
402
403
404
405 */
~FrameHeapTemplate()406 virtual ~FrameHeapTemplate() {}
407
408 /* Please see man pages for details
409
410
411
412
413
414
415
416
417 */
418 void* Allocate(size_t size, s32 alignment = DEFAULT_ALIGNMENT)
419 {
420 ScopedLock lk(*this);
421 return Base::Allocate(size, alignment);
422 }
423
424 /* Please see man pages for details
425
426
427
428
429
430
431
432
433 */
ResizeBlock(void * p,size_t newSize)434 size_t ResizeBlock(void* p, size_t newSize)
435 {
436 ScopedLock lk(*this);
437 return Base::ResizeBlock(p, newSize);
438 }
439
440 /* Please see man pages for details
441
442
443
444
445
446
447
448
449
450
451
452 */
453 void Free(int mode = NN_FND_FRAMEHEAP_FREE_ALL)
454 {
455 ScopedLock lk(*this);
456 Base::FreeAll(mode);
457 }
458
459 /* Please see man pages for details
460
461
462
463
464
465 */
FreeV(void *)466 virtual void FreeV(void*) { NN_TASSERT_(0); }
467
468 class ScopedFrame;
469
470 /* Please see man pages for details
471
472
473
474 */
SaveState()475 State SaveState()
476 {
477 ScopedLock lk(*this);
478 return Base::SaveState();
479 }
480
481 /* Please see man pages for details
482
483
484
485
486
487 */
RestoreState(State state)488 void RestoreState(State state)
489 {
490 ScopedLock lk(*this);
491 Base::RestoreState(state);
492 }
493
494 /* Please see man pages for details
495
496
497
498
499
500
501
502
503
504
505
506 */
507 MemoryRange Adjust(int mode = NN_FND_FRAMEHEAP_ADJUST_TAIL)
508 {
509 ScopedLock lk(*this);
510 return Base::Adjust(mode);
511 }
512
513 /* Please see man pages for details
514
515
516
517
518
519 */
520 size_t GetAllocatableSize(s32 alignment = DEFAULT_ALIGNMENT) const
521 {
522 ScopedLock lk(*this);
523 return Base::GetAllocatableSize(alignment);
524 }
525
526 /* Please see man pages for details
527
528
529
530 */
GetStartAddress()531 virtual void* GetStartAddress() const
532 {
533 ScopedLock lk(*this);
534 return Base::GetStartAddress();
535 }
536
537 /* Please see man pages for details
538
539
540
541 */
GetTotalSize()542 virtual size_t GetTotalSize() const
543 {
544 ScopedLock lk(*this);
545 return Base::GetTotalSize();
546 }
547
548 /* Please see man pages for details
549
550
551
552
553
554 */
HasAddress(const void * addr)555 virtual bool HasAddress(const void* addr) const
556 {
557 ScopedLock lk(*this);
558 return Base::HasAddress(addr);
559 }
560
561 /* Please see man pages for details
562
563
564
565 */
Dump()566 virtual void Dump() const { Base::Dump(); };
567
568 // FrameHeap's allocator is not supported
569 //class Allocator;
570
571 private:
572 uptr m_Addr;
573 size_t m_Size;
574 uptr m_CurrentHead; // The first address for the blank region
575 uptr m_CurrentTail; // The last address + 4 for the blank region
576 bit32 m_Option;
577 };
578
579 /* Please see man pages for details
580
581 */
582 template <class LockPolicy>
583 class FrameHeapTemplate<LockPolicy>::ScopedFrame
584 {
585 public:
586 /* Please see man pages for details
587
588
589
590 */
ScopedFrame(FrameHeapTemplate<LockPolicy> & heap)591 explicit ScopedFrame(FrameHeapTemplate<LockPolicy>& heap) : m_State(heap), m_Heap(heap) {}
592 /* Please see man pages for details
593
594 */
~ScopedFrame()595 ~ScopedFrame() { m_Heap.RestoreState(m_State); }
596
597 private:
598 FrameHeapTemplate<LockPolicy>::State m_State;
599 FrameHeapTemplate<LockPolicy>& m_Heap;
600 };
601
602 /* Please see man pages for details
603
604 */
605 typedef FrameHeapTemplate<nn::os::LockPolicy::NoLock> FrameHeap;
606
607 /* Please see man pages for details
608
609 */
610 typedef FrameHeapTemplate<nn::os::LockPolicy::Object<nn::os::CriticalSection> > ThreadSafeFrameHeap;
611
612 template <class LockPolicy>
Create(HeapBase * parent,void * addr,size_t size,bit32 option,bit32 placement)613 FrameHeapTemplate<LockPolicy>* FrameHeapTemplate<LockPolicy>::Create(HeapBase* parent, void* addr, size_t size, bit32 option, bit32 placement)
614 {
615 FrameHeapTemplate* heap;
616
617 if ( parent->FindHeap(addr) != parent ) return 0;
618
619 if ( placement == HEAP_INFOPLACEMENT_HEAD )
620 {
621 heap = new (addr) FrameHeapTemplate(reinterpret_cast<uptr>(addr)+sizeof(FrameHeapTemplate), static_cast<size_t>(size - sizeof(FrameHeapTemplate)), option);
622 }
623 else if ( placement == HEAP_INFOPLACEMENT_TAIL )
624 {
625 void* placeaddr = reinterpret_cast<void*>(reinterpret_cast<uptr>(addr)+static_cast<size_t>(size - sizeof(FrameHeapTemplate)));
626 heap = new (placeaddr) FrameHeapTemplate(reinterpret_cast<uptr>(addr), static_cast<size_t>(size - sizeof(FrameHeapTemplate)), option);
627 }
628 else
629 {
630 return 0;
631 }
632
633 heap->SetParent(parent);
634 return heap;
635 }
636
637 }}
638
639 #endif
640
641 #endif
642