blob: 7318c90e6a1a3c0800c3306730b747d2f5056027 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "hmac.h"
6
7#include "common.h"
8#include "hmac_regs.h"
9
10#define HMAC0_BASE_ADDR 0x40120000
11#define HMAC_FIFO_MAX 16
12#define HMAC_FIFO_GROUP_SIZE HMAC_FIFO_MAX / 2
13
14void hmac_init(hmac_cfg_t hmac_cfg) {
15 REG32(HMAC_CFG(0)) = hmac_cfg.input_endian_swap << HMAC_CFG_ENDIAN_SWAP |
16 1 << hmac_cfg.mode |
17 hmac_cfg.digest_endian_swap << HMAC_CFG_DIGEST_SWAP;
18
19 REG32(HMAC_MSG_LENGTH_LOWER(0)) = hmac_cfg.length_lower;
20 REG32(HMAC_MSG_LENGTH_UPPER(0)) = hmac_cfg.length_upper;
21
22 for (int i = 0; i < 8; i++) {
23 REG32(HMAC_KEY0(0) + i * sizeof(uint32_t)) = hmac_cfg.keys[i];
24 }
25
26 REG32(HMAC_CMD(0)) = -1;
27};
28
29int hmac_fifo_full(void) {
30 return (REG32(HMAC_STATUS(0)) >> HMAC_STATUS_FIFO_FULL) & 0x1;
31}
32
33static int hmac_fifo_depth(void) {
34 return (REG32(HMAC_STATUS(0)) >> HMAC_STATUS_FIFO_DEPTH_OFFSET) &
35 HMAC_STATUS_FIFO_DEPTH_MASK;
36}
37
38static int fifo_avail(void) { return HMAC_FIFO_MAX - hmac_fifo_depth(); }
39
40void hmac_write(const void *data, size_t size_in_bytes) {
41 const uint8_t *bp;
42 const uint32_t *wp;
43 uint32_t bytes_per_word = sizeof(uint32_t) / sizeof(uint8_t);
44 uint32_t bytes_left_over = (size_in_bytes % bytes_per_word);
45 size_t words_remaining = size_in_bytes / bytes_per_word;
46
47 wp = (uint32_t *)data;
48
49 // write in all words
50 while (words_remaining > 0) {
51 if (words_remaining > HMAC_FIFO_GROUP_SIZE) {
52 // wait until FIFO is at least half drained
53 while (fifo_avail() <= HMAC_FIFO_GROUP_SIZE) {
54 }
55
56 // write a whole group
57 REG32(HMAC_MSG_FIFO(0)) = *wp++;
58 REG32(HMAC_MSG_FIFO(0)) = *wp++;
59 REG32(HMAC_MSG_FIFO(0)) = *wp++;
60 REG32(HMAC_MSG_FIFO(0)) = *wp++;
61 REG32(HMAC_MSG_FIFO(0)) = *wp++;
62 REG32(HMAC_MSG_FIFO(0)) = *wp++;
63 REG32(HMAC_MSG_FIFO(0)) = *wp++;
64 REG32(HMAC_MSG_FIFO(0)) = *wp++;
65 words_remaining -= HMAC_FIFO_GROUP_SIZE;
66
67 } else {
68 REG32(HMAC_MSG_FIFO(0)) = *wp++;
69 words_remaining--;
70 };
71 }
72
73 // TODO: this is necessary because hmac only understands words right now, we
74 // cannot do a byte write. Once that is addressed, change following to
75 // byte writes directly
76 // Despite no byte support, it would have been okay to just read the entire
77 // word and write it to hmac, since hmac knows exactly which bytes to ignore /
78 // process. The problem however, is that the DV environment does not like
79 // reading of unknown data. So imagine if we have one byte (0xab) left over,
80 // in DV memory, this is represented as
81 // XXXX_XXab. Our environment assertions will fail when a full word read is
82 // made to the X's, thus it is converted to byte reads below to avoid that
83 // problem
84 uint32_t padded_word = 0;
85 uint8_t *last_word_ptr = (uint8_t *)&padded_word;
86 bp = (uint8_t *)wp;
87
88 while (bytes_left_over > 0) {
89 *last_word_ptr++ = *bp++;
90 bytes_left_over--;
91 }
92
93 // this word is ignored if no bytes are left over
94 REG32(HMAC_MSG_FIFO(0)) = padded_word;
95}
96
97int hmac_done(uint32_t *digest) {
98 // TODO need a timeout mechanism
99 // wait for done to assert
100 while (!((REG32(HMAC_INTR_STATE(0)) >> HMAC_INTR_STATE_HMAC_DONE) & 0x1)) {
101 }
102
103 for (uint32_t i = 0; i < 8; i++) {
104 *digest++ = REG32(HMAC_DIGEST0(0) + i * sizeof(uintptr_t));
105 }
106
107 // eventually when we timeout, need to return an error code
108 return 0;
109}