1 // Copyright 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "host-common/address_space_host_memory_allocator.h"
16 #include "host-common/address_space_device.hpp"
17 #include "host-common/vm_operations.h"
18 #include "host-common/crash_reporter.h"
19 #include "base/AlignedBuf.h"
20
21 namespace android {
22 namespace emulation {
23
AddressSpaceHostMemoryAllocatorContext(const address_space_device_control_ops * ops)24 AddressSpaceHostMemoryAllocatorContext::AddressSpaceHostMemoryAllocatorContext(
25 const address_space_device_control_ops *ops)
26 : m_ops(ops) {
27 }
28
~AddressSpaceHostMemoryAllocatorContext()29 AddressSpaceHostMemoryAllocatorContext::~AddressSpaceHostMemoryAllocatorContext() {
30 clear();
31 }
32
perform(AddressSpaceDevicePingInfo * info)33 void AddressSpaceHostMemoryAllocatorContext::perform(AddressSpaceDevicePingInfo *info) {
34 uint64_t result;
35
36 switch (static_cast<HostMemoryAllocatorCommand>(info->metadata)) {
37 case HostMemoryAllocatorCommand::Allocate:
38 result = allocate(info);
39 break;
40
41 case HostMemoryAllocatorCommand::Unallocate:
42 result = unallocate(info);
43 break;
44
45 default:
46 result = -1;
47 break;
48 }
49
50 info->metadata = result;
51 }
52
allocate_impl(const uint64_t phys_addr,const uint64_t size)53 void *AddressSpaceHostMemoryAllocatorContext::allocate_impl(const uint64_t phys_addr,
54 const uint64_t size) {
55 #if defined(__APPLE__) && defined(__arm64__)
56 constexpr uint64_t alignment = 16384;
57 #else
58 constexpr uint64_t alignment = 4096;
59 #endif
60 const uint64_t aligned_size = ((size + alignment - 1) / alignment) * alignment;
61
62 void *host_ptr = android::aligned_buf_alloc(alignment, aligned_size);
63 if (host_ptr) {
64 auto r = m_paddr2ptr.insert({phys_addr, {host_ptr, aligned_size}});
65 if (r.second) {
66 if (m_ops->add_memory_mapping(phys_addr, host_ptr, aligned_size)) {
67 return host_ptr;
68 } else {
69 m_paddr2ptr.erase(r.first);
70 android::aligned_buf_free(host_ptr);
71 return nullptr;
72 }
73 } else {
74 android::aligned_buf_free(host_ptr);
75 return nullptr;
76 }
77 } else {
78 return nullptr;
79 }
80 }
81
allocate(AddressSpaceDevicePingInfo * info)82 uint64_t AddressSpaceHostMemoryAllocatorContext::allocate(AddressSpaceDevicePingInfo *info) {
83 void* host_ptr = allocate_impl(info->phys_addr, info->size);
84 if (host_ptr) {
85 return 0;
86 } else {
87 return -1;
88 }
89 }
90
unallocate(AddressSpaceDevicePingInfo * info)91 uint64_t AddressSpaceHostMemoryAllocatorContext::unallocate(AddressSpaceDevicePingInfo *info) {
92 const uint64_t phys_addr = info->phys_addr;
93 const auto i = m_paddr2ptr.find(phys_addr);
94 if (i != m_paddr2ptr.end()) {
95 void* host_ptr = i->second.first;
96 const uint64_t size = i->second.second;
97
98 if (m_ops->remove_memory_mapping(phys_addr, host_ptr, size)) {
99 android::aligned_buf_free(host_ptr);
100 m_paddr2ptr.erase(i);
101 return 0;
102 } else {
103 crashhandler_die("Failed remove a memory mapping {phys_addr=%lx, host_ptr=%p, size=%lu}",
104 phys_addr, host_ptr, size);
105 }
106 } else {
107 return -1;
108 }
109 return 0;
110 }
111
getDeviceType() const112 AddressSpaceDeviceType AddressSpaceHostMemoryAllocatorContext::getDeviceType() const {
113 return AddressSpaceDeviceType::HostMemoryAllocator;
114 }
115
save(base::Stream * stream) const116 void AddressSpaceHostMemoryAllocatorContext::save(base::Stream* stream) const {
117 stream->putBe32(m_paddr2ptr.size());
118
119 for (const auto &kv : m_paddr2ptr) {
120 const uint64_t phys_addr = kv.first;
121 const uint64_t size = kv.second.second;
122 const void *mem = kv.second.first;
123
124 stream->putBe64(phys_addr);
125 stream->putBe64(size);
126 stream->write(mem, size);
127 }
128 }
129
load(base::Stream * stream)130 bool AddressSpaceHostMemoryAllocatorContext::load(base::Stream* stream) {
131 clear();
132
133 size_t size = stream->getBe32();
134
135 for (size_t i = 0; i < size; ++i) {
136 uint64_t phys_addr = stream->getBe64();
137 uint64_t size = stream->getBe64();
138 void *mem = allocate_impl(phys_addr, size);
139 if (mem) {
140 if (stream->read(mem, size) != static_cast<ssize_t>(size)) {
141 return false;
142 }
143 } else {
144 return false;
145 }
146 }
147
148 return true;
149 }
150
clear()151 void AddressSpaceHostMemoryAllocatorContext::clear() {
152 for (const auto& kv : m_paddr2ptr) {
153 uint64_t phys_addr = kv.first;
154 void *host_ptr = kv.second.first;
155 size_t size = kv.second.second;
156
157 if (m_ops->remove_memory_mapping(phys_addr, host_ptr, size)) {
158 android::aligned_buf_free(host_ptr);
159 } else {
160 crashhandler_die("Failed remove a memory mapping {phys_addr=%lx, host_ptr=%p, size=%lu}",
161 phys_addr, host_ptr, size);
162 }
163 }
164 }
165
166 } // namespace emulation
167 } // namespace android
168