lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 1 | // 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 | |
| 14 | void 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 | |
| 29 | int hmac_fifo_full(void) { |
| 30 | return (REG32(HMAC_STATUS(0)) >> HMAC_STATUS_FIFO_FULL) & 0x1; |
| 31 | } |
| 32 | |
| 33 | static int hmac_fifo_depth(void) { |
| 34 | return (REG32(HMAC_STATUS(0)) >> HMAC_STATUS_FIFO_DEPTH_OFFSET) & |
| 35 | HMAC_STATUS_FIFO_DEPTH_MASK; |
| 36 | } |
| 37 | |
| 38 | static int fifo_avail(void) { return HMAC_FIFO_MAX - hmac_fifo_depth(); } |
| 39 | |
| 40 | void 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 | |
| 97 | int 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 | } |