1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_Memory.cpp
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: 47383 $
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/os/os_MemoryMapSelect.h>
23 #include <nn/os/os_ErrorHandlerSelect.h>
24
25 //---------------------------------------------------------------------------
26
27 using namespace nn;
28 using namespace nn::svc;
29
30 extern "C" bit8 Load$$LR$$TEXT_SECTION$$Base[];
31 extern "C" bit8 Load$$LR$$TEXT_SECTION$$Length[];
32
33 namespace nn{ namespace os{
34
35 namespace
36 {
37 uptr s_DeviceMemoryAddress = 0; //
38 size_t s_DeviceMemorySize = 0; //
39
40 size_t s_HeapSize = 0; //
41 }
42
43
44 // Gets the device memory address.
GetDeviceMemoryAddress()45 uptr GetDeviceMemoryAddress()
46 {
47 NN_TASSERTMSG_(s_DeviceMemoryAddress != NULL, "Device Memory is NOT Initialized.");
48 return s_DeviceMemoryAddress;
49 }
50
51 // Sets the device memory size.
SetDeviceMemorySize(size_t size)52 Result SetDeviceMemorySize(size_t size)
53 {
54 // The device memory size must be a multiple of 4096.
55 if ( (size % NN_OS_MEMORY_PAGE_SIZE) != 0 )
56 {
57 return ResultMisalignedSize();
58 }
59 Result result;
60
61 if( size > s_DeviceMemorySize )
62 {
63 // Allocates device memory.
64 // If device memory has already been allocated, immediately allocates the portion of continuous memory that was insufficient
65 if (s_DeviceMemorySize != 0)
66 {
67 // If already allocated, the size before and after must be 1 MiB aligned.
68 if (!(s_DeviceMemorySize % (1024 * 1024) == 0 && size % (1024 * 1024) == 0))
69 {
70 return ResultMisalignedSize();
71 }
72 }
73 uptr addr;
74 const size_t mapSize = size - s_DeviceMemorySize;
75 const uptr requestAddress = (s_DeviceMemorySize == 0) ? NULL: (s_DeviceMemoryAddress + s_DeviceMemorySize);
76
77 // Continuous memory can be allocated by specifying nn::os::MEMORY_OPERATION_FLAG_LINEAR.
78 result = nn::svc::ControlMemory( &addr,
79 requestAddress,
80 NULL,
81 mapSize,
82 (nn::os::MEMORY_OPERATION_COMMIT | nn::os::MEMORY_OPERATION_FLAG_LINEAR),
83 nn::os::MEMORY_PERMISSION_READ_WRITE );
84
85 if( result.IsSuccess() )
86 {
87 // If this is not the first time device memory has been allocated, checks if memory was obtained for the continuous address.
88 NN_TASSERT_( s_DeviceMemorySize == 0 || addr == requestAddress );
89
90 // For first time device memory allocation, save addresses.
91 if( s_DeviceMemorySize == 0 )
92 {
93 s_DeviceMemoryAddress = addr;
94 }
95
96 s_DeviceMemorySize = size;
97 }
98 }
99 else
100 {
101 // Releases unnecessary memory of size amount from the end of the device memory.
102 uptr addr;
103 const size_t unmapSize = s_DeviceMemorySize - size;
104 const uptr freeAddress = s_DeviceMemoryAddress + size;
105
106 result = nn::svc::ControlMemory( &addr,
107 freeAddress,
108 NULL,
109 unmapSize,
110 nn::os::MEMORY_OPERATION_FREE,
111 nn::os::MEMORY_PERMISSION_NONE );
112
113 if( result.IsSuccess() )
114 {
115 if( size == 0 )
116 {
117 s_DeviceMemoryAddress = NULL;
118 }
119
120 s_DeviceMemorySize = size;
121 }
122 }
123
124 return result;
125 }
126
127 // Gets the device memory size.
GetDeviceMemorySize()128 size_t GetDeviceMemorySize()
129 {
130 return s_DeviceMemorySize;
131 }
132
133 // Sets the heap size.
SetHeapSize(size_t size)134 Result SetHeapSize(size_t size)
135 {
136 NN_TASSERTMSG_( ! nninitIsStartUpDefaultUsing(),
137 "Using default nninitStartUp.\nPlease override nninitStartUp.");
138
139 // The heap size must be a multiple of 4096.
140 if ( (size % NN_OS_MEMORY_PAGE_SIZE) != 0 )
141 {
142 return ResultMisalignedSize();
143 }
144 Result result;
145
146 if( size > s_HeapSize )
147 {
148 // Allocate a region in size amount from the start of the heap.
149 // If already allocated, immediately afterwards allocates the memory size that was insufficient
150 uptr addr;
151 const size_t mapSize = size - s_HeapSize;
152 const uptr requestAddress = NN_OS_ADDR_HEAP_BEGIN + s_HeapSize;
153
154 result = nn::svc::ControlMemory( &addr,
155 requestAddress,
156 NULL,
157 mapSize,
158 nn::os::MEMORY_OPERATION_COMMIT,
159 nn::os::MEMORY_PERMISSION_READ_WRITE );
160
161 if( result.IsSuccess() )
162 {
163 NN_TASSERT_( addr == requestAddress );
164 s_HeapSize = size;
165 }
166 }
167 else
168 {
169 // Releases unnecessary memory region in size amount from the end of the heap.
170 uptr addr;
171 const size_t unmapSize = s_HeapSize - size;
172 const uptr freeAddress = NN_OS_ADDR_HEAP_BEGIN + size;
173
174 result = nn::svc::ControlMemory( &addr,
175 freeAddress,
176 NULL,
177 unmapSize,
178 nn::os::MEMORY_OPERATION_FREE,
179 nn::os::MEMORY_PERMISSION_NONE );
180
181 if( result.IsSuccess() )
182 {
183 s_HeapSize = size;
184 }
185 }
186
187 return result;
188 }
189
GetHeapAddress()190 uptr GetHeapAddress()
191 {
192 NN_TASSERTMSG_( ! nninitIsStartUpDefaultUsing(),
193 "Using default nninitStartUp.\nPlease override nninitStartUp.");
194 return nn::os::detail::GetHeapAddressWithoutCheck();
195 }
196
197 // Get heap size.
GetHeapSize()198 size_t GetHeapSize()
199 {
200 NN_TASSERTMSG_( ! nninitIsStartUpDefaultUsing(),
201 "Using default nninitStartUp.\nPlease override nninitStartUp.");
202 return s_HeapSize;
203 }
204
GetCodeRegionAddress()205 uptr GetCodeRegionAddress()
206 {
207 return reinterpret_cast<uptr>(Load$$LR$$TEXT_SECTION$$Base);
208 }
209
GetCodeRegionSize()210 size_t GetCodeRegionSize()
211 {
212 return reinterpret_cast<size_t>(Load$$LR$$TEXT_SECTION$$Length);
213 }
214
215 #if NN_PLATFORM_HAS_MMU
SetupHeapForMemoryBlock(size_t heapSize)216 void SetupHeapForMemoryBlock(size_t heapSize)
217 {
218 Result result;
219
220 result = SetHeapSize( heapSize );
221 NN_OS_ERROR_IF_FAILED( result );
222
223 InitializeMemoryBlock(GetHeapAddress(), GetHeapSize());
224
225 SetDefaultAutoStackManager();
226 }
227 #endif // if NN_PLATFORM_HAS_MMU
228
229
230
231
232
233 }} // namespace nn::os
234
235
236 #include <new>
237 using namespace nn::os;
238
239 extern "C" {
240
nnosGetDeviceMemoryAddress()241 uptr nnosGetDeviceMemoryAddress()
242 {
243 return nn::os::GetDeviceMemoryAddress();
244 }
245
246 }
247