panwrap-syscall.c 32.9 KB
Newer Older
1
/*
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
2
 * © Copyright 2017 The Panfrost Community
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Lyude's avatar
Lyude committed
18
#include <stdbool.h>
19
#include <stdarg.h>
20 21 22 23
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <linux/ioctl.h>
24
#include <math.h>
Lyude's avatar
Lyude committed
25
#include <sys/mman.h>
Lyude Paul's avatar
Lyude Paul committed
26
#include <unistd.h>
Lyude Paul's avatar
Lyude Paul committed
27 28 29
#include <linux/limits.h>
#include <sys/stat.h>
#include <errno.h>
30
#include <ctype.h>
31 32

#include <mali-ioctl.h>
Lyude's avatar
Lyude committed
33
#include <list.h>
34 35
#include "panwrap.h"

36 37 38 39 40 41 42 43 44
static pthread_mutex_t l;
PANLOADER_CONSTRUCTOR {
	pthread_mutexattr_t mattr;

	pthread_mutexattr_init(&mattr);
	pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
	pthread_mutex_init(&l, &mattr);
	pthread_mutexattr_destroy(&mattr);
}
45

Lyude's avatar
Lyude committed
46 47 48 49 50 51 52
#define IOCTL_CASE(request) (_IOWR(_IOC_TYPE(request), _IOC_NR(request), \
				   _IOC_SIZE(request)))

struct ioctl_info {
	const char *name;
};

53 54
struct device_info {
	const char *name;
Lyude's avatar
Lyude committed
55
	const struct ioctl_info info[MALI_IOCTL_TYPE_COUNT][_IOC_NR(0xffffffff)];
56 57
};

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
58
typedef void* (mmap_func)(void *, size_t, int, int, int, loff_t);
59
typedef int (open_func)(const char *, int flags, ...);
Lyude's avatar
Lyude committed
60

Lyude's avatar
Lyude committed
61 62
#define IOCTL_TYPE(type) [type - MALI_IOCTL_TYPE_BASE] =
#define IOCTL_INFO(n) [_IOC_NR(MALI_IOCTL_##n)] = { .name = #n }
63 64
static struct device_info mali_info = {
	.name = "mali",
Lyude's avatar
Lyude committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
	.info = {
		IOCTL_TYPE(0x80) {
			IOCTL_INFO(GET_VERSION),
		},
		IOCTL_TYPE(0x82) {
			IOCTL_INFO(MEM_ALLOC),
			IOCTL_INFO(MEM_IMPORT),
			IOCTL_INFO(MEM_COMMIT),
			IOCTL_INFO(MEM_QUERY),
			IOCTL_INFO(MEM_FREE),
			IOCTL_INFO(MEM_FLAGS_CHANGE),
			IOCTL_INFO(MEM_ALIAS),
			IOCTL_INFO(SYNC),
			IOCTL_INFO(POST_TERM),
			IOCTL_INFO(HWCNT_SETUP),
			IOCTL_INFO(HWCNT_DUMP),
			IOCTL_INFO(HWCNT_CLEAR),
			IOCTL_INFO(GPU_PROPS_REG_DUMP),
			IOCTL_INFO(FIND_CPU_OFFSET),
			IOCTL_INFO(GET_VERSION_NEW),
			IOCTL_INFO(SET_FLAGS),
			IOCTL_INFO(SET_TEST_DATA),
			IOCTL_INFO(INJECT_ERROR),
			IOCTL_INFO(MODEL_CONTROL),
			IOCTL_INFO(KEEP_GPU_POWERED),
			IOCTL_INFO(FENCE_VALIDATE),
			IOCTL_INFO(STREAM_CREATE),
			IOCTL_INFO(GET_PROFILING_CONTROLS),
			IOCTL_INFO(SET_PROFILING_CONTROLS),
			IOCTL_INFO(DEBUGFS_MEM_PROFILE_ADD),
			IOCTL_INFO(JOB_SUBMIT),
			IOCTL_INFO(DISJOINT_QUERY),
			IOCTL_INFO(GET_CONTEXT_ID),
			IOCTL_INFO(TLSTREAM_ACQUIRE_V10_4),
			IOCTL_INFO(TLSTREAM_TEST),
			IOCTL_INFO(TLSTREAM_STATS),
			IOCTL_INFO(TLSTREAM_FLUSH),
			IOCTL_INFO(HWCNT_READER_SETUP),
			IOCTL_INFO(SET_PRFCNT_VALUES),
			IOCTL_INFO(SOFT_EVENT_UPDATE),
			IOCTL_INFO(MEM_JIT_INIT),
			IOCTL_INFO(TLSTREAM_ACQUIRE),
		},
108 109 110
	},
};
#undef IOCTL_INFO
Lyude's avatar
Lyude committed
111
#undef IOCTL_TYPE
112

Lyude's avatar
Lyude committed
113 114
static inline const struct ioctl_info *
ioctl_get_info(unsigned long int request)
115
{
Lyude's avatar
Lyude committed
116 117
	return &mali_info.info[_IOC_TYPE(request) - MALI_IOCTL_TYPE_BASE]
	                      [_IOC_NR(request)];
118 119
}

Lyude's avatar
Lyude committed
120
static int mali_fd = 0;
Lyude Paul's avatar
Lyude Paul committed
121 122
static long context_id = 0;
static char debugfs_ctx_path[PATH_MAX] = {0};
Lyude's avatar
Lyude committed
123 124
static LIST_HEAD(allocations);
static LIST_HEAD(mmaps);
Lyude's avatar
Lyude committed
125

Lyude Paul's avatar
Lyude Paul committed
126
static bool step_mode;
Lyude Paul's avatar
Lyude Paul committed
127
static long log_delay;
Lyude Paul's avatar
Lyude Paul committed
128 129
const char* replace_fragment;
const char* replace_vertex;
Lyude Paul's avatar
Lyude Paul committed
130 131 132 133

static const char *dump_dir;
static int dump_dir_fd;
static int debugfs_fd;
Lyude Paul's avatar
Lyude Paul committed
134
PANLOADER_CONSTRUCTOR {
Lyude Paul's avatar
Lyude Paul committed
135
	log_delay = panwrap_parse_env_long("PANWRAP_LOG_DELAY", 0);
136 137
	replace_fragment = panwrap_parse_env_string("PANWRAP_REPLACE_FRAGMENT", "");
	replace_vertex = panwrap_parse_env_string("PANWRAP_REPLACE_VERTEX", "");
Lyude Paul's avatar
Lyude Paul committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151
	dump_dir = panwrap_parse_env_string("PANWRAP_DUMP_DIR", NULL);
	step_mode = panwrap_parse_env_bool("PANWRAP_STEP", false);

	if (dump_dir != NULL) {
		mkdir(dump_dir, 0777);

		dump_dir_fd = open(dump_dir, O_DIRECTORY);
		if (dump_dir_fd < 0) {
			fprintf(stderr,
				"Failed to create/open %s: %s\n",
				dump_dir, strerror(errno));
			abort();
		}
	}
Lyude Paul's avatar
Lyude Paul committed
152 153
}

Lyude Paul's avatar
Lyude Paul committed
154
#define LOCK()   pthread_mutex_lock(&l);
155
#define UNLOCK() panwrap_log_flush(); pthread_mutex_unlock(&l)
Lyude Paul's avatar
Lyude Paul committed
156

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
157
#define FLAG_INFO(flag) { MALI_MEM_##flag, "MALI_MEM_" #flag }
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
static const struct panwrap_flag_info mem_flag_info[] = {
	FLAG_INFO(PROT_CPU_RD),
	FLAG_INFO(PROT_CPU_WR),
	FLAG_INFO(PROT_GPU_RD),
	FLAG_INFO(PROT_GPU_WR),
	FLAG_INFO(PROT_GPU_EX),
	FLAG_INFO(GROW_ON_GPF),
	FLAG_INFO(COHERENT_SYSTEM),
	FLAG_INFO(COHERENT_LOCAL),
	FLAG_INFO(CACHED_CPU),
	FLAG_INFO(SAME_VA),
	FLAG_INFO(NEED_MMAP),
	FLAG_INFO(COHERENT_SYSTEM_REQUIRED),
	FLAG_INFO(SECURE),
	FLAG_INFO(DONT_NEED),
	FLAG_INFO(IMPORT_SHARED),
	{}
};
#undef FLAG_INFO

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
178
#define FLAG_INFO(flag) { MALI_JD_REQ_##flag, "MALI_JD_REQ_" #flag }
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
static const struct panwrap_flag_info jd_req_flag_info[] = {
	FLAG_INFO(FS),
	FLAG_INFO(CS),
	FLAG_INFO(T),
	FLAG_INFO(CF),
	FLAG_INFO(V),
	FLAG_INFO(FS_AFBC),
	FLAG_INFO(EVENT_COALESCE),
	FLAG_INFO(COHERENT_GROUP),
	FLAG_INFO(PERMON),
	FLAG_INFO(EXTERNAL_RESOURCES),
	FLAG_INFO(ONLY_COMPUTE),
	FLAG_INFO(SPECIFIC_COHERENT_GROUP),
	FLAG_INFO(EVENT_ONLY_ON_FAILURE),
	FLAG_INFO(EVENT_NEVER),
	FLAG_INFO(SKIP_CACHE_START),
	FLAG_INFO(SKIP_CACHE_END),
	{}
};
#undef FLAG_INFO

Lyude's avatar
Lyude committed
200
#define FLAG_INFO(flag) { flag, #flag }
201 202 203 204 205 206 207 208 209 210 211
static const struct panwrap_flag_info external_resources_access_flag_info[] = {
	FLAG_INFO(MALI_EXT_RES_ACCESS_SHARED),
	FLAG_INFO(MALI_EXT_RES_ACCESS_EXCLUSIVE),
	{}
};

static const struct panwrap_flag_info mali_jd_dep_type_flag_info[] = {
	FLAG_INFO(MALI_JD_DEP_TYPE_DATA),
	FLAG_INFO(MALI_JD_DEP_TYPE_ORDER),
	{}
};
Lyude's avatar
Lyude committed
212 213
#undef FLAG_INFO

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
214
#define FLAG_INFO(flag) { JS_FEATURE_##flag, "JS_FEATURE_" #flag }
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
static const struct panwrap_flag_info js_feature_info[] = {
	FLAG_INFO(NULL_JOB),
	FLAG_INFO(SET_VALUE_JOB),
	FLAG_INFO(CACHE_FLUSH_JOB),
	FLAG_INFO(COMPUTE_JOB),
	FLAG_INFO(VERTEX_JOB),
	FLAG_INFO(GEOMETRY_JOB),
	FLAG_INFO(TILER_JOB),
	FLAG_INFO(FUSED_JOB),
	FLAG_INFO(FRAGMENT_JOB),
	{}
};
#undef FLAG_INFO



231 232 233 234 235 236 237 238 239 240 241
static inline const char *
ioctl_decode_coherency_mode(enum mali_ioctl_coherency_mode mode)
{
	switch (mode) {
	case COHERENCY_ACE_LITE: return "ACE_LITE";
	case COHERENCY_ACE:      return "ACE";
	case COHERENCY_NONE:     return "None";
	default:                 return "???";
	}
}

242 243 244 245 246 247 248 249 250 251 252
static inline const char *
ioctl_decode_jd_prio(mali_jd_prio prio)
{
	switch (prio) {
	case MALI_JD_PRIO_LOW:    return "Low";
	case MALI_JD_PRIO_MEDIUM: return "Medium";
	case MALI_JD_PRIO_HIGH:   return "High";
	default:                  return "???";
	}
}

253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
/*
 * Decodes the jd_core_req flags and their real meanings
 * See mali_kbase_jd.c
 */
