gralloc: add BOARD_USES_LEGACY_QCOM

Change-Id: I7fae5cf67ed4a1f00012c64c384bb621ab8bb183
This commit is contained in:
andrew sutherland 2012-01-07 22:40:24 -06:00
parent 0cba1f7659
commit bd4bfd035d
17 changed files with 3302 additions and 0 deletions

View File

@ -1,7 +1,11 @@
#Enables the listed display HAL modules
ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
ifeq ($(BOARD_USES_LEGACY_QCOM),true)
display-hals := libgralloc-legacy libcopybit
else
display-hals := libhwcomposer liboverlay libgralloc libcopybit libgenlock libtilerenderer
display-hals += libqcomui
endif
include $(call all-named-subdir-makefiles,$(display-hals))
endif

View File

@ -0,0 +1,49 @@
# 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)
# HAL module implemenation stored in
# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
include $(CLEAR_VARS)
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libcutils libGLESv1_CM
LOCAL_SRC_FILES := \
allocator.cpp \
framebuffer.cpp \
gpu.cpp \
gralloc.cpp \
mapper.cpp \
pmemalloc.cpp
LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\"
include $(BUILD_SHARED_LIBRARY)
# Build a host library for testing
ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
gpu.cpp \
pmemalloc.cpp
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := libgralloc_qsd8k_host
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc-qsd8k\"
include $(BUILD_HOST_STATIC_LIBRARY)
endif

View File

190
libgralloc-legacy/NOTICE Normal file
View File

