1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_Memory.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: 17558 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/os.h>
17 #include <nn/assert.h>
18 #include <nn/svc.h>
19 #include <nn/dbg.h>
20 #include <nn/util.h>
21 #include <nn/init.h>
22 
23 #include <nn/os/os_MemoryMapSelect.h>
24 
25 //---------------------------------------------------------------------------
26 
27 using namespace nn;
28 using namespace nn::svc;
29 
30 namespace nn{ namespace os{
31 
32 namespace
33 {
34     uptr    s_DeviceMemoryAddress   = 0; //!< デバイスメモリのアドレス
35     size_t  s_DeviceMemorySize      = 0; //!< デバイスメモリのサイズ
36 
37     size_t  s_HeapSize      = 0;         //!< ヒープサイズ
38 }
39 
40 // デバイスメモリを初期化します。
InitializeDeviceMemory()41 void InitializeDeviceMemory()
42 {
43     if ( s_DeviceMemorySize == 0 )
44     {
45         Result result;
46         result = SetDeviceMemorySize( DEVICE_MEMORY_SIZE );
47         NN_UTIL_PANIC_IF_FAILED( result );
48     }
49 }
50 
51 // デバイスメモリのアドレスを取得します。
GetDeviceMemoryAddress()52 uptr GetDeviceMemoryAddress()
53 {
54     NN_TASSERTMSG_(s_DeviceMemoryAddress != NULL, "Device Memory is NOT Initialized.");
55     return s_DeviceMemoryAddress;
56 }
57 
58 // デバイスメモリのサイズを設定します。
SetDeviceMemorySize(size_t size)59 Result SetDeviceMemorySize(size_t size)
60 {
61 	// CHECK: ページサイズには定数 NN_OS_MEMORY_PAGE_SIZE の使用を推奨します。
62     // デバイスメモリのサイズは4096の倍数である必要があります。
63     NN_ALIGN_TASSERT_(size, 4096);
64     Result result;
65 
66     if( size > s_DeviceMemorySize )
67     {
68         // デバイスメモリを確保します。
69         // すでにデバイスメモリを確保していれば、直後に足りない分のメモリを確保します。
70         uptr addr;
71         const size_t mapSize = size - s_DeviceMemorySize;
72         const uptr requestAddress = (s_DeviceMemorySize == 0) ? NULL: (s_DeviceMemoryAddress + s_DeviceMemorySize);
73 
74         // nn::os::MEMORY_OPERATION_FLAG_LINEARを指定して連続したメモリを確保できるようにします。
75         result = nn::svc::ControlMemory( &addr,
76                                          requestAddress,
77                                          NULL,
78                                          mapSize,
79                                          (nn::os::MEMORY_OPERATION_COMMIT | nn::os::MEMORY_OPERATION_FLAG_LINEAR),
80                                          nn::os::MEMORY_PERMISSION_READ_WRITE );
81 
82         if( result.IsSuccess() )
83         {
84             // 初回デバイスメモリ確保でなければ、連続したアドレスにメモリを取得できたことをチェックします。
85             NN_TASSERT_( s_DeviceMemorySize == 0 || addr == requestAddress );
86 
87             // 初回デバイスメモリ確保時にはアドレスを保存します。
88             if( s_DeviceMemorySize == 0 )
89             {
90                 s_DeviceMemoryAddress   = addr;
91             }
92 
93             s_DeviceMemorySize  = size;
94         }
95     }
96     else
97     {
98         // デバイスメモリの末尾から不要なサイズ分を解放します。
99         uptr addr;
100         const size_t unmapSize = s_DeviceMemorySize - size;
101         const uptr freeAddress = s_DeviceMemoryAddress + size;
102 
103         result = nn::svc::ControlMemory( &addr,
104                                          freeAddress,
105                                          NULL,
106                                          unmapSize,
107                                          nn::os::MEMORY_OPERATION_FREE,
108                                          nn::os::MEMORY_PERMISSION_NONE );
109 
110         if( result.IsSuccess() )
111         {
112             if( size == 0 )
113             {
114                 s_DeviceMemoryAddress   = NULL;
115             }
116 
117             s_DeviceMemorySize  = size;
118         }
119     }
120 
121     return result;
122 }
123 
124 // デバイスメモリのサイズを取得します。
GetDeviceMemorySize()125 size_t GetDeviceMemorySize()
126 {
127     return s_DeviceMemorySize;
128 }
129 
130 // ヒープサイズを設定します。
SetHeapSize(size_t size)131 Result SetHeapSize(size_t size)
132 {
133 	// CHECK: ページサイズには定数 NN_OS_MEMORY_PAGE_SIZE の使用を推奨します。
134     // ヒープのサイズは4096の倍数である必要があります。
135     NN_ALIGN_TASSERT_(size, 4096);
136     Result result;
137 
138     if( size > s_HeapSize )
139     {
140         // ヒープの先頭からサイズ分の領域を確保します。
141         // すでに確保していれば、直後に足りない分のメモリを確保します。
142         uptr addr;
143         const size_t mapSize = size - s_HeapSize;
144         const uptr requestAddress = NN_OS_ADDR_HEAP_BEGIN + s_HeapSize;
145 
146         result = nn::svc::ControlMemory( &addr,
147                                          requestAddress,
148                                          NULL,
149                                          mapSize,
150                                          nn::os::MEMORY_OPERATION_COMMIT,
151                                          nn::os::MEMORY_PERMISSION_READ_WRITE );
152 
153         if( result.IsSuccess() )
154         {
155             NN_TASSERT_( addr == requestAddress );
156             s_HeapSize  = size;
157         }
158     }
159     else
160     {
161         // ヒープの末尾から不要になったサイズ分の領域を解放します。
162         uptr addr;
163         const size_t unmapSize = s_HeapSize - size;
164         const uptr freeAddress = NN_OS_ADDR_HEAP_BEGIN + size;
165 
166         result = nn::svc::ControlMemory( &addr,
167                                          freeAddress,
168                                          NULL,
169                                          unmapSize,
170                                          nn::os::MEMORY_OPERATION_FREE,
171                                          nn::os::MEMORY_PERMISSION_NONE );
172 
173         if( result.IsSuccess() )
174         {
175             s_HeapSize  = size;
176         }
177     }
178 
179     return result;
180 }
181 
182 // ヒープサイズを取得します。
GetHeapSize()183 size_t GetHeapSize()
184 {
185     return s_HeapSize;
186 }
187 
188 
189 #if NN_PLATFORM_HAS_MMU
SetupHeapForMemoryBlock(size_t heapSize)190 void SetupHeapForMemoryBlock(size_t heapSize)
191 {
192     Result result;
193 
194     result = SetHeapSize( heapSize );
195     NN_UTIL_PANIC_IF_FAILED( result );
196 
197     InitializeMemoryBlock(GetHeapAddress(), GetHeapSize());
198 
199     SetDefaultAutoStackManager();
200 }
201 #endif  // if NN_PLATFORM_HAS_MMU
202 
203 
204 
205 
206 
207 }} // namespace nn::os
208 
209 
210 #include <new>
211 using namespace nn::os;
212 
213 extern "C" {
214 
nnosInitializeDeviceMemory()215 void nnosInitializeDeviceMemory()
216 {
217 #pragma push
218 #pragma diag_suppress 1361
219     nn::os::InitializeDeviceMemory();
220 #pragma pop
221 }
222 
nnosGetDeviceMemoryAddress()223 uptr nnosGetDeviceMemoryAddress()
224 {
225     return nn::os::GetDeviceMemoryAddress();
226 }
227 
228 }
229