static inline const char *
ioctl_get_job_type_from_jd_core_req(mali_jd_core_req req)
{
	if (req & MALI_JD_REQ_SOFT_JOB)
		return "Soft job";
	if (req & MALI_JD_REQ_ONLY_COMPUTE)
		return "Compute Shader Job";

	switch (req & (MALI_JD_REQ_FS | MALI_JD_REQ_CS | MALI_JD_REQ_T)) {
	case MALI_JD_REQ_DEP:
		return "Dependency only job";
	case MALI_JD_REQ_FS:
		return "Fragment shader job";
	case MALI_JD_REQ_CS:
		return "Vertex/Geometry shader job";
	case MALI_JD_REQ_T:
		return "Tiler job";
	case (MALI_JD_REQ_FS | MALI_JD_REQ_CS):
		return "Fragment shader + vertex/geometry shader job";
	case (MALI_JD_REQ_FS | MALI_JD_REQ_T):
		return "Fragment shader + tiler job";
	case (MALI_JD_REQ_CS | MALI_JD_REQ_T):
		return "Vertex/geometry shader job + tiler job";
	case (MALI_JD_REQ_FS | MALI_JD_REQ_CS | MALI_JD_REQ_T):
		return "Fragment shader + vertex/geometry shader job + tiler job";
	}

	return "???";
}

