summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamie Gennis <jgennis@google.com>2010-04-21 17:33:32 -0700
committerJamie Gennis <jgennis@google.com>2010-07-02 12:57:36 -0700
commitf5a83a9c024dee0617dbc3dab98cd307e8d54665 (patch)
tree54e0195eb8d3c43f1908aa76ddb59a26dec8b2b5
parente6b86f5c9a4e748421f10c47eade47aebd557bbd (diff)
downloadmsm7k-f5a83a9c024dee0617dbc3dab98cd307e8d54665.tar.gz
Refactor the qsd8k gralloc implementation.
The purpose of this change is to add support for allocating gralloc buffers from either /dev/pmem or /dev/pmem_adsp depending on the usage flags. It does this by factoring out and abstracting the interactions with the pmem device. For /dev/pmem allocations, the kernel allocator is not used, so a single master fd is opened, and all the allocations are sub-allocated from that by gralloc. For /dev/pmem_adsp the kernel allocator is used, so it simply opens a new fd for each allocation. A very basic unit test that can be run on the host is included. It requires gtest, so to run it on a host system gtest must (currently) be compiled with BUILD_WITH_ASTL=true. Change-Id: If2ae0151698fad8107e18e808a3fa012a846263f
-rw-r--r--libgralloc-qsd8k/Android.mk16
-rw-r--r--libgralloc-qsd8k/allocator.h13
-rw-r--r--libgralloc-qsd8k/gpu.cpp340
-rw-r--r--libgralloc-qsd8k/gpu.h76
-rw-r--r--libgralloc-qsd8k/gralloc.cpp484
-rw-r--r--libgralloc-qsd8k/gralloc_priv.h15
-rw-r--r--libgralloc-qsd8k/mapper.cpp3
-rw-r--r--libgralloc-qsd8k/pmemalloc.cpp324
-rw-r--r--libgralloc-qsd8k/pmemalloc.h161
-rw-r--r--libgralloc-qsd8k/tests/Android.mk55
-rw-r--r--libgralloc-qsd8k/tests/pmemalloc_test.cpp601
11 files changed, 1680 insertions, 408 deletions
diff --git a/libgralloc-qsd8k/Android.mk b/libgralloc-qsd8k/Android.mk
index d5ffa42..cc92d04 100644
--- a/libgralloc-qsd8k/Android.mk
+++ b/libgralloc-qsd8k/Android.mk
@@ -23,10 +23,22 @@ LOCAL_SHARED_LIBRARIES := liblog libcutils libGLESv1_CM
LOCAL_SRC_FILES := \
allocator.cpp \
- gralloc.cpp \
framebuffer.cpp \
- mapper.cpp
+ gpu.cpp \
+ gralloc.cpp \
+ mapper.cpp \
+ pmemalloc.cpp
LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM)
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\"
include $(BUILD_SHARED_LIBRARY)
+
+# Build a host library for testing
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ gpu.cpp \
+ pmemalloc.cpp
+
+LOCAL_MODULE := libgralloc_qsd8k_host
+LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc-qsd8k\"
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libgralloc-qsd8k/allocator.h b/libgralloc-qsd8k/allocator.h
index b0d89e9..dc81f51 100644
--- a/libgralloc-qsd8k/allocator.h
+++ b/libgralloc-qsd8k/allocator.h
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include "gr.h"
+#include "pmemalloc.h"
// ----------------------------------------------------------------------------
@@ -91,19 +92,19 @@ public:
}
};
-class SimpleBestFitAllocator
+class SimpleBestFitAllocator : public PmemUserspaceAllocator::Deps::Allocator
{
public:
SimpleBestFitAllocator();
SimpleBestFitAllocator(size_t size);
- ~SimpleBestFitAllocator();
+ virtual ~SimpleBestFitAllocator();
- ssize_t setSize(size_t size);
+ virtual ssize_t setSize(size_t size);
- ssize_t allocate(size_t size, uint32_t flags = 0);
- ssize_t deallocate(size_t offset);
- size_t size() const;
+ virtual ssize_t allocate(size_t size, uint32_t flags = 0);
+ virtual ssize_t deallocate(size_t offset);
+ virtual size_t size() const;
private:
struct chunk_t {
diff --git a/libgralloc-qsd8k/gpu.cpp b/libgralloc-qsd8k/gpu.cpp
new file mode 100644
index 0000000..2a2d6d5
--- /dev/null
+++ b/libgralloc-qsd8k/gpu.cpp
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/mman.h>
+
+#include "gr.h"
+#include "gpu.h"
+
+gpu_context_t::gpu_context_t(Deps& deps, PmemAllocator& pmemAllocator,
+ PmemAllocator& pmemAdspAllocator, const private_module_t* module) :
+ deps(deps),
+ pmemAllocator(pmemAllocator),
+ pmemAdspAllocator(pmemAdspAllocator)
+{
+ // Zero out the alloc_device_t
+ memset(static_cast<alloc_device_t*>(this), 0, sizeof(alloc_device_t));
+
+ // Initialize the procs
+ common.tag = HARDWARE_DEVICE_TAG;
+ common.version = 0;
+ common.module = const_cast<hw_module_t*>(&module->base.common);
+ common.close = gralloc_close;
+ alloc = gralloc_alloc;
+ free = gralloc_free;
+}
+
+int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage,
+ buffer_handle_t* pHandle)
+{
+ private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
+
+ // we don't support allocations with both the FB and PMEM_ADSP flags
+ if (usage & GRALLOC_USAGE_PRIVATE_PMEM_ADSP) {
+ return -EINVAL;
+ }
+
+ // allocate the framebuffer
+ if (m->framebuffer == NULL) {
+ // initialize the framebuffer, the framebuffer is mapped once
+ // and forever.
+ int err = deps.mapFrameBufferLocked(m);
+ if (err < 0) {
+ return err;
+ }
+ }
+
+ const uint32_t bufferMask = m->bufferMask;
+ const uint32_t numBuffers = m->numBuffers;
+ const size_t bufferSize = m->finfo.line_length * m->info.yres;
+ if (numBuffers == 1) {
+ // If we have only one buffer, we never use page-flipping. Instead,
+ // we return a regular buffer which will be memcpy'ed to the main
+ // screen when post is called.
+ int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
+ return gralloc_alloc_buffer(bufferSize, newUsage, pHandle);
+ }
+
+ if (bufferMask >= ((1LU<<numBuffers)-1)) {
+ // We ran out of buffers.
+ return -ENOMEM;
+ }
+
+ // create a "fake" handles for it
+ intptr_t vaddr = intptr_t(m->framebuffer->base);
+ private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
+ private_handle_t::PRIV_FLAGS_USES_PMEM |
+ private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
+
+ // find a free slot
+ for (uint32_t i=0 ; i<numBuffers ; i++) {
+ if ((bufferMask & (1LU<<i)) == 0) {
+ m->bufferMask |= (1LU<<i);
+ break;
+ }
+ vaddr += bufferSize;
+ }
+
+ hnd->base = vaddr;
+ hnd->offset = vaddr - intptr_t(m->framebuffer->base);
+ *pHandle = hnd;
+
+ return 0;
+}
+
+
+int gpu_context_t::gralloc_alloc_framebuffer(size_t size, int usage,
+ buffer_handle_t* pHandle)
+{
+ private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
+ pthread_mutex_lock(&m->lock);
+ int err = gralloc_alloc_framebuffer_locked(size, usage, pHandle);
+ pthread_mutex_unlock(&m->lock);
+ return err;
+}
+
+
+int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* pHandle)
+{
+ int err = 0;
+ int flags = 0;
+
+ int fd = -1;
+ void* base = 0; // XXX JMG: This should change to just get an address from
+ // the PmemAllocator rather than getting the base & offset separately
+ int offset = 0;
+ int lockState = 0;
+
+ size = roundUpToPageSize(size);
+
+ if (usage & GRALLOC_USAGE_HW_TEXTURE) {
+ // enable pmem in that case, so our software GL can fallback to
+ // the copybit module.
+ flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
+ }
+
+ if (usage & GRALLOC_USAGE_HW_2D) {
+ flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
+ }
+
+ if (usage & GRALLOC_USAGE_PRIVATE_PMEM_ADSP) {
+ flags |= private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
+ flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM;
+ }
+
+ private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
+
+ if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0 ||
+ (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0) {
+
+ PmemAllocator* pma = 0;
+
+ if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0) {
+ if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0) {
+ LOGE("attempting to allocate a gralloc buffer with both the "
+ "USES_PMEM and USES_PMEM_ADSP flags. Unsetting the "
+ "USES_PMEM_ADSP flag.");
+ flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
+ }
+ pma = &pmemAllocator;
+ } else { // (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0
+ pma = &pmemAdspAllocator;
+ }
+
+ // PMEM buffers are always mmapped
+ lockState |= private_handle_t::LOCK_STATE_MAPPED;
+
+ // Allocate the buffer from pmem
+ err = pma->alloc_pmem_buffer(size, usage, &base, &offset, &fd);
+ if (err < 0) {
+ if (((usage & GRALLOC_USAGE_HW_2D) == 0) &&
+ ((usage & GRALLOC_USAGE_PRIVATE_PMEM_ADSP) == 0)) {
+ // the caller didn't request PMEM, so we can try something else
+ flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM;
+ err = 0;
+ goto try_ashmem;
+ } else {
+ LOGE("couldn't open pmem (%s)", strerror(errno));
+ }
+ }
+ } else {
+try_ashmem:
+ fd = deps.ashmem_create_region("gralloc-buffer", size);
+ if (fd < 0) {
+ LOGE("couldn't create ashmem (%s)", strerror(errno));
+ err = -errno;
+ }
+ }
+
+ if (err == 0) {
+ private_handle_t* hnd = new private_handle_t(fd, size, flags);
+ hnd->offset = offset;
+ hnd->base = int(base)+offset;
+ hnd->lockState = lockState;
+ *pHandle = hnd;
+ }
+
+ LOGE_IF(err, "gralloc failed err=%s", strerror(-err));
+
+ return err;
+}
+
+static inline size_t ALIGN(size_t x, size_t align) {
+ return (x + align-1) & ~(align-1);
+}
+
+int gpu_context_t::alloc_impl(int w, int h, int format, int usage,
+ buffer_handle_t* pHandle, int* pStride) {
+ if (!pHandle || !pStride)
+ return -EINVAL;
+
+ size_t size, alignedw, alignedh;
+
+ alignedw = ALIGN(w, 32);
+ alignedh = ALIGN(h, 32);
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ size = alignedw * alignedh * 4;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ size = alignedw * alignedh * 3;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ size = alignedw * alignedh * 2;
+ break;
+
+ // adreno formats
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP: // NV21
+ size = ALIGN(alignedw*alignedh, 4096);
+ size += ALIGN(2 * ALIGN(w/2, 32) * ALIGN(h/2, 32), 4096);
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: // NV12
+ // The chroma plane is subsampled,
+ // but the pitch in bytes is unchanged
+ // The GPU needs 4K alignment, but the video decoder needs 8K
+ alignedw = ALIGN(w, 128);
+ size = ALIGN( alignedw * alignedh, 8192);
+ size += ALIGN( alignedw * ALIGN(h/2, 32), 4096);
+ break;
+
+ case HAL_PIXEL_FORMAT_YV12:
+ alignedw = ALIGN(w, 16);
+ alignedh = ALIGN(h, 16);
+ size = alignedw * alignedh;
+ size += size / 2;
+ break;
+
+ case HAL_PIXEL_FORMAT_YV16:
+ alignedh = ALIGN(h, 16);
+ size = alignedw * alignedh * 2;
+ break;
+
+ default:
+ LOGE("unrecognized pixel format: %d", format);
+ return -EINVAL;
+ }
+
+ if ((ssize_t)size <= 0)
+ return -EINVAL;
+
+ int err;
+ if (usage & GRALLOC_USAGE_HW_FB) {
+ err = gralloc_alloc_framebuffer(size, usage, pHandle);
+ } else {
+ err = gralloc_alloc_buffer(size, usage, pHandle);
+ }
+
+ if (err < 0) {
+ return err;
+ }
+
+ *pStride = alignedw;
+ return 0;
+}
+
+int gpu_context_t::free_impl(private_handle_t const* hnd) {
+ private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
+ // free this buffer
+ const size_t bufferSize = m->finfo.line_length * m->info.yres;
+ int index = (hnd->base - m->framebuffer->base) / bufferSize;
+ m->bufferMask &= ~(1<<index);
+ } else {
+ PmemAllocator* pmem_allocator = 0;
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) {
+ pmem_allocator = &pmemAllocator;
+ } else if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) {
+ pmem_allocator = &pmemAdspAllocator;
+ }
+ pmem_allocator->free_pmem_buffer(hnd->size, (void*)hnd->base,
+ hnd->offset, hnd->fd);
+ deps.terminateBuffer(&m->base, const_cast<private_handle_t*>(hnd));
+ }
+
+ deps.close(hnd->fd);
+ delete hnd; // XXX JMG: move this to the deps
+ return 0;
+}
+
+/******************************************************************************
+ * Static functions
+ *****************************************************************************/
+
+int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
+ int usage, buffer_handle_t* pHandle, int* pStride)
+{
+ if (!dev) {
+ return -EINVAL;
+ }
+ gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(dev);
+ return gpu->alloc_impl(w, h, format, usage, pHandle, pStride);
+}
+
+int gpu_context_t::gralloc_free(alloc_device_t* dev,
+ buffer_handle_t handle)
+{
+ if (private_handle_t::validate(handle) < 0)
+ return -EINVAL;
+
+ private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);
+ gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(dev);
+ return gpu->free_impl(hnd);
+}
+
+/*****************************************************************************/
+
+int gpu_context_t::gralloc_close(struct hw_device_t *dev)
+{
+ gpu_context_t* ctx = reinterpret_cast<gpu_context_t*>(dev);
+ if (ctx) {
+ /* TODO: keep a list of all buffer_handle_t created, and free them
+ * all here.
+ */
+ delete ctx;
+ }
+ return 0;
+}
+
+
+gpu_context_t::Deps::~Deps() {}
diff --git a/libgralloc-qsd8k/gpu.h b/libgralloc-qsd8k/gpu.h
new file mode 100644
index 0000000..5da7b6a
--- /dev/null
+++ b/libgralloc-qsd8k/gpu.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef GRALLOC_QSD8K_GPU_H_
+#define GRALLOC_QSD8K_GPU_H_
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/log.h>
+#include <cutils/ashmem.h>
+
+#include "gralloc_priv.h"
+#include "pmemalloc.h"
+
+
+class gpu_context_t : public alloc_device_t {
+ public:
+
+ class Deps {
+ public:
+
+ virtual ~Deps();
+
+ // ashmem
+ virtual int ashmem_create_region(const char *name, size_t size) = 0;
+
+ // POSIX
+ virtual int close(int fd) = 0;
+
+ // Framebuffer (locally defined)
+ virtual int mapFrameBufferLocked(struct private_module_t* module) = 0;
+ virtual int terminateBuffer(gralloc_module_t const* module,
+ private_handle_t* hnd) = 0;
+ };
+
+ gpu_context_t(Deps& deps, PmemAllocator& pmemAllocator,
+ PmemAllocator& pmemAdspAllocator, const private_module_t* module);
+
+ int gralloc_alloc_framebuffer_locked(size_t size, int usage,
+ buffer_handle_t* pHandle);
+ int gralloc_alloc_framebuffer(size_t size, int usage,
+ buffer_handle_t* pHandle);
+ int gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* pHandle);
+ int free_impl(private_handle_t const* hnd);
+ int alloc_impl(int w, int h, int format, int usage,
+ buffer_handle_t* pHandle, int* pStride);
+
+ static int gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
+ int usage, buffer_handle_t* pHandle, int* pStride);
+ static int gralloc_free(alloc_device_t* dev, buffer_handle_t handle);
+ static int gralloc_close(struct hw_device_t *dev);
+
+ private:
+
+ Deps& deps;
+ PmemAllocator& pmemAllocator;
+ PmemAllocator& pmemAdspAllocator;
+};
+
+#endif // GRALLOC_QSD8K_GPU_H
diff --git a/libgralloc-qsd8k/gralloc.cpp b/libgralloc-qsd8k/gralloc.cpp
index 3d08cfd..bf60324 100644
--- a/libgralloc-qsd8k/gralloc.cpp
+++ b/libgralloc-qsd8k/gralloc.cpp
@@ -14,44 +14,22 @@
* limitations under the License.
*/
-#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
-#include <errno.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <cutils/ashmem.h>
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-
-#include <hardware/hardware.h>
-#include <hardware/gralloc.h>
-
-#include "gralloc_priv.h"
-#include "allocator.h"
-
-#if HAVE_ANDROID_OS
#include <linux/android_pmem.h>
-#endif
-/*****************************************************************************/
-
-static SimpleBestFitAllocator sAllocator;
+#include "allocator.h"
+#include "gr.h"
+#include "gpu.h"
/*****************************************************************************/
-struct gralloc_context_t {
- alloc_device_t device;
- /* our private data here */
-};
-
static int gralloc_alloc_buffer(alloc_device_t* dev,
size_t size, int usage, buffer_handle_t* pHandle);
@@ -82,416 +60,134 @@ extern int gralloc_perform(struct gralloc_module_t const* module,
/*****************************************************************************/
-static struct hw_module_methods_t gralloc_module_methods = {
- open: gralloc_device_open
-};
-
-struct private_module_t HAL_MODULE_INFO_SYM = {
- base: {
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
- id: GRALLOC_HARDWARE_MODULE_ID,
- name: "Graphics Memory Allocator Module",
- author: "The Android Open Source Project",
- methods: &gralloc_module_methods
- },
- registerBuffer: gralloc_register_buffer,
- unregisterBuffer: gralloc_unregister_buffer,
- lock: gralloc_lock,
- unlock: gralloc_unlock,
- perform: gralloc_perform,
- },
- framebuffer: 0,
- fbFormat: 0,
- flags: 0,
- numBuffers: 0,
- bufferMask: 0,
- lock: PTHREAD_MUTEX_INITIALIZER,
- currentBuffer: 0,
- pmem_master: -1,
- pmem_master_base: 0,
-};
-
-/*****************************************************************************/
+/* On-device dependency implementation */
+class PmemAllocatorDepsDeviceImpl : public PmemUserspaceAllocator::Deps,
+ public PmemKernelAllocator::Deps {
-static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev,
- size_t size, int usage, buffer_handle_t* pHandle)
-{
- private_module_t* m = reinterpret_cast<private_module_t*>(
- dev->common.module);
-
- // allocate the framebuffer
- if (m->framebuffer == NULL) {
- // initialize the framebuffer, the framebuffer is mapped once
- // and forever.
- int err = mapFrameBufferLocked(m);
- if (err < 0) {
- return err;
+ virtual size_t getPmemTotalSize(int fd, size_t* size) {
+ pmem_region region;
+ int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, &region);
+ if (err == 0) {
+ *size = region.len;
}
+ return err;
}
- const uint32_t bufferMask = m->bufferMask;
- const uint32_t numBuffers = m->numBuffers;
- const size_t bufferSize = m->finfo.line_length * m->info.yres;
- if (numBuffers == 1) {
- // If we have only one buffer, we never use page-flipping. Instead,
- // we return a regular buffer which will be memcpy'ed to the main
- // screen when post is called.
- int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
- return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle);
+ virtual int connectPmem(int fd, int master_fd) {
+ return ioctl(fd, PMEM_CONNECT, master_fd);
}
- if (bufferMask >= ((1LU<<numBuffers)-1)) {
- // We ran out of buffers.
- return -ENOMEM;
+ virtual int mapPmem(int fd, int offset, size_t size) {
+ struct pmem_region sub = { offset, size };
+ return ioctl(fd, PMEM_MAP, &sub);
}
- // create a "fake" handles for it
- intptr_t vaddr = intptr_t(m->framebuffer->base);
- private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
- private_handle_t::PRIV_FLAGS_USES_PMEM |
- private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
-
- // find a free slot
- for (uint32_t i=0 ; i<numBuffers ; i++) {
- if ((bufferMask & (1LU<<i)) == 0) {
- m->bufferMask |= (1LU<<i);
- break;
- }
- vaddr += bufferSize;
+ virtual int unmapPmem(int fd, int offset, size_t size) {
+ struct pmem_region sub = { offset, size };
+ return ioctl(fd, PMEM_UNMAP, &sub);
}
-
- hnd->base = vaddr;
- hnd->offset = vaddr - intptr_t(m->framebuffer->base);
- *pHandle = hnd;
-
- return 0;
-}
-
-static int gralloc_alloc_framebuffer(alloc_device_t* dev,
- size_t size, int usage, buffer_handle_t* pHandle)
-{
- private_module_t* m = reinterpret_cast<private_module_t*>(
- dev->common.module);
- pthread_mutex_lock(&m->lock);
- int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);
- pthread_mutex_unlock(&m->lock);
- return err;
-}
-
-static int init_pmem_area_locked(private_module_t* m)
-{
- int err = 0;
- int master_fd = open("/dev/pmem", O_RDWR, 0);
- if (master_fd >= 0) {
- size_t size;
- pmem_region region;
- if (ioctl(master_fd, PMEM_GET_TOTAL_SIZE, &region) < 0) {
- LOGE("PMEM_GET_TOTAL_SIZE failed, limp mode");
- size = 8<<20; // 8 MiB
- } else {
- size = region.len;
- }
- sAllocator.setSize(size);
-
- void* base = mmap(0, size,
- PROT_READ|PROT_WRITE, MAP_SHARED, master_fd, 0);
- if (base == MAP_FAILED) {
- err = -errno;
- base = 0;
- close(master_fd);
- master_fd = -1;
- }
- m->pmem_master = master_fd;
- m->pmem_master_base = base;
- } else {
- err = -errno;
+ virtual int getErrno() {
+ return errno;
}
- return err;
-}
-static int init_pmem_area(private_module_t* m)
-{
- pthread_mutex_lock(&m->lock);
- int err = m->pmem_master;
- if (err == -1) {
- // first time, try to initialize pmem
- err = init_pmem_area_locked(m);
- if (err) {
- m->pmem_master = err;
- }
- } else if (err < 0) {
- // pmem couldn't be initialized, never use it
- } else {
- // pmem OK
- err = 0;
+ virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ return ::mmap(start, length, prot, flags, fd, offset);
}
- pthread_mutex_unlock(&m->lock);
- return err;
-}
-static int gralloc_alloc_buffer(alloc_device_t* dev,
- size_t size, int usage, buffer_handle_t* pHandle)
-{
- int err = 0;
- int flags = 0;
-
- int fd = -1;
- void* base = 0;
- int offset = 0;
- int lockState = 0;
-
- size = roundUpToPageSize(size);
-
- if (usage & GRALLOC_USAGE_HW_TEXTURE) {
- // enable pmem in that case, so our software GL can fallback to
- // the copybit module.
- flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
+ virtual int munmap(void* start, size_t length) {
+ return ::munmap(start, length);
}
-
- if (usage & GRALLOC_USAGE_HW_2D) {
- flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
- }
-
- if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) == 0) {
-try_ashmem:
- fd = ashmem_create_region("gralloc-buffer", size);
- if (fd < 0) {
- LOGE("couldn't create ashmem (%s)", strerror(errno));
- err = -errno;
- }
- } else {
- private_module_t* m = reinterpret_cast<private_module_t*>(
- dev->common.module);
- err = init_pmem_area(m);
- if (err == 0) {
- // PMEM buffers are always mmapped
- base = m->pmem_master_base;
- lockState |= private_handle_t::LOCK_STATE_MAPPED;
-
- offset = sAllocator.allocate(size);
- if (offset < 0) {
- // no more pmem memory
- err = -ENOMEM;
- } else {
- struct pmem_region sub = { offset, size };
- int openFlags = O_RDWR | O_SYNC;
- uint32_t uread = usage & GRALLOC_USAGE_SW_READ_MASK;
- uint32_t uwrite = usage & GRALLOC_USAGE_SW_WRITE_MASK;
- if (uread == GRALLOC_USAGE_SW_READ_OFTEN ||
- uwrite == GRALLOC_USAGE_SW_WRITE_OFTEN) {
- openFlags &= ~O_SYNC;
- }
-
- // now create the "sub-heap"
- fd = open("/dev/pmem", openFlags, 0);
- err = fd < 0 ? fd : 0;
-
- // and connect to it
- if (err == 0)
- err = ioctl(fd, PMEM_CONNECT, m->pmem_master);
-
- // and make it available to the client process
- if (err == 0)
- err = ioctl(fd, PMEM_MAP, &sub);
-
- if (err < 0) {
- err = -errno;
- close(fd);
- sAllocator.deallocate(offset);
- fd = -1;
- } else {
- memset((char*)base + offset, 0, size);
- // clean and invalidate the new allocation
- cacheflush(intptr_t(base) + offset, size, 0);
- }
- //LOGD_IF(!err, "allocating pmem size=%d, offset=%d", size, offset);
- }
- } else {
- if ((usage & GRALLOC_USAGE_HW_2D) == 0) {
- // the caller didn't request PMEM, so we can try something else
- flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM;
- err = 0;
- goto try_ashmem;
- } else {
- LOGE("couldn't open pmem (%s)", strerror(errno));
- }
- }
+ virtual int open(const char* pathname, int flags, int mode) {
+ return ::open(pathname, flags, mode);
}
- if (err == 0) {
- private_handle_t* hnd = new private_handle_t(fd, size, flags);
- hnd->offset = offset;
- hnd->base = int(base)+offset;
- hnd->lockState = lockState;
- *pHandle = hnd;
+ virtual int close(int fd) {
+ return ::close(fd);
}
-
- LOGE_IF(err, "gralloc failed err=%s", strerror(-err));
-
- return err;
-}
+};
-/*****************************************************************************/
+class GpuContextDepsDeviceImpl : public gpu_context_t::Deps {
-static inline size_t ALIGN(size_t x, size_t align) {
- return (x + align-1) & ~(align-1);
-}
+ public:
-static int gralloc_alloc(alloc_device_t* dev,
- int w, int h, int format, int usage,
- buffer_handle_t* pHandle, int* pStride)
-{
- if (!pHandle || !pStride)
- return -EINVAL;
-
- size_t size, alignedw, alignedh;
-
- alignedw = ALIGN(w, 32);
- alignedh = ALIGN(h, 32);
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- size = alignedw * alignedh * 4;
- break;
- case HAL_PIXEL_FORMAT_RGB_888:
- size = alignedw * alignedh * 3;
- break;
- case HAL_PIXEL_FORMAT_RGB_565:
- case HAL_PIXEL_FORMAT_RGBA_5551:
- case HAL_PIXEL_FORMAT_RGBA_4444:
- size = alignedw * alignedh * 2;
- break;
-
- // adreno formats
- case HAL_PIXEL_FORMAT_YCrCb_420_SP: // NV21
- size = ALIGN(alignedw*alignedh, 4096);
- size += ALIGN(2 * ALIGN(w/2, 32) * ALIGN(h/2, 32), 4096);
- break;
- case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: // NV12
- // The chroma plane is subsampled,
- // but the pitch in bytes is unchanged
- // The GPU needs 4K alignment, but the video decoder needs 8K
- alignedw = ALIGN(w, 128);
- size = ALIGN( ALIGN(w, 128) * alignedh, 8192);
- size += ALIGN( ALIGN(w, 128) * ALIGN(h/2, 32), 4096);
- break;
-
- case HAL_PIXEL_FORMAT_YV12:
- alignedw = ALIGN(w, 16);
- alignedh = ALIGN(h, 16);
- size = alignedw * alignedh;
- size += size / 2;
- break;
-
- case HAL_PIXEL_FORMAT_YV16:
- alignedh = ALIGN(h, 16);
- size = alignedw * alignedh * 2;
- break;
-
- default:
- return -EINVAL;
+ virtual int ashmem_create_region(const char *name, size_t size) {
+ return ::ashmem_create_region(name, size);
}
- if ((ssize_t)size <= 0)
- return -EINVAL;
+ virtual int mapFrameBufferLocked(struct private_module_t* module) {
+ return ::mapFrameBufferLocked(module);
+ }
- int err;
- if (usage & GRALLOC_USAGE_HW_FB) {
- err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);
- } else {
- err = gralloc_alloc_buffer(dev, size, usage, pHandle);
+ virtual int terminateBuffer(gralloc_module_t const* module,
+ private_handle_t* hnd) {
+ return ::terminateBuffer(module, hnd);
}
- if (err < 0) {
- return err;
+ virtual int close(int fd) {
+ return ::close(fd);
}
+};
- *pStride = alignedw;
- return 0;
-}
+static PmemAllocatorDepsDeviceImpl pmemAllocatorDeviceDepsImpl;
+static GpuContextDepsDeviceImpl gpuContextDeviceDepsImpl;
-static int gralloc_free(alloc_device_t* dev,
- buffer_handle_t handle)
-{
- if (private_handle_t::validate(handle) < 0)
- return -EINVAL;
-
- private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);
- if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
- // free this buffer
- private_module_t* m = reinterpret_cast<private_module_t*>(
- dev->common.module);
- const size_t bufferSize = m->finfo.line_length * m->info.yres;
- int index = (hnd->base - m->framebuffer->base) / bufferSize;
- m->bufferMask &= ~(1<<index);
- } else {
- if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) {
- if (hnd->fd >= 0) {
- struct pmem_region sub = { hnd->offset, hnd->size };
- int err = ioctl(hnd->fd, PMEM_UNMAP, &sub);
- LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
- "fd=%d, sub.offset=%lu, sub.size=%lu",
- strerror(errno), hnd->fd, hnd->offset, hnd->size);
- if (err == 0) {
- // we can't deallocate the memory in case of UNMAP failure
- // because it would give that process access to someone else's
- // surfaces, which would be a security breach.
- sAllocator.deallocate(hnd->offset);
- }
- }
- }
+/*****************************************************************************/
- gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(
- dev->common.module);
- terminateBuffer(module, const_cast<private_handle_t*>(hnd));
- }
+static SimpleBestFitAllocator pmemAllocMgr;
+static PmemUserspaceAllocator pmemAllocator(pmemAllocatorDeviceDepsImpl, pmemAllocMgr,
+ "/dev/pmem");
- close(hnd->fd);
- delete hnd;
- return 0;
-}
+static PmemKernelAllocator pmemAdspAllocator(pmemAllocatorDeviceDepsImpl,
+ "/dev/pmem_adsp");
/*****************************************************************************/
-static int gralloc_close(struct hw_device_t *dev)
-{
- gralloc_context_t* ctx = reinterpret_cast<gralloc_context_t*>(dev);
- if (ctx) {
- /* TODO: keep a list of all buffer_handle_t created, and free them
- * all here.
- */
- free(ctx);
- }
- return 0;
-}
+static struct hw_module_methods_t gralloc_module_methods = {
+ open: gralloc_device_open
+};
+
+struct private_module_t HAL_MODULE_INFO_SYM = {
+ base: {
+ common: {
+ tag: HARDWARE_MODULE_TAG,
+ version_major: 1,
+ version_minor: 0,
+ id: GRALLOC_HARDWARE_MODULE_ID,
+ name: "Graphics Memory Allocator Module",
+ author: "The Android Open Source Project",
+ methods: &gralloc_module_methods
+ },
+ registerBuffer: gralloc_register_buffer,
+ unregisterBuffer: gralloc_unregister_buffer,
+ lock: gralloc_lock,
+ unlock: gralloc_unlock,
+ perform: gralloc_perform,
+ },
+ framebuffer: 0,
+ fbFormat: 0,
+ flags: 0,
+ numBuffers: 0,
+ bufferMask: 0,
+ lock: PTHREAD_MUTEX_INITIALIZER,
+ currentBuffer: 0,
+};
+
+/*****************************************************************************/
int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
- gralloc_context_t *dev;
- dev = (gralloc_context_t*)malloc(sizeof(*dev));
-
- /* initialize our state here */
- memset(dev, 0, sizeof(*dev));
-
- /* initialize the procs */
- dev->device.common.tag = HARDWARE_DEVICE_TAG;
- dev->device.common.version = 0;
- dev->device.common.module = const_cast<hw_module_t*>(module);
- dev->device.common.close = gralloc_close;
-
- dev->device.alloc = gralloc_alloc;
- dev->device.free = gralloc_free;
-
- *device = &dev->device.common;
+ const private_module_t* m = reinterpret_cast<const private_module_t*>(
+ module);
+ gpu_context_t *dev;
+ dev = new gpu_context_t(gpuContextDeviceDepsImpl, pmemAllocator,
+ pmemAdspAllocator, m);
+ *device = &dev->common;
status = 0;
} else {
status = fb_device_open(module, name, device);
diff --git a/libgralloc-qsd8k/gralloc_priv.h b/libgralloc-qsd8k/gralloc_priv.h
index 28ea79b..36e6796 100644
--- a/libgralloc-qsd8k/gralloc_priv.h
+++ b/libgralloc-qsd8k/gralloc_priv.h
@@ -29,10 +29,16 @@
#include <linux/fb.h>
+enum {
+ /* gralloc usage bit indicating a pmem_adsp allocation should be used */
+ GRALLOC_USAGE_PRIVATE_PMEM_ADSP = GRALLOC_USAGE_PRIVATE_0,
+};
+
/*****************************************************************************/
struct private_module_t;
struct private_handle_t;
+struct PmemAllocator;
struct private_module_t {
gralloc_module_t base;
@@ -44,8 +50,6 @@ struct private_module_t {
uint32_t bufferMask;
pthread_mutex_t lock;
buffer_handle_t currentBuffer;
- int pmem_master;
- void* pmem_master_base;
struct fb_var_screeninfo info;
struct fb_fix_screeninfo finfo;
@@ -69,9 +73,10 @@ struct private_handle_t {
#endif
enum {
- PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
- PRIV_FLAGS_USES_PMEM = 0x00000002,
- PRIV_FLAGS_NEEDS_FLUSH = 0x00000004,
+ PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
+ PRIV_FLAGS_USES_PMEM = 0x00000002,
+ PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004,
+ PRIV_FLAGS_NEEDS_FLUSH = 0x00000008,
};
enum {
diff --git a/libgralloc-qsd8k/mapper.cpp b/libgralloc-qsd8k/mapper.cpp
index 9e9fad0..e8be6f6 100644
--- a/libgralloc-qsd8k/mapper.cpp
+++ b/libgralloc-qsd8k/mapper.cpp
@@ -171,7 +171,8 @@ int terminateBuffer(gralloc_module_t const* module,
if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
// this buffer was mapped, unmap it now
- if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) {
+ if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) ||
+ (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)) {
if (hnd->pid != getpid()) {
// ... unless it's a "master" pmem buffer, that is a buffer
// mapped in the process it's been allocated.
diff --git a/libgralloc-qsd8k/pmemalloc.cpp b/libgralloc-qsd8k/pmemalloc.cpp
new file mode 100644
index 0000000..e42e898
--- /dev/null
+++ b/libgralloc-qsd8k/pmemalloc.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2010 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 LOG_NDEBUG 0
+
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/mman.h>
+
+#include <cutils/log.h>
+#include <cutils/ashmem.h>
+
+#include "gralloc_priv.h"
+#include "pmemalloc.h"
+
+
+#define BEGIN_FUNC LOGV("%s begin", __PRETTY_FUNCTION__)
+#define END_FUNC LOGV("%s end", __PRETTY_FUNCTION__)
+
+
+static int get_open_flags(int usage) {
+ int openFlags = O_RDWR | O_SYNC;
+ uint32_t uread = usage & GRALLOC_USAGE_SW_READ_MASK;
+ uint32_t uwrite = usage & GRALLOC_USAGE_SW_WRITE_MASK;
+ if (uread == GRALLOC_USAGE_SW_READ_OFTEN ||
+ uwrite == GRALLOC_USAGE_SW_WRITE_OFTEN) {
+ openFlags &= ~O_SYNC;
+ }
+ return openFlags;
+}
+
+PmemAllocator::~PmemAllocator()
+{
+ BEGIN_FUNC;
+ END_FUNC;
+}
+
+
+PmemUserspaceAllocator::PmemUserspaceAllocator(Deps& deps, Deps::Allocator& allocator, const char* pmemdev):
+ deps(deps),
+ allocator(allocator),
+ pmemdev(pmemdev),
+ master_fd(MASTER_FD_INIT)
+{
+ BEGIN_FUNC;
+ pthread_mutex_init(&lock, NULL);
+ END_FUNC;
+}
+
+
+PmemUserspaceAllocator::~PmemUserspaceAllocator()
+{
+ BEGIN_FUNC;
+ END_FUNC;
+}
+
+
+void* PmemUserspaceAllocator::get_base_address() {
+ BEGIN_FUNC;
+ END_FUNC;
+ return master_base;
+}
+
+
+int PmemUserspaceAllocator::init_pmem_area_locked()
+{
+ BEGIN_FUNC;
+ int err = 0;
+ int fd = deps.open(pmemdev, O_RDWR, 0);
+ if (fd >= 0) {
+ size_t size = 0;
+ err = deps.getPmemTotalSize(fd, &size);
+ if (err < 0) {
+ LOGE("%s: PMEM_GET_TOTAL_SIZE failed (%d), limp mode", pmemdev,
+ err);
+ size = 8<<20; // 8 MiB
+ }
+ allocator.setSize(size);
+
+ void* base = deps.mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd,
+ 0);
+ if (base == MAP_FAILED) {
+ LOGE("%s: failed to map pmem master fd: %s", pmemdev,
+ strerror(deps.getErrno()));
+ err = -deps.getErrno();
+ base = 0;
+ deps.close(fd);
+ fd = -1;
+ } else {
+ master_fd = fd;
+ master_base = base;
+ }
+ } else {
+ LOGE("%s: failed to open pmem device: %s", pmemdev,
+ strerror(deps.getErrno()));
+ err = -deps.getErrno();
+ }
+ END_FUNC;
+ return err;
+}
+
+
+int PmemUserspaceAllocator::init_pmem_area()
+{
+ BEGIN_FUNC;
+ pthread_mutex_lock(&lock);
+ int err = master_fd;
+ if (err == MASTER_FD_INIT) {
+ // first time, try to initialize pmem
+ err = init_pmem_area_locked();
+ if (err) {
+ LOGE("%s: failed to initialize pmem area", pmemdev);
+ master_fd = err;
+ }
+ } else if (err < 0) {
+ // pmem couldn't be initialized, never use it
+ } else {
+ // pmem OK
+ err = 0;
+ }
+ pthread_mutex_unlock(&lock);
+ END_FUNC;
+ return err;
+}
+
+
+int PmemUserspaceAllocator::alloc_pmem_buffer(size_t size, int usage,
+ void** pBase, int* pOffset, int* pFd)
+{
+ BEGIN_FUNC;
+ int err = init_pmem_area();
+ if (err == 0) {
+ void* base = master_base;
+ int offset = allocator.allocate(size);
+ if (offset < 0) {
+ // no more pmem memory
+ LOGE("%s: no more pmem available", pmemdev);
+ err = -ENOMEM;
+ } else {
+ int openFlags = get_open_flags(usage);
+
+ //LOGD("%s: allocating pmem at offset 0x%p", pmemdev, offset);
+
+ // now create the "sub-heap"
+ int fd = deps.open(pmemdev, openFlags, 0);
+ err = fd < 0 ? fd : 0;
+
+ // and connect to it
+ if (err == 0)
+ err = deps.connectPmem(fd, master_fd);
+
+ // and make it available to the client process
+ if (err == 0)
+ err = deps.mapPmem(fd, offset, size);
+
+ if (err < 0) {
+ LOGE("%s: failed to initialize pmem sub-heap: %d", pmemdev,
+ err);
+ err = -deps.getErrno();
+ deps.close(fd);
+ allocator.deallocate(offset);
+ fd = -1;
+ } else {
+ LOGV("%s: mapped fd %d at offset %d, size %d", pmemdev, fd, offset, size);
+ memset((char*)base + offset, 0, size);
+ *pBase = base;
+ *pOffset = offset;
+ *pFd = fd;
+ }
+ //LOGD_IF(!err, "%s: allocating pmem size=%d, offset=%d", pmemdev, size, offset);
+ }
+ }
+ END_FUNC;
+ return err;
+}
+
+
+int PmemUserspaceAllocator::free_pmem_buffer(size_t size, void* base, int offset, int fd)
+{
+ BEGIN_FUNC;
+ int err = 0;
+ if (fd >= 0) {
+ int err = deps.unmapPmem(fd, offset, size);
+ LOGE_IF(err<0, "PMEM_UNMAP failed (%s), fd=%d, sub.offset=%u, "
+ "sub.size=%u", strerror(deps.getErrno()), fd, offset, size);
+ if (err == 0) {
+ // we can't deallocate the memory in case of UNMAP failure
+ // because it would give that process access to someone else's
+ // surfaces, which would be a security breach.
+ allocator.deallocate(offset);
+ }
+ }
+ END_FUNC;
+ return err;
+}
+
+PmemUserspaceAllocator::Deps::Allocator::~Allocator()
+{
+ BEGIN_FUNC;
+ END_FUNC;
+}
+
+PmemUserspaceAllocator::Deps::~Deps()
+{
+ BEGIN_FUNC;
+ END_FUNC;
+}
+
+PmemKernelAllocator::PmemKernelAllocator(Deps& deps, const char* pmemdev):
+ deps(deps),
+ pmemdev(pmemdev)
+{
+ BEGIN_FUNC;
+ END_FUNC;
+}
+
+
+PmemKernelAllocator::~PmemKernelAllocator()
+{
+ BEGIN_FUNC;
+ END_FUNC;
+}
+
+
+void* PmemKernelAllocator::get_base_address() {
+ BEGIN_FUNC;
+ END_FUNC;
+ return 0;
+}
+
+
+static unsigned clp2(unsigned x) {
+ x = x - 1;
+ x = x | (x >> 1);
+ x = x | (x >> 2);
+ x = x | (x >> 4);
+ x = x | (x >> 8);
+ x = x | (x >>16);
+ return x + 1;
+}
+
+
+int PmemKernelAllocator::alloc_pmem_buffer(size_t size, int usage,
+ void** pBase,int* pOffset, int* pFd)
+{
+ BEGIN_FUNC;
+
+ *pBase = 0;
+ *pOffset = 0;
+ *pFd = -1;
+
+ int err;
+ int openFlags = get_open_flags(usage);
+ int fd = deps.open(pmemdev, openFlags, 0);
+ if (fd < 0) {
+ err = -deps.getErrno();
+ END_FUNC;
+ return err;
+ }
+
+ // The size should already be page aligned, now round it up to a power of 2.
+ size = clp2(size);
+
+ void* base = deps.mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (base == MAP_FAILED) {
+ LOGE("%s: failed to map pmem fd: %s", pmemdev,
+ strerror(deps.getErrno()));
+ err = -deps.getErrno();
+ deps.close(fd);
+ END_FUNC;
+ return err;
+ }
+
+ memset(base, 0, size);
+
+ *pBase = base;
+ *pOffset = 0;
+ *pFd = fd;
+
+ END_FUNC;
+ return 0;
+}
+
+
+int PmemKernelAllocator::free_pmem_buffer(size_t size, void* base, int offset, int fd)
+{
+ BEGIN_FUNC;
+ // The size should already be page aligned, now round it up to a power of 2
+ // like we did when allocating.
+ size = clp2(size);
+
+ int err = deps.munmap(base, size);
+ if (err < 0) {
+ err = deps.getErrno();
+ LOGW("%s: error unmapping pmem fd: %s", pmemdev, strerror(err));
+ return -err;
+ }
+ END_FUNC;
+ return 0;
+}
+
+PmemKernelAllocator::Deps::~Deps()
+{
+ BEGIN_FUNC;
+ END_FUNC;
+}
diff --git a/libgralloc-qsd8k/pmemalloc.h b/libgralloc-qsd8k/pmemalloc.h
new file mode 100644
index 0000000..b0f45c7
--- /dev/null
+++ b/libgralloc-qsd8k/pmemalloc.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef GRALLOC_QSD8K_PMEMALLOC_H
+#define GRALLOC_QSD8K_PMEMALLOC_H
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+
+/**
+ * An interface to the PMEM allocators.
+ */
+class PmemAllocator {
+
+ public:
+
+ virtual ~PmemAllocator();
+
+ // Only valid after init_pmem_area() has completed successfully.
+ virtual void* get_base_address() = 0;
+
+ virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase,
+ int* pOffset, int* pFd) = 0;
+ virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd) = 0;
+};
+
+
+/**
+ * A PMEM allocator that allocates the entire pmem memory from the kernel and
+ * then uses a user-space allocator to suballocate from that. This requires
+ * that the PMEM device driver have kernel allocation disabled.
+ */
+class PmemUserspaceAllocator: public PmemAllocator {
+
+ public:
+
+ class Deps {
+ public:
+
+ class Allocator {
+ public:
+ virtual ~Allocator();
+ virtual ssize_t setSize(size_t size) = 0;
+ virtual size_t size() const = 0;
+ virtual ssize_t allocate(size_t size, uint32_t flags = 0) = 0;
+ virtual ssize_t deallocate(size_t offset) = 0;
+ };
+
+ virtual ~Deps();
+
+ // pmem
+ virtual size_t getPmemTotalSize(int fd, size_t* size) = 0;
+ virtual int connectPmem(int fd, int master_fd) = 0;
+ virtual int mapPmem(int fd, int offset, size_t size) = 0;
+ virtual int unmapPmem(int fd, int offset, size_t size) = 0;
+
+ // C99
+ virtual int getErrno() = 0;
+
+ // POSIX
+ virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
+ off_t offset) = 0;
+ virtual int open(const char* pathname, int flags, int mode) = 0;
+ virtual int close(int fd) = 0;
+ };
+
+ PmemUserspaceAllocator(Deps& deps, Deps::Allocator& allocator, const char* pmemdev);
+ virtual ~PmemUserspaceAllocator();
+
+ // Only valid after init_pmem_area() has completed successfully.
+ virtual void* get_base_address();
+
+ virtual int init_pmem_area_locked();
+ virtual int init_pmem_area();
+ virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase,
+ int* pOffset, int* pFd);
+ virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd);
+
+#ifndef ANDROID_OS
+ // DO NOT USE: For testing purposes only.
+ void set_master_values(int fd, void* base) {
+ master_fd = fd;
+ master_base = base;
+ }
+#endif // ANDROID_OS
+
+ private:
+
+ enum {
+ MASTER_FD_INIT = -1,
+ };
+
+ Deps& deps;
+ Deps::Allocator& allocator;
+
+ pthread_mutex_t lock;
+ const char* pmemdev;
+ int master_fd;
+ void* master_base;
+};
+
+
+/**
+ * A PMEM allocator that allocates each individual allocation from the kernel
+ * (using the kernel's allocator). This requires the kernel driver for the
+ * particular PMEM device being allocated from to support kernel allocation.
+ */
+class PmemKernelAllocator: public PmemAllocator {
+
+ public:
+
+ class Deps {
+ public:
+
+ virtual ~Deps();
+
+ // C99
+ virtual int getErrno() = 0;
+
+ // POSIX
+ virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
+ off_t offset) = 0;
+ virtual int munmap(void* start, size_t length) = 0;
+ virtual int open(const char* pathname, int flags, int mode) = 0;
+ virtual int close(int fd) = 0;
+ };
+
+ PmemKernelAllocator(Deps& deps, const char* pmemdev);
+ virtual ~PmemKernelAllocator();
+
+ // Only valid after init_pmem_area() has completed successfully.
+ virtual void* get_base_address();
+
+ virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase,
+ int* pOffset, int* pFd);
+ virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd);
+
+ private:
+
+ Deps& deps;
+
+ const char* pmemdev;
+};
+
+#endif // GRALLOC_QSD8K_PMEMALLOC_H
diff --git a/libgralloc-qsd8k/tests/Android.mk b/libgralloc-qsd8k/tests/Android.mk
new file mode 100644
index 0000000..b9a7459
--- /dev/null
+++ b/libgralloc-qsd8k/tests/Android.mk
@@ -0,0 +1,55 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# you can use EXTRA_CFLAGS to indicate additional CFLAGS to use
+# in the build. The variables will be cleaned on exit
+#
+#
+
+libgralloc_test_includes:= \
+ bionic/libstdc++/include \
+ external/astl/include \
+ external/gtest/include \
+ $(LOCAL_PATH)/..
+
+libgralloc_test_static_libs := \
+ libgralloc_qsd8k_host \
+ libgtest_main_host \
+ libgtest_host \
+ libastl_host \
+ liblog
+
+define host-test
+ $(foreach file,$(1), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_CPP_EXTENSION := .cpp) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_C_INCLUDES := $(libgralloc_test_includes)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \
+ $(eval LOCAL_LDLIBS += $(EXTRA_LDLIBS)) \
+ $(eval LOCAL_STATIC_LIBRARIES := $(libgralloc_test_static_libs)) \
+ $(eval LOCAL_MODULE_TAGS := eng tests) \
+ $(eval include $(BUILD_HOST_EXECUTABLE)) \
+ ) \
+ $(eval EXTRA_CFLAGS :=) \
+ $(eval EXTRA_LDLIBS :=)
+endef
+
+TEST_SRC_FILES := \
+ pmemalloc_test.cpp
+
+$(call host-test, $(TEST_SRC_FILES))
diff --git a/libgralloc-qsd8k/tests/pmemalloc_test.cpp b/libgralloc-qsd8k/tests/pmemalloc_test.cpp
new file mode 100644
index 0000000..94e86bf
--- /dev/null
+++ b/libgralloc-qsd8k/tests/pmemalloc_test.cpp
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "pmemalloc.h"
+
+class DepsStub : public PmemUserspaceAllocator::Deps, public PmemKernelAllocator::Deps {
+
+ public:
+
+ virtual size_t getPmemTotalSize(int fd, size_t* size) {
+ return 0;
+ }
+
+ virtual int connectPmem(int fd, int master_fd) {
+ return 0;
+ }
+
+ virtual int mapPmem(int fd, int offset, size_t size) {
+ return 0;
+ }
+
+ virtual int unmapPmem(int fd, int offset, size_t size) {
+ return 0;
+ }
+
+ virtual int getErrno() {
+ return 0;
+ }
+
+ virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ return 0;
+ }
+
+ virtual int munmap(void* start, size_t length) {
+ return 0;
+ }
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ return 0;
+ }
+
+ virtual int close(int fd) {
+ return 0;
+ }
+};
+
+/******************************************************************************/
+
+class AllocatorStub : public PmemUserspaceAllocator::Deps::Allocator {
+ virtual ssize_t setSize(size_t size) {
+ return 0;
+ }
+
+ virtual size_t size() const {
+ return 0;
+ }
+
+ virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
+ return 0;
+ }
+
+ virtual ssize_t deallocate(size_t offset) {
+ return 0;
+ }
+};
+
+/******************************************************************************/
+
+static const char* fakePmemDev = "/foo/bar";
+
+/******************************************************************************/
+
+struct Deps_InitPmemAreaLockedWithSuccessfulCompletion : public DepsStub {
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ EXPECT_EQ(fakePmemDev, pathname);
+ EXPECT_EQ(O_RDWR, flags);
+ EXPECT_EQ(0, mode);
+ return 1234;
+ }
+
+ virtual size_t getPmemTotalSize(int fd, size_t* size) {
+ EXPECT_EQ(1234, fd);
+ *size = 16 << 20;
+ return 0;
+ }
+
+ virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ EXPECT_EQ(1234, fd);
+ return (void*)0x87654321;
+ }
+
+};
+
+struct Allocator_InitPmemAreaLockedWithSuccessfulCompletion : public AllocatorStub {
+
+ virtual ssize_t setSize(size_t size) {
+ EXPECT_EQ(size_t(16 << 20), size);
+ return 0;
+ }
+};
+
+TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithSuccessfulCompletion) {
+ Deps_InitPmemAreaLockedWithSuccessfulCompletion depsMock;
+ Allocator_InitPmemAreaLockedWithSuccessfulCompletion allocMock;
+ PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
+
+ int result = pma.init_pmem_area_locked();
+ ASSERT_EQ(0, result);
+}
+
+/******************************************************************************/
+
+struct Deps_InitPmemAreaLockedWithEnomemOnMmap : public DepsStub {
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ EXPECT_EQ(fakePmemDev, pathname);
+ EXPECT_EQ(O_RDWR, flags);
+ EXPECT_EQ(0, mode);
+ return 1234;
+ }
+
+ virtual size_t getPmemTotalSize(int fd, size_t* size) {
+ EXPECT_EQ(1234, fd);
+ *size = 16 << 20;
+ return 0;
+ }
+
+ virtual int getErrno() {
+ return ENOMEM;
+ }
+
+ virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ return (void*)MAP_FAILED;
+ }
+
+};
+
+struct Allocator_InitPmemAreaLockedWithEnomemOnMmap : public AllocatorStub {
+
+ virtual ssize_t setSize(size_t size) {
+ EXPECT_EQ(size_t(16 << 20), size);
+ return 0;
+ }
+};
+
+TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEnomemOnMmap) {
+ Deps_InitPmemAreaLockedWithEnomemOnMmap depsMock;
+ Allocator_InitPmemAreaLockedWithEnomemOnMmap allocMock;
+ PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
+
+ int result = pma.init_pmem_area_locked();
+ ASSERT_EQ(-ENOMEM, result);
+}
+
+/******************************************************************************/
+
+struct Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize : public DepsStub {
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ EXPECT_EQ(fakePmemDev, pathname);
+ EXPECT_EQ(O_RDWR, flags);
+ EXPECT_EQ(0, mode);
+ return 1234;
+ }
+
+ virtual size_t getPmemTotalSize(int fd, size_t* size) {
+ EXPECT_EQ(1234, fd);
+ return -EACCES;
+ }
+};
+
+TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEaccesOnGetPmemTotalSize) {
+ Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize depsMock;
+ AllocatorStub allocStub;
+ PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
+
+ int result = pma.init_pmem_area_locked();
+ ASSERT_EQ(-EACCES, result);
+}
+
+/******************************************************************************/
+
+struct Deps_InitPmemAreaLockedWithEaccesOnOpen : public DepsStub {
+
+ virtual int getErrno() {
+ return EACCES;
+ }
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ EXPECT_EQ(fakePmemDev, pathname);
+ EXPECT_EQ(O_RDWR, flags);
+ EXPECT_EQ(0, mode);
+ return -1;
+ }
+};
+
+TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithEaccesOnOpenMaster) {
+ Deps_InitPmemAreaLockedWithEaccesOnOpen depsMock;
+ AllocatorStub allocStub;
+ PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
+
+ int result = pma.init_pmem_area_locked();
+ ASSERT_EQ(-EACCES, result);
+}
+
+/******************************************************************************/
+
+typedef Deps_InitPmemAreaLockedWithSuccessfulCompletion Deps_InitPmemAreaWithSuccessfulInitialCompletion;
+
+TEST(test_pmem_userspace_allocator, testInitPmemAreaWithSuccessfulInitialCompletion) {
+ Deps_InitPmemAreaWithSuccessfulInitialCompletion depsMock;
+ AllocatorStub allocStub;
+ PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
+
+ int result = pma.init_pmem_area();
+ ASSERT_EQ(0, result);
+}
+
+/******************************************************************************/
+
+typedef Deps_InitPmemAreaLockedWithEaccesOnOpen Deps_InitPmemAreaWithEaccesOnInitLocked;
+
+TEST(test_pmem_userspace_allocator, testInitPmemAreaWithEaccesOnInitLocked) {
+ Deps_InitPmemAreaWithEaccesOnInitLocked depsMock;
+ AllocatorStub allocStub;
+ PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
+
+ int result = pma.init_pmem_area();
+ ASSERT_EQ(-EACCES, result);
+}
+
+/******************************************************************************/
+
+TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterSuccessfulInitialCompletion) {
+ DepsStub depsStub;
+ AllocatorStub allocStub;
+ PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
+
+ pma.set_master_values(1234, 0); // Indicate that the pma has been successfully init'd
+
+ int result = pma.init_pmem_area();
+ ASSERT_EQ(0, result);
+ //XXX JMG: Add this back in maybe? ASSERT_EQ(1234, pmi.master); // Make sure the master fd wasn't changed
+}
+
+/******************************************************************************/
+
+TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterFailedInit) {
+ DepsStub depsStub;
+ AllocatorStub allocStub;
+ PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
+
+ pma.set_master_values(-EACCES, 0); // Indicate that the pma has failed init
+
+ int result = pma.init_pmem_area();
+ ASSERT_EQ(-EACCES, result);
+}
+
+/******************************************************************************/
+
+struct Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags : public DepsStub {
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ EXPECT_EQ(fakePmemDev, pathname);
+ EXPECT_EQ(O_RDWR, flags & O_RDWR);
+ EXPECT_EQ(0, mode);
+ return 5678;
+ }
+
+ virtual int connectPmem(int fd, int master_fd) {
+ EXPECT_EQ(5678, fd);
+ EXPECT_EQ(1234, master_fd);
+ return 0;
+ }
+
+ virtual int mapPmem(int fd, int offset, size_t size) {
+ EXPECT_EQ(5678, fd);
+ EXPECT_EQ(0x300, offset);
+ EXPECT_EQ(size_t(0x100), size);
+ return 0;
+ }
+};
+
+
+struct Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags : public AllocatorStub {
+
+ virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
+ EXPECT_EQ(size_t(0x100), size);
+ EXPECT_EQ(uint32_t(0x0), flags);
+ return 0x300;
+ }
+};
+
+TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
+ Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags depsMock;
+ Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags allocMock;
+ PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
+
+ uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
+ pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
+
+ void* base = 0;
+ int offset = -9182, fd = -9182;
+ int size = 0x100;
+ int flags = 0;
+ int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
+ ASSERT_EQ(0, result);
+ ASSERT_EQ(0x300, offset);
+ ASSERT_EQ(5678, fd);
+ for (int i = 0x300; i < 0x400; ++i) {
+ ASSERT_EQ(uint8_t(0), buf[i]);
+ }
+}
+
+/******************************************************************************/
+
+typedef Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags;
+
+typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags;
+
+TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
+ Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags depsMock;
+ Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags allocMock;
+ PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
+
+ uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
+ pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
+
+ void* base = 0;
+ int offset = -9182, fd = -9182;
+ int size = 0x100;
+ int flags = ~0;
+ int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
+ ASSERT_EQ(0, result);
+ ASSERT_EQ(0x300, offset);
+ ASSERT_EQ(5678, fd);
+ for (int i = 0x300; i < 0x400; ++i) {
+ ASSERT_EQ(0, buf[i]);
+ }
+}
+
+/******************************************************************************/
+
+struct Deps_InitPmemAreaLockedWithEnodevOnOpen : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
+
+ virtual int getErrno() {
+ return ENODEV;
+ }
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ EXPECT_EQ(fakePmemDev, pathname);
+ EXPECT_EQ(O_RDWR, flags & O_RDWR);
+ EXPECT_EQ(0, mode);
+ return -1;
+ }
+};
+
+typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnodevOnOpen;
+
+TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnodevOnOpen) {
+ Deps_InitPmemAreaLockedWithEnodevOnOpen depsMock;
+ Allocator_AllocPmemBufferWithEnodevOnOpen allocMock;
+ PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
+
+ uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
+ pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
+
+ void* base = 0;
+ int offset = -9182, fd = -9182;
+ int size = 0x100;
+ int flags = ~0;
+ int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
+ ASSERT_EQ(-ENODEV, result);
+}
+
+/******************************************************************************/
+
+struct Deps_InitPmemAreaLockedWithEnomemOnConnectPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
+
+ virtual int getErrno() {
+ return ENOMEM;
+ }
+
+ virtual int connectPmem(int fd, int master_fd) {
+ EXPECT_EQ(5678, fd);
+ EXPECT_EQ(1234, master_fd);
+ return -1;
+ }
+};
+
+typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnConnectPmem;
+
+TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnomemOnConnectPmem) {
+ Deps_InitPmemAreaLockedWithEnomemOnConnectPmem depsMock;
+ Allocator_AllocPmemBufferWithEnomemOnConnectPmem allocMock;
+ PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
+
+ uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
+ pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
+
+ void* base = 0;
+ int offset = -9182, fd = -9182;
+ int size = 0x100;
+ int flags = ~0;
+ int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
+ ASSERT_EQ(-ENOMEM, result);
+}
+
+/******************************************************************************/
+
+struct Deps_InitPmemAreaLockedWithEnomemOnMapPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
+
+ virtual int getErrno() {
+ return ENOMEM;
+ }
+
+ virtual int mapPmem(int fd, int offset, size_t size) {
+ EXPECT_EQ(5678, fd);
+ EXPECT_EQ(0x300, offset);
+ EXPECT_EQ(size_t(0x100), size);
+ return -1;
+ }
+};
+
+typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnMapPmem;
+
+TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithEnomemOnMapPmem) {
+ Deps_InitPmemAreaLockedWithEnomemOnMapPmem depsMock;
+ Allocator_AllocPmemBufferWithEnomemOnMapPmem allocMock;
+ PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
+
+ uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
+ pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
+
+ void* base = 0;
+ int offset = -9182, fd = -9182;
+ int size = 0x100;
+ int flags = ~0;
+ int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
+ ASSERT_EQ(-ENOMEM, result);
+}
+
+/******************************************************************************/
+
+struct Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags : public DepsStub {
+
+ void* mmapResult;
+
+ Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags(void* mmapResult) :
+ mmapResult(mmapResult) {}
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ EXPECT_EQ(fakePmemDev, pathname);
+ EXPECT_EQ(O_RDWR, flags & O_RDWR);
+ EXPECT_EQ(0, mode);
+ return 5678;
+ }
+
+ virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ EXPECT_EQ(5678, fd);
+ return mmapResult;
+ }
+};
+
+TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
+ uint8_t buf[0x100]; // Create a buffer to get memzero'd
+ Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags depsMock(buf);
+ PmemKernelAllocator pma(depsMock, fakePmemDev);
+
+ void* base = 0;
+ int offset = -9182, fd = -9182;
+ int size = 0x100;
+ int flags = 0;
+ int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
+ ASSERT_EQ(0, result);
+ ASSERT_EQ(buf, base);
+ ASSERT_EQ(0, offset);
+ ASSERT_EQ(5678, fd);
+ for (int i = 0; i < 0x100; ++i) {
+ ASSERT_EQ(0, buf[i]);
+ }
+}
+
+/******************************************************************************/
+
+typedef Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags;
+
+TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
+ uint8_t buf[0x100]; // Create a buffer to get memzero'd
+ Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags depsMock(buf);
+ PmemKernelAllocator pma(depsMock, fakePmemDev);
+
+ void* base = 0;
+ int offset = -9182, fd = -9182;
+ int size = 0x100;
+ int flags = ~0;
+ int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
+ ASSERT_EQ(0, result);
+ ASSERT_EQ(buf, base);
+ ASSERT_EQ(0, offset);
+ ASSERT_EQ(5678, fd);
+ for (int i = 0; i < 0x100; ++i) {
+ ASSERT_EQ(0, buf[i]);
+ }
+}
+
+/******************************************************************************/
+
+struct Deps_KernelAllocPmemBufferWithEpermOnOpen : public DepsStub {
+
+ virtual int getErrno() {
+ return EPERM;
+ }
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ EXPECT_EQ(fakePmemDev, pathname);
+ EXPECT_EQ(O_RDWR, flags & O_RDWR);
+ EXPECT_EQ(0, mode);
+ return -1;
+ }
+};
+
+
+TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEpermOnOpen) {
+ Deps_KernelAllocPmemBufferWithEpermOnOpen depsMock;
+ PmemKernelAllocator pma(depsMock, fakePmemDev);
+
+ void* base = 0;
+ int offset = -9182, fd = -9182;
+ int size = 0x100;
+ int flags = ~0;
+ int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
+ ASSERT_EQ(-EPERM, result);
+ ASSERT_EQ(0, base);
+ ASSERT_EQ(0, offset);
+ ASSERT_EQ(-1, fd);
+}
+
+/******************************************************************************/
+
+struct Deps_KernelAllocPmemBufferWithEnomemOnMmap : DepsStub {
+
+ virtual int open(const char* pathname, int flags, int mode) {
+ EXPECT_EQ(fakePmemDev, pathname);
+ EXPECT_EQ(O_RDWR, flags & O_RDWR);
+ EXPECT_EQ(0, mode);
+ return 5678;
+ }
+
+ virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ return (void*)MAP_FAILED;
+ }
+
+ virtual int getErrno() {
+ return ENOMEM;
+ }
+};
+
+
+TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEnomemOnMmap) {
+ Deps_KernelAllocPmemBufferWithEnomemOnMmap depsMock;
+ PmemKernelAllocator pma(depsMock, fakePmemDev);
+
+ void* base = 0;
+ int offset = -9182, fd = -9182;
+ int size = 0x100;
+ int flags = ~0;
+ int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
+ ASSERT_EQ(-ENOMEM, result);
+ ASSERT_EQ(0, base);
+ ASSERT_EQ(0, offset);
+ ASSERT_EQ(-1, fd);
+}
+
+/******************************************************************************/