panwrap-syscall.c 7.04 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>
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
33
#include <mali-props.h>
Lyude's avatar
Lyude committed
34
#include <list.h>
35 36
#include "panwrap.h"

37
static pthread_mutex_t l;
Alyssa 'Not HdkR' Rosenzweig's avatar
Squash  
Alyssa 'Not HdkR' Rosenzweig committed
38
static void __attribute__((constructor)) panloader_constructor(void) {
39 40 41 42 43 44 45
	pthread_mutexattr_t mattr;

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

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

struct ioctl_info {
	const char *name;
};

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

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

Lyude's avatar
Lyude committed
62 63
#define IOCTL_TYPE(type) [type - MALI_IOCTL_TYPE_BASE] =
#define IOCTL_INFO(n) [_IOC_NR(MALI_IOCTL_##n)] = { .name = #n }
64 65
static struct device_info mali_info = {
	.name = "mali",
Lyude's avatar
Lyude committed
66 67 68
	.info = {
		IOCTL_TYPE(0x80) {
			IOCTL_INFO(GET_VERSION),
69
#ifndef dvalin
Lyude's avatar
Lyude committed
70 71
		},
		IOCTL_TYPE(0x82) {
72
#endif
Lyude's avatar
Lyude committed
73 74 75 76 77 78 79 80
			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),
81
#ifndef dvalin
Lyude's avatar
Lyude committed
82 83
			IOCTL_INFO(GPU_PROPS_REG_DUMP),
			IOCTL_INFO(GET_VERSION_NEW),
84
#endif
Lyude's avatar
Lyude committed
85 86
			IOCTL_INFO(JOB_SUBMIT),
		},
87 88 89
	},
};
#undef IOCTL_INFO
Lyude's avatar
Lyude committed
90
#undef IOCTL_TYPE
91

Lyude's avatar
Lyude committed
92 93
static inline const struct ioctl_info *
ioctl_get_info(unsigned long int request)
94
{
Lyude's avatar
Lyude committed
95 96
	return &mali_info.info[_IOC_TYPE(request) - MALI_IOCTL_TYPE_BASE]
	                      [_IOC_NR(request)];
97 98
}

Lyude's avatar
Lyude committed
99
static int mali_fd = 0;
Lyude's avatar
Lyude committed
100 101
static LIST_HEAD(allocations);
static LIST_HEAD(mmaps);
Lyude's avatar
Lyude committed
102

Lyude Paul's avatar
Lyude Paul committed
103
#define LOCK()   pthread_mutex_lock(&l);
Alyssa 'Not HdkR' Rosenzweig's avatar
Cleanup  
Alyssa 'Not HdkR' Rosenzweig committed
104
#define UNLOCK() pthread_mutex_unlock(&l)
Lyude Paul's avatar
Lyude Paul committed
105

106 107 108
/**
 * Overriden libc functions start here
 */
109 110
static inline int
panwrap_open_wrap(open_func *func, const char *path, int flags, va_list args)
111 112 113 114 115 116
{
	mode_t mode = 0;
	int ret;

	if (flags & O_CREAT) {
		mode = (mode_t) va_arg(args, int);
117
		ret = func(path, flags, mode);
118
	} else {
119
		ret = func(path, flags);
120 121 122
	}

	LOCK();
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
123 124
	if (ret != -1 && strcmp(path, "/dev/mali0") == 0)
		mali_fd = ret;
125 126 127 128 129
	UNLOCK();

	return ret;
}

130
//#ifdef IS_OPEN64_SEPERATE_SYMBOL
131 132 133 134 135 136 137 138 139 140
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;
}
141
//#endif
142 143 144 145 146 147 148 149 150 151 152 153

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;
}

154 155 156 157 158
int
close(int fd)
{
	PROLOG(close);

159 160 161 162 163
        /* 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);

164
	LOCK();
165
	if (!fd || fd != mali_fd) {
166 167 168 169 170 171 172
		mali_fd = 0;
	}
	UNLOCK();

	return orig_close(fd);
}

173 174
/* HW version */
static bool bifrost = false;
Alyssa 'Not HdkR' Rosenzweig's avatar
Cont  
Alyssa 'Not HdkR' Rosenzweig committed
175
int allocation_number = 0;
Alyssa 'Not HdkR' Rosenzweig's avatar
Dump JS  
Alyssa 'Not HdkR' Rosenzweig committed
176
extern FILE * log_output;
177

178
/* XXX: Android has a messed up ioctl signature */
179
int ioctl(int fd, int _request, ...)
180 181
{
	PROLOG(ioctl);
182
	unsigned long int request = _request;
183 184 185 186
	int ioc_size = _IOC_SIZE(request);
	int ret;
	void *ptr;

187 188 189 190 191
#ifdef dvalin
	if (request & 0x0F00)
		ioc_size = 1;
#endif

192 193 194
	if (ioc_size) {
		va_list args;

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
195
		va_start(args, _request);
196 197 198 199 200 201 202 203 204 205
		ptr = va_arg(args, void *);
		va_end(args);
	} else {
		ptr = NULL;
	}

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

	LOCK();
206

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
207
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_JOB_SUBMIT)) {
Alyssa 'Not HdkR' Rosenzweig's avatar
Dump JS  
Alyssa 'Not HdkR' Rosenzweig committed
208 209 210 211 212
		const struct mali_ioctl_job_submit *js = ptr;

		struct mali_jd_atom_v2 *atoms = js->addr;
		for (unsigned i = 0; i < js->nr_atoms; ++i) {
			unsigned core_req = atoms[i].core_req | atoms[i].compat_core_req;
Alyssa 'Not HdkR' Rosenzweig's avatar
Cleanup  
Alyssa 'Not HdkR' Rosenzweig committed
213
			fprintf(log_output, "JS %" PRIx64 " %X %d\n", atoms[i].jc, core_req, bifrost);
Alyssa 'Not HdkR' Rosenzweig's avatar
Dump JS  
Alyssa 'Not HdkR' Rosenzweig committed
214 215
		}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
216 217
		replay_memory();
	}
