1 // Copyright 2016 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 "goldfish_dma.h"
16 
17 #include <qemu_pipe_bp.h>
18 
19 #if PLATFORM_SDK_VERSION < 26
20 #include <cutils/log.h>
21 #else
22 #include <log/log.h>
23 #endif
24 #include <errno.h>
25 #ifdef __ANDROID__
26 #include <linux/ioctl.h>
27 #include <linux/types.h>
28 #include <sys/cdefs.h>
29 #endif
30 #include <sys/ioctl.h>
31 #include <sys/mman.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 /* There is an ioctl associated with goldfish dma driver.
39  * Make it conflict with ioctls that are not likely to be used
40  * in the emulator.
41  * 'G'	00-3F	drivers/misc/sgi-gru/grulib.h	conflict!
42  * 'G'	00-0F	linux/gigaset_dev.h	conflict!
43  */
44 #define GOLDFISH_DMA_IOC_MAGIC	'G'
45 
46 #define GOLDFISH_DMA_IOC_LOCK			_IOWR(GOLDFISH_DMA_IOC_MAGIC, 0, struct goldfish_dma_ioctl_info)
47 #define GOLDFISH_DMA_IOC_UNLOCK			_IOWR(GOLDFISH_DMA_IOC_MAGIC, 1, struct goldfish_dma_ioctl_info)
48 #define GOLDFISH_DMA_IOC_GETOFF			_IOWR(GOLDFISH_DMA_IOC_MAGIC, 2, struct goldfish_dma_ioctl_info)
49 #define GOLDFISH_DMA_IOC_CREATE_REGION	_IOWR(GOLDFISH_DMA_IOC_MAGIC, 3, struct goldfish_dma_ioctl_info)
50 
51 struct goldfish_dma_ioctl_info {
52     uint64_t phys_begin;
53     uint64_t size;
54 };
55 
goldfish_dma_create_region(uint32_t sz,struct goldfish_dma_context * res)56 int goldfish_dma_create_region(uint32_t sz, struct goldfish_dma_context* res) {
57 
58     res->fd = qemu_pipe_open("opengles");
59     res->mapped_addr = 0;
60     res->size = 0;
61 
62     if (res->fd > 0) {
63         // now alloc
64         struct goldfish_dma_ioctl_info info;
65         info.size = sz;
66         int alloc_res = ioctl(res->fd, GOLDFISH_DMA_IOC_CREATE_REGION, &info);
67 
68         if (alloc_res) {
69             ALOGE("%s: failed to allocate DMA region. errno=%d",
70                   __FUNCTION__, errno);
71             close(res->fd);
72             res->fd = -1;
73             return alloc_res;
74         }
75 
76         res->size = sz;
77         ALOGV("%s: successfully allocated goldfish DMA region with size %u cxt=%p fd=%d",
78               __FUNCTION__, sz, res, res->fd);
79         return 0;
80     } else {
81         ALOGE("%s: could not obtain fd to device! fd %d errno=%d\n",
82               __FUNCTION__, res->fd, errno);
83         return ENODEV;
84     }
85 }
86 
goldfish_dma_map(struct goldfish_dma_context * cxt)87 void* goldfish_dma_map(struct goldfish_dma_context* cxt) {
88     ALOGV("%s: on fd %d errno=%d", __FUNCTION__, cxt->fd, errno);
89     void *mapped = mmap(0, cxt->size, PROT_WRITE, MAP_SHARED, cxt->fd, 0);
90     ALOGV("%s: cxt=%p mapped=%p size=%u errno=%d",
91         __FUNCTION__, cxt, mapped, cxt->size, errno);
92 
93     if (mapped == MAP_FAILED) {
94         mapped = NULL;
95     }
96 
97     cxt->mapped_addr = reinterpret_cast<uint64_t>(mapped);
98     return mapped;
99 }
100 
goldfish_dma_unmap(struct goldfish_dma_context * cxt)101 int goldfish_dma_unmap(struct goldfish_dma_context* cxt) {
102     ALOGV("%s: cxt=%p mapped=0x%" PRIu64, __FUNCTION__, cxt, cxt->mapped_addr);
103     munmap(reinterpret_cast<void *>(cxt->mapped_addr), cxt->size);
104     cxt->mapped_addr = 0;
105     cxt->size = 0;
106     return 0;
107 }
108 
goldfish_dma_write(struct goldfish_dma_context * cxt,const void * to_write,uint32_t sz)109 void goldfish_dma_write(struct goldfish_dma_context* cxt,
110                                const void* to_write,
111                                uint32_t sz) {
112     ALOGV("%s: cxt=%p mapped=0x%" PRIu64 " to_write=%p size=%u",
113         __FUNCTION__, cxt, cxt->mapped_addr, to_write, sz);
114     memcpy(reinterpret_cast<void *>(cxt->mapped_addr), to_write, sz);
115 }
116 
goldfish_dma_free(goldfish_dma_context * cxt)117 void goldfish_dma_free(goldfish_dma_context* cxt) {
118     close(cxt->fd);
119 }
120 
goldfish_dma_guest_paddr(const struct goldfish_dma_context * cxt)121 uint64_t goldfish_dma_guest_paddr(const struct goldfish_dma_context* cxt) {
122     struct goldfish_dma_ioctl_info info;
123     ioctl(cxt->fd, GOLDFISH_DMA_IOC_GETOFF, &info);
124     return info.phys_begin;
125 }
126