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