1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_TransferMemoryBlock.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_TransferMemoryBlock.h>
23 #include <nn/os/os_SharedMemory.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 
Initialize(void * p,size_t size,bit32 myPermission,bit32 otherPermission)30 void TransferMemoryBlock::Initialize(
31         void*   p,
32         size_t  size,
33         bit32   myPermission,
34         bit32   otherPermission )
35 {
36     NN_OS_ERROR_IF_FAILED(TryInitialize(p, size, myPermission, otherPermission));
37 }
38 
TryInitialize(void * p,size_t size,bit32 myPermission,bit32 otherPermission)39 Result TransferMemoryBlock::TryInitialize(
40         void*   p,
41         size_t  size,
42         bit32   myPermission,
43         bit32   otherPermission )
44 {
45     // Check that it is uninitialized.
46     NN_TASSERTMSG_( GetAddress() == NULL, "This TransferMemoryBlock instance has already been initialized.\n" );
47     if ( GetAddress() )
48     {
49         return ResultAlreadyInitialized();
50     }
51 
52     // Check alignment.
53     if ( (reinterpret_cast<uptr>(p) % NN_OS_MEMORY_PAGE_SIZE ) != 0 )
54     {
55         return ResultMisalignedAddress();
56     }
57     if ( ( size % NN_OS_MEMORY_PAGE_SIZE ) != 0 )
58     {
59         return ResultMisalignedSize();
60     }
61 
62     Handle handle;
63     Result result;
64     result = nn::svc::CreateMemoryBlock(&handle, reinterpret_cast<uptr>(p), size, myPermission, otherPermission);
65     NN_UTIL_RETURN_IF_FAILED(result);
66     this->SetHandle(handle);
67 
68     SetAddressAndSize(reinterpret_cast<uptr>(p), size);
69     return result;
70 }
71 
Finalize()72 void TransferMemoryBlock::Finalize()
73 {
74     if (this->IsValid())
75     {
76         Unmap();
77         this->HandleObject::Close();
78     }
79 }
80 
81 
82 
83 
AttachAndMap(Handle handle,size_t size,bit32 otherPermission,bit32 myPermission)84 Result TransferMemoryBlock::AttachAndMap(
85         Handle  handle,
86         size_t  size,
87         bit32   otherPermission,
88         bit32   myPermission )
89 {
90     // Check alignment.
91     if ( ( size % NN_OS_MEMORY_PAGE_SIZE ) != 0 )
92     {
93         return ResultMisalignedSize();
94     }
95 
96     this->SetHandle(handle);
97     return Map(size, otherPermission, myPermission);
98 }
99 
Map(size_t size,bit32 otherPermission,bit32 myPermission)100 Result TransferMemoryBlock::Map(
101         size_t  size,
102         bit32   otherPermission,
103         bit32   myPermission )
104 {
105     // Check that it is uninitialized.
106     NN_TASSERT_( GetAddress() == NULL );
107     if ( GetAddress() )
108     {
109         return ResultAlreadyInitialized();
110     }
111 
112     // Check alignment.
113     if ( ( size % NN_OS_MEMORY_PAGE_SIZE ) != 0 )
114     {
115         return ResultMisalignedSize();
116     }
117 
118     // Get memory from the virtual address space.
119     uptr addr = os::detail::AllocateFromSharedMemorySpace(this, size);
120     if (addr == NULL)
121     {
122         return ResultNoAddressSpace();
123     }
124 
125     this->MemoryBlockBase::SetReadOnly((myPermission & os::MEMORY_PERMISSION_WRITE) == 0);
126 
127     Result result = nn::svc::MapMemoryBlock(GetHandle(), addr, myPermission, otherPermission);
128     if( result.IsFailure() )
129     {
130         os::detail::FreeToSharedMemorySpace(this);
131         return result;
132     }
133 
134     m_SpaceAllocated = true;
135     return result;
136 }
137 
Unmap()138 void TransferMemoryBlock::Unmap()
139 {
140     if (GetAddress() != NULL)
141     {
142         if( m_SpaceAllocated )
143         {
144             nn::svc::UnmapMemoryBlock(GetHandle(), GetAddress());
145             os::detail::FreeToSharedMemorySpace(this);
146         }
147         else
148         {
149             SetAddressAndSize(0, 0);
150         }
151     }
152 }
153 
154 
155 }}
156 
157 #endif  // if NN_PLATFORM_HAS_MMU
158