@ -0,0 +1,190 @@
Copyright (c) 2008-2009, 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.
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.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -0,0 +1,165 @@
/*
* Copyright (C) 2009 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 <cutils/log.h>
#include "allocator.h"
// align all the memory blocks on a cache-line boundary
const int SimpleBestFitAllocator::kMemoryAlign = 32;
SimpleBestFitAllocator::SimpleBestFitAllocator()
: mHeapSize(0)
{
}
SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
: mHeapSize(0)
{
setSize(size);
}
SimpleBestFitAllocator::~SimpleBestFitAllocator()
{
while(!mList.isEmpty()) {
delete mList.remove(mList.head());
}
}
ssize_t SimpleBestFitAllocator::setSize(size_t size)
{
Locker::Autolock _l(mLock);
if (mHeapSize != 0) return -EINVAL;
size_t pagesize = getpagesize();
mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
mList.insertHead(node);
return size;
}
size_t SimpleBestFitAllocator::size() const
{
return mHeapSize;
}
ssize_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
{
Locker::Autolock _l(mLock);
if (mHeapSize == 0) return -EINVAL;
ssize_t offset = alloc(size, flags);
return offset;
}
ssize_t SimpleBestFitAllocator::deallocate(size_t offset)
{
Locker::Autolock _l(mLock);
if (mHeapSize == 0) return -EINVAL;
chunk_t const * const freed = dealloc(offset);
if (freed) {
return 0;
}
return -ENOENT;
}
ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
{
if (size == 0) {
return 0;
}
size = (size + kMemoryAlign-1) / kMemoryAlign;
chunk_t* free_chunk = 0;
chunk_t* cur = mList.head();
size_t pagesize = getpagesize();
while (cur) {
int extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
// best fit
if (cur->free && (cur->size >= (size+extra))) {
if ((!free_chunk) || (cur->size < free_chunk->size)) {
free_chunk = cur;
}
if (cur->size == size) {
break;
}
}
cur = cur->next;
}
if (free_chunk) {
const size_t free_size = free_chunk->size;
free_chunk->free = 0;
free_chunk->size = size;
if (free_size > size) {
int extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
if (extra) {
chunk_t* split = new chunk_t(free_chunk->start, extra);
free_chunk->start += extra;
mList.insertBefore(free_chunk, split);
}
LOGE_IF(((free_chunk->start*kMemoryAlign)&(pagesize-1)),
"page is not aligned!!!");
const ssize_t tail_free = free_size - (size+extra);
if (tail_free > 0) {
chunk_t* split = new chunk_t(
free_chunk->start + free_chunk->size, tail_free);
mList.insertAfter(free_chunk, split);
}
}
return (free_chunk->start)*kMemoryAlign;
}
return -ENOMEM;
}
SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
{
start = start / kMemoryAlign;
chunk_t* cur = mList.head();
while (cur) {
if (cur->start == start) {
LOG_FATAL_IF(cur->free,
"block at offset 0x%08lX of size 0x%08lX already freed",
cur->start*kMemoryAlign, cur->size*kMemoryAlign);
// merge freed blocks together
chunk_t* freed = cur;
cur->free = 1;
do {
chunk_t* const p = cur->prev;
chunk_t* const n = cur->next;
if (p && (p->free || !cur->size)) {
freed = p;
p->size += cur->size;
mList.remove(cur);
delete cur;
}
cur = n;
} while (cur && cur->free);
LOG_FATAL_IF(!freed->free,
"freed block at offset 0x%08lX of size 0x%08lX is not free!",
freed->start * kMemoryAlign, freed->size * kMemoryAlign);
return freed;
}
cur = cur->next;
}
return 0;
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2009 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_ALLOCATOR_H_
#define GRALLOC_ALLOCATOR_H_
#include <stdint.h>
#include <sys/types.h>
#include "gr.h"
#include "pmemalloc.h"
// ----------------------------------------------------------------------------
/*
* A simple templatized doubly linked-list implementation
*/
template <typename NODE>
class LinkedList
{
NODE* mFirst;
NODE* mLast;
public:
LinkedList() : mFirst(0), mLast(0) { }
bool isEmpty() const { return mFirst == 0; }
NODE const* head() const { return mFirst; }
NODE* head() { return mFirst; }
NODE const* tail() const { return mLast; }
NODE* tail() { return mLast; }
void insertAfter(NODE* node, NODE* newNode) {
newNode->prev = node;
newNode->next = node->next;
if (node->next == 0) mLast = newNode;
else node->next->prev = newNode;
node->next = newNode;
}
void insertBefore(NODE* node, NODE* newNode) {
newNode->prev = node->prev;
newNode->next = node;
if (node->prev == 0) mFirst = newNode;
else node->prev->next = newNode;
node->prev = newNode;
}
void insertHead(NODE* newNode) {
if (mFirst == 0) {
mFirst = mLast = newNode;
newNode->prev = newNode->next = 0;
} else {
newNode->prev = 0;
newNode->next = mFirst;
mFirst->prev = newNode;
mFirst = newNode;
}
}
void insertTail(NODE* newNode) {
if (mLast == 0) {
insertHead(newNode);
} else {
newNode->prev = mLast;
newNode->next = 0;
mLast->next = newNode;
mLast = newNode;
}
}
NODE* remove(NODE* node) {
if (node->prev == 0) mFirst = node->next;
else node->prev->next = node->next;
if (node->next == 0) mLast = node->prev;
else node->next->prev = node->prev;
return node;
}
};
class SimpleBestFitAllocator : public PmemUserspaceAllocator::Deps::Allocator
{
public:
SimpleBestFitAllocator();
SimpleBestFitAllocator(size_t size);
virtual ~SimpleBestFitAllocator();
virtual ssize_t setSize(size_t size);
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 {
chunk_t(size_t start, size_t size)
: start(start), size(size), free(1), prev(0), next(0) {
}
size_t start;
size_t size : 28;
int free : 4;
mutable chunk_t* prev;
mutable chunk_t* next;
};
ssize_t alloc(size_t size, uint32_t flags);
chunk_t* dealloc(size_t start);
static const int kMemoryAlign;
mutable Locker mLock;
LinkedList<chunk_t> mList;
size_t mHeapSize;
};
#endif /* GRALLOC_ALLOCATOR_H_ */

View File

