Secure DPU: Allocate buffer from NS

New commands are added to the secure DPU:

SECURE_DPU_CMD_ALLOCATE_BUFFER: this command sends the request to NS
for allocating buffer with buffer length as the argument. The response
indicates the handle used to map the buffer on the Trusty.

Bug: 176508588
Change-Id: Ida8cbee736bb77928b4abfe45fad059930ae2bc9
diff --git a/interface/secure_dpu/include/interface/secure_dpu/secure_dpu.h b/interface/secure_dpu/include/interface/secure_dpu/secure_dpu.h
index 921d24b..b939d44 100644
--- a/interface/secure_dpu/include/interface/secure_dpu/secure_dpu.h
+++ b/interface/secure_dpu/include/interface/secure_dpu/secure_dpu.h
@@ -23,13 +23,18 @@
  *
  * The Secure DPU works as the persistent channel between the non-secure and the
  * secure world. The channel is established during the boot up stage of the
- * non-secure world system.
+ * non-secure world system. In general, the established channel allows the
+ * secure world applications initiate requests or notifications to the non-secure
+ * world.
  *
- * The channel allows the secure world application to issue commands with
- * operations needed to be performed by the non-secure world system. These
- * operations include starting / stopping the secure display mode. The secure
- * world application can only control the display when the system is set as the
- * secure display mode.
+ * For particular devices, the secure world can only perform operations on the
+ * display when in the TUI session if device-specific setup is done by the
+ * non-secure world. Besides, the non-secure world could allocate framebuffer
+ * for the secure world application if the memory is limited in the secure world
+ * on specific devices.
+ *
+ * Currently, supported requests are to start / stop the secure display mode and
+ * to allocate framebuffer.
  *
  * This header file needs to be synced on both the Trusty and the Android
  * codebase.
@@ -48,12 +53,35 @@
  *      Notify the system to start secure display mode
  * @SECURE_DPU_CMD_STOP_SECURE_DISPLAY:
  *      Notify the system to stop secure display mode
+ * @SECURE_DPU_CMD_ALLOCATE_BUFFER:
+ *      Request non-secure world to allocate the buffer
  */
 enum secure_dpu_cmd {
     SECURE_DPU_CMD_RESP_BIT = 1,
     SECURE_DPU_CMD_REQ_SHIFT = 1,
     SECURE_DPU_CMD_START_SECURE_DISPLAY = (1 << SECURE_DPU_CMD_REQ_SHIFT),
     SECURE_DPU_CMD_STOP_SECURE_DISPLAY = (2 << SECURE_DPU_CMD_REQ_SHIFT),
+    SECURE_DPU_CMD_ALLOCATE_BUFFER = (3 << SECURE_DPU_CMD_REQ_SHIFT),
+};
+
+/**
+ * struct secure_dpu_allocate_buffer_req - payload for
+ *                                         %SECURE_DPU_CMD_ALLOCATE_BUFFER
+ *                                         request
+ * @buffer_len: Requested length
+ */
+struct secure_dpu_allocate_buffer_req {
+    uint64_t buffer_len;
+};
+
+/**
+ * struct secure_dpu_allocate_buffer_resp - payload for
+ *                                          %SECURE_DPU_CMD_ALLOCATE_BUFFER
+ *                                          response
+ * @buffer_len: Allocated length
+ */
+struct secure_dpu_allocate_buffer_resp {
+    uint64_t buffer_len;
 };
 
 /**
diff --git a/lib/secure_dpu/include/lib/secure_dpu/secure_dpu.h b/lib/secure_dpu/include/lib/secure_dpu/secure_dpu.h
index 6d6d604..43d0d0d 100644
--- a/lib/secure_dpu/include/lib/secure_dpu/secure_dpu.h
+++ b/lib/secure_dpu/include/lib/secure_dpu/secure_dpu.h
@@ -21,6 +21,11 @@
 
 __BEGIN_CDECLS
 
+struct secure_dpu_buf_info {
+    void* addr;
+    size_t len;
+};
+
 /**
  * add_secure_dpu_service() - Add secure_dpu service.
  * @hset: pointer to the tipc hset.
@@ -38,21 +43,22 @@
 /**
  * secure_dpu_allocate_buffer() - Allocate framebuffer.
  * @chan: channel handle
- * @buffer_ptr: The physical address of the allocated buffer
- * @buffer_len: The requested size / The size of the allocated buffer
+ * @buffer_len: requested length of the buffer
+ * @buf_info: information of the allocated buffer.
  *
  * Return: 0 on success, or an error code < 0 on failure.
  */