287 288
#define SOFT_FLAG(flag)                                  \
	case MALI_JD_REQ_SOFT_##flag:                    \
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
289
		panwrap_log_cont("MALI_JD_REQ_%s", "SOFT_" #flag); \
290
		break
291
/* Decodes the actual jd_core_req flags, but not their meanings */
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
292
void
293 294 295
ioctl_log_decoded_jd_core_req(mali_jd_core_req req)
{
	if (req & MALI_JD_REQ_SOFT_JOB) {
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
296 297 298 299 300 301
		/* External resources are allowed in e.g. replay jobs */

		if (req & MALI_JD_REQ_EXTERNAL_RESOURCES) {
			panwrap_log_cont("MALI_JD_REQ_EXTERNAL_RESOURCES | ");
			req &= ~(MALI_JD_REQ_EXTERNAL_RESOURCES);
		}
302 303 304 305 306 307 308 309 310 311 312 313 314 315

		switch (req) {
		SOFT_FLAG(DUMP_CPU_GPU_TIME);
		SOFT_FLAG(FENCE_TRIGGER);
		SOFT_FLAG(FENCE_WAIT);
		SOFT_FLAG(REPLAY);
		SOFT_FLAG(EVENT_WAIT);
		SOFT_FLAG(EVENT_SET);
		SOFT_FLAG(EVENT_RESET);
		SOFT_FLAG(DEBUG_COPY);
		SOFT_FLAG(JIT_ALLOC);
		SOFT_FLAG(JIT_FREE);
		SOFT_FLAG(EXT_RES_MAP);
		SOFT_FLAG(EXT_RES_UNMAP);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
316
		default: panwrap_log_cont("0x%010x", req); break;
317 318
		}
	} else {
319
		panwrap_log_decoded_flags(jd_req_flag_info, req);
320 321 322 323
	}
}
#undef SOFT_FLAG

Lyude Paul's avatar
Lyude Paul committed
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
static void
do_dump_file(const char *name, int in, int out)
{
	unsigned char buf[4096];
	ssize_t in_ret, out_ret;

	do {
		in_ret = read(in, buf, sizeof(buf));
		if (in_ret < 0 && errno != EAGAIN) {
			fprintf(stderr, "Failed to read %s: %s\n",
				name, strerror(errno));
			abort();
		}

		out_ret = write(out, buf, in_ret);
		if (out_ret && out_ret != in_ret) {
			fprintf(stderr, "Failed to write %s: %s\n",
				name, strerror(errno));
			abort();
		}
	} while (in_ret > 0);
}

static void
348 349
dump_debugfs(unsigned int request) {
	const struct ioctl_info *ioc_info;
Lyude Paul's avatar
Lyude Paul committed
350 351 352 353 354 355 356 357 358 359 360 361
	int outd_fd,
	    mem_view_fd, mem_view_out_fd,
	    mem_profile_fd, mem_profile_out_fd,
	    atoms_fd, atoms_out_fd;
	char outd_name[PATH_MAX];
	struct timespec tp;
	int ret;

	if (dump_dir == NULL)
		return;

	if (context_id == 0) {
362
		panwrap_msg("Error! dump_debugfs() called but no context_id?\n");
Lyude Paul's avatar
Lyude Paul committed
363 364 365
		return;
	}

366 367
	ioc_info = ioctl_get_info(request);

Lyude Paul's avatar
Lyude Paul committed
368 369 370
	/* Create outd */
	panwrap_timestamp(&tp);
	snprintf(outd_name, sizeof(outd_name),
371
		 "%ld.%ld-%s", tp.tv_sec, tp.tv_nsec, ioc_info->name);
Lyude Paul's avatar
Lyude Paul committed
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387

	ret = mkdirat(dump_dir_fd, outd_name, 0777);
	if (ret < 0) {
		fprintf(stderr,
			"Error! Failed to create dump dir %s: %s\n",
			outd_name, strerror(errno));
		abort();
	}
	outd_fd = openat(dump_dir_fd, outd_name, O_DIRECTORY);
	if (outd_fd < 0) {
		fprintf(stderr,
			"Error! Failed to open dump dir %s: %s\n",
			outd_name, strerror(errno));
		abort();
	}

388
#define TRY_COPY(name)                                                \
Lyude Paul's avatar
Lyude Paul committed
389
	name ## _fd = openat(debugfs_fd, #name, O_RDONLY);            \
390 391 392 393 394
	if (name ## _fd < 0) {                                        \
		fprintf(stderr, "Error: Failed to open %s: %s\n",     \
                        #name, strerror(errno));                      \
		abort();                                              \
	}                                                             \
Lyude Paul's avatar
Lyude Paul committed
395
	name ## _out_fd = openat(outd_fd, #name, O_WRONLY | O_CREAT); \
396 397 398 399 400 401 402 403
	if (name ## _out_fd < 0) {                                    \
		fprintf(stderr, "Error: Failed to create %s: %s\n",   \
                        #name, strerror(errno));                      \
		abort();                                              \
	}                                                             \
                                                                      \
	do_dump_file(#name, name ## _fd, name ## _out_fd);            \
	close(name ## _fd);                                           \
Lyude Paul's avatar
Lyude Paul committed
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
	close(name ## _out_fd);

	TRY_COPY(mem_view);
	TRY_COPY(atoms);

	/* mem_profile doesn't always exist! */
	mem_profile_fd = openat(debugfs_fd, "mem_profile",
				O_RDONLY | O_NONBLOCK);
	if (mem_profile_fd > 0) {
		mem_profile_out_fd = openat(outd_fd,
					    "mem_profile",
					    O_WRONLY | O_NONBLOCK | O_CREAT);
		if (mem_profile_out_fd < 0) {
			fprintf(stderr, "Error: Failed to create mem_profile: %s\n",
				strerror(errno));
			abort();
		}

422 423
		do_dump_file("mem_profile", mem_profile_fd, mem_profile_out_fd);

Lyude Paul's avatar
Lyude Paul committed
424 425 426 427 428 429 430
		close(mem_profile_fd);
		close(mem_profile_out_fd);
	}

	close(outd_fd);
}

431 432 433 434 435 436 437 438 439
static inline void
ioctl_decode_pre_get_version(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_get_version *args = ptr;

	panwrap_prop("major = %3d", args->major);
	panwrap_prop("minor = %3d", args->minor);
}

440
static inline void
441 442 443 444
ioctl_decode_pre_mem_alloc(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_alloc *args = ptr;

445 446 447
	panwrap_prop("va_pages = %" PRId64, args->va_pages);
	panwrap_prop("commit_pages = %" PRId64, args->commit_pages);
	panwrap_prop("extent = 0x%" PRIx64, args->extent);
448

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
449
	/* XXX: Caching can be helpful... */
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
450
	panwrap_log(".flags = ");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
451
	panwrap_log_decoded_flags(mem_flag_info, args->flags & ~MALI_MEM_CACHED_CPU);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
452
	panwrap_log_cont(",\n");
453 454
}

455
static inline void
456 457 458
ioctl_decode_pre_mem_import(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_import *args = ptr;
459

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
460 461 462
	/* Imports afaik are just used for framebuffers, so we'll emit an allocation for that here */
	panwrap_prop("phandle = (uint64_t) (uintptr_t) &framebuffer_handle");
	panwrap_prop("type = MALI_MEM_IMPORT_TYPE_USER_BUFFER");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
463 464 465 466

	panwrap_log(".flags = ");
	panwrap_log_decoded_flags(mem_flag_info, args->flags);
	panwrap_log_cont(",\n");
467 468
}

469
static inline void
470 471 472 473
ioctl_decode_pre_mem_commit(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_commit *args = ptr;

474 475
	panwrap_prop("gpu_addr = " MALI_PTR_FMT, args->gpu_addr);
	panwrap_prop("pages = %" PRId64, args->pages);
476 477
}

478
static inline void
479 480 481 482 483 484 485 486 487 488 489 490
ioctl_decode_pre_mem_query(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_query *args = ptr;
	char *query_name;

	switch (args->query) {
	case MALI_MEM_QUERY_COMMIT_SIZE: query_name = "Commit size"; break;
	case MALI_MEM_QUERY_VA_SIZE:     query_name = "VA size"; break;
	case MALI_MEM_QUERY_FLAGS:       query_name = "Flags"; break;
	default:                         query_name = "???"; break;
	}

491 492
	panwrap_prop("gpu_addr = " MALI_PTR_FMT, args->gpu_addr);
	panwrap_prop("query = %d (%s)", args->query, query_name);
493 494
}

495
static inline void
496 497 498 499
ioctl_decode_pre_mem_free(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_free *args = ptr;

500
	panwrap_prop("gpu_addr = " MALI_PTR_FMT, args->gpu_addr);
501 502
}

503
static inline void
504 505 506 507
ioctl_decode_pre_mem_flags_change(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_flags_change *args = ptr;

508
	panwrap_prop("gpu_va = " MALI_PTR_FMT, args->gpu_va);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
509
	panwrap_log(".flags = ");
510
	panwrap_log_decoded_flags(mem_flag_info, args->flags);
511
	panwrap_log_cont("\n");
512
	panwrap_prop("mask = 0x%" PRIx64, args->mask);
513 514
}

515
static inline void
516 517 518 519
ioctl_decode_pre_mem_alias(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_alias *args = ptr;

520
	panwrap_prop("flags = ");
521
	panwrap_log_decoded_flags(mem_flag_info, args->flags);
522
	panwrap_log_cont("\n");
523 524 525
	panwrap_prop("stride = %" PRId64, args->stride);
	panwrap_prop("nents = %" PRId64, args->nents);
	panwrap_prop("ai = 0x%" PRIx64, args->ai);
526 527
}

528
static inline void
529 530 531
ioctl_decode_pre_sync(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_sync *args = ptr;
532
	struct panwrap_mapped_memory *mem =
533
		panwrap_find_mapped_gpu_mem(args->handle);
534

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
535
	panwrap_prop("size = %" PRId64, args->size);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
536

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
537 538 539 540 541 542 543
	if (!mem) {
		panwrap_msg("ERROR! Unknown handle specified\n");
		panwrap_prop("handle = " MALI_PTR_FMT, args->handle);
		panwrap_prop("user_addr = %p", args->user_addr);
		return;
	}

544 545 546
	char *a = pointer_as_memory_reference(mem->gpu_va);
	panwrap_prop("handle = %s", a);
	free(a);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
547

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
548
	panwrap_prop("user_addr = %s + %d", mem->name, args->user_addr - mem->addr);
549

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
550
	panwrap_prop("type = %s", args->type == MALI_SYNC_TO_DEVICE ? "MALI_SYNC_TO_DEVICE" : "MALI_SYNC_TO_CPU");
551 552
}

553
static inline void
554 555 556 557
ioctl_decode_pre_set_flags(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_set_flags *args = ptr;

558
	panwrap_prop("create_flags = %08x", args->create_flags);
559 560
}

561 562
static int stream_count = 0;

563 564 565 566 567
static inline void
ioctl_decode_pre_stream_create(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_stream_create *args = ptr;

568 569 570
	/* Stream name is not semantic as far as I know, but the blob allocates
	 * them nondeterministically. Patch over this here for repro. */

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
571
	panwrap_prop("name = \"stream_%d\"", stream_count++);
572 573
}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
574 575 576 577 578 579 580 581
static int job_count = 0;

static void emit_atoms(void *ptr) {
	const struct mali_ioctl_job_submit *args = ptr;
	const struct mali_jd_atom_v2 *atoms = args->addr;

	int job_no = job_count++;

582 583 584
	int job_numbers[256] = { 0 };
	//assert(args->nr_atoms < 256); /* XXX */

585 586 587
	for (int i = 0; i < args->nr_atoms; i++) {
		const struct mali_jd_atom_v2 *a = &atoms[i];

588
		if (a->jc) {
589 590 591
			int req = a->core_req | a->compat_core_req;

			if (!(req & MALI_JD_REQ_SOFT_JOB))
592
				job_numbers[i] = panwrap_replay_jc(a->jc);
593
			else if (req & MALI_JD_REQ_SOFT_REPLAY)
594
				job_numbers[i] = panwrap_replay_soft_replay(a->jc);
595
		}
596 597
	}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
598 599 600 601
	for (int i = 0; i < args->nr_atoms; i++) {
		const struct mali_jd_atom_v2 *a = &atoms[i];

		if (a->ext_res_list) {
602
			panwrap_log("mali_external_resource resources_%d_%d[] = {\n", job_no, i);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
603 604 605
			panwrap_indent++;

			for (int j = 0; j < a->nr_ext_res; j++) {
606
				/* Substitute in our framebuffer (TODO: what about other kinds of extres?) */
607
				panwrap_log("framebuffer_va | MALI_EXT_RES_ACCESS_EXCLUSIVE,\n");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
608 609 610
			}

			panwrap_indent--;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
611
			panwrap_log("};\n\n");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
612 613 614 615

		}
	}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
616
	panwrap_log("struct mali_jd_atom_v2 atoms_%d[] = {\n", job_no);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
617 618 619 620 621 622 623 624
	panwrap_indent++;

	for (int i = 0; i < args->nr_atoms; i++) {
		const struct mali_jd_atom_v2 *a = &atoms[i];

		panwrap_log("{\n");
		panwrap_indent++;

625
		panwrap_prop("jc = job_%d_p", job_numbers[i]);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
626

627 628
		/* Don't passthrough udata; it's nondeterministic and for userspace use only */

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
629 630
		panwrap_prop("nr_ext_res = %d", a->nr_ext_res);

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
631
		if (a->ext_res_list)
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
632 633
			panwrap_prop("ext_res_list = resources_%d_%d", job_no, i);

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
634 635
		if (a->compat_core_req)
			panwrap_prop("compat_core_req = 0x%x", a->compat_core_req);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
636 637 638 639

		panwrap_log(".pre_dep = {\n");
		panwrap_indent++;
		for (int j = 0; j < ARRAY_SIZE(a->pre_dep); j++) {
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
640 641 642
			if (a->pre_dep[i].dependency_type || a->pre_dep[i].atom_id)
				panwrap_log("{ .atom_id = %d, .dependency_type = %d },\n",
					    a->pre_dep[i].atom_id, a->pre_dep[i].dependency_type);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
643 644 645 646
		}
		panwrap_indent--;
		panwrap_log("},\n");

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
647 648 649
		/* TODO: Compute atom numbers dynamically and correctly */
		panwrap_prop("atom_number = %d + %d*%s", a->atom_number, 3, "i");

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
650 651 652
		panwrap_prop("prio = %d", a->prio);
		panwrap_prop("device_nr = %d", a->device_nr);

653 654 655 656 657 658
		/* XXX This probably breaks replay on new kernels XXX */
		if (!a->compat_core_req) {
			panwrap_log(".compat_core_req = ");
			ioctl_log_decoded_jd_core_req(a->core_req);
			panwrap_log_cont("\n");
		}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
659 660 661 662 663 664 665

		panwrap_indent--;
		panwrap_log("},\n");

	}

	panwrap_indent--;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
666
	panwrap_log("};\n\n");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
667 668
}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
669 670 671 672 673 674 675 676
static inline void
ioctl_decode_pre_job_submit(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_job_submit *args = ptr;
	const struct mali_jd_atom_v2 *atoms = args->addr;

	dump_debugfs(request);

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
677
	panwrap_prop("addr = atoms_%d", job_count - 1); /* XXX */
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
678 679 680 681 682 683 684 685 686 687 688 689 690
	panwrap_prop("nr_atoms = %d", args->nr_atoms);
	panwrap_prop("stride = %d", args->stride);

	/* The stride should be equivalent to the length of the structure,
	 * if it isn't then it's possible we're somehow tracing one of the
	 * legacy job formats
	 */
	if (args->stride != sizeof(*atoms)) {
		panwrap_msg("SIZE MISMATCH (stride should be %zd, was %d)\n",
			    sizeof(*atoms), args->stride);
		panwrap_msg("Cannot dump atoms :(, maybe it's a legacy job format?\n");
		return;
	}
691 692
}

693
static inline void
694 695
ioctl_decode_pre(unsigned long int request, void *ptr)
{
Lyude's avatar
Lyude committed
696
	switch (IOCTL_CASE(request)) {
697 698 699
	case IOCTL_CASE(MALI_IOCTL_GET_VERSION):
		ioctl_decode_pre_get_version(request, ptr);
		break;
Lyude's avatar
Lyude committed
700
	case IOCTL_CASE(MALI_IOCTL_MEM_ALLOC):
701 702
		ioctl_decode_pre_mem_alloc(request, ptr);
		break;
Lyude's avatar
Lyude committed
703
	case IOCTL_CASE(MALI_IOCTL_MEM_IMPORT):
704 705
		ioctl_decode_pre_mem_import(request, ptr);
		break;
Lyude's avatar
Lyude committed
706
	case IOCTL_CASE(MALI_IOCTL_MEM_COMMIT):
707 708
		ioctl_decode_pre_mem_commit(request, ptr);
		break;
Lyude's avatar
Lyude committed
709
	case IOCTL_CASE(MALI_IOCTL_MEM_QUERY):
710 711
		ioctl_decode_pre_mem_query(request, ptr);
		break;
Lyude's avatar
Lyude committed
712
	case IOCTL_CASE(MALI_IOCTL_MEM_FREE):
713 714
		ioctl_decode_pre_mem_free(request, ptr);
		break;
Lyude's avatar
Lyude committed
715
	case IOCTL_CASE(MALI_IOCTL_MEM_FLAGS_CHANGE):
716 717
		ioctl_decode_pre_mem_flags_change(request, ptr);
		break;
Lyude's avatar
Lyude committed
718
	case IOCTL_CASE(MALI_IOCTL_MEM_ALIAS):
719 720
		ioctl_decode_pre_mem_alias(request, ptr);
		break;
721 722 723
	case IOCTL_CASE(MALI_IOCTL_SYNC):
		ioctl_decode_pre_sync(request, ptr);
		break;
Lyude's avatar
Lyude committed
724
	case IOCTL_CASE(MALI_IOCTL_SET_FLAGS):
725 726
		ioctl_decode_pre_set_flags(request, ptr);
		break;
727 728 729 730 731 732
	case IOCTL_CASE(MALI_IOCTL_STREAM_CREATE):
		ioctl_decode_pre_stream_create(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_JOB_SUBMIT):
		ioctl_decode_pre_job_submit(request, ptr);
		break;
733 734 735 736 737
	default:
		break;
	}
}

738 739
#define PRINT_IF_NO(text, value) if (!value) panwrap_log("%s present? No\n", text);

740
static inline void
741 742 743 744 745 746 747 748 749 750 751 752
ioctl_decode_post_gpu_props_reg_dump(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_gpu_props_reg_dump *args = ptr;
	const char *implementation;

	switch (args->thread.impl_tech) {
	case MALI_GPU_IMPLEMENTATION_UNKNOWN: implementation = "Unknown"; break;
	case MALI_GPU_IMPLEMENTATION_SILICON: implementation = "Silicon"; break;
	case MALI_GPU_IMPLEMENTATION_FPGA:    implementation = "FPGA"; break;
	case MALI_GPU_IMPLEMENTATION_SW:      implementation = "Software"; break;
	}

753 754 755 756 757 758
	panwrap_log("core:\n");
	panwrap_indent++;
	panwrap_log("Product ID: %d\n", args->core.product_id);
	panwrap_log("Version status: %d\n", args->core.version_status);
	panwrap_log("Minor revision: %d\n", args->core.minor_revision);
	panwrap_log("Major revision: %d\n", args->core.major_revision);
759 760
	panwrap_log("Current GPU clock rate: %dMHz\n", args->core.gpu_speed_mhz);
	panwrap_log("GPU clock range: %dKHz-%dKHz\n",
761
		    args->core.gpu_freq_khz_min, args->core.gpu_freq_khz_max);
762
	panwrap_log("Shader program counter size: %.lf MB\n",
763 764
		    pow(2, args->core.log2_program_counter_size) / 1024 / 1024);

765 766
	panwrap_log("Texture features:\n");
	panwrap_indent++;
767
	for (int i = 0; i < ARRAY_SIZE(args->core.texture_features); i++)
768 769
		panwrap_log("%010x\n", args->core.texture_features[i]);
	panwrap_indent--;
770

771
	panwrap_log("Available memory: %" PRId64 " bytes\n",
772
		    args->core.gpu_available_memory_size);
773
	panwrap_indent--;
774

775 776 777
	panwrap_log("L2 cache:\n");
	panwrap_indent++;
	panwrap_log("Line size: %.lf (bytes, words?)\n",
778
		    pow(2, args->l2.log2_line_size));
779
	panwrap_log("Cache size: %.lf KB\n",
780
		    pow(2, args->l2.log2_cache_size) / 1024);
781 782
	panwrap_log("Associativity: %d\n", (args->raw.l2_features & 0xFF00) >> 8);
	panwrap_log("External bus width: %d\n", (args->raw.l2_features & 0xFF000000) >> 24);
783 784
	panwrap_log("L2 slice count: %d\n", args->l2.num_l2_slices);
	panwrap_indent--;
785

786 787 788
	panwrap_log("Tiler:\n");
	panwrap_indent++;
	panwrap_log("Binary size: %d bytes\n",
789
		    args->tiler.bin_size_bytes);
790
	panwrap_log("Max active levels: %d\n",
791
		    args->tiler.max_active_levels);
792
	panwrap_indent--;
793

794 795 796 797
	panwrap_log("Threads:\n");
	panwrap_indent++;
	panwrap_log("Max threads: %d\n", args->thread.max_threads);
	panwrap_log("Max threads per workgroup: %d\n",
798
		    args->thread.max_workgroup_size);
799
	panwrap_log("Max threads allowed for synchronizing on simple barrier: %d\n",
800
		    args->thread.max_barrier_size);
801
	panwrap_log("Max registers available per-core: %d\n",
802
		    args->thread.max_registers);
803
	panwrap_log("Max tasks that can be sent to a core before blocking: %d\n",
804
		    args->thread.max_task_queue);
805
	panwrap_log("Max allowed thread group split value: %d\n",
806
		    args->thread.max_thread_group_split);
807
	panwrap_log("Implementation type: %d (%s)\n",
808
		    args->thread.impl_tech, implementation);
809
	panwrap_indent--;
810

811 812 813 814
	panwrap_log("Raw props:\n");

	panwrap_indent++;

815 816 817 818 819
	/* Generally, these should be present, so be optimistic */

	PRINT_IF_NO("Shader", args->raw.shader_present);
	PRINT_IF_NO("Tiler", args->raw.tiler_present);
	PRINT_IF_NO("L2", args->raw.l2_present);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
820 821
	PRINT_IF_NO("Address spaces", args->raw.as_present);
	PRINT_IF_NO("Job slots", args->raw.js_present);
822 823
	PRINT_IF_NO("Stack", args->raw.stack_present);

824
	panwrap_log("Suspend size: %d\n", args->raw.suspend_size);
825

826 827 828 829
	/* As far as we know, these features are fully decoded, with the other
	 * bits being zeroes. Just in case, dump them if something non-zero
	 * comes up in the alleged "reserved" fields */

830 831 832
	if (args->raw.l2_features & (~0xFFFFFFFF))
		panwrap_log("L2 features (undecoded) : 0x%010x\n", args->raw.l2_features & (~0xFFFFFFFF));

833 834 835 836 837 838
	if (args->raw.thread_features & (~0xFFFFFFFF))
		panwrap_log("Thread features (undecoded): 0x%x\n", args->raw.thread_features);

	if (args->raw.mmu_features & ~(0xFFFF))
		panwrap_log("MMU features (undecoded): %d\n", args->raw.mmu_features & ~(0xFFFF));

839 840
	if (args->raw.mem_features & (~1) & (~(((1 << 5) - 1) << 8)))
		panwrap_log("Memory features: 0x%010x\n", args->raw.mem_features & (~1) & (~(((1 << 5) - 1) << 8)));
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
841 842 843 844 845 846 847

	panwrap_log("MMU features:\n");
	panwrap_indent++;
	panwrap_log("Virtual address bits: %d\n", args->raw.mmu_features & 0x00FF);
	panwrap_log("Physical address bits: %d\n", (args->raw.mmu_features & 0xFF00) >> 8);
	panwrap_indent--;

848
	panwrap_log("Job slot features:\n");
849 850

	panwrap_indent++;
851
	for (int i = 0; i < ARRAY_SIZE(args->raw.js_features); i++)
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
852 853 854 855 856
		if (args->raw.js_features[i]) {
			panwrap_log("Slot %d: ", i);
			panwrap_log_decoded_flags(js_feature_info, args->raw.js_features[i]);
			panwrap_log_cont("\n");
		}
857
	panwrap_indent--;
858

859 860 861 862 863
	/* Bit field -- the other values are extracted above */
	int leftover_tiler = args->raw.tiler_features & ~((1 << 7) - 1) & ~(((1 << 5) - 1) << 8);

	if (leftover_tiler)
		panwrap_log("Tiler features (undecoded): %010x\n", leftover_tiler);
864

865 866
	panwrap_log("GPU ID: 0x%x\n", args->raw.gpu_id);
	panwrap_log("Coherency mode: 0x%x (%s)\n",
867 868 869
		    args->raw.coherency_mode,
		    ioctl_decode_coherency_mode(args->raw.coherency_mode));

870 871 872 873 874 875
	panwrap_indent--;

	panwrap_log("Coherency info:\n");
	panwrap_indent++;
	panwrap_log("Number of groups: %d\n", args->coherency_info.num_groups);
	panwrap_log("Number of core groups (coherent or not): %d\n",
876
		    args->coherency_info.num_core_groups);
877 878 879
	panwrap_log("Features: 0x%x\n", args->coherency_info.coherency);
	panwrap_log("Groups:\n");
	panwrap_indent++;
880
	for (int i = 0; i < args->coherency_info.num_groups; i++) {
881
		panwrap_log("- Core mask: %010" PRIx64 "\n",
882
			    args->coherency_info.group[i].core_mask);
883
		panwrap_log("  Number of cores: %d\n",
884
			    args->coherency_info.group[i].num_cores);
885
	}
886 887
	panwrap_indent--;
	panwrap_indent--;
888 889
}

890 891 892
/**
 * Overriden libc functions start here
 */
893 894
static inline int
panwrap_open_wrap(open_func *func, const char *path, int flags, va_list args)
895 896 897 898 899 900
{
	mode_t mode = 0;
	int ret;

	if (flags & O_CREAT) {
		mode = (mode_t) va_arg(args, int);
901
		ret = func(path, flags, mode);
902
	} else {
903
		ret = func(path, flags);
904 905 906
	}

	LOCK();
Lyude Paul's avatar
Lyude Paul committed
907
	msleep(log_delay);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
908 909
	if (ret != -1 && strcmp(path, "/dev/mali0") == 0)
		mali_fd = ret;
910 911 912 913 914
	UNLOCK();

	return ret;
}

915
//#ifdef IS_OPEN64_SEPERATE_SYMBOL
916 917 918 919 920 921 922 923 924 925
int
open(const char *path, int flags, ...)
{
	PROLOG(open);
	va_list args;
	va_start(args, flags);
	int o = panwrap_open_wrap(orig_open, path, flags, args);
	va_end(args);
	return o;
}
926
//#endif
927 928 929 930 931 932 933 934 935 936 937 938

int
open64(const char *path, int flags, ...)
{
	PROLOG(open64);
	va_list args;
	va_start(args, flags);
	int o = panwrap_open_wrap(orig_open64, path, flags, args);
	va_end(args);
	return o;
}

939 940 941 942 943
int
close(int fd)
{
	PROLOG(close);

944 945 946 947 948
        /* Intentionally racy: prevents us from trying to hold the global mutex
         * in calls from system libraries */
        if (fd <= 0 || !mali_fd || fd != mali_fd)
                return orig_close(fd);

949
	LOCK();
Lyude Paul's avatar
Lyude Paul committed
950
	msleep(log_delay);
951
	if (!fd || fd != mali_fd) {
952
		panwrap_log("/dev/mali0 closed\n");
953 954 955 956 957 958 959
		mali_fd = 0;
	}
	UNLOCK();

	return orig_close(fd);
}

960 961 962
static char *panwrap_lower_string(const char *str)
{
	char *out = (char *) malloc(strlen(str) + 1);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
963

964 965 966 967 968 969 970 971 972 973 974 975
	for (int i = 0; i < strlen(str); ++i)
		out[i] = tolower(str[i]);

	out[strlen(str)] = 0;

	return out;
}

/* Global count of ioctls, for replay purposes */

static int ioctl_count = 0;

976 977 978 979
/* XXX: Android has a messed up ioctl signature */
int ioctl(int fd, int request, ...)
{
	const char *name;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
980 981
	char *lname;
	int number;
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
	union mali_ioctl_header *header;
	PROLOG(ioctl);
	int ioc_size = _IOC_SIZE(request);
	int ret;
	void *ptr;

	if (ioc_size) {
		va_list args;

		va_start(args, request);
		ptr = va_arg(args, void *);
		va_end(args);
	} else {
		ptr = NULL;
	}

	if (fd && fd != mali_fd)
		return orig_ioctl(fd, request, ptr);

	LOCK();
Lyude Paul's avatar
Lyude Paul committed
1002
	msleep(log_delay);
Lyude's avatar
Lyude committed
1003
	name = ioctl_get_info(request)->name ?: "???";
1004 1005
	header = ptr;

Alyssa Rosenzweig's avatar
Fixes  
Alyssa Rosenzweig committed
1006 1007 1008
	bool ignore = false;

	/* Race condition... */
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1009
	if (!panwrap_indent)
Alyssa Rosenzweig's avatar
Fixes  
Alyssa Rosenzweig committed
1010 1011 1012 1013 1014 1015
		ignore = true;

	/* Queries are not interesting for replay */
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_MEM_QUERY))
		ignore = true;

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1016 1017 1018
	/* Neither is debugfs nonsense */
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_DEBUGFS_MEM_PROFILE_ADD))
		ignore = true;
1019 1020
	
	/* Syncs -are-, but we disable caching */
1021
#if 0
1022 1023
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_SYNC))
		ignore = true;
1024
#endif
1025
	
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1026 1027
	lname = panwrap_lower_string(name);
	number = ioctl_count++;
1028

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1029 1030 1031 1032 1033 1034
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_JOB_SUBMIT)) {
		panwrap_log("for (int i = 0; i < 30; ++i) {\n");
		panwrap_indent++;
		emit_atoms(ptr);
		replay_memory();
	}
