1/*
2 * Copyright (C) 2008 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 <limits.h>
18#include <errno.h>
19#include <pthread.h>
20#include <unistd.h>
21#include <string.h>
22#include <stdarg.h>
23
24#include <sys/mman.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <sys/ioctl.h>
28
29#include <cutils/log.h>
30#include <cutils/atomic.h>
31
32#include <hardware/hardware.h>
33#include <hardware/gralloc.h>
34
35#include <linux/android_pmem.h>
36
37#include "gralloc_priv.h"
38
39
40// we need this for now because pmem cannot mmap at an offset
41#define PMEM_HACK   1
42
43/* desktop Linux needs a little help with gettid() */
44#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)
45#define __KERNEL__
46# include <linux/unistd.h>
47pid_t gettid() { return syscall(__NR_gettid);}
48#undef __KERNEL__
49#endif
50
51/*****************************************************************************/
52
53static int gralloc_map(gralloc_module_t const* module,
54        buffer_handle_t handle,
55        void** vaddr)
56{
57    private_handle_t* hnd = (private_handle_t*)handle;
58    if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
59        size_t size = hnd->size;
60#if PMEM_HACK
61        size += hnd->offset;
62#endif
63        void* mappedAddress = mmap(0, size,
64                PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
65        if (mappedAddress == MAP_FAILED) {
66            ALOGE("Could not mmap handle %p, fd=%d (%s)",
67                    handle, hnd->fd, strerror(errno));
68            hnd->base = 0;
69            return -errno;
70        }
71        hnd->base = intptr_t(mappedAddress) + hnd->offset;
72        //ALOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
73        //        hnd->fd, hnd->offset, hnd->size, mappedAddress);
74    }
75    *vaddr = (void*)hnd->base;
76    return 0;
77}
78
79static int gralloc_unmap(gralloc_module_t const* module,
80        buffer_handle_t handle)
81{
82    private_handle_t* hnd = (private_handle_t*)handle;
83    if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
84        void* base = (void*)hnd->base;
85        size_t size = hnd->size;
86#if PMEM_HACK
87        base = (void*)(intptr_t(base) - hnd->offset);
88        size += hnd->offset;
89#endif
90        //ALOGD("unmapping from %p, size=%d", base, size);
91        if (munmap(base, size) < 0) {
92            ALOGE("Could not unmap %s", strerror(errno));
93        }
94    }
95    hnd->base = 0;
96    return 0;
97}
98
99/*****************************************************************************/
100
101static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER;
102
103/*****************************************************************************/
104
105int gralloc_register_buffer(gralloc_module_t const* module,
106        buffer_handle_t handle)
107{
108    if (private_handle_t::validate(handle) < 0)
109        return -EINVAL;
110
111    // In this implementation, we don't need to do anything here
112
113    /* NOTE: we need to initialize the buffer as not mapped/not locked
114     * because it shouldn't when this function is called the first time
115     * in a new process. Ideally these flags shouldn't be part of the
116     * handle, but instead maintained in the kernel or at least
117     * out-of-line
118     */
119
120    // if this handle was created in this process, then we keep it as is.
121    private_handle_t* hnd = (private_handle_t*)handle;
122    if (hnd->pid != getpid()) {
123        hnd->base = 0;
124        hnd->lockState  = 0;
125        hnd->writeOwner = 0;
126    }
127    return 0;
128}
129
130int gralloc_unregister_buffer(gralloc_module_t const* module,
131        buffer_handle_t handle)
132{
133    if (private_handle_t::validate(handle) < 0)
134        return -EINVAL;
135
136    /*
137     * If the buffer has been mapped during a lock operation, it's time
138     * to un-map it. It's an error to be here with a locked buffer.
139     * NOTE: the framebuffer is handled differently and is never unmapped.
140     */
141
142    private_handle_t* hnd = (private_handle_t*)handle;
143
144    ALOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
145            "[unregister] handle %p still locked (state=%08x)",
146            hnd, hnd->lockState);
147
148    // never unmap buffers that were created in this process
149    if (hnd->pid != getpid()) {
150        if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
151            gralloc_unmap(module, handle);
152        }
153        hnd->base = 0;
154        hnd->lockState  = 0;
155        hnd->writeOwner = 0;
156    }
157    return 0;
158}
159
160int terminateBuffer(gralloc_module_t const* module,
161        private_handle_t* hnd)
162{
163    /*
164     * If the buffer has been mapped during a lock operation, it's time
165     * to un-map it. It's an error to be here with a locked buffer.
166     */
167
168    ALOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
169            "[terminate] handle %p still locked (state=%08x)",
170            hnd, hnd->lockState);
171
172    if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
173        // this buffer was mapped, unmap it now
174        if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) ||
175            (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)) {
176            if (hnd->pid != getpid()) {
177                // ... unless it's a "master" pmem buffer, that is a buffer
178                // mapped in the process it's been allocated.
179                // (see gralloc_alloc_buffer())
180                gralloc_unmap(module, hnd);
181            }
182        } else {
183            gralloc_unmap(module, hnd);
184        }
185    }
186
187    return 0;
188}
189
190int gralloc_lock(gralloc_module_t const* module,
191        buffer_handle_t handle, int usage,
192        int l, int t, int w, int h,
193        void** vaddr)
194{
195    if (private_handle_t::validate(handle) < 0)
196        return -EINVAL;
197
198    int err = 0;
199    private_handle_t* hnd = (private_handle_t*)handle;
200    int32_t current_value, new_value;
201    int retry;
202
203    do {
204        current_value = hnd->lockState;
205        new_value = current_value;
206
207        if (current_value & private_handle_t::LOCK_STATE_WRITE) {
208            // already locked for write
209            ALOGE("handle %p already locked for write", handle);
210            return -EBUSY;
211        } else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) {
212            // already locked for read
213            if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
214                ALOGE("handle %p already locked for read", handle);
215                return -EBUSY;
216            } else {
217                // this is not an error
218                //ALOGD("%p already locked for read... count = %d",
219                //        handle, (current_value & ~(1<<31)));
220            }
221        }
222
223        // not currently locked
224        if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
225            // locking for write
226            new_value |= private_handle_t::LOCK_STATE_WRITE;
227        }
228        new_value++;
229
230        retry = android_atomic_cmpxchg(current_value, new_value,
231                (volatile int32_t*)&hnd->lockState);
232    } while (retry);
233
234    if (new_value & private_handle_t::LOCK_STATE_WRITE) {
235        // locking for write, store the tid
236        hnd->writeOwner = gettid();
237    }
238
239    // if requesting sw write for non-framebuffer handles, flag for
240    // flushing at unlock
241
242    const uint32_t pmemMask =
243            private_handle_t::PRIV_FLAGS_USES_PMEM |
244            private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
245
246    if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) &&
247            (hnd->flags & pmemMask) &&
248            !(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
249        hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
250    }
251
252    if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
253        if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) {
254            // we need to map for real
255            pthread_mutex_t* const lock = &sMapLock;
256            pthread_mutex_lock(lock);
257            if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) {
258                err = gralloc_map(module, handle, vaddr);
259                if (err == 0) {
260                    android_atomic_or(private_handle_t::LOCK_STATE_MAPPED,
261                            (volatile int32_t*)&(hnd->lockState));
262                }
263            }
264            pthread_mutex_unlock(lock);
265        }
266        *vaddr = (void*)hnd->base;
267    }
268
269    return err;
270}
271
272int gralloc_unlock(gralloc_module_t const* module,
273        buffer_handle_t handle)
274{
275    if (private_handle_t::validate(handle) < 0)
276        return -EINVAL;
277
278    private_handle_t* hnd = (private_handle_t*)handle;
279    int32_t current_value, new_value;
280
281    if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) {
282        struct pmem_region region;
283        int err;
284
285        region.offset = hnd->offset;
286        region.len = hnd->size;
287        err = ioctl(hnd->fd, PMEM_CACHE_FLUSH, &region);
288        ALOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x)\n",
289                hnd, hnd->offset, hnd->size);
290        hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
291    }
292
293    do {
294        current_value = hnd->lockState;
295        new_value = current_value;
296
297        if (current_value & private_handle_t::LOCK_STATE_WRITE) {
298            // locked for write
299            if (hnd->writeOwner == gettid()) {
300                hnd->writeOwner = 0;
301                new_value &= ~private_handle_t::LOCK_STATE_WRITE;
302            }
303        }
304
305        if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) {
306            ALOGE("handle %p not locked", handle);
307            return -EINVAL;
308        }
309
310        new_value--;
311
312    } while (android_atomic_cmpxchg(current_value, new_value,
313            (volatile int32_t*)&hnd->lockState));
314
315    return 0;
316}
317
318/*****************************************************************************/
319
320int gralloc_perform(struct gralloc_module_t const* module,
321        int operation, ... )
322{
323    int res = -EINVAL;
324    return res;
325}
326