1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_SharedMemory.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/svc.h>
20 #include <nn/util/util_Result.h>
21 #include <nn/os/os_Result.h>
22 #include <nn/os/os_SharedMemory.h>
23 #include <nn/os/os_CriticalSection.h>
24 #include <nn/os/os_MemoryMapSelect.h>
25 #include <nn/os/os_ErrorHandlerSelect.h>
26 #include "os_AddressSpaceManager.h"
27
28 namespace nn { namespace os {
29
30 namespace
31 {
32 nnosAddressSpaceManager s_SpaceManager;
33
GetPageAlignedSize(size_t size)34 size_t GetPageAlignedSize(size_t size)
35 {
36 return (size + NN_OS_MEMORY_PAGE_SIZE - 1) & ~(NN_OS_MEMORY_PAGE_SIZE - 1);
37 }
38 }
39
40 namespace detail
41 {
InitializeSharedMemory()42 void InitializeSharedMemory()
43 {
44 nnosAddressSpaceManagerInitialize(&s_SpaceManager, NN_OS_ADDR_SHARED_BEGIN, NN_OS_ADDR_SHARED_SIZE);
45 }
AllocateFromSharedMemorySpace(MemoryBlockBase * p,size_t s)46 uptr AllocateFromSharedMemorySpace(MemoryBlockBase* p, size_t s)
47 {
48 AddressSpaceManager* pManager = reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager);
49 return pManager->Allocate(p, s, NN_OS_MEMORY_PAGE_SIZE);
50 }
FreeToSharedMemorySpace(MemoryBlockBase * p)51 void FreeToSharedMemorySpace(MemoryBlockBase* p)
52 {
53 AddressSpaceManager* pManager = reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager);
54 pManager->Free(p);
55 }
56
57 } // detail
58
59
Map(size_t size,bool readOnly)60 Result SharedMemoryBlock::Map(size_t size, bool readOnly)
61 {
62 // Check that it is uninitialized.
63 NN_TASSERTMSG_( GetAddress() == NULL, "This SharedMemoryBlock instance has already been initialized.\n" );
64 if ( GetAddress() )
65 {
66 return ResultAlreadyInitialized();
67 }
68
69 // Check alignment.
70 if ( ( size % NN_OS_MEMORY_PAGE_SIZE ) != 0 )
71 {
72 return ResultMisalignedSize();
73 }
74
75 // Get memory from the virtual address space.
76 uptr addr = os::detail::AllocateFromSharedMemorySpace(this, size);
77 if (addr == NULL)
78 {
79 return ResultNoAddressSpace();
80 }
81
82 this->MemoryBlockBase::SetReadOnly(readOnly);
83
84 Result result;
85 const bit32 myPermission = readOnly ? MEMORY_PERMISSION_READ : (MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE);
86 result = nn::svc::MapMemoryBlock(GetHandle(), addr, myPermission, os::MEMORY_PERMISSION_DONT_CARE);
87 NN_UTIL_RETURN_IF_FAILED(result);
88 m_SpaceAllocated = true;
89
90 // TODO: When the nn::svc::QueryMemory operation stabilizes, this comment-out will be deleted
91 //MemoryInfo memoryInfo;
92 //PageInfo pageInfo;
93 //result = nn::svc::QueryMemory(&memoryInfo, &pageInfo, addr);
94 //if (result.IsFailure())
95 //{
96 // NN_TPANIC_("QueryMemory failed.");
97 //}
98 //
99 //// Can it also be done by remapping with the acquired size?
100 //if (memoryInfo.size != size)
101 //{
102 // NN_TPANIC_("Mismatch size.");
103 //}
104
105 return result;
106 }
107
TryInitialize(size_t size,bool readOnly,bool otherReadOnly,bool noMap)108 Result SharedMemoryBlock::TryInitialize(size_t size, bool readOnly, bool otherReadOnly, bool noMap)
109 {
110 size = GetPageAlignedSize(size);
111 bit32 myPermission = readOnly ? MEMORY_PERMISSION_READ : MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE;
112 bit32 otherPermission = otherReadOnly ? MEMORY_PERMISSION_READ : MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE;
113
114 Handle handle;
115 Result result;
116 result = nn::svc::CreateMemoryBlock(&handle, NULL, size, myPermission, otherPermission);
117 NN_UTIL_RETURN_IF_FAILED(result);
118 this->SetHandle(handle);
119
120 if (!noMap)
121 {
122 result = Map(size, readOnly);
123 }
124 return result;
125 }
126
Initialize(size_t size,bool readOnly,bool otherReadOnly,bool noMap)127 void SharedMemoryBlock::Initialize(size_t size, bool readOnly, bool otherReadOnly, bool noMap)
128 {
129 NN_OS_ERROR_IF_FAILED(TryInitialize(size, readOnly, otherReadOnly, noMap));
130 }
131
AttachAndMap(Handle handle,size_t size,bool readOnly)132 Result SharedMemoryBlock::AttachAndMap(Handle handle, size_t size, bool readOnly)
133 {
134 // TODO: If SVC is maintained, insert size or attribute check code.
135 size = GetPageAlignedSize(size);
136
137 this->SetHandle(handle);
138 return Map(size, readOnly);
139 }
140
Unmap()141 void SharedMemoryBlock::Unmap()
142 {
143 if (GetAddress() != NULL)
144 {
145 if( m_SpaceAllocated )
146 {
147 NN_OS_ERROR_IF_FAILED(nn::svc::UnmapMemoryBlock(GetHandle(), GetAddress()));
148 os::detail::FreeToSharedMemorySpace(this);
149 }
150 else
151 {
152 SetAddressAndSize(0, 0);
153 }
154 }
155 }
156
Finalize()157 void SharedMemoryBlock::Finalize()
158 {
159 if (this->IsValid())
160 {
161 Unmap();
162 this->HandleObject::Close();
163 }
164 }
165
166
167 }}
168
169 #include <new>
170 using namespace nn::os;
171
172 // SharedMemoryBlock
173
nnosSharedMemoryBlockAllocate(nnosSharedMemoryBlock * this_,size_t size,bool readOnly,bool otherReadOnly,bool noMap)174 void nnosSharedMemoryBlockAllocate(nnosSharedMemoryBlock* this_, size_t size, bool readOnly, bool otherReadOnly, bool noMap)
175 {
176 new (this_) SharedMemoryBlock(size, readOnly, otherReadOnly, noMap);
177 }
178
nnosSharedMemoryBlockInitializeNoAllocate(nnosSharedMemoryBlock * this_)179 void nnosSharedMemoryBlockInitializeNoAllocate(nnosSharedMemoryBlock* this_)
180 {
181 new (this_) SharedMemoryBlock();
182 }
183
nnosSharedMemoryBlockFree(nnosSharedMemoryBlock * this_)184 void nnosSharedMemoryBlockFree(nnosSharedMemoryBlock* this_)
185 {
186 SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
187 pSharedMemoryBlock->~SharedMemoryBlock();
188 }
189
nnosSharedMemoryBlockGetAddress(nnosSharedMemoryBlock * this_)190 uptr nnosSharedMemoryBlockGetAddress(nnosSharedMemoryBlock* this_)
191 {
192 SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
193 return pSharedMemoryBlock->GetAddress();
194 }
195
nnosSharedMemoryBlockGetSize(nnosSharedMemoryBlock * this_)196 size_t nnosSharedMemoryBlockGetSize(nnosSharedMemoryBlock* this_)
197 {
198 SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
199 return pSharedMemoryBlock->GetSize();
200 }
201
nnosSharedMemoryBlockIsReadOnly(nnosSharedMemoryBlock * this_)202 bool nnosSharedMemoryBlockIsReadOnly(nnosSharedMemoryBlock* this_)
203 {
204 SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
205 return pSharedMemoryBlock->IsReadOnly();
206 }
207
208 #endif // if NN_PLATFORM_HAS_MMU
209