@ -0,0 +1,457 @@
/*
* 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.
*/
#include <sys/mman.h>
#include <dlfcn.h>
#include <cutils/ashmem.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <linux/fb.h>
#include <linux/msm_mdp.h>
#include <GLES/gl.h>
#include "gralloc_priv.h"
#include "gr.h"
/*****************************************************************************/
// numbers of buffers for page flipping
#define NUM_BUFFERS 2
enum {
PAGE_FLIP = 0x00000001,
LOCKED = 0x00000002
};
struct fb_context_t {
framebuffer_device_t device;
};
/*****************************************************************************/
static void
msm_copy_buffer(buffer_handle_t handle, int fd,
int width, int height, int format,
int x, int y, int w, int h);
static int fb_setSwapInterval(struct framebuffer_device_t* dev,
int interval)
{
fb_context_t* ctx = (fb_context_t*)dev;
if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval)
return -EINVAL;
// FIXME: implement fb_setSwapInterval
return 0;
}
static int fb_setUpdateRect(struct framebuffer_device_t* dev,
int l, int t, int w, int h)
{
if (((w|h) <= 0) || ((l|t)<0))
return -EINVAL;
fb_context_t* ctx = (fb_context_t*)dev;
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
m->info.reserved[0] = 0x54445055; // "UPDT";
m->info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
m->info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
return 0;
}
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
if (private_handle_t::validate(buffer) < 0)
return -EINVAL;
fb_context_t* ctx = (fb_context_t*)dev;
private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
if (m->currentBuffer) {
m->base.unlock(&m->base, m->currentBuffer);
m->currentBuffer = 0;
}
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
m->base.lock(&m->base, buffer,
private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
0, 0, m->info.xres, m->info.yres, NULL);
const size_t offset = hnd->base - m->framebuffer->base;
m->info.activate = FB_ACTIVATE_VBL;
m->info.yoffset = offset / m->finfo.line_length;
if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
LOGE("FBIOPUT_VSCREENINFO failed");
m->base.unlock(&m->base, buffer);
return -errno;
}
m->currentBuffer = buffer;
} else {
void* fb_vaddr;
void* buffer_vaddr;
m->base.lock(&m->base, m->framebuffer,
GRALLOC_USAGE_SW_WRITE_RARELY,
0, 0, m->info.xres, m->info.yres,
&fb_vaddr);
m->base.lock(&m->base, buffer,
GRALLOC_USAGE_SW_READ_RARELY,
0, 0, m->info.xres, m->info.yres,
&buffer_vaddr);
//memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
msm_copy_buffer(
m->framebuffer, m->framebuffer->fd,
m->info.xres, m->info.yres, m->fbFormat,
m->info.xoffset, m->info.yoffset,
m->info.width, m->info.height);
m->base.unlock(&m->base, buffer);
m->base.unlock(&m->base, m->framebuffer);
}
return 0;
}
static int fb_compositionComplete(struct framebuffer_device_t* dev)
{
// TODO: Properly implement composition complete callback
glFinish();
return 0;
}
/*****************************************************************************/
int mapFrameBufferLocked(struct private_module_t* module)
{
// already initialized...
if (module->framebuffer) {
return 0;
}
char const * const device_template[] = {
"/dev/graphics/fb%u",
"/dev/fb%u",
0 };
int fd = -1;
int i=0;
char name[64];
while ((fd==-1) && device_template[i]) {
snprintf(name, 64, device_template[i], 0);
fd = open(name, O_RDWR, 0);
i++;
}
if (fd < 0)
return -errno;
struct fb_fix_screeninfo finfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
struct fb_var_screeninfo info;
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
info.reserved[0] = 0;
info.reserved[1] = 0;
info.reserved[2] = 0;
info.xoffset = 0;
info.yoffset = 0;
info.activate = FB_ACTIVATE_NOW;
/* Interpretation of offset for color fields: All offsets are from the right,
* inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you
* can use the offset as right argument to <<). A pixel afterwards is a bit
* stream and is written to video memory as that unmodified. This implies
* big-endian byte order if bits_per_pixel is greater than 8.
*/
/*
* Explicitly request RGBA_8888
*/
info.bits_per_pixel = 32;
info.red.offset = 24;
info.red.length = 8;
info.green.offset = 16;
info.green.length = 8;
info.blue.offset = 8;
info.blue.length = 8;
info.transp.offset = 0;
info.transp.length = 0;
/* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do
* not use the MDP for composition (i.e. hw composition == 0), ask for
* RGBA instead of RGBX. */
char property[PROPERTY_VALUE_MAX];
if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0)
module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;
else
module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888;
/*
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
*/
info.yres_virtual = info.yres * NUM_BUFFERS;
uint32_t flags = PAGE_FLIP;
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
}
if (info.yres_virtual < info.yres * 2) {
// we need at least 2 for page-flipping
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
info.yres_virtual, info.yres*2);
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
uint64_t refreshQuotient =
(
uint64_t( info.upper_margin + info.lower_margin + info.yres )
* ( info.left_margin + info.right_margin + info.xres )
* info.pixclock
);
/* Beware, info.pixclock might be 0 under emulation, so avoid a
* division-by-0 here (SIGFPE on ARM) */
int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;
if (refreshRate == 0) {
// bleagh, bad info from the driver
refreshRate = 60*1000; // 60 Hz
}
if (int(info.width) <= 0 || int(info.height) <= 0) {
// the driver doesn't return that information
// default to 160 dpi
info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
}
float xdpi = (info.xres * 25.4f) / info.width;
float ydpi = (info.yres * 25.4f) / info.height;
float fps = refreshRate / 1000.0f;
LOGI( "using (fd=%d)\n"
"id = %s\n"
"xres = %d px\n"
"yres = %d px\n"
"xres_virtual = %d px\n"
"yres_virtual = %d px\n"
"bpp = %d\n"
"r = %2u:%u\n"
"g = %2u:%u\n"
"b = %2u:%u\n",
fd,
finfo.id,
info.xres,
info.yres,
info.xres_virtual,
info.yres_virtual,
info.bits_per_pixel,
info.red.offset, info.red.length,
info.green.offset, info.green.length,
info.blue.offset, info.blue.length
);
LOGI( "width = %d mm (%f dpi)\n"
"height = %d mm (%f dpi)\n"
"refresh rate = %.2f Hz\n",
info.width, xdpi,
info.height, ydpi,
fps
);
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
if (finfo.smem_len <= 0)
return -errno;
module->flags = flags;
module->info = info;
module->finfo = finfo;
module->xdpi = xdpi;
module->ydpi = ydpi;
module->fps = fps;
/*
* map the framebuffer
*/
int err;
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
module->framebuffer = new private_handle_t(dup(fd), fbSize,
private_handle_t::PRIV_FLAGS_USES_PMEM);
module->numBuffers = info.yres_virtual / info.yres;
module->bufferMask = 0;
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr == MAP_FAILED) {
LOGE("Error mapping the framebuffer (%s)", strerror(errno));
return -errno;
}
module->framebuffer->base = intptr_t(vaddr);
memset(vaddr, 0, fbSize);
return 0;
}
static int mapFrameBuffer(struct private_module_t* module)
{
pthread_mutex_lock(&module->lock);
int err = mapFrameBufferLocked(module);
pthread_mutex_unlock(&module->lock);
return err;
}
/*****************************************************************************/
static int fb_close(struct hw_device_t *dev)
{
fb_context_t* ctx = (fb_context_t*)dev;
if (ctx) {
free(ctx);
}
return 0;
}
int fb_device_open(hw_module_t const* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
alloc_device_t* gralloc_device;
status = gralloc_open(module, &gralloc_device);
if (status < 0)
return status;
/* initialize our state here */
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
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 = fb_close;
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;
dev->device.setUpdateRect = 0;
dev->device.compositionComplete = fb_compositionComplete;
private_module_t* m = (private_module_t*)module;
status = mapFrameBuffer(m);
if (status >= 0) {
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
const_cast<uint32_t&>(dev->device.flags) = 0;
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.stride) = stride;
const_cast<int&>(dev->device.format) = m->fbFormat;
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
const_cast<int&>(dev->device.minSwapInterval) = 1;
const_cast<int&>(dev->device.maxSwapInterval) = 1;
if (m->finfo.reserved[0] == 0x5444 &&
m->finfo.reserved[1] == 0x5055) {
dev->device.setUpdateRect = fb_setUpdateRect;
LOGD("UPDATE_ON_DEMAND supported");
}
*device = &dev->device.common;
}
}
return status;
}
/* Copy a pmem buffer to the framebuffer */
static void
msm_copy_buffer(buffer_handle_t handle, int fd,
int width, int height, int format,
int x, int y, int w, int h)
{
struct {
unsigned int count;
mdp_blit_req req;
} blit;
private_handle_t *priv = (private_handle_t*) handle;
memset(&blit, 0, sizeof(blit));
blit.count = 1;
blit.req.flags = 0;
blit.req.alpha = 0xff;
blit.req.transp_mask = 0xffffffff;
blit.req.src.width = width;
blit.req.src.height = height;
blit.req.src.offset = 0;
blit.req.src.memory_id = priv->fd;
blit.req.dst.width = width;
blit.req.dst.height = height;
blit.req.dst.offset = 0;
blit.req.dst.memory_id = fd;
blit.req.dst.format = format;
blit.req.src_rect.x = blit.req.dst_rect.x = x;
blit.req.src_rect.y = blit.req.dst_rect.y = y;
blit.req.src_rect.w = blit.req.dst_rect.w = w;
blit.req.src_rect.h = blit.req.dst_rect.h = h;
if (ioctl(fd, MSMFB_BLIT, &blit))
LOGE("MSMFB_BLIT failed = %d", -errno);
}

