fix(intel): allow non-secure access to FPGA Crypto Services (FCS)

Allows non-secure software to access FPGA Crypto Services (FCS)
through secure monitor calls (SMC).

Signed-off-by: Abdul Halim, Muhammad Hadi Asyrafi <muhammad.hadi.asyrafi.abdul.halim@intel.com>
Signed-off-by: Sieu Mun Tang <sieu.mun.tang@intel.com>
Change-Id: I805b3f650abf5e118e2c55e469866d5d0ca68048
diff --git a/plat/intel/soc/common/include/socfpga_mailbox.h b/plat/intel/soc/common/include/socfpga_mailbox.h
index 64024b8..fcf5fc2 100644
--- a/plat/intel/soc/common/include/socfpga_mailbox.h
+++ b/plat/intel/soc/common/include/socfpga_mailbox.h
@@ -108,6 +108,7 @@
 #define MBOX_NO_RESPONSE		-2
 #define MBOX_WRONG_ID			-3
 #define MBOX_BUFFER_FULL		-4
+#define MBOX_BUSY			-5
 #define MBOX_TIMEOUT			-2047
 
 /* Reconfig Status Response */
@@ -157,6 +158,10 @@
 #define MBOX_INDIRECT(val)		((val) << 11)
 #define MBOX_CMD_MASK(header)		((header) & 0x7ff)
 
+/* Mailbox payload */
+#define MBOX_DATA_MAX_LEN		0x3ff
+#define MBOX_PAYLOAD_FLAG_BUSY		BIT(0)
+
 /* RSU Macros */
 #define RSU_VERSION_ACMF		BIT(8)
 #define RSU_VERSION_ACMF_MASK		0xff00
@@ -166,6 +171,19 @@
 #define CONFIG_STATUS_FW_VER_OFFSET	1
 #define CONFIG_STATUS_FW_VER_MASK	0x00FFFFFF
 
+/* Data structure */
+
+typedef struct mailbox_payload {
+	uint32_t header;
+	uint32_t data[MBOX_DATA_MAX_LEN];
+} mailbox_payload_t;
+
+typedef struct mailbox_container {
+	uint32_t flag;
+	uint32_t index;
+	mailbox_payload_t *payload;
+} mailbox_container_t;
+
 /* Mailbox Function Definitions */
 
 void mailbox_set_int(uint32_t interrupt_input);
@@ -180,6 +198,9 @@
 			unsigned int len, unsigned int indirect);
 int mailbox_read_response(uint32_t *job_id, uint32_t *response,
 			unsigned int *resp_len);
+int mailbox_read_response_async(uint32_t *job_id, uint32_t *header,
+			uint32_t *response, unsigned int *resp_len,
+			uint8_t ignore_client_id);
 int iterate_resp(uint32_t mbox_resp_len, uint32_t *resp_buf,
 			unsigned int *resp_len);
 
diff --git a/plat/intel/soc/common/include/socfpga_sip_svc.h b/plat/intel/soc/common/include/socfpga_sip_svc.h
index 53aece3..e46bee7 100644
--- a/plat/intel/soc/common/include/socfpga_sip_svc.h
+++ b/plat/intel/soc/common/include/socfpga_sip_svc.h
@@ -12,6 +12,7 @@
 #define INTEL_SIP_SMC_STATUS_OK				0
 #define INTEL_SIP_SMC_STATUS_BUSY			0x1
 #define INTEL_SIP_SMC_STATUS_REJECTED			0x2
+#define INTEL_SIP_SMC_STATUS_NO_RESPONSE		0x3
 #define INTEL_SIP_SMC_STATUS_ERROR			0x4
 #define INTEL_SIP_SMC_RSU_ERROR				0x7
 
@@ -68,16 +69,21 @@
 #define INTEL_SIP_SMC_FIRMWARE_VERSION			0xC200001F
 #define INTEL_SIP_SMC_HPS_SET_BRIDGES			0xC2000032
 
+#define SERVICE_COMPLETED_MODE_ASYNC			0x00004F4E
+
 /* Mailbox Command */
 #define INTEL_SIP_SMC_GET_USERCODE			0xC200003D
 
 /* FPGA Crypto Services */
+#define INTEL_SIP_SMC_FCS_RANDOM_NUMBER			0xC200005A
 #define INTEL_SIP_SMC_FCS_CRYPTION			0x4200005B
