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