1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_StackMemory.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: 46347 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/config.h>
17 #if NN_PLATFORM_HAS_MMU
18 
19 #include <nn/os/os_StackMemory.h>
20 #include <nn/os/os_MemoryBlock.h>
21 #include <nn/os/os_Result.h>
22 #include <nn/assert.h>
23 #include <nn/svc/svc_Stub.h>
24 #include <nn/dbg/dbg_Logger.h>
25 #include <nn/util/util_Result.h>
26 #include <nn/os/os_Memory.h>
27 #include <nn/os/os_CriticalSection.h>
28 #include <nn/os/os_MemoryMapSelect.h>
29 #include <nn/os/os_ErrorHandlerSelect.h>
30 #include "os_AddressSpaceManager.h"
31 
32 //---------------------------------------------------------------------------
33 
34 using namespace nn;
35 using namespace nn::svc;
36 
37 namespace nn{ namespace os{
38 
39     namespace
40     {
41         nnosAddressSpaceManager s_SpaceManager;
42     }
43 
44     namespace detail
45     {
InitializeStackMemory()46         void InitializeStackMemory()
47         {
48             nnosAddressSpaceManagerInitialize(&s_SpaceManager, NN_OS_ADDR_STACK_BEGIN, NN_OS_ADDR_STACK_SIZE);
49         }
50     }
51 
52 
Initialize(void * pMem,size_t size)53 void StackMemory::Initialize(void* pMem, size_t size)
54 {
55     NN_OS_ERROR_IF_FAILED(TryInitialize(pMem, size));
56 }
57 
TryInitialize(void * pMem,size_t size)58 Result StackMemory::TryInitialize(void* pMem, size_t size)
59 {
60     // Check that it is uninitialized.
61     if ( GetAddress() )
62     {
63         return ResultAlreadyInitialized();
64     }
65 
66     // Check alignment.
67     //NN_ALIGN_TASSERT_( pMem, NN_OS_MEMORY_PAGE_SIZE );
68     //NN_ALIGN_TASSERT_( size, NN_OS_MEMORY_PAGE_SIZE );
69     if ( ( size % NN_OS_MEMORY_PAGE_SIZE ) != 0 )
70     {
71         return ResultMisalignedSize();
72     }
73     if ( ( reinterpret_cast<uptr>(pMem) % NN_OS_MEMORY_PAGE_SIZE ) != 0 )
74     {
75         return ResultMisalignedAddress();
76     }
77 
78     // Get memory from the virtual address space.
79     uptr addr = nnosAddressSpaceManagerAllocate(&s_SpaceManager, os::detail::ConvertToC(this), size, NN_OS_MEMORY_PAGE_SIZE);
80     if (addr == NULL)
81     {
82         return ResultNoAddressSpace();
83     }
84 
85     m_MemoryAddress = reinterpret_cast<uptr>(pMem);
86 
87     Result result;
88     uptr dummy;
89     result = nn::svc::ControlMemory( &dummy,
90                                      addr,
91                                      m_MemoryAddress,
92                                      size,
93                                      nn::os::MEMORY_OPERATION_MAP,
94                                      nn::os::MEMORY_PERMISSION_READ_WRITE );
95 
96     if ( result.IsFailure() )
97     {
98         nnosAddressSpaceManagerFree(&s_SpaceManager, os::detail::ConvertToC(this));
99 
100         return result;
101     }
102 
103     result = nn::svc::ControlMemory( &dummy,
104                                      m_MemoryAddress,
105                                      NULL,
106                                      size,
107                                      nn::os::MEMORY_OPERATION_PROTECT,
108                                      nn::os::MEMORY_PERMISSION_NONE );
109 
110     if ( result.IsFailure() )
111     {
112         uptr memAddr = m_MemoryAddress;
113 
114         nnosAddressSpaceManagerFree(&s_SpaceManager, os::detail::ConvertToC(this));
115 
116         nn::svc::ControlMemory( &dummy,
117                                 addr,
118                                 memAddr,
119                                 size,
120                                 nn::os::MEMORY_OPERATION_UNMAP,
121                                 nn::os::MEMORY_PERMISSION_READ_WRITE );
122     }
123 
124     return result;
125 }
126 
Finalize()127 void* StackMemory::Finalize()
128 {
129     if ( GetAddress() != NULL )
130     {
131         const uptr addr = GetAddress();
132         const size_t size = GetSize();
133         const uptr memAddr = m_MemoryAddress;
134 
135         nnosAddressSpaceManagerFree(&s_SpaceManager, os::detail::ConvertToC(this));
136 
137         Result result;
138         uptr dummy;
139         result = nn::svc::ControlMemory( &dummy,
140                                          addr,
141                                          memAddr,
142                                          size,
143                                          nn::os::MEMORY_OPERATION_UNMAP,
144                                          nn::os::MEMORY_PERMISSION_READ_WRITE );
145         NN_OS_ERROR_IF_FAILED(result);
146         // Hereafter, must not access this
147 
148         result = nn::svc::ControlMemory( &dummy,
149                                          memAddr,
150                                          NULL,
151                                          size,
152                                          nn::os::MEMORY_OPERATION_PROTECT,
153                                          nn::os::MEMORY_PERMISSION_READ_WRITE );
154         NN_OS_ERROR_IF_FAILED(result);
155 
156         return reinterpret_cast<void*>(memAddr);
157     }
158 
159     return NULL;
160 }
161 
MoveFrom(StackMemory * pFrom)162 void StackMemory::MoveFrom(StackMemory* pFrom)
163 {
164     reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager)->Switch(this, pFrom);
165     this->m_MemoryAddress = pFrom->m_MemoryAddress;
166     pFrom->m_MemoryAddress = NULL;
167 }
168 
169 
170 }} // namespace nn::os
171 
172 
173 #include <new>
174 using namespace nn::os;
175 
176 extern "C" {
177 
178 // StackMemory
179 
nnosStackMemoryProtect(nnosStackMemory * p,void * pMem,size_t size)180 void nnosStackMemoryProtect(nnosStackMemory* p, void* pMem, size_t size)
181 {
182     new (p) StackMemory(pMem, size);
183 }
184 
nnosStackMemoryUnprotect(nnosStackMemory * p)185 void nnosStackMemoryUnprotect(nnosStackMemory* p)
186 {
187     StackMemory* pStackMemory = reinterpret_cast<StackMemory*>(p);
188     pStackMemory->~StackMemory();
189 }
190 
nnosStackMemoryGetAddress(nnosStackMemory * p)191 uptr nnosStackMemoryGetAddress(nnosStackMemory* p)
192 {
193     StackMemory* pStackMemory = reinterpret_cast<StackMemory*>(p);
194     return pStackMemory->GetAddress();
195 }
196 
nnosStackMemoryGetSize(nnosStackMemory * p)197 size_t nnosStackMemoryGetSize(nnosStackMemory* p)
198 {
199     StackMemory* pStackMemory = reinterpret_cast<StackMemory*>(p);
200     return pStackMemory->GetSize();
201 }
202 
nnosStackMemoryGetStackBottom(nnosStackMemory * p)203 uptr nnosStackMemoryGetStackBottom(nnosStackMemory* p)
204 {
205     StackMemory* pStackMemory = reinterpret_cast<StackMemory*>(p);
206     return pStackMemory->GetStackBottom();
207 }
208 
209 }
210 #endif  // if NN_PLATFORM_HAS_MMU
211