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