| /* |
| * Copyright (C) 2016-2020 ARM Limited. All rights reserved. |
| * |
| * Copyright (C) 2008 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 ATRACE_TAG ATRACE_TAG_GRAPHICS |
| |
| #include <string.h> |
| #include <errno.h> |
| #include <inttypes.h> |
| #include <pthread.h> |
| #include <stdlib.h> |
| #include <limits.h> |
| |
| #include <log/log.h> |
| #include <cutils/atomic.h> |
| #include <utils/Trace.h> |
| |
| #include <linux/dma-buf.h> |
| #include <vector> |
| #include <sys/ioctl.h> |
| |
| #include <hardware/hardware.h> |
| #include <hardware/gralloc1.h> |
| |
| #include <BufferAllocator/BufferAllocator.h> |
| #include "mali_gralloc_buffer.h" |
| #include "gralloc_helper.h" |
| #include "mali_gralloc_formats.h" |
| #include "mali_gralloc_usages.h" |
| #include "core/format_info.h" |
| #include "core/mali_gralloc_bufferdescriptor.h" |
| #include "core/mali_gralloc_bufferallocation.h" |
| |
| #include "mali_gralloc_ion.h" |
| |
| #include <array> |
| #include <cassert> |
| #include <string> |
| |
| static const char kDmabufSensorDirectHeapName[] = "sensor_direct_heap"; |
| static const char kDmabufFaceauthTpuHeapName[] = "faceauth_tpu-secure"; |
| static const char kDmabufFaceauthImgHeapName[] = "faimg-secure"; |
| static const char kDmabufFaceauthRawImgHeapName[] = "farawimg-secure"; |
| static const char kDmabufFaceauthPrevHeapName[] = "faprev-secure"; |
| static const char kDmabufFaceauthModelHeapName[] = "famodel-secure"; |
| static const char kDmabufVframeSecureHeapName[] = "vframe-secure"; |
| static const char kDmabufVstreamSecureHeapName[] = "vstream-secure"; |
| static const char kDmabufVscalerSecureHeapName[] = "vscaler-secure"; |
| static const char kDmabufFramebufferSecureHeapName[] = "framebuffer-secure"; |
| static const char kDmabufGcmaCameraHeapName[] = "gcma_camera"; |
| static const char kDmabufGcmaCameraUncachedHeapName[] = "gcma_camera-uncached"; |
| |
| BufferAllocator& get_allocator() { |
| static BufferAllocator allocator; |
| return allocator; |
| } |
| |
| std::string find_first_available_heap(const std::initializer_list<std::string>&& options) { |
| static auto available_heaps = BufferAllocator::GetDmabufHeapList(); |
| |
| for (const auto& heap: options) |
| if (available_heaps.find(heap) != available_heaps.end()) |
| return heap; |
| |
| return ""; |
| } |
| |
| std::string select_dmabuf_heap(uint64_t usage) |
| { |
| struct HeapSpecifier |
| { |
| uint64_t usage_bits; |
| std::string name; |
| }; |
| |
| static const std::array<HeapSpecifier, 7> exact_usage_heaps = |
| {{ |
| // Faceauth heaps |
| { // isp_image_heap |
| GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_CAMERA_WRITE | GS101_GRALLOC_USAGE_TPU_INPUT, |
| kDmabufFaceauthImgHeapName |
| }, |
| { // isp_internal_heap |
| GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_CAMERA_WRITE | GRALLOC_USAGE_HW_CAMERA_READ, |
| kDmabufFaceauthRawImgHeapName |
| }, |
| { // isp_preview_heap |
| GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_CAMERA_WRITE | GRALLOC_USAGE_HW_COMPOSER | |
| GRALLOC_USAGE_HW_TEXTURE, |
| kDmabufFaceauthPrevHeapName |
| }, |
| { // ml_model_heap |
| GRALLOC_USAGE_PROTECTED | GS101_GRALLOC_USAGE_TPU_INPUT, |
| kDmabufFaceauthModelHeapName |
| }, |
| { // tpu_heap |
| GRALLOC_USAGE_PROTECTED | GS101_GRALLOC_USAGE_TPU_OUTPUT | GS101_GRALLOC_USAGE_TPU_INPUT, |
| kDmabufFaceauthTpuHeapName |
| }, |
| |
| { |
| GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER | |
| GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB, |
| find_first_available_heap({kDmabufFramebufferSecureHeapName, kDmabufVframeSecureHeapName}) |
| }, |
| |
| { |
| GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER | |
| GRALLOC_USAGE_HW_COMPOSER, |
| find_first_available_heap({kDmabufFramebufferSecureHeapName, kDmabufVframeSecureHeapName}) |
| }, |
| }}; |
| |
| static const std::array<HeapSpecifier, 8> inexact_usage_heaps = |
| {{ |
| // If GPU, use vframe-secure |
| { |
| GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_TEXTURE, |
| kDmabufVframeSecureHeapName |
| }, |
| { |
| GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_RENDER, |
| kDmabufVframeSecureHeapName |
| }, |
| |
| // If HWC but not GPU |
| { |
| GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_COMPOSER, |
| kDmabufVscalerSecureHeapName |
| }, |
| |
| // Catchall for protected |
| { |
| GRALLOC_USAGE_PROTECTED, |
| kDmabufVframeSecureHeapName |
| }, |
| |
| // Sensor heap |
| { |
| GRALLOC_USAGE_SENSOR_DIRECT_DATA, |
| kDmabufSensorDirectHeapName |
| }, |
| |
| // Camera GCMA heap |
| { |
| GRALLOC_USAGE_HW_CAMERA_WRITE, |
| find_first_available_heap({kDmabufGcmaCameraUncachedHeapName, kDmabufSystemUncachedHeapName}) |
| }, |
| |
| // Camera GCMA heap |
| { |
| GRALLOC_USAGE_HW_CAMERA_READ, |
| find_first_available_heap({kDmabufGcmaCameraUncachedHeapName, kDmabufSystemUncachedHeapName}) |
| }, |
| |
| // Catchall to system |
| { |
| 0, |
| kDmabufSystemUncachedHeapName |
| } |
| }}; |
| |
| for (const HeapSpecifier &heap : exact_usage_heaps) |
| { |
| if (usage == heap.usage_bits) |
| { |
| return heap.name; |
| } |
| } |
| |
| for (const HeapSpecifier &heap : inexact_usage_heaps) |
| { |
| if ((usage & heap.usage_bits) == heap.usage_bits) |
| { |
| if (heap.name == kDmabufGcmaCameraUncachedHeapName && |
| ((usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN)) |
| return kDmabufGcmaCameraHeapName; |
| else if (heap.name == kDmabufSystemUncachedHeapName && |
| ((usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN)) |
| return kDmabufSystemHeapName; |
| |
| return heap.name; |
| } |
| } |
| |
| return ""; |
| } |
| |
| int alloc_from_dmabuf_heap(uint64_t usage, size_t size, const std::string& buffer_name = "") |
| { |
| ATRACE_CALL(); |
| if (size == 0) { return -1; } |
| |
| auto heap_name = select_dmabuf_heap(usage); |
| if (heap_name.empty()) { |
| MALI_GRALLOC_LOGW("No heap found for usage: %s (0x%" PRIx64 ")", describe_usage(usage).c_str(), usage); |
| return -EINVAL; |
| } |
| |
| ATRACE_NAME(("alloc_from_dmabuf_heap " + heap_name).c_str()); |
| int shared_fd = get_allocator().Alloc(heap_name, size, 0); |
| if (shared_fd < 0) |
| { |
| ALOGE("Allocation failed for heap %s error: %d\n", heap_name.c_str(), shared_fd); |
| } |
| |
| if (!buffer_name.empty()) { |
| if (get_allocator().DmabufSetName(shared_fd, buffer_name)) { |
| ALOGW("Unable to set buffer name %s: %s", buffer_name.c_str(), strerror(errno)); |
| } |
| } |
| |
| return shared_fd; |
| } |
| |
| SyncType sync_type_for_flags(const bool read, const bool write) |
| { |
| if (read && !write) |
| { |
| return SyncType::kSyncRead; |
| } |
| else if (write && !read) |
| { |
| return SyncType::kSyncWrite; |
| } |
| else |
| { |
| // Deliberately also allowing "not sure" to map to ReadWrite. |
| return SyncType::kSyncReadWrite; |
| } |
| } |
| |
| int sync(const int fd, const bool read, const bool write, const bool start) |
| { |
| if (start) |
| { |
| return get_allocator().CpuSyncStart(fd, sync_type_for_flags(read, write)); |
| } |
| else |
| { |
| return get_allocator().CpuSyncEnd(fd, sync_type_for_flags(read, write)); |
| } |
| } |
| |
| int mali_gralloc_ion_sync(const private_handle_t * const hnd, |
| const bool read, |
| const bool write, |
| const bool start) |
| { |
| if (hnd == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| for (int i = 0; i < hnd->fd_count; i++) |
| { |
| const int fd = hnd->fds[i]; |
| if (const int ret = sync(fd, read, write, start)) |
| { |
| return ret; |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| int mali_gralloc_ion_sync_start(const private_handle_t * const hnd, |
| const bool read, |
| const bool write) |
| { |
| return mali_gralloc_ion_sync(hnd, read, write, true); |
| } |
| |
| |
| int mali_gralloc_ion_sync_end(const private_handle_t * const hnd, |
| const bool read, |
| const bool write) |
| { |
| return mali_gralloc_ion_sync(hnd, read, write, false); |
| } |
| |
| |
| void mali_gralloc_ion_free(private_handle_t * const hnd) |
| { |
| for (int i = 0; i < hnd->fd_count; i++) |
| { |
| close(hnd->fds[i]); |
| hnd->fds[i] = -1; |
| } |
| delete hnd; |
| } |
| |
| void mali_gralloc_ion_free_internal(buffer_handle_t * const pHandle, |
| const uint32_t num_hnds) |
| { |
| for (uint32_t i = 0; i < num_hnds; i++) |
| { |
| if (pHandle[i] != NULL) |
| { |
| private_handle_t * const hnd = (private_handle_t * const)pHandle[i]; |
| mali_gralloc_ion_free(hnd); |
| } |
| } |
| } |
| |
| int mali_gralloc_ion_allocate_attr(private_handle_t *hnd) |
| { |
| ATRACE_CALL(); |
| |
| int idx = hnd->get_share_attr_fd_index(); |
| uint64_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; |
| |
| hnd->fds[idx] = alloc_from_dmabuf_heap(usage, hnd->attr_size); |
| if (hnd->fds[idx] < 0) |
| { |
| MALI_GRALLOC_LOGE("ion_alloc failed"); |
| return -1; |
| } |
| |
| hnd->incr_numfds(1); |
| |
| return 0; |
| } |
| |
| /* |
| * Allocates ION buffers |
| * |
| * @param descriptors [in] Buffer request descriptors |
| * @param numDescriptors [in] Number of descriptors |
| * @param pHandle [out] Handle for each allocated buffer |
| * @param shared_backend [out] Shared buffers flag |
| * |
| * @return File handle which can be used for allocation, on success |
| * -1, otherwise. |
| */ |
| int mali_gralloc_ion_allocate(const gralloc_buffer_descriptor_t *descriptors, |
| uint32_t numDescriptors, buffer_handle_t *pHandle, |
| bool *shared_backend, int ion_fd) |
| { |
| ATRACE_CALL(); |
| GRALLOC_UNUSED(shared_backend); |
| |
| unsigned int priv_heap_flag = 0; |
| uint64_t usage; |
| uint32_t i; |
| |
| for (i = 0; i < numDescriptors; i++) |
| { |
| buffer_descriptor_t *bufDescriptor = reinterpret_cast<buffer_descriptor_t *>(descriptors[i]); |
| assert(bufDescriptor); |
| assert(bufDescriptor->fd_count >= 0); |
| assert(bufDescriptor->fd_count <= MAX_FDS); |
| |
| auto hnd = new private_handle_t( |
| priv_heap_flag, |
| bufDescriptor->alloc_sizes, |
| bufDescriptor->consumer_usage, bufDescriptor->producer_usage, |
| nullptr, bufDescriptor->fd_count, |
| bufDescriptor->hal_format, bufDescriptor->alloc_format, |
| bufDescriptor->width, bufDescriptor->height, bufDescriptor->pixel_stride, |
| bufDescriptor->layer_count, bufDescriptor->plane_info); |
| |
| /* Reset the number of valid filedescriptors, we will increment |
| * it each time a valid fd is added, so we can rely on the |
| * cleanup functions to close open fds. */ |
| hnd->set_numfds(0); |
| |
| if (nullptr == hnd) |
| { |
| MALI_GRALLOC_LOGE("Private handle could not be created for descriptor:%d in non-shared usecase", i); |
| mali_gralloc_ion_free_internal(pHandle, i); |
| return -1; |
| } |
| |
| pHandle[i] = hnd; |
| usage = bufDescriptor->consumer_usage | bufDescriptor->producer_usage; |
| |
| for (uint32_t fidx = 0; fidx < bufDescriptor->fd_count; fidx++) |
| { |
| int& fd = hnd->fds[fidx]; |
| |
| if (ion_fd >= 0 && fidx == 0) { |
| fd = ion_fd; |
| } else { |
| fd = alloc_from_dmabuf_heap(usage, bufDescriptor->alloc_sizes[fidx], bufDescriptor->name); |
| } |
| |
| if (fd < 0) |
| { |
| MALI_GRALLOC_LOGE("ion_alloc failed for fds[%u] = %d", fidx, fd); |
| mali_gralloc_ion_free_internal(pHandle, i + 1); |
| return -1; |
| } |
| |
| hnd->incr_numfds(1); |
| } |
| } |
| |
| #if defined(GRALLOC_INIT_AFBC) && (GRALLOC_INIT_AFBC == 1) |
| ATRACE_NAME("AFBC init block"); |
| unsigned char *cpu_ptr = NULL; |
| for (i = 0; i < numDescriptors; i++) |
| { |
| buffer_descriptor_t *bufDescriptor = reinterpret_cast<buffer_descriptor_t *>(descriptors[i]); |
| const private_handle_t *hnd = static_cast<const private_handle_t *>(pHandle[i]); |
| |
| usage = bufDescriptor->consumer_usage | bufDescriptor->producer_usage; |
| |
| if ((bufDescriptor->alloc_format & MALI_GRALLOC_INTFMT_AFBCENABLE_MASK) |
| && !(usage & GRALLOC_USAGE_PROTECTED)) |
| { |
| { |
| ATRACE_NAME("mmap"); |
| /* TODO: only map for AFBC buffers */ |
| cpu_ptr = |
| (unsigned char *)mmap(NULL, bufDescriptor->alloc_sizes[0], PROT_READ | PROT_WRITE, MAP_SHARED, hnd->fds[0], 0); |
| |
| if (MAP_FAILED == cpu_ptr) |
| { |
| MALI_GRALLOC_LOGE("mmap failed for fd ( %d )", hnd->fds[0]); |
| mali_gralloc_ion_free_internal(pHandle, numDescriptors); |
| return -1; |
| } |
| |
| mali_gralloc_ion_sync_start(hnd, true, true); |
| } |
| |
| { |
| ATRACE_NAME("data init"); |
| /* For separated plane YUV, there is a header to initialise per plane. */ |
| const plane_info_t *plane_info = bufDescriptor->plane_info; |
| assert(plane_info); |
| const bool is_multi_plane = hnd->is_multi_plane(); |
| for (int i = 0; i < MAX_PLANES && (i == 0 || plane_info[i].byte_stride != 0); i++) |
| { |
| init_afbc(cpu_ptr + plane_info[i].offset, |
| bufDescriptor->alloc_format, |
| is_multi_plane, |
| plane_info[i].alloc_width, |
| plane_info[i].alloc_height); |
| } |
| } |
| |
| { |
| ATRACE_NAME("munmap"); |
| mali_gralloc_ion_sync_end(hnd, true, true); |
| munmap(cpu_ptr, bufDescriptor->alloc_sizes[0]); |
| } |
| } |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| std::array<void*, MAX_BUFFER_FDS> mali_gralloc_ion_map(private_handle_t *hnd) |
| { |
| std::array<void*, MAX_BUFFER_FDS> vaddrs; |
| vaddrs.fill(nullptr); |
| |
| uint64_t usage = hnd->producer_usage | hnd->consumer_usage; |
| /* Do not allow cpu access to secure buffers */ |
| if (usage & (GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_NOZEROED) |
| && !(usage & GRALLOC_USAGE_PRIVATE_NONSECURE)) |
| { |
| return vaddrs; |
| } |
| |
| for (int fidx = 0; fidx < hnd->fd_count; fidx++) { |
| unsigned char *mappedAddress = |
| (unsigned char *)mmap(NULL, hnd->alloc_sizes[fidx], PROT_READ | PROT_WRITE, |
| MAP_SHARED, hnd->fds[fidx], 0); |
| |
| if (MAP_FAILED == mappedAddress) |
| { |
| int err = errno; |
| MALI_GRALLOC_LOGE("mmap( fds[%d]:%d size:%" PRIu64 " ) failed with %s", |
| fidx, hnd->fds[fidx], hnd->alloc_sizes[fidx], strerror(err)); |
| hnd->dump("map fail"); |
| |
| for (int cidx = 0; cidx < fidx; fidx++) |
| { |
| munmap((void*)vaddrs[cidx], hnd->alloc_sizes[cidx]); |
| vaddrs[cidx] = 0; |
| } |
| |
| return vaddrs; |
| } |
| |
| vaddrs[fidx] = mappedAddress; |
| } |
| |
| return vaddrs; |
| } |
| |
| void mali_gralloc_ion_unmap(private_handle_t *hnd, std::array<void*, MAX_BUFFER_FDS>& vaddrs) |
| { |
| for (int i = 0; i < hnd->fd_count; i++) |
| { |
| int err = 0; |
| |
| if (vaddrs[i]) |
| { |
| err = munmap(vaddrs[i], hnd->alloc_sizes[i]); |
| } |
| |
| if (err) |
| { |
| MALI_GRALLOC_LOGE("Could not munmap base:%p size:%" PRIu64 " '%s'", |
| (void*)vaddrs[i], hnd->alloc_sizes[i], strerror(errno)); |
| } |
| else |
| { |
| vaddrs[i] = 0; |
| } |
| } |
| |
| hnd->cpu_read = 0; |
| hnd->cpu_write = 0; |
| } |