v4l2-uvm-test: support SVP [1/1]
PD#SWPL-20176
Problem:
Secure Video Path test application.
Solution:
a) Use secmem API to copy ES frame into secure dmabuf
b) Use MESON_USE_PROTECTED to allocate secure memory from DRM-GEM.
Verify:
U212 with command "v4l2-uvm-test -f /data/1.mp4 -p 26 -d 0 -s"
Change-Id: Iedb23a374cbd198e85b2678eb5034a2c802ec5bb
Signed-off-by: Song Zhao <song.zhao@amlogic.com>
diff --git a/v4l2-uvm-test/src/Makefile b/v4l2-uvm-test/src/Makefile
index f0e0f67..385f857 100644
--- a/v4l2-uvm-test/src/Makefile
+++ b/v4l2-uvm-test/src/Makefile
@@ -1,11 +1,11 @@
-OBJ = drm.c v4l2-dec.c test.c demux.c
+OBJ = drm.c v4l2-dec.c test.c demux.c secmem.c
TARGET = v4l2-uvm-test
# rules
all: $(TARGET)
#TARGET_CFLAGS += -DDEBUG_FRAME
-LD_FLAG = -ldrm -lavformat -lavcodec -lavutil -lm -lpthread -lz -lswresample
+LD_FLAG = -ldrm -lavformat -lavcodec -lavutil -lm -lpthread -lz -lswresample -lsecmem
$(TARGET): $(OBJ)
$(CC) $(TARGET_CFLAGS) -D_FILE_OFFSET_BITS=64 -Wall -I$(STAGING_DIR)/usr/include/ -I$(STAGING_DIR)/usr/include/libdrm/ -L$(STAGING_DIR)/usr/lib $(LD_FLAG) $(OBJ) -o $@
diff --git a/v4l2-uvm-test/src/drm.c b/v4l2-uvm-test/src/drm.c
index a90ef0f..55c1320 100644
--- a/v4l2-uvm-test/src/drm.c
+++ b/v4l2-uvm-test/src/drm.c
@@ -36,6 +36,7 @@
static char* drm_cli_dev_name = "/dev/dri/renderD128";
static int drm_fd, drm_cli_fd;
static int drm_mode_set;
+static int secure_mode;
extern unsigned int global_plane_id;
struct gem_buffer {
@@ -144,6 +145,8 @@
buffer->pitches[i] = width*2;
} else {
gem_create.flags = MESON_USE_VIDEO_PLANE;
+ if (secure_mode)
+ gem_create.flags |= MESON_USE_PROTECTED;
if (i == 0)
gem_create.size = width * height;
else
@@ -657,12 +660,14 @@
return 0;
}
-int display_engine_start()
+int display_engine_start(int smode)
{
unsigned int plane_id;
drmModeModeInfo mode;
int rc;
+ secure_mode = smode;
+
drm_fd = drmOpen("meson", drm_master_dev_name);
if (drm_fd < 0) {
printf("Unable to open DRM node: %s\n",
diff --git a/v4l2-uvm-test/src/secmem.c b/v4l2-uvm-test/src/secmem.c
new file mode 100644
index 0000000..74f93d0
--- /dev/null
+++ b/v4l2-uvm-test/src/secmem.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "secmem.h"
+#include "secmem_ca.h"
+
+static void* sec_sess;
+
+int secmem_init()
+{
+ unsigned int ret;
+ ret = Secure_V2_SessionCreate(&sec_sess);
+ if (ret) {
+ printf("Secure_V2_SessionCreate fail %x\n", ret);
+ return -1;
+ }
+ ret = Secure_V2_Init(sec_sess, 1, 1, 0, 0);
+ if (ret) {
+ Secure_V2_SessionDestroy(sec_sess);
+ printf("Secure_V2_Init fail %x\n", ret);
+ return -1;
+ }
+ return 0;
+}
+
+void secmem_destroy()
+{
+ if (sec_sess)
+ Secure_V2_SessionDestroy(&sec_sess);
+ sec_sess = NULL;
+}
+
+struct secmem* secmem_alloc(uint32_t size)
+{
+ struct secmem* mem = calloc(1, sizeof(*mem));
+ if (mem) {
+ unsigned int ret;
+ uint32_t maxsize;
+
+ ret = Secure_V2_MemCreate(sec_sess, &mem->handle);
+ if (ret) {
+ printf("Secure_V2_MemCreate fail %x\n", ret);
+ goto error;
+ }
+ ret = Secure_V2_MemAlloc(sec_sess, mem->handle, size, &mem->phyaddr);
+ if (ret) {
+ printf("Secure_V2_MemAlloc failed %x\n",ret);
+ goto error2;
+ }
+ ret = Secure_V2_MemExport(sec_sess, mem->handle, &mem->fd, &maxsize);
+ if (ret) {
+ printf("Secure_V2_MemExport failed %x\n",ret);
+ goto error3;
+ }
+ }
+ return mem;
+error3:
+ Secure_V2_MemFree(sec_sess, mem->handle);
+error2:
+ Secure_V2_MemRelease(sec_sess, mem->handle);
+error:
+ free(mem);
+ return NULL;
+}
+
+void secmem_free(struct secmem * mem)
+{
+ unsigned int ret;
+ close(mem->fd);
+ ret = Secure_V2_MemFree(sec_sess, mem->handle);
+ if (ret)
+ printf("Secure_V2_MemFree fail %x\n", ret);
+ ret = Secure_V2_MemRelease(sec_sess, mem->handle);
+ if (ret)
+ printf("Secure_V2_MemRelease fail %x\n", ret);
+ free(mem);
+}
+
+int secmem_fill(struct secmem* mem, uint8_t* buf, uint32_t offset, uint32_t size)
+{
+ unsigned int ret = 0;
+ ret = Secure_V2_MemFill(sec_sess, mem->handle, offset, buf, size);
+ if (ret) {
+ printf("Secure_V2_MemFill fail %x\n", ret);
+ return -1;
+ }
+ return ret;
+}
diff --git a/v4l2-uvm-test/src/secmem.h b/v4l2-uvm-test/src/secmem.h
new file mode 100644
index 0000000..0345cd8
--- /dev/null
+++ b/v4l2-uvm-test/src/secmem.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+
+#ifndef _SECMEMC_H_
+#define _SECMEMC_H_
+
+#include <stdint.h>
+
+struct secmem {
+ uint32_t handle;
+ uint32_t phyaddr;
+ int fd;
+};
+
+int secmem_init();
+void secmem_destroy();
+struct secmem* secmem_alloc(uint32_t size);
+void secmem_free(struct secmem * mem);
+int secmem_fill(struct secmem* mem, uint8_t* buf, uint32_t offset, uint32_t size);
+#endif
diff --git a/v4l2-uvm-test/src/test.c b/v4l2-uvm-test/src/test.c
index 67a5469..9201e0b 100644
--- a/v4l2-uvm-test/src/test.c
+++ b/v4l2-uvm-test/src/test.c
@@ -27,6 +27,7 @@
static sem_t wait_for_end;
int global_plane_id;
int g_dw_mode = 16;
+static int secure_mode = 0;
int ffmpeg_log = 0;
static void usage(int argc, char **argv)
@@ -44,11 +45,12 @@
"-h | --help Print this message\n"
"-p | --plane=id select display plane. 26[pri] 28[overlay 1] 30[overlay 2] 32[video]\n"
"-l | --log enable more ffmpeg demux log.\n"
+ "-s | --secure secure video path.\n"
"",
argv[0]);
}
-static const char short_options[] = "d:hf:p:l";
+static const char short_options[] = "d:hf:p:ls";
static const struct option
long_options[] = {
@@ -57,6 +59,7 @@
{ "help", no_argument, NULL, 'h' },
{ "plane", required_argument, NULL, 'p' },
{ "log", no_argument, NULL, 'l' },
+ { "secure", no_argument, NULL, 's' },
{ 0, 0, 0, 0 }
};
@@ -68,7 +71,7 @@
int start_decoder(struct dmx_v_data *v_data)
{
int ret;
- ret = v4l2_dec_init(v_data->type, decode_finish);
+ ret = v4l2_dec_init(v_data->type, secure_mode, decode_finish);
if (ret) {
printf("FATAL: start_decoder error:%d\n",ret);
exit(1);
@@ -120,6 +123,10 @@
global_plane_id = atoi(optarg);
break;
+ case 's':
+ secure_mode = 1;
+ break;
+
default:
usage(argc, argv);
return -1;
@@ -149,7 +156,7 @@
sem_init(&wait_for_end, 0, 0);
display_engine_register_cb(capture_buffer_recycle);
- rc = display_engine_start();
+ rc = display_engine_start(secure_mode);
if (rc < 0) {
printf("Unable to start display engine\n");
goto error;
diff --git a/v4l2-uvm-test/src/v4l2-dec.c b/v4l2-uvm-test/src/v4l2-dec.c
index bb5c6d0..c15441e 100644
--- a/v4l2-uvm-test/src/v4l2-dec.c
+++ b/v4l2-uvm-test/src/v4l2-dec.c
@@ -26,6 +26,7 @@
#include "demux.h"
#include "drm.h"
#include "v4l2-dec.h"
+#include "secmem.h"
static const char* video_dev_name = "/dev/video26";
static int video_fd;
@@ -37,10 +38,13 @@
static bool eos_received;
extern int g_dw_mode;
static pthread_mutex_t res_lock;
+static enum v4l2_memory sInMemMode;
+static uint8_t* es_buf;
//#define DEBUG_FRAME
#ifdef DEBUG_FRAME
static int frame_checksum;
#endif
+#define ES_BUF_SIZE (2*1024*1024)
static pthread_t dec_thread;
bool quit_thread;
@@ -56,6 +60,8 @@
/* output only */
uint32_t used;
+ struct secmem* smem;
+
/* capture only */
bool free_on_recycle;
struct drm_frame *drm_frame;
@@ -129,7 +135,7 @@
req.count = OUTPUT_BUF_CNT;
}
- req.memory = V4L2_MEMORY_MMAP;
+ req.memory = sInMemMode;
req.type = output_p.type;
ret = ioctl(fd, VIDIOC_REQBUFS, &req);
@@ -153,7 +159,7 @@
struct frame_buffer* pb = output_p.buf[i];
pb->v4lbuf.index = i;
pb->v4lbuf.type = output_p.type;
- pb->v4lbuf.memory = V4L2_MEMORY_MMAP;
+ pb->v4lbuf.memory = sInMemMode;
pb->v4lbuf.length = output_p.plane_num;
pb->v4lbuf.m.planes = pb->v4lplane;
@@ -162,6 +168,9 @@
printf("VIDIOC_QUERYBUF %dth buf fail ret:%d\n", i, ret);
return 3;
}
+
+ if (sInMemMode != V4L2_MEMORY_MMAP)
+ continue;
for (j = 0; j < output_p.plane_num; j++) {
void *vaddr;
vaddr = mmap(NULL, pb->v4lplane[j].length,
@@ -179,13 +188,21 @@
pthread_mutex_init(&output_p.lock, NULL);
pthread_cond_init(&output_p.wait, NULL);
+
+ if (sInMemMode == V4L2_MEMORY_DMABUF) {
+ es_buf = malloc(ES_BUF_SIZE);
+ if (!es_buf) {
+ printf("%d OOM\n", __LINE__);
+ return 5;
+ }
+ }
return 0;
}
static int destroy_output_port(int fd) {
int i;
struct v4l2_requestbuffers req = {
- .memory = V4L2_MEMORY_MMAP,
+ .memory = sInMemMode,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
.count = 0,
};
@@ -195,8 +212,9 @@
for (i = 0 ; i < req.count ; i++) {
struct frame_buffer *buf = output_p.buf[i];
- /* release GEM buf */
- buf->drm_frame->destroy(buf->drm_frame);
+ if (sInMemMode == V4L2_MEMORY_DMABUF)
+ secmem_free(buf->smem);
+
free(buf);
}
free(output_p.buf);
@@ -324,8 +342,12 @@
pthread_mutex_destroy(&capture_p.lock);
pthread_cond_destroy(&capture_p.wait);
ioctl(fd, VIDIOC_REQBUFS, &req);
- for (i = 0 ; i < req.count ; i++)
+ for (i = 0 ; i < req.count ; i++) {
+ struct frame_buffer *buf = capture_p.buf[i];
+ /* release GEM buf */
+ buf->drm_frame->destroy(buf->drm_frame);
free(capture_p.buf[i]);
+ }
free(capture_p.buf);
return 0;
}
@@ -469,7 +491,7 @@
if (pfd.revents & (POLLOUT | POLLWRNORM)) {
memset(&buf, 0, sizeof(buf));
memset(planes, 0, sizeof(planes));
- buf.memory = V4L2_MEMORY_MMAP;
+ buf.memory = sInMemMode;
buf.type = output_p.type;
buf.length = 2;
buf.m.planes = planes;
@@ -478,14 +500,18 @@
if (ret) {
printf("output VIDIOC_DQBUF fail %d\n", ret);
} else {
+ struct frame_buffer *fb = output_p.buf[buf.index];
#ifdef DEBUG_FRAME
printf("dqueue output %d\n", buf.index);
#endif
pthread_mutex_lock(&output_p.lock);
- output_p.buf[buf.index]->queued = false;
+ fb->queued = false;
pthread_mutex_unlock(&output_p.lock);
- output_p.buf[buf.index]->used = 0;
+ fb->used = 0;
d_o_rec_num++;
+ if (sInMemMode == V4L2_MEMORY_DMABUF) {
+ secmem_free(fb->smem);
+ }
pthread_cond_signal(&output_p.wait);
}
}
@@ -641,7 +667,7 @@
return rc;
}
-int v4l2_dec_init(enum vtype type, decode_finish_fn cb)
+int v4l2_dec_init(enum vtype type, int secure, decode_finish_fn cb)
{
int ret = -1;
struct v4l2_capability cap;
@@ -652,6 +678,16 @@
return 1;
decode_finish_cb = cb;
+ if (secure) {
+ sInMemMode = V4L2_MEMORY_DMABUF;
+ ret = secmem_init();
+ if (ret) {
+ printf("secmem_init fail %d\n",ret);
+ return 1;
+ }
+ } else
+ sInMemMode = V4L2_MEMORY_MMAP;
+
/* check decoder mode */
if ((type == VIDEO_TYPE_H264 ||
type == VIDEO_TYPE_MPEG2) &&
@@ -688,7 +724,7 @@
}
if (type != VIDEO_TYPE_MPEG2) {
- ret = v4l2_dec_set_drmmode(false);
+ ret = v4l2_dec_set_drmmode(secure);
if (ret) {
printf("aml_v4l2_dec_set_drmmode fail\n");
goto error;
@@ -745,7 +781,7 @@
output_p.sfmt.fmt.pix_mp.pixelformat = output_p.pixelformat;
/* 4K frame should fit into 2M */
- output_p.sfmt.fmt.pix_mp.plane_fmt[0].sizeimage = 2*1024*1024;
+ output_p.sfmt.fmt.pix_mp.plane_fmt[0].sizeimage = ES_BUF_SIZE;
ret = ioctl(video_fd, VIDIOC_S_FMT, &output_p.sfmt);
if (ret) {
printf("VIDIOC_S_FMT 0x%x fail\n", output_p.pixelformat);
@@ -843,6 +879,9 @@
get_1st_data = false;
pthread_mutex_destroy(&res_lock);
close(video_fd);
+ secmem_destroy();
+ if (es_buf)
+ free(es_buf);
return 0;
}
@@ -896,12 +935,20 @@
}
p = output_p.buf[cur_output_index];
- if ((p->used + size) > p->v4lplane[0].length) {
- printf("fatal frame too big %d > %d\n",
- size + p->used, p->v4lplane[0].length);
+ if ((sInMemMode == V4L2_MEMORY_MMAP &&
+ (p->used + size) > p->v4lplane[0].length) ||
+ (sInMemMode == V4L2_MEMORY_DMABUF &&
+ (p->used + size) > ES_BUF_SIZE)) {
+ printf("fatal frame too big %d\n",
+ size + p->used);
return 0;
}
- memcpy(p->vaddr[0] + p->used, data, size);
+
+ if (sInMemMode == V4L2_MEMORY_MMAP)
+ memcpy(p->vaddr[0] + p->used, data, size);
+ else
+ memcpy(es_buf + p->used, data, size);
+
p->used += size;
#ifdef DEBUG_FRAME
@@ -928,6 +975,20 @@
return 0;
}
p = output_p.buf[cur_output_index];
+ if (sInMemMode == V4L2_MEMORY_DMABUF) {
+ /* copy to secmem */
+ p->smem = secmem_alloc(p->used);
+ if (!p->smem) {
+ printf("%s %d oom:%d\n", __func__, __LINE__, p->used);
+ return 0;
+ }
+ ret = secmem_fill(p->smem, es_buf, 0, p->used);
+ if (ret)
+ return 0;
+ p->v4lbuf.m.planes[0].m.fd = p->smem->fd;
+ p->v4lbuf.m.planes[0].length = p->used;
+ p->v4lbuf.m.planes[0].data_offset = 0;
+ }
p->v4lbuf.m.planes[0].bytesused = p->used;
pthread_mutex_lock(&output_p.lock);
p->queued = true;
diff --git a/v4l2-uvm-test/src/v4l2-dec.h b/v4l2-uvm-test/src/v4l2-dec.h
index 8fed35c..d6e2292 100644
--- a/v4l2-uvm-test/src/v4l2-dec.h
+++ b/v4l2-uvm-test/src/v4l2-dec.h
@@ -23,7 +23,7 @@
typedef void (*decode_finish_fn)();
-int v4l2_dec_init(enum vtype type, decode_finish_fn);
+int v4l2_dec_init(enum vtype type, int secure, decode_finish_fn);
int v4l2_dec_destroy();
int v4l2_dec_write_es(const uint8_t *data, int size);
diff --git a/v4l2-uvm-test/v4l2-uvm-test.mk b/v4l2-uvm-test/v4l2-uvm-test.mk
index aae5e95..4c25926 100644
--- a/v4l2-uvm-test/v4l2-uvm-test.mk
+++ b/v4l2-uvm-test/v4l2-uvm-test.mk
@@ -5,6 +5,15 @@
V4L2_UVM_TEST_SITE = $(TOPDIR)/../multimedia/v4l2-uvm-test/src
V4L2_UVM_TEST_SITE_METHOD = local
+V4L2_UVM_TEST_DEPENDENCIES += ffmpeg
+V4L2_UVM_TEST_DEPENDENCIES += libdrm
+
+ifneq ($(BR2_PACKAGE_LIBSECMEM),y)
+V4L2_UVM_TEST_DEPENDENCIES += libsecmem-bin
+else
+V4L2_UVM_TEST_DEPENDENCIES += libsecmem
+endif
+
define V4L2_UVM_TEST_BUILD_CMDS
$(TARGET_CONFIGURE_OPTS) $(MAKE) CC=$(TARGET_CC) -C $(@D)/
endef