341
libgralloc-legacy/gpu.cpp Normal file
View File

@ -0,0 +1,341 @@
/*
* 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_MASK) == 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_ADRENO: // 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:
if ((w&1) || (h&1)) {
LOGE("w or h is odd for HAL_PIXEL_FORMAT_YV12");
return -EINVAL;
}
alignedw = ALIGN(w, 16);
alignedh = h;
size = alignedw*alignedh +
(ALIGN(alignedw/2, 16) * (alignedh/2))*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;
}
if (pmem_allocator) {
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() {}

76
libgralloc-legacy/gpu.h Normal file
View File

@ -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

63
libgralloc-legacy/gr.h Normal file
View File

@ -0,0 +1,63 @@
/*
* 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 GR_H_
#define GR_H_
#include <stdint.h>
#ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define
# include <asm/page.h>
#else
# include <sys/user.h>
#endif
#include <limits.h>
#include <sys/cdefs.h>
#include <hardware/gralloc.h>
#include <pthread.h>
#include <errno.h>
#include <cutils/native_handle.h>
/*****************************************************************************/
struct private_module_t;
struct private_handle_t;
inline size_t roundUpToPageSize(size_t x) {
return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
}
int mapFrameBufferLocked(struct private_module_t* module);
int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd);
/*****************************************************************************/
class Locker {
pthread_mutex_t mutex;
public:
class Autolock {
Locker& locker;
public:
inline Autolock(Locker& locker) : locker(locker) { locker.lock(); }
inline ~Autolock() { locker.unlock(); }
};
inline Locker() { pthread_mutex_init(&mutex, 0); }
inline ~Locker() { pthread_mutex_destroy(&mutex); }
inline void lock() { pthread_mutex_lock(&mutex); }
inline void unlock() { pthread_mutex_unlock(&mutex); }
};
#endif /* GR_H_ */