1035

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1036 1037 1038 1039 1040 1041 1042
	/* TODO: Is there a better way to handle framebuffers in replay? */
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_MEM_IMPORT)) {
		panwrap_log("uint32_t *framebuffer;\n");
		panwrap_log("posix_memalign((void **) &framebuffer, CACHE_LINE_SIZE, 4096*4096*4);\n");
		panwrap_log("slowfb_init((uint8_t*) (framebuffer + %d), 400, 320);\n", 144); /* XXX: Magic experimentally determined offset */
		panwrap_log("struct mali_mem_import_user_buffer framebuffer_handle = { .ptr = (uint64_t) (uintptr_t) framebuffer, .length = 4096*4096*4 };\n");
	}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1043

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1044 1045 1046
	/* For certain special cases of ioctls, we can use our own functions */
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_MEM_ALLOC)) {
		const struct mali_ioctl_mem_alloc *args = ptr;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1047

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1048
		panwrap_log("u64 alloc_gpu_va_%d;\n", number);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1049

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1050 1051 1052 1053
		if (args->va_pages == args->commit_pages && !args->extent)
			panwrap_log("pandev_standard_allocate(fd, %" PRId64 ", ", args->va_pages);
		else
			panwrap_log("pandev_general_allocate(fd, %" PRId64 ", %" PRId64", %" PRId64 ", ", args->va_pages, args->commit_pages, args->extent);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1054

1055
		panwrap_log_decoded_flags(mem_flag_info, args->flags);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1056
		panwrap_log_cont(", &alloc_gpu_va_%d);\n", number);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1057

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1058
		ignore = true;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1059
	}
