blob: e9ba2ebfc860f6466380c9311cdb1c68e757c524 [file] [log] [blame]
Cody Schuffelen134ff032019-11-22 00:25:32 -08001/*
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
28namespace {
29
30const size_t g_page_size = sysconf(_SC_PAGESIZE);
31
32struct HmLockGuard {
33 HmLockGuard(Hashmap* map) : map_(map) {
34 hashmapLock(map_);
35 }
36 ~HmLockGuard() {
37 hashmapUnlock(map_);
38 }
39 private:
40 Hashmap* map_;
41};
42
43int offset_hash(void* key) {
44 return *reinterpret_cast<int*>(key);
45}
46
47bool 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.
53struct 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
67void* 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
102int 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}