1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_SharedMemory.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: 29304 $
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     // 未初期化であることをチェックします。
62     NN_TASSERT_( GetAddress() == NULL );
63     NN_ALIGN_TASSERT_( size, NN_OS_MEMORY_PAGE_SIZE );
64 
65     // 仮想アドレス空間からメモリを取得します。
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: nn::svc::QueryMemory の動作が安定したらここのコメントアウトを消す
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     //// 取得したサイズでマップし直してあげる手もあり?
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: SVC が整備されたら、サイズや属性のチェックコードを挿入。
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