1060

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1061 1062 1063
	if (!ignore) {
		panwrap_log("struct mali_ioctl_%s %s_%d = {\n", lname, lname, number);
		panwrap_indent++;
Alyssa Rosenzweig's avatar
Fixes  
Alyssa Rosenzweig committed
1064
		ioctl_decode_pre(request, ptr);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1065
	}
1066 1067 1068

	ret = orig_ioctl(fd, request, ptr);

1069 1070 1071 1072 1073 1074 1075
	/* Close up the struct */

	if (!ignore) {
		panwrap_indent--;
		panwrap_log("};\n\n");
	}

1076
	/* Track memory allocation if needed  */
1077 1078 1079
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_MEM_ALLOC)) {
		const struct mali_ioctl_mem_alloc *args = ptr;

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1080
		panwrap_track_allocation(args->gpu_va, args->flags, number, args->va_pages * 4096);
1081 1082
	}

1083 1084 1085 1086 1087
	/* Replay synced memory if that's an issue */
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_SYNC)) {
		const struct mali_ioctl_sync *args = ptr;

		if (args->type == MALI_SYNC_TO_DEVICE) {
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1088 1089 1090 1091 1092 1093
			struct panwrap_mapped_memory *mem = panwrap_find_mapped_mem_containing(args->user_addr);

			if (mem)
				replay_memory_specific(mem, args->user_addr - mem->addr, args->size);
			else
				panwrap_msg("Bad synced memory\n");
1094 1095 1096 1097
		}
	}

	/* Call the actual ioctl */
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1098 1099 1100 1101
	if (!ignore) {
		panwrap_log("rc = pandev_ioctl(fd, MALI_IOCTL_%s, &%s_%d);\n", name, lname, number);
		panwrap_log("if (rc) printf(\"Error %%d in %s_%d\\n\", rc);\n\n", name, number);
	}