-int secure_dpu_allocate_buffer(handle_t chan, void** buffer_ptr, size_t* buffer_len);
+int secure_dpu_allocate_buffer(handle_t chan,
+                               size_t buffer_len,
+                               struct secure_dpu_buf_info* buf_info);
 
 /**
- * secure_dpu_free_buffer() - free framebuffer.
- * @chan: channel handle
- * @buffer_ptr: pointer to buffer to be freed
+ * secure_dpu_release_buffer() - release framebuffer.
+ * @buf_info: information of the buffer to be freed
  *
  * Return: 0 on success, or an error code < 0 on failure.
  */
-int secure_dpu_free_buffer(handle_t chan, void* buffer_ptr);
+int secure_dpu_release_buffer(struct secure_dpu_buf_info* buf_info);
 
 /**
  * secure_dpu_start_secure_display() - notify DPU driver to start secure display
diff --git a/lib/secure_dpu/secure_dpu.c b/lib/secure_dpu/secure_dpu.c
index f26046a..43cffc5 100644
--- a/lib/secure_dpu/secure_dpu.c
+++ b/lib/secure_dpu/secure_dpu.c
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/auxv.h>
+#include <sys/mman.h>
 #include <trusty_ipc.h>
 #include <trusty_log.h>
 #include <uapi/err.h>
@@ -37,7 +38,6 @@
      * Update this pointer when connecting / disconnecting.
      */
     handle_t* chan;
-    void* fb_buf_ptr;
 };
 
 static struct secure_dpu_ctx ctx;
@@ -53,8 +53,98 @@
     .priv = &ctx,
 };
 
