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