Alyssa Rosenzweig's avatar
Fixup  
Alyssa Rosenzweig committed
1102

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1103 1104 1105 1106
	/* Setup framebuffer (part II) */
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_MEM_IMPORT)) {
		panwrap_log("uint64_t framebuffer_va = %s_%d.gpu_va;\n", lname, number);
	}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1107

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1108 1109 1110 1111 1112 1113 1114
	/* Dump the framebuffer :D */
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_JOB_SUBMIT)) {
		panwrap_log("slowfb_update((uint8_t*) framebuffer, 400, 320);\n");
		
		/* We have to acknowledge events from the kernel for
		 * atoms to be released correctly, or else we'll hang
		 * after a few seconds of drawing (255 atom max) */
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1115

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1116 1117
		panwrap_log("uint8_t kernel_events[128];\n");
		panwrap_log("read(fd, kernel_events, 128);\n");
1118

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1119 1120
		panwrap_indent--;
		panwrap_log("}\n");
1121 1122
	}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1123
	free(lname);
1124

Lyude Paul's avatar
Lyude Paul committed
1125 1126 1127 1128 1129
	if (step_mode) {
		panwrap_log("Paused, hit enter to continue\n");
		panwrap_log_flush();
		getchar();
	}
1130 1131 1132 1133
out:
	UNLOCK();
	return ret;
}
Lyude's avatar
Lyude committed
1134 1135 1136

