summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRadu Solea <radu.solea@nxp.com>2017-06-07 17:18:03 +0300
committerRadu Solea <radu.solea@nxp.com>2017-06-20 16:00:20 +0300
commit3cb189789f5f937f3b72608027c49840409d1065 (patch)
tree7f9f09f714bcbf79729aff848e7a625e1eb7bb1f
parent7c280619ed45ba6a0d4ef3710c2a0c0faf5dd53d (diff)
MLK-14765: Fix DCP SHA null hashes and output length
On imx6sl and imx6ull DCP writes at least 32 bytes in the output buffer instead of hash length as documented. Add intermediate buffer to prevent write out of bounds. When requested to produce null hashes DCP fails to produce valid output. Add software workaround to bypass hardware and return valid output. Signed-off-by: Radu Solea <radu.solea@nxp.com>
-rw-r--r--drivers/crypto/mxs-dcp.c63
1 files changed, 51 insertions, 12 deletions
diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
index cce26d83877b..151ea655c398 100644
--- a/drivers/crypto/mxs-dcp.c
+++ b/drivers/crypto/mxs-dcp.c
@@ -29,9 +29,25 @@
#define DCP_MAX_CHANS 4
#define DCP_BUF_SZ PAGE_SIZE
+#define DCP_SHA_PAY_SZ 64
#define DCP_ALIGNMENT 64
+
+/*
+ * Null hashes to align with hw behavior on imx6sl and ull
+ * these are flipped for consistency with hw output
+ */
+const uint8_t sha1_null_hash[] =
+ "\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf"
+ "\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda";
+
+const uint8_t sha256_null_hash[] =
+ "\x55\xb8\x52\x78\x1b\x99\x95\xa4"
+ "\x4c\x93\x9b\x64\xe4\x41\xae\x27"
+ "\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a"
+ "\x14\x1c\xfc\x98\x42\xc4\xb0\xe3";
+
/* DCP DMA descriptor. */
struct dcp_dma_desc {
uint32_t next_cmd_addr;
@@ -49,6 +65,7 @@ struct dcp_coherent_block {
uint8_t aes_in_buf[DCP_BUF_SZ];
uint8_t aes_out_buf[DCP_BUF_SZ];
uint8_t sha_in_buf[DCP_BUF_SZ];
+ uint8_t sha_out_buf[DCP_SHA_PAY_SZ];
uint8_t aes_key[2 * AES_KEYSIZE_128];
@@ -70,6 +87,7 @@ struct dcp {
#ifdef CONFIG_ARM
struct clk *dcp_clk;
#endif
+ int enable_sha_workaround;
};
enum dcp_chan {
@@ -518,8 +536,6 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm);
struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req);
- struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
-
struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
dma_addr_t digest_phys = 0;
@@ -541,10 +557,24 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
desc->payload = 0;
desc->status = 0;
+ /*
+ * Align driver with hw behavior when generating null hashes
+ */
+ if (rctx->init && rctx->fini && desc->size == 0 &&
+ sdcp->enable_sha_workaround) {
+ struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
+ const uint8_t *sha_buf =
+ (actx->alg == MXS_DCP_CONTROL1_HASH_SELECT_SHA1) ?
+ sha1_null_hash : sha256_null_hash;
+ memcpy(sdcp->coh->sha_out_buf, sha_buf, halg->digestsize);
+ ret = 0;
+ goto done_run;
+ }
+
/* Set HASH_TERM bit for last transfer block. */
if (rctx->fini) {
- digest_phys = dma_map_single(sdcp->dev, req->result,
- halg->digestsize, DMA_FROM_DEVICE);
+ digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf,
+ DCP_SHA_PAY_SZ, DMA_FROM_DEVICE);
desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM;
desc->payload = digest_phys;
}
@@ -552,9 +582,10 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
ret = mxs_dcp_start_dma(actx);
if (rctx->fini)
- dma_unmap_single(sdcp->dev, digest_phys, halg->digestsize,
+ dma_unmap_single(sdcp->dev, digest_phys, DCP_SHA_PAY_SZ,
DMA_FROM_DEVICE);
+done_run:
dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
return ret;
@@ -572,6 +603,7 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq)
const int nents = sg_nents(req->src);
uint8_t *in_buf = sdcp->coh->sha_in_buf;
+ uint8_t *out_buf = sdcp->coh->sha_out_buf;
uint8_t *src_buf;
@@ -626,11 +658,9 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq)
actx->fill = 0;
- /* For some reason, the result is flipped. */
- for (i = 0; i < halg->digestsize / 2; i++) {
- swap(req->result[i],
- req->result[halg->digestsize - i - 1]);
- }
+ /* For some reason the result is flipped */
+ for (i = 0; i < halg->digestsize; i++)
+ req->result[i] = out_buf[halg->digestsize - i - 1];
}
return 0;
@@ -766,7 +796,7 @@ static int dcp_sha_export(struct ahash_request *req, void *out)
memcpy(&export->req_ctx, rctx_state, sizeof(struct dcp_sha_req_ctx));
memcpy(&export->async_ctx, actx_state, sizeof(struct dcp_async_ctx));
-
+
return 0;
}
@@ -779,7 +809,7 @@ static int dcp_sha_import(struct ahash_request *req, const void *in)
memset(rctx, 0, sizeof(struct dcp_sha_req_ctx));
memset(actx, 0, sizeof(struct dcp_async_ctx));
-
+
memcpy(rctx, &export->req_ctx, sizeof(struct dcp_sha_req_ctx));
memcpy(actx, &export->async_ctx, sizeof(struct dcp_async_ctx));
@@ -1048,6 +1078,15 @@ static int mxs_dcp_probe(struct platform_device *pdev)
crypto_init_queue(&sdcp->queue[i], 50);
}
+ /*
+ * Enable driver alignment with hw behavior on imx6
+ */
+ if (of_machine_is_compatible("fsl,imx6sl") ||
+ of_machine_is_compatible("fsl,imx6ull")) {
+ sdcp->enable_sha_workaround = 1;
+ } else
+ sdcp->enable_sha_workaround = 0;
+
/* Create the SHA and AES handler threads. */
sdcp->thread[DCP_CHAN_HASH_SHA] = kthread_run(dcp_chan_thread_sha,
NULL, "mxs_dcp_chan/sha");