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: 35672 $
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 // Initializes device memory.
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 // Gets the device memory address.
GetDeviceMemoryAddress()53 uptr GetDeviceMemoryAddress()
54 {
55     NN_TASSERTMSG_(s_DeviceMemoryAddress != NULL, "Device Memory is NOT Initialized.");
56     return s_DeviceMemoryAddress;
57 }
58 
59 // Sets the device memory size.
SetDeviceMemorySize(size_t size)60 Result SetDeviceMemorySize(size_t size)
61 {
62     // CHECK: Recommend using the NN_OS_MEMORY_PAGE_SIZE constant in the page size.
63     // The device memory size must be a multiple of 4096.
64     NN_ALIGN_TASSERT_(size, 4096);
65     Result result;
66 
67     if( size > s_DeviceMemorySize )
68     {
69         // Allocates device memory.
70         // If device memory has already been allocated, immediately afterwards allocates the portion of memory that was insufficient
71         if (s_DeviceMemorySize != 0)
72         {
73             // If already allocated, the size before and after must be 1 MiB aligned.
74             if (!(s_DeviceMemorySize % (1024 * 1024) == 0 && size % (1024 * 1024) == 0))
75             {
76                 NN_TPANIC_("size must be 1 MiB-aligned to change DeviceMemorySize.");
77             }
78         }
79         uptr addr;
80         const size_t mapSize = size - s_DeviceMemorySize;
81         const uptr requestAddress = (s_DeviceMemorySize == 0) ? NULL: (s_DeviceMemoryAddress + s_DeviceMemorySize);
82 
83         // Continuous memory can be allocated by specifying nn::os::MEMORY_OPERATION_FLAG_LINEAR.
84         result = nn::svc::ControlMemory( &addr,
85                                          requestAddress,
86                                          NULL,
87                                          mapSize,
88                                          (nn::os::MEMORY_OPERATION_COMMIT | nn::os::MEMORY_OPERATION_FLAG_LINEAR),
89                                          nn::os::MEMORY_PERMISSION_READ_WRITE );
90 
91         if( result.IsSuccess() )
92         {
93             // If this is not the first time device memory has been allocated, checks if memory was obtained for the continuous address.
94             NN_TASSERT_( s_DeviceMemorySize == 0 || addr == requestAddress );
95 
96             // For first time device memory allocation, save addresses.
97             if( s_DeviceMemorySize == 0 )
98             {
99                 s_DeviceMemoryAddress   = addr;
100             }
101 
102             s_DeviceMemorySize  = size;
103         }
104     }
105     else
106     {
107         // Releases unnecessary memory of size amount from the end of the device memory.
108         uptr addr;
109         const size_t unmapSize = s_DeviceMemorySize - size;
110         const uptr freeAddress = s_DeviceMemoryAddress + size;
111 
112         result = nn::svc::ControlMemory( &addr,
113                                          freeAddress,
114                                          NULL,
115                                          unmapSize,
116                                          nn::os::MEMORY_OPERATION_FREE,
117                                          nn::os::MEMORY_PERMISSION_NONE );
118 
119         if( result.IsSuccess() )
120         {
121             if( size == 0 )
122             {
123                 s_DeviceMemoryAddress   = NULL;
124             }
125 
126             s_DeviceMemorySize  = size;
127         }
128     }
129 
130     return result;
131 }
132 
133 // Gets the device memory size.
GetDeviceMemorySize()134 size_t GetDeviceMemorySize()
135 {
136     return s_DeviceMemorySize;
137 }
138 
139 // Sets the heap size.
SetHeapSize(size_t size)140 Result SetHeapSize(size_t size)
141 {
142     // CHECK: Recommend using the NN_OS_MEMORY_PAGE_SIZE constant in the page size.
143     // The heap size must be a multiple of 4096.
144     NN_ALIGN_TASSERT_(size, 4096);
145     Result result;
146 
147     if( size > s_HeapSize )
148     {
149         // Allocate a region in size amount from the start of the heap.
150         // If already allocated, immediately afterwards allocates the memory size that was insufficient
151         uptr addr;
152         const size_t mapSize = size - s_HeapSize;
153         const uptr requestAddress = NN_OS_ADDR_HEAP_BEGIN + s_HeapSize;
154 
155         result = nn::svc::ControlMemory( &addr,
156                                          requestAddress,
157                                          NULL,
158                                          mapSize,
159                                          nn::os::MEMORY_OPERATION_COMMIT,
160                                          nn::os::MEMORY_PERMISSION_READ_WRITE );
161 
162         if( result.IsSuccess() )
163         {
164             NN_TASSERT_( addr == requestAddress );
165             s_HeapSize  = size;
166         }
167     }
168     else
169     {
170         // Releases unnecessary memory region in size amount from the end of the heap.
171         uptr addr;
172         const size_t unmapSize = s_HeapSize - size;
173         const uptr freeAddress = NN_OS_ADDR_HEAP_BEGIN + size;
174 
175         result = nn::svc::ControlMemory( &addr,
176                                          freeAddress,
177                                          NULL,
178                                          unmapSize,
179                                          nn::os::MEMORY_OPERATION_FREE,
180                                          nn::os::MEMORY_PERMISSION_NONE );
181 
182         if( result.IsSuccess() )
183         {
184             s_HeapSize  = size;
185         }
186     }
187 
188     return result;
189 }
190 
191 // Get heap size.
GetHeapSize()192 size_t GetHeapSize()
193 {
194     return s_HeapSize;
195 }
196 
197 
198 #if NN_PLATFORM_HAS_MMU
SetupHeapForMemoryBlock(size_t heapSize)199 void SetupHeapForMemoryBlock(size_t heapSize)
200 {
201     Result result;
202 
203     result = SetHeapSize( heapSize );
204     NN_ERR_THROW_FATAL( result );
205 
206     InitializeMemoryBlock(GetHeapAddress(), GetHeapSize());
207 
208     SetDefaultAutoStackManager();
209 }
210 #endif  // if NN_PLATFORM_HAS_MMU
211 
212 
213 
214 
215 
216 }} // namespace nn::os
217 
218 
219 #include <new>
220 using namespace nn::os;
221 
222 extern "C" {
223 
nnosInitializeDeviceMemory()224 void nnosInitializeDeviceMemory()
225 {
226 #pragma push
227 #pragma diag_suppress 1361
228     nn::os::InitializeDeviceMemory();
229 #pragma pop
230 }
231 
nnosGetDeviceMemoryAddress()232 uptr nnosGetDeviceMemoryAddress()
233 {
234     return nn::os::GetDeviceMemoryAddress();
235 }
236 
237 }
238