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: 25458 $
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 "os_AddressSpaceManager.h"
25 
26 namespace nn { namespace os {
27 
28     namespace
29     {
30         nnosAddressSpaceManager s_SpaceManager;
31 
GetPageAlignedSize(size_t size)32         size_t GetPageAlignedSize(size_t size)
33         {
34             return (size + NN_OS_MEMORY_PAGE_SIZE - 1) & ~(NN_OS_MEMORY_PAGE_SIZE - 1);
35         }
36     }
37 
38     namespace detail
39     {
InitializeSharedMemory()40         void InitializeSharedMemory()
41         {
42             nnosAddressSpaceManagerInitialize(&s_SpaceManager, NN_OS_ADDR_SHARED_BEGIN, NN_OS_ADDR_SHARED_SIZE);
43         }
AllocateFromSharedMemorySpace(MemoryBlockBase * p,size_t s)44         uptr AllocateFromSharedMemorySpace(MemoryBlockBase* p, size_t s)
45         {
46             AddressSpaceManager* pManager = reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager);
47             return pManager->Allocate(p, s, NN_OS_MEMORY_PAGE_SIZE);
48         }
FreeToSharedMemorySpace(MemoryBlockBase * p)49         void FreeToSharedMemorySpace(MemoryBlockBase* p)
50         {
51             AddressSpaceManager* pManager = reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager);
52             pManager->Free(p);
53         }
54 
55     } // detail
56 
57 
Map(size_t size,bool readOnly)58 void SharedMemoryBlock::Map(size_t size, bool readOnly)
59 {
60     // 未初期化であることをチェックします。
61     NN_TASSERT_( GetAddress() == NULL );
62     NN_ALIGN_TASSERT_( size, NN_OS_MEMORY_PAGE_SIZE );
63 
64     // 仮想アドレス空間からメモリを取得します。
65     uptr addr = detail::AllocateFromSharedMemorySpace(this, size);
66     if (addr == NULL)
67     {
68         NN_TPANIC_("failed to allocate address space.");
69     }
70 
71     this->MemoryBlockBase::SetReadOnly(readOnly);
72 
73     Result result;
74     const bit32 myPermission = readOnly ? MEMORY_PERMISSION_READ : (MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE);
75     result = nn::svc::MapMemoryBlock(GetHandle(), addr, myPermission, os::MEMORY_PERMISSION_DONT_CARE);
76     NN_UTIL_PANIC_IF_FAILED(result);
77     m_SpaceAllocated = true;
78 
79     // TODO: nn::svc::QueryMemory の動作が安定したらここのコメントアウトを消す
80     //MemoryInfo  memoryInfo;
81     //PageInfo    pageInfo;
82     //result = nn::svc::QueryMemory(&memoryInfo, &pageInfo, addr);
83     //if (result.IsFailure())
84     //{
85     //    NN_TPANIC_("QueryMemory failed.");
86     //}
87     //
88     //// 取得したサイズでマップし直してあげる手もあり?
89     //if (memoryInfo.size != size)
90     //{
91     //    NN_TPANIC_("Mismatch size.");
92     //}
93 }
94 
TryInitialize(size_t size,bool readOnly,bool otherReadOnly,bool noMap)95 Result SharedMemoryBlock::TryInitialize(size_t size, bool readOnly, bool otherReadOnly, bool noMap)
96 {
97     size = GetPageAlignedSize(size);
98     bit32 myPermission = readOnly ? MEMORY_PERMISSION_READ : MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE;
99     bit32 otherPermission = otherReadOnly ? MEMORY_PERMISSION_READ : MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE;
100 
101     Handle handle;
102     Result result;
103     result = nn::svc::CreateMemoryBlock(&handle, NULL, size, myPermission, otherPermission);
104     NN_UTIL_RETURN_IF_FAILED(result);
105     this->SetHandle(handle);
106 
107     if (!noMap)
108     {
109         Map(size, readOnly);
110     }
111     return result;
112 }
113 
Initialize(size_t size,bool readOnly,bool otherReadOnly,bool noMap)114 void SharedMemoryBlock::Initialize(size_t size, bool readOnly, bool otherReadOnly, bool noMap)
115 {
116     NN_UTIL_PANIC_IF_FAILED(TryInitialize(size, readOnly, otherReadOnly, noMap));
117 }
118 
AttachAndMap(Handle handle,size_t size,bool readOnly)119 void SharedMemoryBlock::AttachAndMap(Handle handle, size_t size, bool readOnly)
120 {
121     // TODO: SVC が整備されたら、サイズや属性のチェックコードを挿入。
122     size = GetPageAlignedSize(size);
123 
124     this->SetHandle(handle);
125     Map(size, readOnly);
126 }
127 
Unmap()128 void SharedMemoryBlock::Unmap()
129 {
130     if (GetAddress() != NULL)
131     {
132         if( m_SpaceAllocated )
133         {
134             NN_UTIL_PANIC_IF_FAILED(nn::svc::UnmapMemoryBlock(GetHandle(), GetAddress()));
135             detail::FreeToSharedMemorySpace(this);
136         }
137         else
138         {
139             SetAddressAndSize(0, 0);
140         }
141     }
142 }
143 
Finalize()144 void SharedMemoryBlock::Finalize()
145 {
146     if (this->IsValid())
147     {
148         Unmap();
149         this->HandleObject::Close();
150     }
151 }
152 
153 
154 }}
155 
156 #include <new>
157 using namespace nn::os;
158 
159 // SharedMemoryBlock
160 
nnosSharedMemoryBlockAllocate(nnosSharedMemoryBlock * this_,size_t size,bool readOnly,bool otherReadOnly,bool noMap)161 void nnosSharedMemoryBlockAllocate(nnosSharedMemoryBlock* this_, size_t size, bool readOnly, bool otherReadOnly, bool noMap)
162 {
163     new (this_) SharedMemoryBlock(size, readOnly, otherReadOnly, noMap);
164 }
165 
nnosSharedMemoryBlockInitializeNoAllocate(nnosSharedMemoryBlock * this_)166 void nnosSharedMemoryBlockInitializeNoAllocate(nnosSharedMemoryBlock* this_)
167 {
168     new (this_) SharedMemoryBlock();
169 }
170 
nnosSharedMemoryBlockFree(nnosSharedMemoryBlock * this_)171 void nnosSharedMemoryBlockFree(nnosSharedMemoryBlock* this_)
172 {
173     SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
174     pSharedMemoryBlock->~SharedMemoryBlock();
175 }
176 
nnosSharedMemoryBlockGetAddress(nnosSharedMemoryBlock * this_)177 uptr nnosSharedMemoryBlockGetAddress(nnosSharedMemoryBlock* this_)
178 {
179     SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
180     return pSharedMemoryBlock->GetAddress();
181 }
182 
nnosSharedMemoryBlockGetSize(nnosSharedMemoryBlock * this_)183 size_t nnosSharedMemoryBlockGetSize(nnosSharedMemoryBlock* this_)
184 {
185     SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
186     return pSharedMemoryBlock->GetSize();
187 }
188 
nnosSharedMemoryBlockIsReadOnly(nnosSharedMemoryBlock * this_)189 bool nnosSharedMemoryBlockIsReadOnly(nnosSharedMemoryBlock* this_)
190 {
191     SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
192     return pSharedMemoryBlock->IsReadOnly();
193 }
194 
195 #endif  // if NN_PLATFORM_HAS_MMU
196