static void inline *panwrap_mmap_wrap(mmap_func *func,
				      void *addr, size_t length, int prot,
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1137
				      int flags, int fd, loff_t offset)
Lyude's avatar
Lyude committed
1138 1139 1140 1141 1142 1143 1144
{
	void *ret;

	if (!mali_fd || fd != mali_fd)
		return func(addr, length, prot, flags, fd, offset);

	LOCK();
Lyude Paul's avatar
Lyude Paul committed
1145
	msleep(log_delay);
Lyude's avatar
Lyude committed
1146 1147
	ret = func(addr, length, prot, flags, fd, offset);

1148 1149
	switch (offset) { /* offset == gpu_va */
	case MALI_MEM_MAP_TRACKING_HANDLE:
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1150 1151
		panwrap_log("pandev_map_mtp(fd);\n");
		panwrap_log("\n");
1152 1153 1154 1155 1156
		break;
	default:
		panwrap_track_mmap(offset, ret, length, prot, flags);
		break;
	}
1157

Lyude's avatar
Lyude committed
1158 1159 1160 1161
	UNLOCK();
	return ret;
}

1162
void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
1163
	     loff_t offset)
Lyude's avatar
Lyude committed
1164
{
1165
	PROLOG(mmap64);
Lyude's avatar
Lyude committed
1166

1167
	return panwrap_mmap_wrap(orig_mmap64, addr, length, prot, flags, fd,
Lyude's avatar
Lyude committed
1168 1169 1170
				 offset);
}

