+ struct vc4_simulator_bo *sim_bo =
+ vc4_create_simulator_bo(fd, handle, size);
+
+ sim_bo->winsys_stride = winsys_stride;
+ sim_bo->winsys_map = vc4_simulator_map_winsys_bo(fd, sim_bo);
+}
+
+/**
+ * Simulated ioctl(fd, DRM_VC4_CREATE_BO) implementation.
+ *
+ * Making a VC4 BO is just a matter of making a corresponding BO on the host.
+ */
+static int
+vc4_simulator_create_bo_ioctl(int fd, struct drm_vc4_create_bo *args)
+{
+ int ret;
+ struct drm_mode_create_dumb create = {
+ .width = 128,
+ .bpp = 8,
+ .height = (args->size + 127) / 128,
+ };
+
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
+ assert(create.size >= args->size);
+
+ args->handle = create.handle;
+
+ vc4_create_simulator_bo(fd, create.handle, args->size);
+
+ return ret;
+}
+
+/**
+ * Simulated ioctl(fd, DRM_VC4_CREATE_SHADER_BO) implementation.
+ *
+ * In simulation we defer shader validation until exec time. Just make a host
+ * BO and memcpy the contents in.
+ */
+static int
+vc4_simulator_create_shader_bo_ioctl(int fd,
+ struct drm_vc4_create_shader_bo *args)
+{
+ int ret;
+ struct drm_mode_create_dumb create = {
+ .width = 128,
+ .bpp = 8,
+ .height = (args->size + 127) / 128,
+ };
+
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
+ if (ret)
+ return ret;
+ assert(create.size >= args->size);
+
+ args->handle = create.handle;
+
+ vc4_create_simulator_bo(fd, create.handle, args->size);
+
+ struct drm_mode_map_dumb map = {
+ .handle = create.handle
+ };
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
+ if (ret)
+ return ret;
+
+ void *shader = mmap(NULL, args->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, map.offset);
+ memcpy(shader, (void *)(uintptr_t)args->data, args->size);
+ munmap(shader, args->size);
+
+ return 0;
+}
+
+/**
+ * Simulated ioctl(fd, DRM_VC4_MMAP_BO) implementation.
+ *
+ * We just pass this straight through to dumb mmap.
+ */
+static int
+vc4_simulator_mmap_bo_ioctl(int fd, struct drm_vc4_mmap_bo *args)
+{
+ int ret;
+ struct drm_mode_map_dumb map = {
+ .handle = args->handle,
+ };
+
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
+ args->offset = map.offset;
+
+ return ret;
+}
+
+static int
+vc4_simulator_gem_close_ioctl(int fd, struct drm_gem_close *args)
+{
+ /* Free the simulator's internal tracking. */
+ struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd);
+ struct vc4_simulator_bo *sim_bo = vc4_get_simulator_bo(file,
+ args->handle);
+
+ vc4_free_simulator_bo(sim_bo);
+
+ /* Pass the call on down. */
+ return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, args);
+}
+
+static int
+vc4_simulator_get_param_ioctl(int fd, struct drm_vc4_get_param *args)
+{
+ switch (args->param) {
+ case DRM_VC4_PARAM_SUPPORTS_BRANCHES:
+ case DRM_VC4_PARAM_SUPPORTS_ETC1:
+ case DRM_VC4_PARAM_SUPPORTS_THREADED_FS:
+ case DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER:
+ args->value = true;
+ return 0;
+
+ case DRM_VC4_PARAM_SUPPORTS_MADVISE:
+ case DRM_VC4_PARAM_SUPPORTS_PERFMON:
+ errno = -EINVAL;
+ return -1;
+
+ case DRM_VC4_PARAM_V3D_IDENT0:
+ args->value = 0x02000000;
+ return 0;
+
+ case DRM_VC4_PARAM_V3D_IDENT1:
+ args->value = 0x00000001;
+ return 0;
+
+ default:
+ fprintf(stderr, "Unknown DRM_IOCTL_VC4_GET_PARAM(%lld)\n",
+ (long long)args->param);
+ abort();
+ };
+}
+
+int
+vc4_simulator_ioctl(int fd, unsigned long request, void *args)
+{
+ switch (request) {
+ case DRM_IOCTL_VC4_CREATE_BO:
+ return vc4_simulator_create_bo_ioctl(fd, args);
+ case DRM_IOCTL_VC4_CREATE_SHADER_BO:
+ return vc4_simulator_create_shader_bo_ioctl(fd, args);
+ case DRM_IOCTL_VC4_MMAP_BO:
+ return vc4_simulator_mmap_bo_ioctl(fd, args);
+
+ case DRM_IOCTL_VC4_WAIT_BO:
+ case DRM_IOCTL_VC4_WAIT_SEQNO:
+ /* We do all of the vc4 rendering synchronously, so we just
+ * return immediately on the wait ioctls. This ignores any
+ * native rendering to the host BO, so it does mean we race on
+ * front buffer rendering.
+ */
+ return 0;
+
+ case DRM_IOCTL_VC4_LABEL_BO:
+ /* This is just debug information, nothing to do. */
+ return 0;
+
+ case DRM_IOCTL_VC4_GET_TILING:
+ case DRM_IOCTL_VC4_SET_TILING:
+ /* Disable these for now, since the sharing with i965 requires
+ * linear buffers.
+ */
+ errno = -EINVAL;
+ return -1;
+
+ case DRM_IOCTL_VC4_GET_PARAM:
+ return vc4_simulator_get_param_ioctl(fd, args);
+
+ case DRM_IOCTL_GEM_CLOSE:
+ return vc4_simulator_gem_close_ioctl(fd, args);
+
+ case DRM_IOCTL_GEM_OPEN:
+ case DRM_IOCTL_GEM_FLINK:
+ return drmIoctl(fd, request, args);
+ default:
+ fprintf(stderr, "Unknown ioctl 0x%08x\n", (int)request);
+ abort();
+ }
+}
+
+static void
+vc4_simulator_init_global(void)
+{
+ mtx_lock(&sim_state.mutex);
+ if (sim_state.refcount++) {
+ mtx_unlock(&sim_state.mutex);
+ return;
+ }
+
+ sim_state.mem_size = 256 * 1024 * 1024;
+ sim_state.mem = calloc(sim_state.mem_size, 1);
+ if (!sim_state.mem)
+ abort();
+ sim_state.heap = u_mmInit(0, sim_state.mem_size);