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