-#define INTEL_SIP_SMC_FCS_CNTR_SET_PREAUTH			0xC200005F
-#define INTEL_SIP_SMC_FCS_PSGSIGMA_TEARDOWN			0xC2000064
-#define INTEL_SIP_SMC_FCS_CHIP_ID				0xC2000065
-#define INTEL_SIP_SMC_FCS_ATTESTATION_SUBKEY			0xC2000066
-#define INTEL_SIP_SMC_FCS_ATTESTATION_MEASUREMENTS		0xC2000067
+#define INTEL_SIP_SMC_FCS_SEND_CERTIFICATE		0x4200005D
+#define INTEL_SIP_SMC_FCS_GET_PROVISION_DATA		0x4200005E
+#define INTEL_SIP_SMC_FCS_CNTR_SET_PREAUTH		0xC200005F
+#define INTEL_SIP_SMC_FCS_PSGSIGMA_TEARDOWN		0xC2000064
+#define INTEL_SIP_SMC_FCS_CHIP_ID			0xC2000065
+#define INTEL_SIP_SMC_FCS_ATTESTATION_SUBKEY		0xC2000066
+#define INTEL_SIP_SMC_FCS_ATTESTATION_MEASUREMENTS	0xC2000067
 
 /* ECC DBE */
 #define WARM_RESET_WFI_FLAG				BIT(31)
diff --git a/plat/intel/soc/common/soc/socfpga_mailbox.c b/plat/intel/soc/common/soc/socfpga_mailbox.c
index 8ecd6db..0f12147 100644
--- a/plat/intel/soc/common/soc/socfpga_mailbox.c
+++ b/plat/intel/soc/common/soc/socfpga_mailbox.c
@@ -11,6 +11,8 @@
 #include "socfpga_mailbox.h"
 #include "socfpga_sip_svc.h"
 
+static mailbox_payload_t mailbox_resp_payload;
+static mailbox_container_t mailbox_resp_ctr = {0, 0, &mailbox_resp_payload};
 
 static bool is_mailbox_cmdbuf_full(uint32_t cin)
 {
@@ -171,6 +173,95 @@
 	return MBOX_NO_RESPONSE;
 }
 
+int mailbox_read_response_async(unsigned int *job_id, uint32_t *header,
+				uint32_t *response, unsigned int *resp_len,
+				uint8_t ignore_client_id)
+{
+	uint32_t rin;
+	uint32_t rout;
+	uint32_t resp_data;
+	uint32_t ret_resp_len = 0;
+	uint8_t is_done = 0;
+
+	if ((mailbox_resp_ctr.flag & MBOX_PAYLOAD_FLAG_BUSY) != 0) {
+		ret_resp_len = MBOX_RESP_LEN(
+				mailbox_resp_ctr.payload->header) -
+				mailbox_resp_ctr.index;
+	}
+
+	if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) == 1U) {
+		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
+	}
+
+	rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+	rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
+
+	while (rout != rin && !is_done) {
+
+		resp_data = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP, (rout)++));
+
+		rout %= MBOX_RESP_BUFFER_SIZE;
+		mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+		rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+
+		if ((mailbox_resp_ctr.flag & MBOX_PAYLOAD_FLAG_BUSY) != 0) {
+			mailbox_resp_ctr.payload->data[mailbox_resp_ctr.index] = resp_data;
+			mailbox_resp_ctr.index++;
+			ret_resp_len--;
+		} else {
+			if (!ignore_client_id) {
+				if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) {
+					*resp_len = 0;
+					return MBOX_WRONG_ID;
+				}
+			}
+
+			*job_id = MBOX_RESP_JOB_ID(resp_data);
+			ret_resp_len = MBOX_RESP_LEN(resp_data);
+			mailbox_resp_ctr.payload->header = resp_data;
+			mailbox_resp_ctr.flag |= MBOX_PAYLOAD_FLAG_BUSY;
+		}
+
+		if (ret_resp_len == 0) {
+			is_done = 1;
+		}
+	}
+
+	if (is_done != 0) {
+
+		/* copy header data to input address if applicable */
+		if (header != 0) {
+			*header = mailbox_resp_ctr.payload->header;
+		}
+
+		/* copy response data to input buffer if applicable */
+		ret_resp_len = MBOX_RESP_LEN(mailbox_resp_ctr.payload->header);
+		if (ret_resp_len > 0 && response && resp_len) {
+			if (*resp_len > ret_resp_len) {
+				*resp_len = ret_resp_len;
+			}
+
+			memcpy((uint8_t *) response,
+				(uint8_t *) mailbox_resp_ctr.payload->data,
+				*resp_len * MBOX_WORD_BYTE);
+		}
+
+		/* reset async response param */
+		mailbox_resp_ctr.index = 0;
+		mailbox_resp_ctr.flag = 0;
+
+		if (MBOX_RESP_ERR(mailbox_resp_ctr.payload->header) > 0U) {
+			INFO("Error in async response: %x\n",
+				mailbox_resp_ctr.payload->header);
+			return -MBOX_RESP_ERR(mailbox_resp_ctr.payload->header);
+		}
+
+		return MBOX_RET_OK;
+	}
+
+	*resp_len = 0;
+	return (mailbox_resp_ctr.flag & MBOX_PAYLOAD_FLAG_BUSY) ? MBOX_BUSY : MBOX_NO_RESPONSE;
+}
 
 int mailbox_poll_response(uint32_t job_id, uint32_t urgent, uint32_t *response,
 				unsigned int *resp_len)
