1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_StackMemory.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/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, 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     NN_UTIL_RETURN_IF_FAILED(result);
96 
97     result = nn::svc::ControlMemory( &dummy,
98                                      m_MemoryAddress,
99                                      NULL,
100                                      size,
101                                      nn::os::MEMORY_OPERATION_PROTECT,
102                                      nn::os::MEMORY_PERMISSION_NONE );
103     return result;
104 }
105 
Finalize()106 void* StackMemory::Finalize()
107 {
108     if ( GetAddress() != NULL )
109     {
110         const uptr addr = GetAddress();
111         const size_t size = GetSize();
112         const uptr memAddr = m_MemoryAddress;
113 
114         nnosAddressSpaceManagerFree(&s_SpaceManager, detail::ConvertToC(this));
115 
116         Result result;
117         uptr dummy;
118         result = nn::svc::ControlMemory( &dummy,
119                                          addr,
120                                          memAddr,
121                                          size,
122                                          nn::os::MEMORY_OPERATION_UNMAP,
123                                          nn::os::MEMORY_PERMISSION_READ_WRITE );
124         NN_OS_ERROR_IF_FAILED(result);
125         // Hereafter, must not access this
126 
127         result = nn::svc::ControlMemory( &dummy,
128                                          memAddr,
129                                          NULL,
130                                          size,
131                                          nn::os::MEMORY_OPERATION_PROTECT,
132                                          nn::os::MEMORY_PERMISSION_READ_WRITE );
133         NN_OS_ERROR_IF_FAILED(result);
134 
135         return reinterpret_cast<void*>(memAddr);
136     }
137 
138     return NULL;
139 }
140 
MoveFrom(StackMemory * pFrom)141 void StackMemory::MoveFrom(StackMemory* pFrom)
142 {
143     reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager)->Switch(this, pFrom);
144     this->m_MemoryAddress = pFrom->m_MemoryAddress;
145     pFrom->m_MemoryAddress = NULL;
146 }
147 
148 
149 }} // namespace nn::os
150 
151 
152 #include <new>
153 using namespace nn::os;
154 
155 extern "C" {
156 
157 // StackMemory
158 
nnosStackMemoryProtect(nnosStackMemory * p,void * pMem,size_t size)159 void nnosStackMemoryProtect(nnosStackMemory* p, void* pMem, size_t size)
160 {
161     new (p) StackMemory(pMem, size);
162 }
163 
nnosStackMemoryUnprotect(nnosStackMemory * p)164 void nnosStackMemoryUnprotect(nnosStackMemory* p)
165 {
166     StackMemory* pStackMemory = reinterpret_cast<StackMemory*>(p);
167     pStackMemory->~StackMemory();
168 }
169 
nnosStackMemoryGetAddress(nnosStackMemory * p)170 uptr nnosStackMemoryGetAddress(nnosStackMemory* p)
171 {
172     StackMemory* pStackMemory = reinterpret_cast<StackMemory*>(p);
173     return pStackMemory->GetAddress();
174 }
175 
nnosStackMemoryGetSize(nnosStackMemory * p)176 size_t nnosStackMemoryGetSize(nnosStackMemory* p)
177 {
178     StackMemory* pStackMemory = reinterpret_cast<StackMemory*>(p);
179     return pStackMemory->GetSize();
180 }
181 
nnosStackMemoryGetStackBottom(nnosStackMemory * p)182 uptr nnosStackMemoryGetStackBottom(nnosStackMemory* p)
183 {
184     StackMemory* pStackMemory = reinterpret_cast<StackMemory*>(p);
185     return pStackMemory->GetStackBottom();
186 }
187 
188 }
189 #endif  // if NN_PLATFORM_HAS_MMU
190