-int secure_dpu_allocate_buffer(handle_t chan, void** buffer_ptr, size_t* buffer_len) {
-    if (!buffer_ptr || !buffer_len) {
+static int handle_allocate_buffer_resp(handle_t chan,
+                                       size_t buffer_len,
+                                       struct secure_dpu_buf_info* buf_info) {
+    int rc = NO_ERROR;
+    struct uevent evt;
+    struct secure_dpu_resp hdr;
+    struct secure_dpu_allocate_buffer_resp resp;
+    handle_t buf_handle;
+
+    struct iovec iov[] = {
+        {
+            .iov_base = &hdr,
+            .iov_len = sizeof(hdr),
+        },
+        {
+            .iov_base = &resp,
+            .iov_len = sizeof(resp),
+        },
+    };
+
+    struct ipc_msg msg = {
+            .iov = iov,
+            .num_iov = countof(iov),
+            .handles = &buf_handle,
+            .num_handles = 1,
+    };
+
+    rc = wait(chan, &evt, INFINITE_TIME);
+    if (rc != NO_ERROR) {
+        TLOGE("Error waiting for response (%d)\n", rc);
+        return rc;
+    }
+
+    struct ipc_msg_info msg_inf;
+    rc = get_msg(chan, &msg_inf);
+    if (rc) {
+        return rc;
+    }
+
+    if (msg_inf.num_handles != 1) {
+        TLOGE("Message had no handles\n");
+        return ERR_INVALID_ARGS;
+    }
+
+    rc = read_msg(chan, msg_inf.id, 0, &msg);
+    put_msg(chan, msg_inf.id);
+    if (rc != (int)(sizeof(hdr) + sizeof(resp))) {
+        TLOGE("Read length does not match\n");
+        close(buf_handle);
+        return ERR_BAD_LEN;
+    }
+
+    if (hdr.cmd != (SECURE_DPU_CMD_ALLOCATE_BUFFER | SECURE_DPU_CMD_RESP_BIT)) {
+        close(buf_handle);
+        return ERR_CMD_UNKNOWN;
+    }
+
+    if (hdr.status != SECURE_DPU_ERROR_OK) {
+        TLOGE("Failed SECURE_DPU_CMD_ALLOCATE_BUFFER (%d)\n", hdr.status);
+        close(buf_handle);
+        return ERR_GENERIC;
+    }
+
+    if ((size_t)resp.buffer_len < buffer_len) {
+        TLOGE("Not allocated enough buffer length, "
+              "requested (%zu), allocated (%zu)\n", (size_t)buffer_len,
+                                                    (size_t)resp.buffer_len);
+        close(buf_handle);
+        return ERR_NOT_ENOUGH_BUFFER;
+    }
+
+    void* out = mmap(0, (size_t)resp.buffer_len, PROT_READ | PROT_WRITE, 0,
+                     buf_handle, 0);
+    if (!out) {
+        TLOGE("Error when calling mmap()\n");
+        return ERR_BAD_HANDLE;
+    }
+    close(buf_handle);
+    buf_info->addr = (void*)out;
+    buf_info->len = (size_t)resp.buffer_len;
+
+    return NO_ERROR;
+}
+
+int secure_dpu_allocate_buffer(handle_t chan,
+                               size_t buffer_len,
+                               struct secure_dpu_buf_info* buf_info) {
+
+    int rc;
+    struct secure_dpu_req hdr;
+    struct secure_dpu_allocate_buffer_req args;
+    if (!buf_info) {
         TLOGE("Invalid arguments to allocate DPU buffer\n");
         return ERR_INVALID_ARGS;
     }
@@ -63,26 +153,35 @@
         return ERR_NOT_READY;
     }
 
-    /* TODO: allocate buffer from NS */
-    if (!ctx.fb_buf_ptr) {
-        ctx.fb_buf_ptr = memalign(getauxval(AT_PAGESZ), *buffer_len);
-    }
-    if (!ctx.fb_buf_ptr) {
-        return ERR_NO_MEMORY;
-    }
-    *buffer_ptr = ctx.fb_buf_ptr;
+    hdr.cmd = SECURE_DPU_CMD_ALLOCATE_BUFFER;
+    args.buffer_len = (uint64_t)buffer_len;
 
-    return NO_ERROR;
+    rc = tipc_send2(chan, &hdr, sizeof(hdr), &args, sizeof(args));
+    if (rc != (int)(sizeof(hdr) + sizeof(args))) {
+        TLOGE("Failed to send SECURE_DPU_CMD_ALLOCATE_BUFFER request (%d)\n", rc);
+        return rc;
+    }
+
+    rc = handle_allocate_buffer_resp(chan, buffer_len, buf_info);
+    if (rc < 0) {
+        TLOGE("Failed to handle allocate buffer\n");
+        return rc;
+    }
+    return rc;
 }
 
-int secure_dpu_free_buffer(handle_t chan, void* buffer_ptr) {
-
-    if (chan == INVALID_IPC_HANDLE) {
-        TLOGE("Channel is not ready\n");
-        return ERR_NOT_READY;
+int secure_dpu_release_buffer(struct secure_dpu_buf_info* buf_info) {
+    if (!buf_info) {
+        TLOGE("Invalid arguments to release DPU buffer\n");
+        return ERR_INVALID_ARGS;
     }
 
-    /* TODO: free buffer from NS */
+    int rc = munmap(buf_info->addr, buf_info->len);
+    if (rc < 0) {
+        TLOGE("Failed to do munmap\n");
+        return rc;
+    }
+
     return NO_ERROR;
 }
 
@@ -98,7 +197,7 @@
     }
 
     rc = tipc_recv1(chan, sizeof(hdr), &hdr, sizeof(hdr));
-    if (rc < 0) {
+    if (rc != sizeof(hdr)) {
         TLOGE("Failed to receive SECURE_DPU_CMD_START_SECURE_DISPLAY response (%d)\n", rc);
         return rc;
     }
@@ -147,7 +246,7 @@
     }
 
     rc = tipc_recv1(chan, sizeof(hdr), &hdr, sizeof(hdr));
-    if (rc < 0) {
+    if (rc != sizeof(hdr)) {
         TLOGE("Failed to receive SECURE_DPU_CMD_STOP_SECURE_DISPLAY response (%d)\n", rc);
         return rc;
     }