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