secure_fb: Add generic ipc server implementation with service side API.
Add the generic ipc server and the API that services need to implement
when they link against this service.
Bug: 175731623
Change-Id: I5173e9340d9932e1f60150c2badfcd6117f25488
diff --git a/lib/secure_fb/srv/include/lib/secure_fb/srv/dev.h b/lib/secure_fb/srv/include/lib/secure_fb/srv/dev.h
new file mode 100644
index 0000000..e4bb241
--- /dev/null
+++ b/lib/secure_fb/srv/include/lib/secure_fb/srv/dev.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <interface/secure_fb/secure_fb.h>
+#include <lk/compiler.h>
+#include <stdint.h>
+#include <trusty_ipc.h>
+
+__BEGIN_CDECLS
+
+/**
+ * DOC: API notes
+ *
+ * This header defines an API for implementing hardware-specific secure
+ * framebuffer driver. It is expected that it will be working in conjunction
+ * with a higher level service that will make calls described here.
+ */
+
+typedef void* secure_fb_handle_t;
+
+struct secure_fb_impl_buffers {
+ size_t num_fbs;
+ struct secure_fb_desc fbs[SECURE_FB_MAX_FBS];
+ size_t num_handles;
+ handle_t handles[SECURE_FB_MAX_FBS];
+};
+
+/**
+ * secure_fb_impl_init() - This function together with secure_fb_impl_release()
+ * frames the life cycle of a secure_fb session. The life cycle begins with this
+ * function, and the session is represented by the returned handle.
+ *
+ * Return: Session handle for the secure_fb session or NULL on failure.
+ */
+secure_fb_handle_t secure_fb_impl_init(void);
+
+/**
+ * secure_fb_impl_get_fbs() - Gets a set of up to %SECURE_FB_MAX_FBS buffers
+ * that can be used for rendering. The number of buffers is implementation
+ * defined.
+ *
+ * @session: The active session as returned by a previous call to
+ * secure_fb_imppl_init().
+ * @buffers: Describes the buffers returned.
+ *
+ * Return: SECURE_FB_ERROR_OK on success, or an error code < 0 on failure.
+ */
+int secure_fb_impl_get_fbs(secure_fb_handle_t session,
+ struct secure_fb_impl_buffers* buffers);
+
+/**
+ * secure_fb_impl_display_fb() - Select one of the buffers returned by
+ * secure_fb_impl_get_fbs() as active buffer. If only one buffer was
+ * returned this function doubles as render complete barrier indicating to the
+ * driver that the screen may be updated.
+ *
+ * @session: The active session as returned by a previous call to
+ * secure_fb_impl_init().
+ * @buffer_id: Indicates one of the buffers returned by
+ * secure_fb_impl_get_fbs(). The @buffer_id is not an index. It
+ * can be found at @buffers.fbs[index].buffer_id with @buffers being
+ * the structure returned by secure_fb_impl_get_fbs().
+ *
+ * Return: SECURE_FB_ERROR_OK on success, or an error code < 0 on failure.
+ */
+int secure_fb_impl_display_fb(secure_fb_handle_t session, uint32_t buffer_id);
+
+/**
+ * secure_fb_impl_release() - Ends the life cycle of the a secure_fb session.
+ * It must relinquish all resources associated with the secure_fb session.
+ *
+ * @session: The active session as returned by a previous call to
+ * secure_fb_impl_init().
+ *
+ * Return: SECURE_FB_ERROR_OK on success, or an error code < 0 on failure.
+ */
+int secure_fb_impl_release(secure_fb_handle_t session);
+
+__END_CDECLS
diff --git a/lib/secure_fb/srv/include/lib/secure_fb/srv/srv.h b/lib/secure_fb/srv/include/lib/secure_fb/srv/srv.h
new file mode 100644
index 0000000..444b7df
--- /dev/null
+++ b/lib/secure_fb/srv/include/lib/secure_fb/srv/srv.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <lib/tipc/tipc_srv.h>
+#include <lk/compiler.h>
+#include <stdint.h>
+
+__BEGIN_CDECLS
+
+/**
+ * add_secure_fb_service() - Add secure_fb service.
+ * @hset: Handle set created by tipc_hset_create()
+ *
+ * The caller should call tipc_run_event_loop() at some point after this call
+ * returns.
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int add_secure_fb_service(struct tipc_hset* hset);
+
+__END_CDECLS
diff --git a/lib/secure_fb/srv/rules.mk b/lib/secure_fb/srv/rules.mk
new file mode 100644
index 0000000..dc4da10
--- /dev/null
+++ b/lib/secure_fb/srv/rules.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2020 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_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+ $(LOCAL_DIR)/secure_fb_server.c \
+
+MODULE_DEPS += \
+ trusty/user/base/interface/secure_fb \
+ trusty/user/base/lib/libc-trusty \
+ trusty/user/base/lib/tipc \
+
+include make/module.mk
diff --git a/lib/secure_fb/srv/secure_fb_server.c b/lib/secure_fb/srv/secure_fb_server.c
new file mode 100644
index 0000000..036f527
--- /dev/null
+++ b/lib/secure_fb/srv/secure_fb_server.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2020, 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 TLOG_TAG "secure_fb_service"
+
+#include <assert.h>
+#include <interface/secure_fb/secure_fb.h>
+#include <lib/secure_fb/srv/dev.h>
+#include <lib/secure_fb/srv/srv.h>
+#include <lib/tipc/tipc.h>
+#include <lib/tipc/tipc_srv.h>
+#include <lk/compiler.h>
+#include <lk/macros.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trusty_ipc.h>
+#include <trusty_log.h>
+#include <uapi/err.h>
+
+struct secure_fb_ctx {
+ secure_fb_handle_t session;
+};
+
+static int secure_fb_on_connect(const struct tipc_port* port,
+ handle_t chan,
+ const struct uuid* peer,
+ void** ctx_p) {
+ struct secure_fb_ctx* ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ TLOGE("Memory allocation failed.\n");
+ return ERR_NO_MEMORY;
+ }
+
+ ctx->session = secure_fb_impl_init();
+ if (ctx->session == NULL) {
+ TLOGE("Driver initialization failed.\n");
+ free(ctx);
+ return ERR_GENERIC;
+ }
+
+ *ctx_p = ctx;
+ return NO_ERROR;
+}
+
+static void secure_fb_on_channel_cleanup(void* _ctx) {
+ struct secure_fb_ctx* ctx = (struct secure_fb_ctx*)_ctx;
+ if (ctx->session != NULL) {
+ secure_fb_impl_release(ctx);
+ }
+ free(ctx);
+}
+
+static int handle_get_fbs_req(handle_t chan, secure_fb_handle_t session) {
+ int rc;
+ struct secure_fb_impl_buffers buffers;
+ struct secure_fb_resp hdr;
+ struct secure_fb_get_fbs_resp args;
+ struct secure_fb_desc fbs[SECURE_FB_MAX_FBS];
+ size_t fbs_len;
+
+ rc = secure_fb_impl_get_fbs(session, &buffers);
+ if (rc != SECURE_FB_ERROR_OK) {
+ TLOGE("Failed secure_fb_impl_get_fbs() (%d)\n", rc);
+ }
+
+ hdr.cmd = SECURE_FB_CMD_GET_FBS | SECURE_FB_CMD_RESP_BIT;
+ hdr.status = rc;
+
+ args.num_fbs = buffers.num_fbs;
+
+ fbs_len = sizeof(fbs[0]) * args.num_fbs;
+ memcpy(fbs, buffers.fbs, fbs_len);
+
+ struct iovec iovs[] = {
+ {
+ .iov_base = &hdr,
+ .iov_len = sizeof(hdr),
+ },
+ {
+ .iov_base = &args,
+ .iov_len = sizeof(args),
+ },
+ {
+ .iov_base = fbs,
+ .iov_len = fbs_len,
+ },
+ };
+ ipc_msg_t msg = {
+ .num_iov = countof(iovs),
+ .iov = iovs,
+ .num_handles = buffers.num_handles,
+ .handles = buffers.handles,
+ };
+ rc = send_msg(chan, &msg);
+ if (rc != (int)(sizeof(hdr) + sizeof(args) + fbs_len)) {
+ TLOGE("Failed to send SECURE_FB_CMD_GET_FBS response (%d)\n", rc);
+ if (rc >= 0) {
+ return ERR_BAD_LEN;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+static int handle_display_fb(handle_t chan,
+ struct secure_fb_display_fb_req* display_fb,
+ secure_fb_handle_t session) {
+ int rc;
+ struct secure_fb_resp hdr;
+
+ rc = secure_fb_impl_display_fb(session, display_fb->buffer_id);
+ if (rc != SECURE_FB_ERROR_OK) {
+ TLOGE("Failed secure_fb_impl_display_fb() (%d)\n", rc);
+ }
+
+ hdr.cmd = SECURE_FB_CMD_DISPLAY_FB | SECURE_FB_CMD_RESP_BIT;
+ hdr.status = rc;
+
+ rc = tipc_send1(chan, &hdr, sizeof(hdr));
+ if (rc != (int)sizeof(hdr)) {
+ TLOGE("Failed to send SECURE_FB_CMD_DISPLAY_FB response (%d)\n", rc);
+ if (rc >= 0) {
+ return ERR_BAD_LEN;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+static int secure_fb_on_message(const struct tipc_port* port,
+ handle_t chan,
+ void* _ctx) {
+ int rc;
+ struct {
+ struct secure_fb_req hdr;
+ union {
+ struct secure_fb_display_fb_req display_fb;
+ };
+ } req;
+ struct secure_fb_ctx* ctx = (struct secure_fb_ctx*)_ctx;
+
+ rc = tipc_recv1(chan, sizeof(req.hdr), &req, sizeof(req));
+ if (rc < 0) {
+ TLOGE("Failed to read command %d\n", rc);
+ return ERR_BAD_LEN;
+ }
+
+ switch (req.hdr.cmd) {
+ case SECURE_FB_CMD_GET_FBS:
+ if (rc != (int)sizeof(req.hdr)) {
+ TLOGE("Failed to read SECURE_FB_CMD_GET_FBS request (%d)\n", rc);
+ return ERR_BAD_LEN;
+ }
+ return handle_get_fbs_req(chan, ctx->session);
+
+ case SECURE_FB_CMD_DISPLAY_FB:
+ if (rc != (int)(sizeof(req.hdr) + sizeof(req.display_fb))) {
+ TLOGE("Failed to read SECURE_FB_CMD_DISPLAY_FB request (%d)\n", rc);
+ return ERR_BAD_LEN;
+ }
+ return handle_display_fb(chan, &req.display_fb, ctx->session);
+
+ case SECURE_FB_CMD_RELEASE:
+ if (rc != (int)sizeof(req.hdr)) {
+ TLOGE("Failed to read SECURE_FB_CMD_RELEASE request (%d)\n", rc);
+ return ERR_BAD_LEN;
+ }
+ secure_fb_impl_release(ctx->session);
+ ctx->session = NULL;
+ return NO_ERROR;
+
+ default:
+ TLOGW("Received unknown command %x\n", req.hdr.cmd);
+ return ERR_CMD_UNKNOWN;
+ }
+
+ return NO_ERROR;
+}
+
+int add_secure_fb_service(struct tipc_hset* hset) {
+ static struct tipc_port_acl acl = {
+ .flags = IPC_PORT_ALLOW_TA_CONNECT,
+ };
+ static struct tipc_port port = {
+ .name = SECURE_FB_PORT_NAME,
+ .msg_max_size = 1024,
+ .msg_queue_len = 1,
+ .acl = &acl,
+ };
+ static struct tipc_srv_ops ops = {
+ .on_connect = secure_fb_on_connect,
+ .on_message = secure_fb_on_message,
+ .on_channel_cleanup = secure_fb_on_channel_cleanup,
+ };
+
+ /*
+ * The secure display is a limited resource. This means only one client
+ * can have an open session at a time.
+ */
+ return tipc_add_service(hset, &port, 1, 1, &ops);
+}