diff --git a/plat/intel/soc/common/socfpga_sip_svc.c b/plat/intel/soc/common/socfpga_sip_svc.c
index 294040b..b0b56e9 100644
--- a/plat/intel/soc/common/socfpga_sip_svc.c
+++ b/plat/intel/soc/common/socfpga_sip_svc.c
@@ -552,6 +552,52 @@
 	return INTEL_SIP_SMC_STATUS_OK;
 }
 
+uint32_t intel_smc_service_completed(uint64_t addr, uint32_t size,
+				uint32_t mode, uint32_t *job_id,
+				uint32_t *ret_size, uint32_t *mbox_error)
+{
+	int status = 0;
+	uint32_t resp_len = size / MBOX_WORD_BYTE;
+
+	if (resp_len > MBOX_DATA_MAX_LEN) {
+		return INTEL_SIP_SMC_STATUS_REJECTED;
+	}
+
+	if (!is_address_in_ddr_range(addr, size)) {
+		return INTEL_SIP_SMC_STATUS_REJECTED;
+	}
+
+	if (mode == SERVICE_COMPLETED_MODE_ASYNC) {
+		status = mailbox_read_response_async(job_id,
+				NULL, (uint32_t *) addr, &resp_len, 0);
+	} else {
+		status = mailbox_read_response(job_id,
+				(uint32_t *) addr, &resp_len);
+
+		if (status == MBOX_NO_RESPONSE) {
+			status = MBOX_BUSY;
+		}
+	}
+
+	if (status == MBOX_NO_RESPONSE) {
+		return INTEL_SIP_SMC_STATUS_NO_RESPONSE;
+	}
+
+	if (status == MBOX_BUSY) {
+		return INTEL_SIP_SMC_STATUS_BUSY;
+	}
+
+	*ret_size = resp_len * MBOX_WORD_BYTE;
+	flush_dcache_range(addr, *ret_size);
+
+	if (status != MBOX_RET_OK) {
+		*mbox_error = -status;
+		return INTEL_SIP_SMC_STATUS_ERROR;
+	}
+
+	return INTEL_SIP_SMC_STATUS_OK;
+}
+
 /*
  * This function is responsible for handling all SiP calls from the NS world
  */
@@ -724,6 +770,19 @@
 
 		SMC_RET3(handle, status, x4, x5);
 
+	case INTEL_SIP_SMC_FCS_RANDOM_NUMBER:
+		status = intel_fcs_random_number_gen(x1, &retval64,
+							&mbox_error);
+		SMC_RET4(handle, status, mbox_error, x1, retval64);
+
+	case INTEL_SIP_SMC_FCS_SEND_CERTIFICATE:
+		status = intel_fcs_send_cert(x1, x2, &send_id);
+		SMC_RET1(handle, status);
+
+	case INTEL_SIP_SMC_FCS_GET_PROVISION_DATA:
+		status = intel_fcs_get_provision_data(&send_id);
+		SMC_RET1(handle, status);
+
 	case INTEL_SIP_SMC_FCS_CNTR_SET_PREAUTH:
 		status = intel_fcs_cntr_set_preauth(x1, x2, x3,
 							&mbox_error);