218

219 220 221 222 223 224 225 226 227 228 229 230
	mali_ptr alloc_va_pages = 0;

	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_MEM_ALLOC)) {
		const union mali_ioctl_mem_alloc *args = ptr;

#ifdef dvalin
		alloc_va_pages = args->in.va_pages;
#else
		alloc_va_pages = args->inout.va_pages;
#endif
	}

231 232
	ret = orig_ioctl(fd, request, ptr);

233
	/* Track memory allocation if needed  */
234
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_MEM_ALLOC)) {
235 236 237 238 239 240 241 242 243
		const union mali_ioctl_mem_alloc *args = ptr;

#ifdef dvalin
		mali_ptr va = args->out.gpu_va;
		u64 flags = args->out.flags;
#else
		mali_ptr va = args->inout.gpu_va;
		u64 flags = args->inout.flags;
#endif
244

245
		panwrap_track_allocation(va, flags, allocation_number++, alloc_va_pages * 4096);
246 247
	}

248
#ifndef dvalin
249 250 251 252 253 254 255
	if (IOCTL_CASE(request) == IOCTL_CASE(MALI_IOCTL_GPU_PROPS_REG_DUMP)) {
		const struct mali_ioctl_gpu_props_reg_dump *dump = ptr;
		unsigned product_id = dump->core.product_id;
		/* based on mali_kbase_gpu_id.h and mali_kbase_hw.c */
		if (product_id >> 12 == 6 && product_id != 0x6956 /* T60x */)
			bifrost = true;
	}
256 257 258
#else
	bifrost = true;
#endif
259

260 261 262
	UNLOCK();
	return ret;
}
Lyude's avatar
Lyude committed
263

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
264
static inline void *panwrap_mmap_wrap(mmap_func *func,
Lyude's avatar
Lyude committed
265
				      void *addr, size_t length, int prot,
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
266
				      int flags, int fd, loff_t offset)
Lyude's avatar
Lyude committed
267 268 269 270 271 272 273 274 275
{
	void *ret;

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

	LOCK();
	ret = func(addr, length, prot, flags, fd, offset);

276 277 278 279 280 281 282
	switch (offset) { /* offset == gpu_va */
	case MALI_MEM_MAP_TRACKING_HANDLE:
		break;
	default:
		panwrap_track_mmap(offset, ret, length, prot, flags);
		break;
	}
283

Lyude's avatar
Lyude committed
284 285 286 287
	UNLOCK();
	return ret;
}

288
void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
289
	     loff_t offset)
Lyude's avatar
Lyude committed
290
{
291
	PROLOG(mmap64);
Lyude's avatar
Lyude committed
292

293
	return panwrap_mmap_wrap(orig_mmap64, addr, length, prot, flags, fd,
Lyude's avatar
Lyude committed
294 295 296
				 offset);
}

297
//#ifdef IS_MMAP64_SEPERATE_SYMBOL
298
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
Lyude's avatar
Lyude committed
299
{
300
#ifdef __LP64__
301
	PROLOG(mmap);
Lyude's avatar
Lyude committed
302

303
	return panwrap_mmap_wrap(orig_mmap, addr, length, prot, flags, fd,
Lyude's avatar
Lyude committed
304
				 offset);
305 306 307
#else
	return mmap64(addr, length, prot, flags, fd, (loff_t) offset);
#endif
Lyude's avatar
Lyude committed
308
}
309
//#endif
Lyude's avatar
Lyude committed
310 311 312 313

int munmap(void *addr, size_t length)
{
	int ret;
314
	struct panwrap_mapped_memory *mem;
Lyude's avatar
Lyude committed
315 316
	PROLOG(munmap);

Lyude Paul's avatar
Lyude Paul committed
317 318 319
	if (!mali_fd)
		return orig_munmap(addr, length);

Lyude's avatar
Lyude committed
320 321
	LOCK();
	ret = orig_munmap(addr, length);
322
	mem = panwrap_find_mapped_mem(addr);
Lyude's avatar
Lyude committed
323 324 325
	if (!mem)
		goto out;

326 327
	list_del(&mem->node);
	free(mem);
Lyude's avatar
Lyude committed
328 329 330 331
out:
	UNLOCK();
	return ret;
}