1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_AddressSpaceManager.cpp
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: 17610 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/config.h>
17 #if NN_PLATFORM_HAS_MMU
18 
19 #include "os_AddressSpaceManager.h"
20 #include <nn/os/os_MemoryBlock.h>
21 
22 namespace nn {
23     namespace os {
24 
Initialize(uptr begin,size_t size)25 void AddressSpaceManager::Initialize(uptr begin, size_t size)
26 {
27     m_Lock.Initialize();
28 
29     // CHECK: �������ς݂��ǂ������m�F���邱�Ƃ������܂��B
30 
31     m_SpaceBegin = begin;
32     m_SpaceEnd   = begin + size;
33     NN_MIN_TASSERT_(m_SpaceEnd, m_SpaceBegin);
34 }
35 
Allocate(MemoryBlockBase * pBlock,size_t size,size_t skipSize)36 uptr AddressSpaceManager::Allocate(MemoryBlockBase* pBlock, size_t size, size_t skipSize)
37 {
38     NN_NULL_TASSERT_(pBlock);
39     NN_ALIGN_TASSERT_(size, NN_OS_MEMORY_PAGE_SIZE);
40     NN_ALIGN_TASSERT_(skipSize, NN_OS_MEMORY_PAGE_SIZE);
41 
42     Lock::ScopedLock scopedLock(m_Lock);
43 
44     MemoryBlockBase* pPrev = FindSpace(size, skipSize);
45     uptr allocatedAddress;
46 
47     if( pPrev != NULL )
48     {
49         // pPrev �� GetNext(pPrev) �܂��� SpaceEnd �̊Ԃ̋�Ԃ������Ă���
50 
51         allocatedAddress = pPrev->GetAddress() + pPrev->GetSize() + skipSize;
52         MemoryBlockBase* pNext = m_BlockList.GetNext(pPrev);
53 
54         if( pNext != NULL )
55         {
56             NN_MAX_TASSERT_(allocatedAddress + size + skipSize, pNext->GetAddress());
57 
58             m_BlockList.Insert(pNext, pBlock);
59         }
60         else
61         {
62             NN_MAX_TASSERT_(allocatedAddress + size + skipSize, m_SpaceEnd);
63 
64             m_BlockList.PushBack(pBlock);
65         }
66     }
67     else
68     {
69         // SpaceBegin �� GetFront() �܂��� SpaceEnd �̊Ԃ̋�Ԃ������Ă���
70         // �܂��́A�����Ă��Ȃ��B
71 
72         allocatedAddress = m_SpaceBegin;
73         MemoryBlockBase* pNext = m_BlockList.GetFront();
74 
75         if( pNext != NULL )
76         {
77             const uptr allocatedEnd = allocatedAddress + size;
78             const uptr nextBegin    = pNext->GetAddress();
79 
80             if( nextBegin < allocatedEnd + skipSize )
81             {
82                 // �A�h���X��Ԃ̐擪���玟�̃������u���b�N�܂ł̊Ԃ� size ���̋������݂��܂���B
83                 return NULL;
84             }
85 
86             m_BlockList.Insert(pNext, pBlock);
87         }
88         else
89         {
90             // �S��Ԃ����Ă����ꍇ
91             const uptr allocatedEnd = allocatedAddress + size;
92 
93             if( m_SpaceEnd < allocatedEnd )
94             {
95                 // �Ǘ����Ă���A�h���X��Ԃ̗̈�ł� size ���̋������݂��܂���B
96                 return NULL;
97             }
98 
99             m_BlockList.PushBack(pBlock);
100         }
101     }
102 
103     pBlock->SetAddressAndSize(allocatedAddress, size);
104 
105     return allocatedAddress;
106 }
107 
108 // �������u���b�N���A�h���X��Ԃɉ�����܂��B
Free(MemoryBlockBase * pBlock)109 void AddressSpaceManager::Free(MemoryBlockBase* pBlock)
110 {
111     // TODO: pBlock��NULL�`�F�b�N���K�v�ł��B
112     Lock::ScopedLock scopedLock(m_Lock);
113 
114     m_BlockList.Erase(pBlock);
115     pBlock->SetAddressAndSize(NULL, 0);
116 }
117 
118 // �������u���b�N�̏��� pFrom ���� pTo �Ɉڂ��܂��B
Switch(MemoryBlockBase * pTo,MemoryBlockBase * pFrom)119 void AddressSpaceManager::Switch(MemoryBlockBase* pTo, MemoryBlockBase* pFrom)
120 {
121     // TODO: pTo��NULL�`�F�b�N���K�v�ł��B
122     // TODO: pFrom��NULL�`�F�b�N���K�v�ł��B
123     Lock::ScopedLock scopedLock(m_Lock);
124 
125     pTo->SetAddressAndSize(pFrom->GetAddress(), pFrom->GetSize());
126     m_BlockList.Insert(pFrom, pTo);
127 
128     pFrom->SetAddressAndSize(NULL, 0);
129     m_BlockList.Erase(pFrom);
130 }
131 
132 // �w�肵���T�C�Y+�y�[�W�T�C�Y���̋�������̈��T�����܂��B
FindSpace(size_t size,size_t skipSize)133 MemoryBlockBase* AddressSpaceManager::FindSpace(size_t size, size_t skipSize)
134 {
135     MemoryBlockBase* pItem = m_BlockList.GetBack();
136     uptr end = m_SpaceEnd;
137     NN_MIN_TASSERT_(end, m_SpaceBegin);
138 
139     while( pItem != NULL )
140     {
141         const uptr nextBegin = pItem->GetAddress();
142         const uptr nextEnd   = nextBegin + pItem->GetSize();
143         const size_t spaceSize = end - nextEnd;
144         NN_MAX_TASSERT_(nextEnd, end);
145 
146         if( spaceSize >= size + skipSize )
147         {
148             // pItem �̌�낪�����Ă���
149             return pItem;
150         }
151 
152         end = nextBegin - skipSize;
153         pItem = m_BlockList.GetPrevious(pItem);
154     }
155 
156     // �S��Ԃ������Ă���
157     // �܂��́A�擪�̋�Ԃ������Ă���
158     // �܂��́A�����Ă��Ȃ�
159     return NULL;
160 }
161 
162 // �A�h���X��Ԃɑ��݂��郁�����u���b�N���X�g���f�o�b�O�o�͂��܂��B
Dump()163 void AddressSpaceManager::Dump()
164 {
165     // CHECK: �_���v���ɑ��̃X���b�h���烊�X�g�̓��e���ύX����Ȃ��悤�Ƀ��b�N���邱�Ƃ������܂��B
166 
167     MemoryBlockBase* pItem = m_BlockList.GetFront();
168 
169     NN_TLOG_("  --------  %08x %08x\n", m_SpaceBegin, m_SpaceEnd);
170     while( pItem != NULL )
171     {
172         NN_TLOG_("  %08x  %08x %08x\n", pItem, pItem->GetAddress(), pItem->GetAddress() + pItem->GetSize());
173         pItem = m_BlockList.GetNext(pItem);
174     }
175 
176     NN_TPANIC_("dump complete");
177 }
178 
179     }
180 }
181 
182 
183 
184 #include <new>
185 using namespace nn::os;
186 
187 extern "C" {
188 
nnosAddressSpaceManagerInitialize(nnosAddressSpaceManager * p,uptr begin,size_t size)189 void nnosAddressSpaceManagerInitialize(nnosAddressSpaceManager* p, uptr begin, size_t size)
190 {
191     AddressSpaceManager* pThis = new (p) AddressSpaceManager();
192     pThis->Initialize(begin, size);
193 }
194 
nnosAddressSpaceManagerAllocate(nnosAddressSpaceManager * p,nnosMemoryBlockBase * p2,size_t size,size_t skipSize)195 uptr nnosAddressSpaceManagerAllocate(nnosAddressSpaceManager* p, nnosMemoryBlockBase* p2, size_t size, size_t skipSize)
196 {
197     AddressSpaceManager* pThis = reinterpret_cast<AddressSpaceManager*>(p);
198     MemoryBlockBase* pBlock = reinterpret_cast<MemoryBlockBase*>(p2);
199     return pThis->Allocate(pBlock, size, skipSize);
200 }
201 
nnosAddressSpaceManagerFree(nnosAddressSpaceManager * p,nnosMemoryBlockBase * p2)202 void nnosAddressSpaceManagerFree(nnosAddressSpaceManager* p, nnosMemoryBlockBase* p2)
203 {
204     AddressSpaceManager* pThis = reinterpret_cast<AddressSpaceManager*>(p);
205     MemoryBlockBase* pBlock = reinterpret_cast<MemoryBlockBase*>(p2);
206     pThis->Free(pBlock);
207 }
208 
nnosAddressSpaceManagerSwitch(nnosAddressSpaceManager * p,nnosMemoryBlockBase * p2,nnosMemoryBlockBase * p3)209 void nnosAddressSpaceManagerSwitch(nnosAddressSpaceManager* p, nnosMemoryBlockBase* p2, nnosMemoryBlockBase* p3)
210 {
211     AddressSpaceManager* pThis = reinterpret_cast<AddressSpaceManager*>(p);
212     MemoryBlockBase* pTo = reinterpret_cast<MemoryBlockBase*>(p2);
213     MemoryBlockBase* pFrom = reinterpret_cast<MemoryBlockBase*>(p3);
214     pThis->Switch(pTo, pFrom);
215 }
216 
217 }
218 
219 
220 #endif  // if NN_PLATFORM_HAS_MMU
221