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