1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "gralloc_vsoc_priv.h" 18 19 #include <unistd.h> 20 #include <string.h> 21 #include <sys/mman.h> 22 23 #include <cutils/hashmap.h> 24 #include <hardware/gralloc.h> 25 #include <hardware/hardware.h> 26 #include <log/log.h> 27 28 namespace { 29 30 const size_t g_page_size = sysconf(_SC_PAGESIZE); 31 32 struct HmLockGuard { 33 HmLockGuard(Hashmap* map) : map_(map) { 34 hashmapLock(map_); 35 } 36 ~HmLockGuard() { 37 hashmapUnlock(map_); 38 } 39 private: 40 Hashmap* map_; 41 }; 42 43 int offset_hash(void* key) { 44 return *reinterpret_cast<int*>(key); 45 } 46 47 bool offset_equals(void* key1, void* key2) { 48 return *reinterpret_cast<int*>(key1) == 49 *reinterpret_cast<int*>(key2); 50 } 51 52 // Keeps track of how many times a buffer is locked in the current process. 53 struct GrallocBuffer { 54 void* vaddr; 55 int ref_count; 56 GrallocBuffer() : vaddr(NULL), ref_count(0) {} 57 58 static Hashmap* mapped_buffers() { 59 static Hashmap* mapped_buffers = 60 hashmapCreate(19, offset_hash, offset_equals); 61 return mapped_buffers; 62 } 63 }; 64 65 } 66 67 void* reference_buffer(const vsoc_buffer_handle_t* hnd) { 68 Hashmap* map = GrallocBuffer::mapped_buffers(); 69 HmLockGuard lock_guard(map); 70 GrallocBuffer* buffer = reinterpret_cast<GrallocBuffer*>( 71 hashmapGet(map, const_cast<int*>(&hnd->offset))); 72 if (!buffer) { 73 buffer = new GrallocBuffer(); 74 hashmapPut(map, const_cast<int*>(&hnd->offset), buffer); 75 } 76 77 if (!buffer->vaddr) { 78 void* mapped = 79 mmap(NULL, hnd->size, PROT_READ | PROT_WRITE, MAP_SHARED, hnd->fd, 0); 80 if (mapped == MAP_FAILED) { 81 ALOGE("Unable to map buffer (offset: %d, size: %d): %s", 82 hnd->offset, 83 hnd->size, 84 strerror(errno)); 85 return NULL; 86 } 87 // Set up the guard pages. The last page is always a guard 88 uintptr_t base = uintptr_t(mapped); 89 uintptr_t addr = base + hnd->size - g_page_size; 90 if (mprotect((void*)addr, g_page_size, PROT_NONE) == -1) { 91 ALOGW("Unable to protect last page of buffer (offset: %d, size: %d): %s", 92 hnd->offset, 93 hnd->size, 94 strerror(errno)); 95 } 96 buffer->vaddr = mapped; 97 } 98 buffer->ref_count++; 99 return buffer->vaddr; 100 } 101 102 int unreference_buffer(const vsoc_buffer_handle_t* hnd) { 103 int result = 0; 104 Hashmap* map = GrallocBuffer::mapped_buffers(); 105 HmLockGuard lock_guard(map); 106 GrallocBuffer* buffer = reinterpret_cast<GrallocBuffer*>( 107 hashmapGet(map, const_cast<int*>(&hnd->offset))); 108 if (!buffer) { 109 ALOGE("Unreferencing an unknown buffer (offset: %d, size: %d)", 110 hnd->offset, 111 hnd->size); 112 return -EINVAL; 113 } 114 if (buffer->ref_count == 0) { 115 ALOGE("Unbalanced reference/unreference on buffer (offset: %d, size: %d)", 116 hnd->offset, 117 hnd->size); 118 return -EINVAL; 119 } 120 buffer->ref_count--; 121 if (buffer->ref_count == 0) { 122 result = munmap(buffer->vaddr, hnd->size); 123 if (result) { 124 ALOGE("Unable to unmap buffer (offset: %d, size: %d): %s", 125 hnd->offset, 126 hnd->size, 127 strerror(errno)); 128 } 129 buffer->vaddr = NULL; 130 } 131 return result; 132 } 133