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