blob: 646695f759947d0f4798cfa4e71866bf34eca5d1 [file] [log] [blame]
Roman Kiryanov79632592019-06-03 12:31:49 -07001// Copyright (C) 2019 The Android Open Source Project
2// Copyright (C) 2019 Google Inc.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#include <linux/types.h>
17#include <linux/ioctl.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/mman.h>
21#include <sys/ioctl.h>
22#include <fcntl.h>
23#include <unistd.h>
24#include <cstdlib>
25#include <errno.h>
26#include <memory>
27
28#if PLATFORM_SDK_VERSION < 26
29#include <cutils/log.h>
30#else
31#include <log/log.h>
32#endif
33
34#include "goldfish_address_space.h"
35
36namespace {
37
38struct goldfish_address_space_allocate_block {
39 __u64 size;
40 __u64 offset;
41 __u64 phys_addr;
42};
43
Lingfeng Yang8d04bdd2019-10-19 10:59:53 -070044struct goldfish_address_space_claim_shared {
45 __u64 offset;
46 __u64 size;
47};
48
Roman Kiryanov79632592019-06-03 12:31:49 -070049#define GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC 'G'
50#define GOLDFISH_ADDRESS_SPACE_IOCTL_OP(OP, T) _IOWR(GOLDFISH_ADDRESS_SPACE_IOCTL_MAGIC, OP, T)
51#define GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK GOLDFISH_ADDRESS_SPACE_IOCTL_OP(10, struct goldfish_address_space_allocate_block)
52#define GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK GOLDFISH_ADDRESS_SPACE_IOCTL_OP(11, __u64)
53#define GOLDFISH_ADDRESS_SPACE_IOCTL_PING GOLDFISH_ADDRESS_SPACE_IOCTL_OP(12, struct goldfish_address_space_ping)
Lingfeng Yang8d04bdd2019-10-19 10:59:53 -070054#define GOLDFISH_ADDRESS_SPACE_IOCTL_CLAIM_SHARED GOLDFISH_ADDRESS_SPACE_IOCTL_OP(13, struct goldfish_address_space_claim_shared)
55#define GOLDFISH_ADDRESS_SPACE_IOCTL_UNCLAIM_SHARED GOLDFISH_ADDRESS_SPACE_IOCTL_OP(14, __u64)
Roman Kiryanov79632592019-06-03 12:31:49 -070056
57const char GOLDFISH_ADDRESS_SPACE_DEVICE_NAME[] = "/dev/goldfish_address_space";
58
Roman Kiryanov136c39a2019-06-03 19:41:51 -070059const int HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID = 1;
60const int HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID = 2;
61
Roman Kiryanova2bb9c12019-10-09 14:36:28 -070062int create_address_space_fd()
63{
64 return ::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR);
65}
66
Roman Kiryanov79632592019-06-03 12:31:49 -070067long ioctl_allocate(int fd, struct goldfish_address_space_allocate_block *request)
68{
69 return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_ALLOCATE_BLOCK, request);
70}
71
72long ioctl_deallocate(int fd, uint64_t offset)
73{
74 return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_DEALLOCATE_BLOCK, &offset);
75}
76
Roman Kiryanov136c39a2019-06-03 19:41:51 -070077long ioctl_ping(int fd, struct goldfish_address_space_ping *request)
78{
79 return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_PING, request);
80}
81
Roman Kiryanova2bb9c12019-10-09 14:36:28 -070082long set_address_space_subdevice_type(int fd, uint64_t type)
83{
84 struct goldfish_address_space_ping request;
85 ::memset(&request, 0, sizeof(request));
86 request.version = sizeof(request);
87 request.metadata = type;
88
89 return ioctl_ping(fd, &request);
90}
91
Lingfeng Yang8d04bdd2019-10-19 10:59:53 -070092long ioctl_claim_shared(int fd, struct goldfish_address_space_claim_shared *request)
93{
94 return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_CLAIM_SHARED, request);
95}
96
97long ioctl_unclaim_shared(int fd, uint64_t offset)
98{
99 return ::ioctl(fd, GOLDFISH_ADDRESS_SPACE_IOCTL_UNCLAIM_SHARED, &offset);
100}
101
Roman Kiryanov79632592019-06-03 12:31:49 -0700102} // namespace
103
Lingfeng Yang23fef582019-10-30 18:26:54 -0700104GoldfishAddressSpaceBlockProvider::GoldfishAddressSpaceBlockProvider(GoldfishAddressSpaceSubdeviceType subdevice)
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700105 : m_handle(create_address_space_fd())
Roman Kiryanova2bb9c12019-10-09 14:36:28 -0700106{
Lingfeng Yang23fef582019-10-30 18:26:54 -0700107 if ((subdevice != GoldfishAddressSpaceSubdeviceType::NoSubdevice) && is_opened()) {
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700108 const long ret = set_address_space_subdevice_type(m_handle, subdevice);
Roman Kiryanova2bb9c12019-10-09 14:36:28 -0700109 if (ret) {
110 ALOGE("%s: set_address_space_subdevice_type failed for device_type=%lu, ret=%ld",
111 __func__, static_cast<unsigned long>(subdevice), ret);
112 close();
113 }
114 }
115}
Roman Kiryanov79632592019-06-03 12:31:49 -0700116
117GoldfishAddressSpaceBlockProvider::~GoldfishAddressSpaceBlockProvider()
118{
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700119 if (is_opened()) {
120 ::close(m_handle);
121 }
Roman Kiryanov79632592019-06-03 12:31:49 -0700122}
123
124bool GoldfishAddressSpaceBlockProvider::is_opened() const
125{
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700126 return m_handle >= 0;
Roman Kiryanov79632592019-06-03 12:31:49 -0700127}
128
129void GoldfishAddressSpaceBlockProvider::close()
130{
131 if (is_opened()) {
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700132 ::close(m_handle);
133 m_handle = -1;
Roman Kiryanov79632592019-06-03 12:31:49 -0700134 }
135}
136
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700137address_space_handle_t GoldfishAddressSpaceBlockProvider::release()
138{
139 address_space_handle_t handle = m_handle;
140 m_handle = -1;
141 return handle;
142}
143
Roman Kiryanov4126ae32019-10-11 09:30:45 -0700144void GoldfishAddressSpaceBlockProvider::closeHandle(address_space_handle_t handle)
145{
146 ::close(handle);
147}
148
Roman Kiryanov79632592019-06-03 12:31:49 -0700149GoldfishAddressSpaceBlock::GoldfishAddressSpaceBlock()
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700150 : m_handle(-1)
Roman Kiryanov79632592019-06-03 12:31:49 -0700151 , m_mmaped_ptr(NULL)
152 , m_phys_addr(0)
153 , m_host_addr(0)
154 , m_offset(0)
155 , m_size(0) {}
156
157GoldfishAddressSpaceBlock::~GoldfishAddressSpaceBlock()
158{
159 destroy();
160}
161
162GoldfishAddressSpaceBlock &GoldfishAddressSpaceBlock::operator=(const GoldfishAddressSpaceBlock &rhs)
163{
164 m_mmaped_ptr = rhs.m_mmaped_ptr;
165 m_phys_addr = rhs.m_phys_addr;
166 m_host_addr = rhs.m_host_addr;
167 m_offset = rhs.m_offset;
168 m_size = rhs.m_size;
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700169 m_handle = rhs.m_handle;
Roman Kiryanov79632592019-06-03 12:31:49 -0700170
171 return *this;
172}
173
174bool GoldfishAddressSpaceBlock::allocate(GoldfishAddressSpaceBlockProvider *provider, size_t size)
175{
176 ALOGD("%s: Ask for block of size 0x%llx\n", __func__,
177 (unsigned long long)size);
178
179 destroy();
180
181 if (!provider->is_opened()) {
182 return false;
183 }
184
185 struct goldfish_address_space_allocate_block request;
186 ::memset(&request, 0, sizeof(request));
187 request.size = size;
188
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700189 long res = ioctl_allocate(provider->m_handle, &request);
Roman Kiryanov79632592019-06-03 12:31:49 -0700190 if (res) {
191 return false;
192 } else {
193 m_phys_addr = request.phys_addr;
194 m_offset = request.offset;
195 m_size = request.size;
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700196 m_handle = provider->m_handle;
Lingfeng Yang8d04bdd2019-10-19 10:59:53 -0700197 m_is_shared_mapping = false;
Roman Kiryanov79632592019-06-03 12:31:49 -0700198
199 ALOGD("%s: ioctl allocate returned offset 0x%llx size 0x%llx\n", __func__,
200 (unsigned long long)m_offset,
201 (unsigned long long)m_size);
202
203 return true;
204 }
205}
206
Lingfeng Yang8d04bdd2019-10-19 10:59:53 -0700207bool GoldfishAddressSpaceBlock::claimShared(GoldfishAddressSpaceBlockProvider *provider, uint64_t offset, uint64_t size)
208{
209 ALOGD("%s: Ask to claim region [0x%llx 0x%llx]\n", __func__,
210 (unsigned long long)offset,
211 (unsigned long long)offset + size);
212
213 destroy();
214
215 if (!provider->is_opened()) {
216 return false;
217 }
218
219 struct goldfish_address_space_claim_shared request;
220 request.offset = offset;
221 request.size = size;
222 long res = ioctl_claim_shared(provider->m_handle, &request);
223
224 if (res) {
225 return false;
226 }
227
228 m_offset = offset;
229 m_size = size;
230 m_handle = provider->m_handle;
231 m_is_shared_mapping = true;
232
233 return true;
234}
235
Roman Kiryanov79632592019-06-03 12:31:49 -0700236uint64_t GoldfishAddressSpaceBlock::physAddr() const
237{
238 return m_phys_addr;
239}
240
241uint64_t GoldfishAddressSpaceBlock::hostAddr() const
242{
243 return m_host_addr;
244}
245
246void *GoldfishAddressSpaceBlock::mmap(uint64_t host_addr)
247{
248 if (m_size == 0) {
249 ALOGE("%s: called with zero size\n", __func__);
250 return NULL;
251 }
252 if (m_mmaped_ptr) {
253 ALOGE("'mmap' called for an already mmaped address block");
254 ::abort();
255 }
256
Roman Kiryanov2111c062019-10-14 14:23:51 -0700257 void *result;
258 const int res = memoryMap(NULL, m_size, m_handle, m_offset, &result);
259 if (res) {
Roman Kiryanov79632592019-06-03 12:31:49 -0700260 ALOGE("%s: host memory map failed with size 0x%llx "
261 "off 0x%llx errno %d\n",
262 __func__,
263 (unsigned long long)m_size,
Roman Kiryanov2111c062019-10-14 14:23:51 -0700264 (unsigned long long)m_offset, res);
Roman Kiryanov79632592019-06-03 12:31:49 -0700265 return NULL;
266 } else {
267 m_mmaped_ptr = result;
268 m_host_addr = host_addr;
269 return guestPtr();
270 }
271}
272
273void *GoldfishAddressSpaceBlock::guestPtr() const
274{
275 return reinterpret_cast<char *>(m_mmaped_ptr) + (m_host_addr & (PAGE_SIZE - 1));
276}
277
278void GoldfishAddressSpaceBlock::destroy()
279{
280 if (m_mmaped_ptr && m_size) {
Roman Kiryanov4126ae32019-10-11 09:30:45 -0700281 memoryUnmap(m_mmaped_ptr, m_size);
Roman Kiryanov79632592019-06-03 12:31:49 -0700282 m_mmaped_ptr = NULL;
283 }
284
285 if (m_size) {
Lingfeng Yang8d04bdd2019-10-19 10:59:53 -0700286 long res = -EINVAL;
287
288 if (m_is_shared_mapping) {
289 res = ioctl_unclaim_shared(m_handle, m_offset);
290 if (res) {
291 ALOGE("ioctl_unclaim_shared failed, res=%ld", res);
292 ::abort();
293 }
294 } else {
295 res = ioctl_deallocate(m_handle, m_offset);
296 if (res) {
297 ALOGE("ioctl_deallocate failed, res=%ld", res);
298 ::abort();
299 }
Roman Kiryanov79632592019-06-03 12:31:49 -0700300 }
301
Lingfeng Yang8d04bdd2019-10-19 10:59:53 -0700302 m_is_shared_mapping = false;
303
Roman Kiryanov79632592019-06-03 12:31:49 -0700304 m_phys_addr = 0;
305 m_host_addr = 0;
306 m_offset = 0;
307 m_size = 0;
308 }
309}
Roman Kiryanov136c39a2019-06-03 19:41:51 -0700310
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700311void GoldfishAddressSpaceBlock::release()
312{
313 m_handle = -1;
314 m_mmaped_ptr = NULL;
315 m_phys_addr = 0;
316 m_host_addr = 0;
317 m_offset = 0;
318 m_size = 0;
319}
320
Roman Kiryanov2111c062019-10-14 14:23:51 -0700321int GoldfishAddressSpaceBlock::memoryMap(void *addr,
322 size_t len,
323 address_space_handle_t fd,
324 uint64_t off,
325 void** dst) {
326 void* ptr = ::mmap64(addr, len, PROT_WRITE, MAP_SHARED, fd, off);
327 if (MAP_FAILED == ptr) {
328 return errno;
329 } else {
330 *dst = ptr;
331 return 0;
332 }
333}
334
Roman Kiryanov4126ae32019-10-11 09:30:45 -0700335void GoldfishAddressSpaceBlock::memoryUnmap(void *ptr, size_t size)
336{
337 ::munmap(ptr, size);
338}
339
Roman Kiryanov136c39a2019-06-03 19:41:51 -0700340GoldfishAddressSpaceHostMemoryAllocator::GoldfishAddressSpaceHostMemoryAllocator()
Lingfeng Yang23fef582019-10-30 18:26:54 -0700341 : m_provider(GoldfishAddressSpaceSubdeviceType::HostMemoryAllocator) {}
Roman Kiryanov136c39a2019-06-03 19:41:51 -0700342
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700343bool GoldfishAddressSpaceHostMemoryAllocator::is_opened() const { return m_provider.is_opened(); }
344
Roman Kiryanov136c39a2019-06-03 19:41:51 -0700345long GoldfishAddressSpaceHostMemoryAllocator::hostMalloc(GoldfishAddressSpaceBlock *block, size_t size)
346{
347 if (size == 0) {
348 return -EINVAL;
349 }
350 if (block->size() > 0) {
351 return -EINVAL;
352 }
353 if (!m_provider.is_opened()) {
354 return -ENODEV;
355 }
356 if (!block->allocate(&m_provider, size)) {
357 return -ENOMEM;
358 }
359
360 struct goldfish_address_space_ping request;
361 ::memset(&request, 0, sizeof(request));
Roman Kiryanov449b2c82019-08-29 15:44:22 -0700362 request.version = sizeof(request);
Roman Kiryanov136c39a2019-06-03 19:41:51 -0700363 request.offset = block->offset();
364 request.size = block->size();
365 request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_ALLOCATE_ID;
366
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700367 long ret = ioctl_ping(m_provider.m_handle, &request);
Roman Kiryanov136c39a2019-06-03 19:41:51 -0700368 if (ret) {
369 return ret;
370 }
371 ret = static_cast<long>(request.metadata);
372 if (ret) {
373 return ret;
374 }
375
376 block->mmap(0);
377 return 0;
378}
379
380void GoldfishAddressSpaceHostMemoryAllocator::hostFree(GoldfishAddressSpaceBlock *block)
381{
382 if (block->size() == 0) {
383 return;
384 }
385
386 if (!m_provider.is_opened()) {
387 ALOGE("%s: device is not available", __func__);
388 ::abort();
389 }
390
391 if (block->guestPtr()) {
392 struct goldfish_address_space_ping request;
393 ::memset(&request, 0, sizeof(request));
Roman Kiryanov449b2c82019-08-29 15:44:22 -0700394 request.version = sizeof(request);
Roman Kiryanov136c39a2019-06-03 19:41:51 -0700395 request.offset = block->offset();
396 request.metadata = HOST_MEMORY_ALLOCATOR_COMMAND_UNALLOCATE_ID;
397
Roman Kiryanov754c3eb2019-10-10 14:09:23 -0700398 const long ret = ioctl_ping(m_provider.m_handle, &request);
Roman Kiryanov136c39a2019-06-03 19:41:51 -0700399 if (ret) {
400 ALOGE("%s: ioctl_ping failed, ret=%ld", __func__, ret);
401 ::abort();
402 }
403 }
404
405 block->replace(NULL);
406}
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700407
408address_space_handle_t goldfish_address_space_open() {
409 return ::open(GOLDFISH_ADDRESS_SPACE_DEVICE_NAME, O_RDWR);
410}
411
412void goldfish_address_space_close(address_space_handle_t handle) {
413 ::close(handle);
414}
415
416bool goldfish_address_space_allocate(
417 address_space_handle_t handle,
418 size_t size, uint64_t* phys_addr, uint64_t* offset) {
419
420 struct goldfish_address_space_allocate_block request;
421 ::memset(&request, 0, sizeof(request));
422 request.size = size;
423
424 long res = ioctl_allocate(handle, &request);
425
426 if (res) return false;
427
428 *phys_addr = request.phys_addr;
429 *offset = request.offset;
430 return true;
431}
432
433bool goldfish_address_space_free(
434 address_space_handle_t handle, uint64_t offset) {
435
436 long res = ioctl_deallocate(handle, offset);
437
438 if (res) {
439 ALOGE("ioctl_deallocate failed, res=%ld", res);
440 ::abort();
441 }
442
443 return true;
444}
445
446bool goldfish_address_space_claim_shared(
447 address_space_handle_t handle, uint64_t offset, uint64_t size) {
448
449 struct goldfish_address_space_claim_shared request;
450 request.offset = offset;
451 request.size = size;
452 long res = ioctl_claim_shared(handle, &request);
453
454 if (res) return false;
455
456 return true;
457}
458
459bool goldfish_address_space_unclaim_shared(
460 address_space_handle_t handle, uint64_t offset) {
461 long res = ioctl_unclaim_shared(handle, offset);
462 if (res) {
463 ALOGE("ioctl_unclaim_shared failed, res=%ld", res);
464 ::abort();
465 }
466
467 return true;
468}
469
470// pgoff is the offset into the page to return in the result
471void* goldfish_address_space_map(
472 address_space_handle_t handle,
473 uint64_t offset, uint64_t size,
474 uint64_t pgoff) {
475
476 void* res = ::mmap64(0, size, PROT_WRITE, MAP_SHARED, handle, offset);
477
478 if (res == MAP_FAILED) {
479 ALOGE("%s: failed to map. errno: %d\n", __func__, errno);
Lingfeng Yangf629af02019-10-19 20:45:02 -0700480 return 0;
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700481 }
482
483 return (void*)(((char*)res) + (uintptr_t)(pgoff & (PAGE_SIZE - 1)));
484}
485
486void goldfish_address_space_unmap(void* ptr, uint64_t size) {
487 void* pagePtr = (void*)(((uintptr_t)ptr) & ~(PAGE_SIZE - 1));
488 ::munmap(pagePtr, size);
489}
490
Lingfeng Yang23fef582019-10-30 18:26:54 -0700491bool goldfish_address_space_set_subdevice_type(
492 address_space_handle_t handle, GoldfishAddressSpaceSubdeviceType type,
493 address_space_handle_t* handle_out) {
494 struct goldfish_address_space_ping request;
495 request.metadata = (uint64_t)type;
496 *handle_out = handle;
497 return goldfish_address_space_ping(handle, &request);
498}
499
Lingfeng Yang6000a8e2019-10-19 11:56:56 -0700500bool goldfish_address_space_ping(
501 address_space_handle_t handle,
502 struct goldfish_address_space_ping* ping) {
503 long res = ioctl_ping(handle, ping);
504
505 if (res) {
506 ALOGE("%s: ping failed: errno: %d\n", __func__, errno);
507 return false;
508 }
509
510 return true;
511}