View File

@ -0,0 +1,196 @@
/*
* 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.
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/android_pmem.h>
#include "allocator.h"
#include "gr.h"
#include "gpu.h"
/*****************************************************************************/
static int gralloc_alloc_buffer(alloc_device_t* dev,
size_t size, int usage, buffer_handle_t* pHandle);
/*****************************************************************************/
int fb_device_open(const hw_module_t* module, const char* name,
hw_device_t** device);
static int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device);
extern int gralloc_lock(gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
extern int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle);
extern int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle);
extern int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle);
extern int gralloc_perform(struct gralloc_module_t const* module,
int operation, ... );
/*****************************************************************************/
/* On-device dependency implementation */
class PmemAllocatorDepsDeviceImpl : public PmemUserspaceAllocator::Deps,
public PmemKernelAllocator::Deps {
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;
}
virtual int connectPmem(int fd, int master_fd) {
return ioctl(fd, PMEM_CONNECT, master_fd);
}
virtual int mapPmem(int fd, int offset, size_t size) {
struct pmem_region sub = { offset, size };
return ioctl(fd, PMEM_MAP, &sub);
}
virtual int unmapPmem(int fd, int offset, size_t size) {
struct pmem_region sub = { offset, size };
return ioctl(fd, PMEM_UNMAP, &sub);
}
virtual int getErrno() {
return errno;
}
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);
}
virtual int munmap(void* start, size_t length) {
return ::munmap(start, length);
}
virtual int open(const char* pathname, int flags, int mode) {
return ::open(pathname, flags, mode);
}
virtual int close(int fd) {
return ::close(fd);
}
};
class GpuContextDepsDeviceImpl : public gpu_context_t::Deps {
public:
virtual int ashmem_create_region(const char *name, size_t size) {
return ::ashmem_create_region(name, size);
}
virtual int mapFrameBufferLocked(struct private_module_t* module) {
return ::mapFrameBufferLocked(module);
}
virtual int terminateBuffer(gralloc_module_t const* module,
private_handle_t* hnd) {
return ::terminateBuffer(module, hnd);
}
virtual int close(int fd) {
return ::close(fd);
}
};
static PmemAllocatorDepsDeviceImpl pmemAllocatorDeviceDepsImpl;
static GpuContextDepsDeviceImpl gpuContextDeviceDepsImpl;
/*****************************************************************************/
static SimpleBestFitAllocator pmemAllocMgr;
static PmemUserspaceAllocator pmemAllocator(pmemAllocatorDeviceDepsImpl, pmemAllocMgr,
"/dev/pmem");
static PmemKernelAllocator pmemAdspAllocator(pmemAllocatorDeviceDepsImpl,
"/dev/pmem_adsp");
/*****************************************************************************/
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)) {
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);
}
return status;
}

