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-handler.h"
19 #include "host-common/crash_reporter.h"
20 #include "aemu/base/AlignedBuf.h"
21
22 namespace android {
23 namespace emulation {
24
AddressSpaceHostMemoryAllocatorContext(const address_space_device_control_ops * ops)25 AddressSpaceHostMemoryAllocatorContext::AddressSpaceHostMemoryAllocatorContext(
26 const address_space_device_control_ops *ops)
27 : m_ops(ops) {
28 }
29
~AddressSpaceHostMemoryAllocatorContext()30 AddressSpaceHostMemoryAllocatorContext::~AddressSpaceHostMemoryAllocatorContext() {
31 clear();
32 }
33
perform(AddressSpaceDevicePingInfo * info)34 void AddressSpaceHostMemoryAllocatorContext::perform(AddressSpaceDevicePingInfo *info) {
35 uint64_t result;
36
37 switch (static_cast<HostMemoryAllocatorCommand>(info->metadata)) {
38 case HostMemoryAllocatorCommand::Allocate:
39 result = allocate(info);
40 break;
41
42 case HostMemoryAllocatorCommand::Unallocate:
43 result = unallocate(info);
44 break;
45
46 default:
47 result = -1;
48 break;
49 }
50
51 info->metadata = result;
52 }
53
allocate_impl(const uint64_t phys_addr,const uint64_t size)54 void *AddressSpaceHostMemoryAllocatorContext::allocate_impl(const uint64_t phys_addr,
55 const uint64_t size) {
56 #if defined(__APPLE__) && defined(__arm64__)
57 constexpr uint64_t alignment = 16384;
58 #else
59 constexpr uint64_t alignment = 4096;
60 #endif
61 const uint64_t aligned_size = ((size + alignment - 1) / alignment) * alignment;
62
63 void *host_ptr = android::aligned_buf_alloc(alignment, aligned_size);
64 if (host_ptr) {
65 auto r = m_paddr2ptr.insert({phys_addr, {host_ptr, aligned_size}});
66 if (r.second) {
67 if (m_ops->add_memory_mapping(phys_addr, host_ptr, aligned_size)) {
68 return host_ptr;
69 } else {
70 m_paddr2ptr.erase(r.first);
71 android::aligned_buf_free(host_ptr);
72 return nullptr;
73 }
74 } else {
75 android::aligned_buf_free(host_ptr);
76 return nullptr;
77 }
78 } else {
79 return nullptr;
80 }
81 }
82
allocate(AddressSpaceDevicePingInfo * info)83 uint64_t AddressSpaceHostMemoryAllocatorContext::allocate(AddressSpaceDevicePingInfo *info) {
84 void* host_ptr = allocate_impl(info->phys_addr, info->size);
85 if (host_ptr) {
86 return 0;
87 } else {
88 return -1;
89 }
90 }
91
unallocate(AddressSpaceDevicePingInfo * info)92 uint64_t AddressSpaceHostMemoryAllocatorContext::unallocate(AddressSpaceDevicePingInfo *info) {
93 const uint64_t phys_addr = info->phys_addr;
94 const auto i = m_paddr2ptr.find(phys_addr);
95 if (i != m_paddr2ptr.end()) {
96 void* host_ptr = i->second.first;
97 const uint64_t size = i->second.second;
98
99 if (m_ops->remove_memory_mapping(phys_addr, host_ptr, size)) {
100 android::aligned_buf_free(host_ptr);
101 m_paddr2ptr.erase(i);
102 return 0;
103 } else {
104 crashhandler_die("Failed remove a memory mapping {phys_addr=%lx, host_ptr=%p, size=%lu}",
105 phys_addr, host_ptr, size);
106 }
107 } else {
108 return -1;
109 }
110 return 0;
111 }
112
getDeviceType() const113 AddressSpaceDeviceType AddressSpaceHostMemoryAllocatorContext::getDeviceType() const {
114 return AddressSpaceDeviceType::HostMemoryAllocator;
115 }
116
save(base::Stream * stream) const117 void AddressSpaceHostMemoryAllocatorContext::save(base::Stream* stream) const {
118 stream->putBe32(m_paddr2ptr.size());
119
120 for (const auto &kv : m_paddr2ptr) {
121 const uint64_t phys_addr = kv.first;
122 const uint64_t size = kv.second.second;
123 const void *mem = kv.second.first;
124
125 stream->putBe64(phys_addr);
126 stream->putBe64(size);
127 stream->write(mem, size);
128 }
129 }
130
load(base::Stream * stream)131 bool AddressSpaceHostMemoryAllocatorContext::load(base::Stream* stream) {
132 clear();
133
134 size_t size = stream->getBe32();
135
136 for (size_t i = 0; i < size; ++i) {
137 uint64_t phys_addr = stream->getBe64();
138 uint64_t size = stream->getBe64();
139 void *mem = allocate_impl(phys_addr, size);
140 if (mem) {
141 if (stream->read(mem, size) != static_cast<ssize_t>(size)) {
142 return false;
143 }
144 } else {
145 return false;
146 }
147 }
148
149 return true;
150 }
151
clear()152 void AddressSpaceHostMemoryAllocatorContext::clear() {
153 for (const auto& kv : m_paddr2ptr) {
154 uint64_t phys_addr = kv.first;
155 void *host_ptr = kv.second.first;
156 size_t size = kv.second.second;
157
158 if (m_ops->remove_memory_mapping(phys_addr, host_ptr, size)) {
159 android::aligned_buf_free(host_ptr);
160 } else {
161 crashhandler_die("Failed remove a memory mapping {phys_addr=%lx, host_ptr=%p, size=%lu}",
162 phys_addr, host_ptr, size);
163 }
164 }
165 }
166
167 } // namespace emulation
168 } // namespace android
169