1171
//#ifdef IS_MMAP64_SEPERATE_SYMBOL
1172
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
Lyude's avatar
Lyude committed
1173
{
1174
#ifdef __LP64__
1175
	PROLOG(mmap);
Lyude's avatar
Lyude committed
1176

1177
	return panwrap_mmap_wrap(orig_mmap, addr, length, prot, flags, fd,
Lyude's avatar
Lyude committed
1178
				 offset);
1179 1180 1181
#else
	return mmap64(addr, length, prot, flags, fd, (loff_t) offset);
#endif
Lyude's avatar
Lyude committed
1182
}
1183
//#endif
Lyude's avatar
Lyude committed
1184 1185 1186 1187

int munmap(void *addr, size_t length)
{
	int ret;
1188
	struct panwrap_mapped_memory *mem;
Lyude's avatar
Lyude committed
1189 1190
	PROLOG(munmap);

Lyude Paul's avatar
Lyude Paul committed
1191 1192 1193
	if (!mali_fd)
		return orig_munmap(addr, length);

Lyude's avatar
Lyude committed
1194 1195
	LOCK();
	ret = orig_munmap(addr, length);
1196
	mem = panwrap_find_mapped_mem(addr);
Lyude's avatar
Lyude committed
1197 1198 1199
	if (!mem)
		goto out;

Lyude Paul's avatar
Lyude Paul committed
1200 1201
	msleep(log_delay);

1202 1203
	list_del(&mem->node);
	free(mem);
Lyude's avatar
Lyude committed
1204 1205 1206 1207
out:
	UNLOCK();
	return ret;
}