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