View File

@ -0,0 +1,165 @@
/*
* 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_PRIV_H_
#define GRALLOC_PRIV_H_
#include <stdint.h>
#include <limits.h>
#include <sys/cdefs.h>
#include <hardware/gralloc.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <cutils/native_handle.h>
#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,
};
/*****************************************************************************/
enum {
/* OEM specific HAL formats */
//HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x100, // defined in hardware.h
//HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x101, // defined in hardware.h
HAL_PIXEL_FORMAT_YCbCr_422_P = 0x102,
HAL_PIXEL_FORMAT_YCbCr_420_P = 0x103,
//HAL_PIXEL_FORMAT_YCbCr_422_I = 0x104, // defined in hardware.h
HAL_PIXEL_FORMAT_YCbCr_420_I = 0x105,
HAL_PIXEL_FORMAT_CbYCrY_422_I = 0x106,
HAL_PIXEL_FORMAT_CbYCrY_420_I = 0x107,
HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED = 0x108,
HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x109,
HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x10A,
HAL_PIXEL_FORMAT_YCrCb_422_SP = 0x10B,
HAL_PIXEL_FORMAT_YCrCb_420_SP_INTERLACE = 0x10C,
};
/*****************************************************************************/
struct private_module_t;
struct private_handle_t;
struct PmemAllocator;
struct private_module_t {
gralloc_module_t base;
struct private_handle_t* framebuffer;
uint32_t fbFormat;
uint32_t flags;
uint32_t numBuffers;
uint32_t bufferMask;
pthread_mutex_t lock;
buffer_handle_t currentBuffer;
struct fb_var_screeninfo info;
struct fb_fix_screeninfo finfo;
float xdpi;
float ydpi;
float fps;
enum {
// flag to indicate we'll post this buffer
PRIV_USAGE_LOCKED_FOR_POST = 0x80000000
};
};
/*****************************************************************************/
#ifdef __cplusplus
struct private_handle_t : public native_handle {
#else
struct private_handle_t {
native_handle_t nativeHandle;
#endif
enum {
PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
PRIV_FLAGS_USES_PMEM = 0x00000002,
PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004,
PRIV_FLAGS_NEEDS_FLUSH = 0x00000008,
};
enum {
LOCK_STATE_WRITE = 1<<31,
LOCK_STATE_MAPPED = 1<<30,
LOCK_STATE_READ_MASK = 0x3FFFFFFF
};
// file-descriptors
int fd;
// ints
int magic;
int flags;
int size;
int offset;
int gpu_fd; // stored as an int, b/c we don't want it marshalled
// FIXME: the attributes below should be out-of-line
int base;
int lockState;
int writeOwner;
int gpuaddr; // The gpu address mapped into the mmu. If using ashmem, set to 0 They don't care
int pid;
#ifdef __cplusplus
static const int sNumInts = 10;
static const int sNumFds = 1;
static const int sMagic = 'gmsm';
private_handle_t(int fd, int size, int flags) :
fd(fd), magic(sMagic), flags(flags), size(size), offset(0), gpu_fd(-1),
base(0), lockState(0), writeOwner(0), gpuaddr(0), pid(getpid())
{
version = sizeof(native_handle);
numInts = sNumInts;
numFds = sNumFds;
}
~private_handle_t() {
magic = 0;
}
bool usesPhysicallyContiguousMemory() {
return (flags & PRIV_FLAGS_USES_PMEM) != 0;
}
static int validate(const native_handle* h) {
const private_handle_t* hnd = (const private_handle_t*)h;
if (!h || h->version != sizeof(native_handle) ||
h->numInts != sNumInts || h->numFds != sNumFds ||
hnd->magic != sMagic)
{
LOGE("invalid gralloc handle (at %p)", h);
return -EINVAL;
}
return 0;
}
static private_handle_t* dynamicCast(const native_handle* in) {
if (validate(in) == 0) {
return (private_handle_t*) in;
}
return NULL;
}
#endif
};
#endif /* GRALLOC_PRIV_H_ */

View File

@ -0,0 +1,325 @@
/*
* 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.
*/
#include <limits.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <linux/android_pmem.h>
#include "gralloc_priv.h"
// we need this for now because pmem cannot mmap at an offset
#define PMEM_HACK 1
/* desktop Linux needs a little help with gettid() */
#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)
#define __KERNEL__
# include <linux/unistd.h>
pid_t gettid() { return syscall(__NR_gettid);}
#undef __KERNEL__
#endif
/*****************************************************************************/
static int gralloc_map(gralloc_module_t const* module,
buffer_handle_t handle,
void** vaddr)
{
private_handle_t* hnd = (private_handle_t*)handle;
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
size_t size = hnd->size;
#if PMEM_HACK
size += hnd->offset;
#endif
void* mappedAddress = mmap(0, size,
PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
if (mappedAddress == MAP_FAILED) {
LOGE("Could not mmap handle %p, fd=%d (%s)",
handle, hnd->fd, strerror(errno));
hnd->base = 0;
return -errno;
}
hnd->base = intptr_t(mappedAddress) + hnd->offset;
//LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
// hnd->fd, hnd->offset, hnd->size, mappedAddress);
}
*vaddr = (void*)hnd->base;
return 0;
}
static int gralloc_unmap(gralloc_module_t const* module,
buffer_handle_t handle)
{
private_handle_t* hnd = (private_handle_t*)handle;
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
void* base = (void*)hnd->base;
size_t size = hnd->size;
#if PMEM_HACK
base = (void*)(intptr_t(base) - hnd->offset);
size += hnd->offset;
#endif
//LOGD("unmapping from %p, size=%d", base, size);
if (munmap(base, size) < 0) {
LOGE("Could not unmap %s", strerror(errno));
}
}
hnd->base = 0;
return 0;
}
/*****************************************************************************/
static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER;
/*****************************************************************************/
int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
// In this implementation, we don't need to do anything here
/* NOTE: we need to initialize the buffer as not mapped/not locked
* because it shouldn't when this function is called the first time
* in a new process. Ideally these flags shouldn't be part of the
* handle, but instead maintained in the kernel or at least
* out-of-line
*/
// if this handle was created in this process, then we keep it as is.
private_handle_t* hnd = (private_handle_t*)handle;
if (hnd->pid != getpid()) {
hnd->base = 0;
hnd->lockState = 0;
hnd->writeOwner = 0;
}
return 0;
}
int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
/*
* If the buffer has been mapped during a lock operation, it's time
* to un-map it. It's an error to be here with a locked buffer.
* NOTE: the framebuffer is handled differently and is never unmapped.
*/
private_handle_t* hnd = (private_handle_t*)handle;
LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
"[unregister] handle %p still locked (state=%08x)",
hnd, hnd->lockState);
// never unmap buffers that were created in this process
if (hnd->pid != getpid()) {
if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
gralloc_unmap(module, handle);
}
hnd->base = 0;
hnd->lockState = 0;
hnd->writeOwner = 0;
}
return 0;
}
int terminateBuffer(gralloc_module_t const* module,
private_handle_t* hnd)
{
/*
* If the buffer has been mapped during a lock operation, it's time
* to un-map it. It's an error to be here with a locked buffer.
*/
LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
"[terminate] handle %p still locked (state=%08x)",
hnd, hnd->lockState);
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) ||
(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.
// (see gralloc_alloc_buffer())
gralloc_unmap(module, hnd);
}
} else {
gralloc_unmap(module, hnd);
}
}
return 0;
}
int gralloc_lock(gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
int err = 0;
private_handle_t* hnd = (private_handle_t*)handle;
int32_t current_value, new_value;
int retry;
do {
current_value = hnd->lockState;
new_value = current_value;
if (current_value & private_handle_t::LOCK_STATE_WRITE) {
// already locked for write
LOGE("handle %p already locked for write", handle);
return -EBUSY;
} else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) {
// already locked for read
if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
LOGE("handle %p already locked for read", handle);
return -EBUSY;
} else {
// this is not an error
//LOGD("%p already locked for read... count = %d",
// handle, (current_value & ~(1<<31)));
}
}
// not currently locked
if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
// locking for write
new_value |= private_handle_t::LOCK_STATE_WRITE;
}
new_value++;
retry = android_atomic_cmpxchg(current_value, new_value,
(volatile int32_t*)&hnd->lockState);
} while (retry);
if (new_value & private_handle_t::LOCK_STATE_WRITE) {
// locking for write, store the tid
hnd->writeOwner = gettid();
}
// if requesting sw write for non-framebuffer handles, flag for
// flushing at unlock
const uint32_t pmemMask =
private_handle_t::PRIV_FLAGS_USES_PMEM |
private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) &&
(hnd->flags & pmemMask) &&
!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
}
if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) {
// we need to map for real
pthread_mutex_t* const lock = &sMapLock;
pthread_mutex_lock(lock);
if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) {
err = gralloc_map(module, handle, vaddr);
if (err == 0) {
android_atomic_or(private_handle_t::LOCK_STATE_MAPPED,
(volatile int32_t*)&(hnd->lockState));
}
}
pthread_mutex_unlock(lock);
}
*vaddr = (void*)hnd->base;
}
return err;
}
int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
private_handle_t* hnd = (private_handle_t*)handle;
int32_t current_value, new_value;
if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) {
struct pmem_region region;
int err;
region.offset = hnd->offset;
region.len = hnd->size;
err = ioctl(hnd->fd, PMEM_CACHE_FLUSH, &region);
LOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x)\n",
hnd, hnd->offset, hnd->size);
hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
}
do {
current_value = hnd->lockState;
new_value = current_value;
if (current_value & private_handle_t::LOCK_STATE_WRITE) {
// locked for write
if (hnd->writeOwner == gettid()) {
hnd->writeOwner = 0;
new_value &= ~private_handle_t::LOCK_STATE_WRITE;
}
}
if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) {
LOGE("handle %p not locked", handle);
return -EINVAL;
}
new_value--;
} while (android_atomic_cmpxchg(current_value, new_value,
(volatile int32_t*)&hnd->lockState));
return 0;
}
/*****************************************************************************/
int gralloc_perform(struct gralloc_module_t const* module,
int operation, ... )
{
int res = -EINVAL;
return res;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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))

View File

@ -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);
}
/******************************************************************************/