1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_SharedMemory.cpp
4 
5   Copyright (C)2009-2012 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: 46347 $
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_Result.h>
22 #include <nn/os/os_SharedMemory.h>
23 #include <nn/os/os_CriticalSection.h>
24 #include <nn/os/os_MemoryMapSelect.h>
25 #include <nn/os/os_ErrorHandlerSelect.h>
26 #include "os_AddressSpaceManager.h"
27 
28 namespace nn { namespace os {
29 
30     namespace
31     {
32         nnosAddressSpaceManager s_SpaceManager;
33 
GetPageAlignedSize(size_t size)34         size_t GetPageAlignedSize(size_t size)
35         {
36             return (size + NN_OS_MEMORY_PAGE_SIZE - 1) & ~(NN_OS_MEMORY_PAGE_SIZE - 1);
37         }
38     }
39 
40     namespace detail
41     {
InitializeSharedMemory()42         void InitializeSharedMemory()
43         {
44             nnosAddressSpaceManagerInitialize(&s_SpaceManager, NN_OS_ADDR_SHARED_BEGIN, NN_OS_ADDR_SHARED_SIZE);
45         }
AllocateFromSharedMemorySpace(MemoryBlockBase * p,size_t s)46         uptr AllocateFromSharedMemorySpace(MemoryBlockBase* p, size_t s)
47         {
48             AddressSpaceManager* pManager = reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager);
49             return pManager->Allocate(p, s, NN_OS_MEMORY_PAGE_SIZE);
50         }
FreeToSharedMemorySpace(MemoryBlockBase * p)51         void FreeToSharedMemorySpace(MemoryBlockBase* p)
52         {
53             AddressSpaceManager* pManager = reinterpret_cast<AddressSpaceManager*>(&s_SpaceManager);
54             pManager->Free(p);
55         }
56 
57     } // detail
58 
59 
Map(size_t size,bool readOnly)60 Result SharedMemoryBlock::Map(size_t size, bool readOnly)
61 {
62     // Check that it is uninitialized.
63     NN_TASSERTMSG_( GetAddress() == NULL, "This SharedMemoryBlock instance has already been initialized.\n" );
64     if ( GetAddress() )
65     {
66         return ResultAlreadyInitialized();
67     }
68 
69     // Check alignment.
70     if ( ( size % NN_OS_MEMORY_PAGE_SIZE ) != 0 )
71     {
72         return ResultMisalignedSize();
73     }
74 
75     // Get memory from the virtual address space.
76     uptr addr = os::detail::AllocateFromSharedMemorySpace(this, size);
77     if (addr == NULL)
78     {
79         return ResultNoAddressSpace();
80     }
81 
82     this->MemoryBlockBase::SetReadOnly(readOnly);
83 
84     Result result;
85     const bit32 myPermission = readOnly ? MEMORY_PERMISSION_READ : (MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE);
86     result = nn::svc::MapMemoryBlock(GetHandle(), addr, myPermission, os::MEMORY_PERMISSION_DONT_CARE);
87     NN_UTIL_RETURN_IF_FAILED(result);
88     m_SpaceAllocated = true;
89 
90     // TODO: When the nn::svc::QueryMemory operation stabilizes, this comment-out will be deleted
91     //MemoryInfo  memoryInfo;
92     //PageInfo    pageInfo;
93     //result = nn::svc::QueryMemory(&memoryInfo, &pageInfo, addr);
94     //if (result.IsFailure())
95     //{
96     //    NN_TPANIC_("QueryMemory failed.");
97     //}
98     //
99     //// Can it also be done by remapping with the acquired size?
100     //if (memoryInfo.size != size)
101     //{
102     //    NN_TPANIC_("Mismatch size.");
103     //}
104 
105     return result;
106 }
107 
TryInitialize(size_t size,bool readOnly,bool otherReadOnly,bool noMap)108 Result SharedMemoryBlock::TryInitialize(size_t size, bool readOnly, bool otherReadOnly, bool noMap)
109 {
110     size = GetPageAlignedSize(size);
111     bit32 myPermission = readOnly ? MEMORY_PERMISSION_READ : MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE;
112     bit32 otherPermission = otherReadOnly ? MEMORY_PERMISSION_READ : MEMORY_PERMISSION_READ | MEMORY_PERMISSION_WRITE;
113 
114     Handle handle;
115     Result result;
116     result = nn::svc::CreateMemoryBlock(&handle, NULL, size, myPermission, otherPermission);
117     NN_UTIL_RETURN_IF_FAILED(result);
118     this->SetHandle(handle);
119 
120     if (!noMap)
121     {
122         result = Map(size, readOnly);
123     }
124     return result;
125 }
126 
Initialize(size_t size,bool readOnly,bool otherReadOnly,bool noMap)127 void SharedMemoryBlock::Initialize(size_t size, bool readOnly, bool otherReadOnly, bool noMap)
128 {
129     NN_OS_ERROR_IF_FAILED(TryInitialize(size, readOnly, otherReadOnly, noMap));
130 }
131 
AttachAndMap(Handle handle,size_t size,bool readOnly)132 Result SharedMemoryBlock::AttachAndMap(Handle handle, size_t size, bool readOnly)
133 {
134     // TODO: If SVC is maintained, insert size or attribute check code.
135     size = GetPageAlignedSize(size);
136 
137     this->SetHandle(handle);
138     return Map(size, readOnly);
139 }
140 
Unmap()141 void SharedMemoryBlock::Unmap()
142 {
143     if (GetAddress() != NULL)
144     {
145         if( m_SpaceAllocated )
146         {
147             NN_OS_ERROR_IF_FAILED(nn::svc::UnmapMemoryBlock(GetHandle(), GetAddress()));
148             os::detail::FreeToSharedMemorySpace(this);
149         }
150         else
151         {
152             SetAddressAndSize(0, 0);
153         }
154     }
155 }
156 
Finalize()157 void SharedMemoryBlock::Finalize()
158 {
159     if (this->IsValid())
160     {
161         Unmap();
162         this->HandleObject::Close();
163     }
164 }
165 
166 
167 }}
168 
169 #include <new>
170 using namespace nn::os;
171 
172 // SharedMemoryBlock
173 
nnosSharedMemoryBlockAllocate(nnosSharedMemoryBlock * this_,size_t size,bool readOnly,bool otherReadOnly,bool noMap)174 void nnosSharedMemoryBlockAllocate(nnosSharedMemoryBlock* this_, size_t size, bool readOnly, bool otherReadOnly, bool noMap)
175 {
176     new (this_) SharedMemoryBlock(size, readOnly, otherReadOnly, noMap);
177 }
178 
nnosSharedMemoryBlockInitializeNoAllocate(nnosSharedMemoryBlock * this_)179 void nnosSharedMemoryBlockInitializeNoAllocate(nnosSharedMemoryBlock* this_)
180 {
181     new (this_) SharedMemoryBlock();
182 }
183 
nnosSharedMemoryBlockFree(nnosSharedMemoryBlock * this_)184 void nnosSharedMemoryBlockFree(nnosSharedMemoryBlock* this_)
185 {
186     SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
187     pSharedMemoryBlock->~SharedMemoryBlock();
188 }
189 
nnosSharedMemoryBlockGetAddress(nnosSharedMemoryBlock * this_)190 uptr nnosSharedMemoryBlockGetAddress(nnosSharedMemoryBlock* this_)
191 {
192     SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
193     return pSharedMemoryBlock->GetAddress();
194 }
195 
nnosSharedMemoryBlockGetSize(nnosSharedMemoryBlock * this_)196 size_t nnosSharedMemoryBlockGetSize(nnosSharedMemoryBlock* this_)
197 {
198     SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
199     return pSharedMemoryBlock->GetSize();
200 }
201 
nnosSharedMemoryBlockIsReadOnly(nnosSharedMemoryBlock * this_)202 bool nnosSharedMemoryBlockIsReadOnly(nnosSharedMemoryBlock* this_)
203 {
204     SharedMemoryBlock* pSharedMemoryBlock = reinterpret_cast<SharedMemoryBlock*>(this_);
205     return pSharedMemoryBlock->IsReadOnly();
206 }
207 
208 #endif  // if NN_PLATFORM_HAS_MMU
209