1 /*
2 * Copyright © 2022 Google, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 #include "util/libsync.h"
29 #include "util/u_process.h"
30
31 #include "virtio_priv.h"
32
33
34 static int virtio_execbuf_flush(struct fd_device *dev);
35
36 static void
virtio_device_destroy(struct fd_device * dev)37 virtio_device_destroy(struct fd_device *dev)
38 {
39 struct virtio_device *virtio_dev = to_virtio_device(dev);
40
41 util_vma_heap_finish(&virtio_dev->address_space);
42 }
43
44 static uint32_t
virtio_handle_from_dmabuf(struct fd_device * dev,int fd)45 virtio_handle_from_dmabuf(struct fd_device *dev, int fd)
46 {
47 struct virtio_device *virtio_dev = to_virtio_device(dev);
48
49 return vdrm_dmabuf_to_handle(virtio_dev->vdrm, fd);
50 }
51
52 static void
virtio_close_handle(struct fd_bo * bo)53 virtio_close_handle(struct fd_bo *bo)
54 {
55 struct virtio_device *virtio_dev = to_virtio_device(bo->dev);
56
57 vdrm_bo_close(virtio_dev->vdrm, bo->handle);
58 }
59
60 static const struct fd_device_funcs funcs = {
61 .bo_new = virtio_bo_new,
62 .bo_from_handle = virtio_bo_from_handle,
63 .handle_from_dmabuf = virtio_handle_from_dmabuf,
64 .bo_from_dmabuf = fd_bo_from_dmabuf_drm,
65 .bo_close_handle = virtio_close_handle,
66 .pipe_new = virtio_pipe_new,
67 .flush = virtio_execbuf_flush,
68 .destroy = virtio_device_destroy,
69 };
70
71 static void
set_debuginfo(struct fd_device * dev)72 set_debuginfo(struct fd_device *dev)
73 {
74 const char *comm = util_get_process_name();
75 static char cmdline[0x1000+1];
76 int fd = open("/proc/self/cmdline", O_RDONLY);
77 if (fd < 0)
78 return;
79
80 int n = read(fd, cmdline, sizeof(cmdline) - 1);
81 if (n < 0)
82 return;
83
84 /* arguments are separated by NULL, convert to spaces: */
85 for (int i = 0; i < n; i++) {
86 if (cmdline[i] == '\0') {
87 cmdline[i] = ' ';
88 }
89 }
90
91 cmdline[n] = '\0';
92
93 unsigned comm_len = strlen(comm) + 1;
94 unsigned cmdline_len = strlen(cmdline) + 1;
95
96 struct msm_ccmd_set_debuginfo_req *req;
97
98 unsigned req_len = align(sizeof(*req) + comm_len + cmdline_len, 4);
99
100 req = malloc(req_len);
101
102 req->hdr = MSM_CCMD(SET_DEBUGINFO, req_len);
103 req->comm_len = comm_len;
104 req->cmdline_len = cmdline_len;
105
106 memcpy(&req->payload[0], comm, comm_len);
107 memcpy(&req->payload[comm_len], cmdline, cmdline_len);
108
109 vdrm_send_req(to_virtio_device(dev)->vdrm, &req->hdr, false);
110
111 free(req);
112 }
113
114 struct fd_device *
virtio_device_new(int fd,drmVersionPtr version)115 virtio_device_new(int fd, drmVersionPtr version)
116 {
117 struct virgl_renderer_capset_drm caps;
118 struct virtio_device *virtio_dev;
119 struct vdrm_device *vdrm;
120 struct fd_device *dev;
121
122 STATIC_ASSERT(FD_BO_PREP_READ == MSM_PREP_READ);
123 STATIC_ASSERT(FD_BO_PREP_WRITE == MSM_PREP_WRITE);
124 STATIC_ASSERT(FD_BO_PREP_NOSYNC == MSM_PREP_NOSYNC);
125
126 /* Debug option to force fallback to virgl: */
127 if (debug_get_bool_option("FD_NO_VIRTIO", false))
128 return NULL;
129
130 vdrm = vdrm_device_connect(fd, VIRTGPU_DRM_CONTEXT_MSM);
131 if (!vdrm) {
132 INFO_MSG("could not connect vdrm");
133 return NULL;
134 }
135
136 caps = vdrm->caps;
137
138 INFO_MSG("wire_format_version: %u", caps.wire_format_version);
139 INFO_MSG("version_major: %u", caps.version_major);
140 INFO_MSG("version_minor: %u", caps.version_minor);
141 INFO_MSG("version_patchlevel: %u", caps.version_patchlevel);
142 INFO_MSG("has_cached_coherent: %u", caps.u.msm.has_cached_coherent);
143 INFO_MSG("va_start: 0x%0"PRIx64, caps.u.msm.va_start);
144 INFO_MSG("va_size: 0x%0"PRIx64, caps.u.msm.va_size);
145 INFO_MSG("gpu_id: %u", caps.u.msm.gpu_id);
146 INFO_MSG("gmem_size: %u", caps.u.msm.gmem_size);
147 INFO_MSG("gmem_base: 0x%0" PRIx64, caps.u.msm.gmem_base);
148 INFO_MSG("chip_id: 0x%0" PRIx64, caps.u.msm.chip_id);
149 INFO_MSG("max_freq: %u", caps.u.msm.max_freq);
150
151 if (caps.wire_format_version != 2) {
152 ERROR_MSG("Unsupported protocol version: %u", caps.wire_format_version);
153 goto error;
154 }
155
156 if ((caps.version_major != 1) || (caps.version_minor < FD_VERSION_SOFTPIN)) {
157 ERROR_MSG("unsupported version: %u.%u.%u", caps.version_major,
158 caps.version_minor, caps.version_patchlevel);
159 goto error;
160 }
161
162 if (!caps.u.msm.va_size) {
163 ERROR_MSG("No address space");
164 goto error;
165 }
166
167 virtio_dev = calloc(1, sizeof(*virtio_dev));
168 if (!virtio_dev)
169 goto error;
170
171 dev = &virtio_dev->base;
172 dev->funcs = &funcs;
173 dev->fd = fd;
174 dev->version = caps.version_minor;
175 dev->has_cached_coherent = caps.u.msm.has_cached_coherent;
176
177 p_atomic_set(&virtio_dev->next_blob_id, 1);
178 virtio_dev->shmem = to_msm_shmem(vdrm->shmem);
179 virtio_dev->vdrm = vdrm;
180
181 util_queue_init(&dev->submit_queue, "sq", 8, 1, 0, NULL);
182
183 dev->bo_size = sizeof(struct virtio_bo);
184
185 set_debuginfo(dev);
186
187 util_vma_heap_init(&virtio_dev->address_space,
188 caps.u.msm.va_start,
189 caps.u.msm.va_size);
190 simple_mtx_init(&virtio_dev->address_space_lock, mtx_plain);
191
192 return dev;
193
194 error:
195 vdrm_device_close(vdrm);
196 return NULL;
197 }
198
199 static int
virtio_execbuf_flush(struct fd_device * dev)200 virtio_execbuf_flush(struct fd_device *dev)
201 {
202 return vdrm_flush(to_virtio_device(dev)->vdrm);
203 }
204
205 /**
206 * Helper for simple pass-thru ioctls
207 */
208 int
virtio_simple_ioctl(struct fd_device * dev,unsigned cmd,void * _req)209 virtio_simple_ioctl(struct fd_device *dev, unsigned cmd, void *_req)
210 {
211 MESA_TRACE_FUNC();
212 struct vdrm_device *vdrm = to_virtio_device(dev)->vdrm;
213 unsigned req_len = sizeof(struct msm_ccmd_ioctl_simple_req);
214 unsigned rsp_len = sizeof(struct msm_ccmd_ioctl_simple_rsp);
215
216 req_len += _IOC_SIZE(cmd);
217 if (cmd & IOC_OUT)
218 rsp_len += _IOC_SIZE(cmd);
219
220 uint8_t buf[req_len];
221 struct msm_ccmd_ioctl_simple_req *req = (void *)buf;
222 struct msm_ccmd_ioctl_simple_rsp *rsp;
223
224 req->hdr = MSM_CCMD(IOCTL_SIMPLE, req_len);
225 req->cmd = cmd;
226 memcpy(req->payload, _req, _IOC_SIZE(cmd));
227
228 rsp = vdrm_alloc_rsp(vdrm, &req->hdr, rsp_len);
229
230 int ret = vdrm_send_req(vdrm, &req->hdr, true);
231
232 if (cmd & IOC_OUT)
233 memcpy(_req, rsp->payload, _IOC_SIZE(cmd));
234
235 ret = rsp->ret;
236
237 return ret;
238 }
239