Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 Google, Inc. |
| 3 | * |
| 4 | * This software is licensed under the terms of the GNU General Public |
| 5 | * License version 2, as published by the Free Software Foundation, and |
| 6 | * may be copied, distributed, and modified under those terms. |
| 7 | * |
| 8 | * This program is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * GNU General Public License for more details. |
| 12 | * |
| 13 | */ |
| 14 | |
| 15 | #include "goldfish_dma.h" |
| 16 | #include "qemu_pipe.h" |
| 17 | |
Luca Stefani | 1cb647a | 2019-03-07 21:58:17 +0100 | [diff] [blame] | 18 | #if PLATFORM_SDK_VERSION < 26 |
Logan Chien | d7bf00d | 2018-09-21 06:30:09 +0000 | [diff] [blame] | 19 | #include <cutils/log.h> |
Luca Stefani | 1cb647a | 2019-03-07 21:58:17 +0100 | [diff] [blame] | 20 | #else |
| 21 | #include <log/log.h> |
| 22 | #endif |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 23 | #include <errno.h> |
David Reveman | 74e99bb | 2019-02-15 18:47:25 -0500 | [diff] [blame] | 24 | #ifdef __ANDROID__ |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 25 | #include <linux/ioctl.h> |
| 26 | #include <linux/types.h> |
| 27 | #include <sys/cdefs.h> |
David Reveman | 74e99bb | 2019-02-15 18:47:25 -0500 | [diff] [blame] | 28 | #endif |
| 29 | #include <sys/ioctl.h> |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 30 | #include <sys/mman.h> |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 31 | #include <fcntl.h> |
| 32 | #include <stdlib.h> |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 33 | #include <stdlib.h> |
| 34 | #include <string.h> |
| 35 | |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 36 | /* There is an ioctl associated with goldfish dma driver. |
| 37 | * Make it conflict with ioctls that are not likely to be used |
| 38 | * in the emulator. |
| 39 | * 'G' 00-3F drivers/misc/sgi-gru/grulib.h conflict! |
| 40 | * 'G' 00-0F linux/gigaset_dev.h conflict! |
| 41 | */ |
| 42 | #define GOLDFISH_DMA_IOC_MAGIC 'G' |
| 43 | |
| 44 | #define GOLDFISH_DMA_IOC_LOCK _IOWR(GOLDFISH_DMA_IOC_MAGIC, 0, struct goldfish_dma_ioctl_info) |
| 45 | #define GOLDFISH_DMA_IOC_UNLOCK _IOWR(GOLDFISH_DMA_IOC_MAGIC, 1, struct goldfish_dma_ioctl_info) |
| 46 | #define GOLDFISH_DMA_IOC_GETOFF _IOWR(GOLDFISH_DMA_IOC_MAGIC, 2, struct goldfish_dma_ioctl_info) |
| 47 | #define GOLDFISH_DMA_IOC_CREATE_REGION _IOWR(GOLDFISH_DMA_IOC_MAGIC, 3, struct goldfish_dma_ioctl_info) |
| 48 | |
| 49 | struct goldfish_dma_ioctl_info { |
| 50 | uint64_t phys_begin; |
| 51 | uint64_t size; |
| 52 | }; |
| 53 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 54 | int goldfish_dma_create_region(uint32_t sz, struct goldfish_dma_context* res) { |
| 55 | |
| 56 | res->fd = qemu_pipe_open("opengles"); |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 57 | res->mapped_addr = 0; |
| 58 | res->size = 0; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 59 | |
| 60 | if (res->fd > 0) { |
| 61 | // now alloc |
| 62 | struct goldfish_dma_ioctl_info info; |
| 63 | info.size = sz; |
| 64 | int alloc_res = ioctl(res->fd, GOLDFISH_DMA_IOC_CREATE_REGION, &info); |
| 65 | |
| 66 | if (alloc_res) { |
| 67 | ALOGE("%s: failed to allocate DMA region. errno=%d", |
| 68 | __FUNCTION__, errno); |
| 69 | close(res->fd); |
| 70 | res->fd = -1; |
| 71 | return alloc_res; |
| 72 | } |
| 73 | |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 74 | res->size = sz; |
Matt Wachowski | f270f58 | 2018-08-10 12:47:56 -0700 | [diff] [blame] | 75 | ALOGV("%s: successfully allocated goldfish DMA region with size %u cxt=%p fd=%d", |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 76 | __FUNCTION__, sz, res, res->fd); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 77 | return 0; |
| 78 | } else { |
| 79 | ALOGE("%s: could not obtain fd to device! fd %d errno=%d\n", |
| 80 | __FUNCTION__, res->fd, errno); |
| 81 | return ENODEV; |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | void* goldfish_dma_map(struct goldfish_dma_context* cxt) { |
| 86 | ALOGV("%s: on fd %d errno=%d", __FUNCTION__, cxt->fd, errno); |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 87 | void *mapped = mmap(0, cxt->size, PROT_WRITE, MAP_SHARED, cxt->fd, 0); |
Matt Wachowski | f270f58 | 2018-08-10 12:47:56 -0700 | [diff] [blame] | 88 | ALOGV("%s: cxt=%p mapped=%p size=%u errno=%d", |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 89 | __FUNCTION__, cxt, mapped, cxt->size, errno); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 90 | |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 91 | if (mapped == MAP_FAILED) { |
| 92 | mapped = NULL; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 93 | } |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 94 | |
| 95 | cxt->mapped_addr = reinterpret_cast<uint64_t>(mapped); |
| 96 | return mapped; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | int goldfish_dma_unmap(struct goldfish_dma_context* cxt) { |
Luca Stefani | 1cb647a | 2019-03-07 21:58:17 +0100 | [diff] [blame] | 100 | ALOGV("%s: cxt=%p mapped=0x%" PRIu64, __FUNCTION__, cxt, cxt->mapped_addr); |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 101 | munmap(reinterpret_cast<void *>(cxt->mapped_addr), cxt->size); |
| 102 | cxt->mapped_addr = 0; |
| 103 | cxt->size = 0; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 104 | return 0; |
| 105 | } |
| 106 | |
| 107 | void goldfish_dma_write(struct goldfish_dma_context* cxt, |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 108 | const void* to_write, |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 109 | uint32_t sz) { |
David Reveman | 74e99bb | 2019-02-15 18:47:25 -0500 | [diff] [blame] | 110 | ALOGV("%s: cxt=%p mapped=0x%" PRIu64 " to_write=%p size=%u", |
Matt Wachowski | f270f58 | 2018-08-10 12:47:56 -0700 | [diff] [blame] | 111 | __FUNCTION__, cxt, cxt->mapped_addr, to_write, sz); |
Roman Kiryanov | 96a068f | 2018-06-13 17:05:05 -0700 | [diff] [blame] | 112 | memcpy(reinterpret_cast<void *>(cxt->mapped_addr), to_write, sz); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | void goldfish_dma_free(goldfish_dma_context* cxt) { |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 116 | close(cxt->fd); |
| 117 | } |
| 118 | |
Roman Kiryanov | be1c0c2 | 2018-10-02 18:07:14 -0700 | [diff] [blame] | 119 | uint64_t goldfish_dma_guest_paddr(const struct goldfish_dma_context* cxt) { |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 120 | struct goldfish_dma_ioctl_info info; |
| 121 | ioctl(cxt->fd, GOLDFISH_DMA_IOC_GETOFF, &info); |
| 122 | return info.phys_begin; |
| 123 | } |