1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_SharedMemory.cpp
4 Copyright (C)2009 Nintendo Co., Ltd. All rights reserved.
5 These coded instructions, statements, and computer programs contain
6 proprietary information of Nintendo of America Inc. and/or Nintendo
7 Company Ltd., and are protected by Federal copyright law. They may
8 not be disclosed to third parties or copied or duplicated in any form,
9 in whole or in part, without the prior written consent of Nintendo.
10 $Rev: 31762 $
11 *---------------------------------------------------------------------------
12
13
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_SharedMemory.h>
22 #include <nn/os/os_CriticalSection.h>
23 #include <nn/os/os_MemoryMapSelect.h>
24 #include <nn/err.h>
25 #include "os_AddressSpaceManager.h"
26
27 namespace nn { namespace os {
28
29 namespace
30 {
31 nnosAddressSpaceManager s_SpaceManager;
32
GetPageAlignedSize(size_t size)33 size_t GetPageAlignedSize(size_t size)
34 {
35 return (size + NN_OS_MEMORY_PAGE_SIZE - 1) & ~(NN_OS_MEMORY_PAGE_SIZE - 1);
36 }
37 }
38
39 namespace detail
40 {
InitializeSharedMemory()41 void InitializeSharedMemory()
42 {
43 nnosAddressSpaceManagerInitialize(&s_SpaceManager, NN_OS_ADDR_SHARED_BEGIN, NN_OS_ADDR_SHARED_SIZE);
44 }
AllocateFromSharedMemorySpace(MemoryBlockBase * p,size_t s)45 uptr AllocateFromSharedMemorySpace(MemoryBlockBase* p, size_t s)
46 {
47 AddressSpaceManager* pManager = reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager);
48 return pManager->Allocate(p, s, NN_OS_MEMORY_PAGE_SIZE);
49 }
FreeToSharedMemorySpace(MemoryBlockBase * p)50 void FreeToSharedMemorySpace(MemoryBlockBase* p)
51 {
52 AddressSpaceManager* pManager = reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager);
53 pManager->Free(p);
54 }
55
56 } // detail
57
58
Map(size_t size,bool readOnly)59 void SharedMemoryBlock::Map(size_t size, bool readOnly)
60 {
61 // Check that it is not initialized.
62 NN_TASSERT_( GetAddress() == NULL );
63 NN_ALIGN_TASSERT_( size, NN_OS_MEMORY_PAGE_SIZE );
64
65 // Get memory from the virtual address space.
66 uptr addr = detail::AllocateFromSharedMemorySpace(this, size);
67 if (addr == NULL)
68 {
69 NN_TPANIC_("failed to allocate address space.");
70 }
71
72 this->MemoryBlockBase::SetReadOnly(readOnly);
73
74 Result result;
75 const bit32 myPermission = readOnly ? MEMORY_PERMISSION_READ : (MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE);
76 result = nn::svc::MapMemoryBlock(GetHandle(), addr, myPermission, os::MEMORY_PERMISSION_DONT_CARE);
77 NN_ERR_THROW_FATAL(result);
78 m_SpaceAllocated = true;
79
80 // TODO: Delete this commented out portion if nn::svc::QueryMemory operations are stable.
81 //MemoryInfo memoryInfo;
82 //PageInfo pageInfo;
83 //result = nn::svc::QueryMemory(&memoryInfo, &pageInfo, addr);
84 //if (result.IsFailure())
85 //{
86 // NN_TPANIC_("QueryMemory failed.");
87 //}
88 //
89 //// Could also redo by mapping the obtained size?
90 //if (memoryInfo.size != size)
91 //{
92 // NN_TPANIC_("Mismatch size.");
93 //}
94 }
95
TryInitialize(size_t size,bool readOnly,bool otherReadOnly,bool noMap)96 Result SharedMemoryBlock::TryInitialize(size_t size, bool readOnly, bool otherReadOnly, bool noMap)
97 {
98 size = GetPageAlignedSize(size);
99 bit32 myPermission = readOnly ? MEMORY_PERMISSION_READ : MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE;
100 bit32 otherPermission = otherReadOnly ? MEMORY_PERMISSION_READ : MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE;
101
102 Handle handle;
103 Result result;
104 result = nn::svc::CreateMemoryBlock(&handle, NULL, size, myPermission, otherPermission);
105 NN_UTIL_RETURN_IF_FAILED(result);
106 this->SetHandle(handle);
107
108 if (!noMap)
109 {
110 Map(size, readOnly);
111 }
112 return result;
113 }
114
Initialize(size_t size,bool readOnly,bool otherReadOnly,bool noMap)115 void SharedMemoryBlock::Initialize(size_t size, bool readOnly, bool otherReadOnly, bool noMap)
116 {
117 NN_ERR_THROW_FATAL(TryInitialize(size, readOnly, otherReadOnly, noMap));
118 }
119
AttachAndMap(Handle handle,size_t size,bool readOnly)120 void SharedMemoryBlock::AttachAndMap(Handle handle, size_t size, bool readOnly)
121 {
122 // TODO: Insert check code for size and attributes if SVC is maintained.
123 size = GetPageAlignedSize(size);
124
125 this->SetHandle(handle);
126 Map(size, readOnly);
127 }
128
Unmap()129 void SharedMemoryBlock::Unmap()
130 {
131 if (GetAddress() != NULL)
132 {
133 if( m_SpaceAllocated )
134 {
135 NN_ERR_THROW_FATAL(nn::svc::UnmapMemoryBlock(GetHandle(), GetAddress()));
136 detail::FreeToSharedMemorySpace(this);
137 }
138 else
139 {
140 SetAddressAndSize(0, 0);
141 }
142 }
143 }
144
Finalize()145 void SharedMemoryBlock::Finalize()
146 {
147 if (this->IsValid())
148 {
149 Unmap();
150 this->HandleObject::Close();
151 }
152 }
153
154
155 }}
156
157 #include <new>
158 using namespace nn::os;
159
160 // SharedMemoryBlock
161
nnosSharedMemoryBlockAllocate(nnosSharedMemoryBlock * this_,size_t size,bool readOnly,bool otherReadOnly,bool noMap)162 void nnosSharedMemoryBlockAllocate(nnosSharedMemoryBlock* this_, size_t size, bool readOnly, bool otherReadOnly, bool noMap)
163 {
164 new (this_) SharedMemoryBlock(size, readOnly, otherReadOnly, noMap);
165 }
166
nnosSharedMemoryBlockInitializeNoAllocate(nnosSharedMemoryBlock * this_)167 void nnosSharedMemoryBlockInitializeNoAllocate(nnosSharedMemoryBlock* this_)
168 {
169 new (this_) SharedMemoryBlock();
170 }
171
nnosSharedMemoryBlockFree(nnosSharedMemoryBlock * this_)172 void nnosSharedMemoryBlockFree(nnosSharedMemoryBlock* this_)
173 {
174 SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
175 pSharedMemoryBlock->~SharedMemoryBlock();
176 }
177
nnosSharedMemoryBlockGetAddress(nnosSharedMemoryBlock * this_)178 uptr nnosSharedMemoryBlockGetAddress(nnosSharedMemoryBlock* this_)
179 {
180 SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
181 return pSharedMemoryBlock->GetAddress();
182 }
183
nnosSharedMemoryBlockGetSize(nnosSharedMemoryBlock * this_)184 size_t nnosSharedMemoryBlockGetSize(nnosSharedMemoryBlock* this_)
185 {
186 SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
187 return pSharedMemoryBlock->GetSize();
188 }
189
nnosSharedMemoryBlockIsReadOnly(nnosSharedMemoryBlock * this_)190 bool nnosSharedMemoryBlockIsReadOnly(nnosSharedMemoryBlock* this_)
191 {
192 SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
193 return pSharedMemoryBlock->IsReadOnly();
194 }
195
196 #endif // if NN_PLATFORM_HAS_MMU
197