From b93820a7a76e8e2f37335cdb4e3f9074ced6415a Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Aug 2014 15:49:06 +0100 Subject: Add support to permit mapping memory with protection info The standard galcore user memory mapping function fails when asked to map read-only memory, such as X shmem buffers. The reason these fail is because get_user_pages() is always attempted with "write" mode enabled, which is not permissible with read-only mappings. To allow this to work (so that Xv can be implemented efficiently) we must be able to map read-only buffers. This adds an extension to etnaviv, found in my Dove galcore driver and Jon Nettleton's iMX6 kernels which permit this without changing the existing galcore APIs. Signed-off-by: Russell King --- src/etnaviv/etna_bo.c | 18 ++++++++++++++++++ src/etnaviv/etna_bo.h | 3 +++ src/etnaviv/viv.c | 29 +++++++++++++++++++++++++++++ src/etnaviv/viv.h | 5 +++++ 4 files changed, 55 insertions(+) diff --git a/src/etnaviv/etna_bo.c b/src/etnaviv/etna_bo.c index ea5248b..010b62a 100644 --- a/src/etnaviv/etna_bo.c +++ b/src/etnaviv/etna_bo.c @@ -232,6 +232,24 @@ struct etna_bo* etna_bo_new(struct viv_conn *conn, size_t bytes, uint32_t flags) return mem; } +struct etna_bo *etna_bo_from_usermem_prot(struct viv_conn *conn, void *memory, size_t size, int prot) +{ + struct etna_bo *mem = ETNA_CALLOC_STRUCT(etna_bo); + if(mem == NULL) return NULL; + + mem->bo_type = ETNA_BO_TYPE_USERMEM; + mem->logical = memory; + mem->size = size; + + if(viv_map_user_memory_prot(conn, memory, size, prot, &mem->usermem_info, &mem->address)!=0) + { + ETNA_FREE(mem); + return NULL; + } + + return mem; +} + struct etna_bo *etna_bo_from_usermem(struct viv_conn *conn, void *memory, size_t size) { struct etna_bo *mem = ETNA_CALLOC_STRUCT(etna_bo); diff --git a/src/etnaviv/etna_bo.h b/src/etnaviv/etna_bo.h index a4f1024..ad5bffb 100644 --- a/src/etnaviv/etna_bo.h +++ b/src/etnaviv/etna_bo.h @@ -62,6 +62,9 @@ struct etna_bo; /* Allocate linear block of video memory */ struct etna_bo *etna_bo_new(struct viv_conn *conn, size_t bytes, uint32_t flags); +/* Map user memory (which may be write protected) into GPU memory space */ +struct etna_bo *etna_bo_from_usermem_prot(struct viv_conn *conn, void *memory, size_t size, int prot); + /* Map user memory into GPU memory space */ struct etna_bo *etna_bo_from_usermem(struct viv_conn *conn, void *memory, size_t size); diff --git a/src/etnaviv/viv.c b/src/etnaviv/viv.c index b3f6225..f476a47 100644 --- a/src/etnaviv/viv.c +++ b/src/etnaviv/viv.c @@ -70,6 +70,17 @@ struct viv_dmabuf_map { }; #define IOC_GDMABUF_MAP _IOWR('_', 0, struct viv_dmabuf_map) +/* rmk's extension for mapping read-only memory (X shmem buffers) */ +struct viv_membuf_map { + union rmk_gcabi_header hdr; + uint64_t info; + uint64_t address; + uint64_t virt; + uint32_t size; + uint32_t prot; +}; +#define IOC_GMEMBUF_MAP _IOWR('_', 1, struct viv_membuf_map) + const char *galcore_device[] = {"/dev/gal3d", "/dev/galcore", "/dev/graphics/galcore", NULL}; #define INTERFACE_SIZE (sizeof(gcsHAL_INTERFACE)) @@ -616,6 +627,24 @@ int viv_map_dmabuf(struct viv_conn *conn, int fd, viv_usermem_t *info, viv_addr_ return VIV_STATUS_OK; } +int viv_map_user_memory_prot(struct viv_conn *conn, void *memory, size_t size, int prot, viv_usermem_t *info, viv_addr_t *address) +{ + struct viv_membuf_map map = { +#ifdef GCABI_HAS_HARDWARE_TYPE + .hdr.v4.hwtype = (gceHARDWARE_TYPE)conn->hw_type, +#endif + .virt = (uintptr_t)memory, + .size = size, + .prot = prot, + }; + int ret = viv_ioctl(conn, IOC_GMEMBUF_MAP, &map, sizeof(map)); + if(ret < 0 || map.hdr.v4.status) + return -1; + *info = VIV_TO_HANDLE(map.info); + *address = map.address; + return VIV_STATUS_OK; +} + int viv_map_user_memory(struct viv_conn *conn, void *memory, size_t size, viv_usermem_t *info, viv_addr_t *address) { gcsHAL_INTERFACE id = { diff --git a/src/etnaviv/viv.h b/src/etnaviv/viv.h index ec044f5..4496840 100644 --- a/src/etnaviv/viv.h +++ b/src/etnaviv/viv.h @@ -268,6 +268,11 @@ int viv_free_contiguous(struct viv_conn *conn, size_t bytes, viv_addr_t physical */ int viv_map_dmabuf(struct viv_conn *conn, int fd, viv_usermem_t *info, viv_addr_t *address, int prot); +/** Map user memory to GPU memory, allowing for read/write protections. + * Note: GPU is not protected against reads/writes. + */ +int viv_map_user_memory_prot(struct viv_conn *conn, void *memory, size_t size, int prot, viv_usermem_t *info, viv_addr_t *address); + /** Map user memory to GPU memory. */ int viv_map_user_memory(struct viv_conn *conn, void *memory, size_t size, viv_usermem_t *info, viv_addr_t *address); -- cgit