Implement MemChunk::registerAllocFreeCallbacks().

This function allows a driver implementation to register its own handler for
allocating/freeing MemChunk objects. MemChunk is primarily used by the ELF
loader for various code/data segments.

Change-Id: If497f07a538c714933fcaa1b0c04ed5a6febeeba
diff --git a/driver/linkloader/include/MemChunk.h b/driver/linkloader/include/MemChunk.h
index fb853e9..c4d78c9 100644
--- a/driver/linkloader/include/MemChunk.h
+++ b/driver/linkloader/include/MemChunk.h
@@ -18,12 +18,22 @@
 #define MEM_CHUNK_H
 
 #include <stddef.h>
+#include <stdint.h>
 #include <stdlib.h>
 
+typedef void *(*AllocFunc) (size_t, uint32_t);
+typedef void (*FreeFunc) (void *);
+
 class MemChunk {
 private:
   unsigned char *buf;
   size_t buf_size;
+  bool bVendorBuf;
+
+  static AllocFunc VendorAlloc;
+  static FreeFunc VendorFree;
+
+  bool invalidBuf() const;
 
 public:
   MemChunk();
@@ -56,6 +66,12 @@
     return buf_size;
   }
 
+  // The allocation function must return page-aligned memory or we will be
+  // unable to mprotect the region appropriately.
+  static void registerAllocFreeCallbacks(AllocFunc a, FreeFunc f) {
+    VendorAlloc = a;
+    VendorFree = f;
+  }
 };
 
 #endif // MEM_CHUNK_H
diff --git a/driver/linkloader/lib/MemChunk.cpp b/driver/linkloader/lib/MemChunk.cpp
index 24dcf8e..c01305a 100644
--- a/driver/linkloader/lib/MemChunk.cpp
+++ b/driver/linkloader/lib/MemChunk.cpp
@@ -37,32 +37,49 @@
 static uintptr_t StartAddr = 0x7e000000UL;
 #endif
 
-MemChunk::MemChunk() : buf((unsigned char *)MAP_FAILED), buf_size(0) {
+AllocFunc MemChunk::VendorAlloc = NULL;
+FreeFunc MemChunk::VendorFree = NULL;
+
+MemChunk::MemChunk() : buf(NULL), buf_size(0), bVendorBuf(true) {
 }
 
 MemChunk::~MemChunk() {
-  if (buf != MAP_FAILED) {
+  if (!invalidBuf() && bVendorBuf && VendorFree) {
+    (*VendorFree)(buf);
+    return;
+  }
+  if (!invalidBuf()) {
     munmap(buf, buf_size);
   }
 }
 
+bool MemChunk::invalidBuf() const {
+  return (buf == 0 || buf == (unsigned char *)MAP_FAILED);
+}
+
 bool MemChunk::allocate(size_t size) {
   if (size == 0) {
     return true;
   }
+  if (VendorAlloc) {
+    buf = (unsigned char*)(*VendorAlloc)(size, 0);
+  }
+  if (invalidBuf()) {
+    bVendorBuf = false;
 #if USE_FIXED_ADDR_MEM_CHUNK
-  buf = (unsigned char *)mmap((void *)StartAddr, size,
-                              PROT_READ | PROT_WRITE,
-                              MAP_PRIVATE | MAP_ANON | MAP_32BIT,
-                              -1, 0);
+    buf = (unsigned char *)mmap((void *)StartAddr, size,
+                                PROT_READ | PROT_WRITE,
+                                MAP_PRIVATE | MAP_ANON | MAP_32BIT,
+                                -1, 0);
 #else
-  buf = (unsigned char *)mmap(0, size,
-                              PROT_READ | PROT_WRITE,
-                              MAP_PRIVATE | MAP_ANON | MAP_32BIT,
-                              -1, 0);
+    buf = (unsigned char *)mmap(0, size,
+                                PROT_READ | PROT_WRITE,
+                                MAP_PRIVATE | MAP_ANON | MAP_32BIT,
+                                -1, 0);
 #endif
+  }
 
-  if (buf == MAP_FAILED) {
+  if (invalidBuf()) {
     return false;
   }
 
@@ -75,7 +92,7 @@
 }
 
 void MemChunk::print() const {
-  if (buf != MAP_FAILED) {
+  if (!invalidBuf()) {
     dump_hex(buf, buf_size, 0, buf_size);
   }
 }
diff --git a/driver/rsdCore.cpp b/driver/rsdCore.cpp
index 3357969..4aad52a 100644
--- a/driver/rsdCore.cpp
+++ b/driver/rsdCore.cpp
@@ -20,6 +20,7 @@
 #include "rsdAllocation.h"
 #include "rsdBcc.h"
 #ifndef RS_COMPATIBILITY_LIB
+    #include "MemChunk.h"
     #include "rsdGL.h"
     #include "rsdPath.h"
     #include "rsdProgramStore.h"
@@ -189,7 +190,7 @@
     }
     rsc->mHal.drv = dc;
 
-    dc->mCpuRef = RsdCpuReference::create((Context *)c, version_major, version_minor,
+    dc->mCpuRef = RsdCpuReference::create(rsc, version_major, version_minor,
                                           &rsdLookupRuntimeStub, &LookupScript);
     if (!dc->mCpuRef) {
         ALOGE("RsdCpuReference::create for driver hal failed.");
@@ -202,6 +203,16 @@
     if (false) {
         dc->mCpuRef->setSetupCompilerCallback(NULL);
     }
+
+    // Set a callback for switching MemChunk's allocator here.
+    // Note that the allocation function must return page-aligned memory, so
+    // that it can be mprotected properly (i.e. code should be written and
+    // later switched to read+execute only).
+    if (false) {
+        MemChunk::registerAllocFreeCallbacks(
+                rsc->mHal.funcs.allocRuntimeMem,
+                rsc->mHal.funcs.freeRuntimeMem);
+    }
 #endif
 
     return true;