diff --git a/cpu/cc2538/dev/aes.c b/cpu/cc2538/dev/aes.c index d5920fee0..7fe52e07e 100644 --- a/cpu/cc2538/dev/aes.c +++ b/cpu/cc2538/dev/aes.c @@ -52,6 +52,10 @@ aes_load_key(const void *key, uint8_t key_area) { uint32_t aligned_key[4]; + if(REG(AES_CTRL_ALG_SEL) != 0x00000000) { + return CRYPTO_RESOURCE_IN_USE; + } + /* The key address needs to be 4-byte aligned */ rom_util_memcpy(aligned_key, key, sizeof(aligned_key)); @@ -93,10 +97,14 @@ aes_load_key(const void *key, uint8_t key_area) /* Check for absence of errors in DMA and key store */ if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_DMA_BUS_ERR) { REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR; + /* Disable master control / DMA clock */ + REG(AES_CTRL_ALG_SEL) = 0x00000000; return CRYPTO_DMA_BUS_ERROR; } if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_KEY_ST_WR_ERR) { REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_KEY_ST_WR_ERR; + /* Disable master control / DMA clock */ + REG(AES_CTRL_ALG_SEL) = 0x00000000; return AES_KEYSTORE_WRITE_ERROR; } diff --git a/cpu/cc2538/dev/aes.h b/cpu/cc2538/dev/aes.h index 5b9e4c343..8a6762739 100644 --- a/cpu/cc2538/dev/aes.h +++ b/cpu/cc2538/dev/aes.h @@ -462,8 +462,8 @@ /** \name AES drivers return codes * @{ */ -#define AES_KEYSTORE_READ_ERROR 4 -#define AES_KEYSTORE_WRITE_ERROR 5 +#define AES_KEYSTORE_READ_ERROR 5 +#define AES_KEYSTORE_WRITE_ERROR 6 /** @} */ /*---------------------------------------------------------------------------*/ /** \name AES functions diff --git a/cpu/cc2538/dev/ccm.c b/cpu/cc2538/dev/ccm.c index b18992802..79c535d03 100644 --- a/cpu/cc2538/dev/ccm.c +++ b/cpu/cc2538/dev/ccm.c @@ -43,6 +43,7 @@ #include "contiki.h" #include "sys/cc.h" #include "dev/rom-util.h" +#include "dev/nvic.h" #include "dev/ccm.h" #include "reg.h" @@ -52,10 +53,15 @@ uint8_t ccm_auth_encrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, const void *adata, uint16_t adata_len, void *pdata, - uint16_t pdata_len, uint8_t mic_len) + uint16_t pdata_len, uint8_t mic_len, + struct process *process) { uint32_t iv[4]; + if(REG(AES_CTRL_ALG_SEL) != 0x00000000) { + return CRYPTO_RESOURCE_IN_USE; + } + /* Workaround for AES registers not retained after PM2 */ REG(AES_CTRL_INT_CFG) = AES_CTRL_INT_CFG_LEVEL; REG(AES_CTRL_INT_EN) = AES_CTRL_INT_EN_DMA_IN_DONE | @@ -74,6 +80,8 @@ ccm_auth_encrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_KEY_ST_RD_ERR) { /* Clear the Keystore Read error bit */ REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_KEY_ST_RD_ERR; + /* Disable the master control / DMA clock */ + REG(AES_CTRL_ALG_SEL) = 0x00000000; return AES_KEYSTORE_READ_ERROR; } @@ -125,6 +133,8 @@ ccm_auth_encrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_DMA_BUS_ERR) { /* Clear the DMA error */ REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR; + /* Disable the master control / DMA clock */ + REG(AES_CTRL_ALG_SEL) = 0x00000000; return CRYPTO_DMA_BUS_ERROR; } } @@ -133,6 +143,12 @@ ccm_auth_encrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_IN_DONE | AES_CTRL_INT_CLR_RESULT_AV; + if(process != NULL) { + crypto_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_AES); + nvic_interrupt_enable(NVIC_INT_AES); + } + /* Enable result available bit in interrupt enable */ REG(AES_CTRL_INT_EN) = AES_CTRL_INT_EN_RESULT_AV; @@ -167,27 +183,31 @@ ccm_auth_encrypt_check_status(void) uint8_t ccm_auth_encrypt_get_result(void *mic, uint8_t mic_len) { + uint32_t aes_ctrl_int_stat; uint32_t tag[4]; - if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_DMA_BUS_ERR) { - /* Clear the DMA error bit */ - REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR; - return CRYPTO_DMA_BUS_ERROR; - } - if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_KEY_ST_WR_ERR) { - /* Clear the Key Store Write error bit */ - REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_KEY_ST_WR_ERR; - return AES_KEYSTORE_WRITE_ERROR; - } - if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_KEY_ST_RD_ERR) { - /* Clear the Key Store Read error bit */ - REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_KEY_ST_RD_ERR; - return AES_KEYSTORE_READ_ERROR; - } + aes_ctrl_int_stat = REG(AES_CTRL_INT_STAT); + /* Clear the error bits */ + REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR | + AES_CTRL_INT_CLR_KEY_ST_WR_ERR | + AES_CTRL_INT_CLR_KEY_ST_RD_ERR; + + nvic_interrupt_disable(NVIC_INT_AES); + crypto_register_process_notification(NULL); /* Disable the master control / DMA clock */ REG(AES_CTRL_ALG_SEL) = 0x00000000; + if(aes_ctrl_int_stat & AES_CTRL_INT_STAT_DMA_BUS_ERR) { + return CRYPTO_DMA_BUS_ERROR; + } + if(aes_ctrl_int_stat & AES_CTRL_INT_STAT_KEY_ST_WR_ERR) { + return AES_KEYSTORE_WRITE_ERROR; + } + if(aes_ctrl_int_stat & AES_CTRL_INT_STAT_KEY_ST_RD_ERR) { + return AES_KEYSTORE_READ_ERROR; + } + /* Read tag * Wait for the context ready bit */ while(!(REG(AES_AES_CTRL) & AES_AES_CTRL_SAVED_CONTEXT_READY)); @@ -211,11 +231,16 @@ ccm_auth_encrypt_get_result(void *mic, uint8_t mic_len) uint8_t ccm_auth_decrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, const void *adata, uint16_t adata_len, void *cdata, - uint16_t cdata_len, uint8_t mic_len) + uint16_t cdata_len, uint8_t mic_len, + struct process *process) { uint16_t pdata_len = cdata_len - mic_len; uint32_t iv[4]; + if(REG(AES_CTRL_ALG_SEL) != 0x00000000) { + return CRYPTO_RESOURCE_IN_USE; + } + /* Workaround for AES registers not retained after PM2 */ REG(AES_CTRL_INT_CFG) = AES_CTRL_INT_CFG_LEVEL; REG(AES_CTRL_INT_EN) = AES_CTRL_INT_EN_DMA_IN_DONE | @@ -234,6 +259,8 @@ ccm_auth_decrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_KEY_ST_RD_ERR) { /* Clear the Keystore Read error bit */ REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_KEY_ST_RD_ERR; + /* Disable the master control / DMA clock */ + REG(AES_CTRL_ALG_SEL) = 0x00000000; return AES_KEYSTORE_READ_ERROR; } @@ -284,6 +311,8 @@ ccm_auth_decrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_DMA_BUS_ERR) { /* Clear the DMA error */ REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR; + /* Disable the master control / DMA clock */ + REG(AES_CTRL_ALG_SEL) = 0x00000000; return CRYPTO_DMA_BUS_ERROR; } } @@ -292,6 +321,12 @@ ccm_auth_decrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_IN_DONE | AES_CTRL_INT_CLR_RESULT_AV; + if(process != NULL) { + crypto_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_AES); + nvic_interrupt_enable(NVIC_INT_AES); + } + /* Enable result available bit in interrupt enable */ REG(AES_CTRL_INT_EN) = AES_CTRL_INT_EN_RESULT_AV; @@ -326,28 +361,32 @@ uint8_t ccm_auth_decrypt_get_result(const void *cdata, uint16_t cdata_len, void *mic, uint8_t mic_len) { + uint32_t aes_ctrl_int_stat; uint16_t pdata_len = cdata_len - mic_len; uint32_t tag[4]; - if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_DMA_BUS_ERR) { - /* Clear the DMA error */ - REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR; - return CRYPTO_DMA_BUS_ERROR; - } - if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_KEY_ST_WR_ERR) { - /* Clear the Key Store Write error bit */ - REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_KEY_ST_WR_ERR; - return AES_KEYSTORE_WRITE_ERROR; - } - if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_KEY_ST_RD_ERR) { - /* Clear the Key Store Read error bit */ - REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_KEY_ST_RD_ERR; - return AES_KEYSTORE_READ_ERROR; - } + aes_ctrl_int_stat = REG(AES_CTRL_INT_STAT); + /* Clear the error bits */ + REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR | + AES_CTRL_INT_CLR_KEY_ST_WR_ERR | + AES_CTRL_INT_CLR_KEY_ST_RD_ERR; + + nvic_interrupt_disable(NVIC_INT_AES); + crypto_register_process_notification(NULL); /* Disable the master control / DMA clock */ REG(AES_CTRL_ALG_SEL) = 0x00000000; + if(aes_ctrl_int_stat & AES_CTRL_INT_STAT_DMA_BUS_ERR) { + return CRYPTO_DMA_BUS_ERROR; + } + if(aes_ctrl_int_stat & AES_CTRL_INT_STAT_KEY_ST_WR_ERR) { + return AES_KEYSTORE_WRITE_ERROR; + } + if(aes_ctrl_int_stat & AES_CTRL_INT_STAT_KEY_ST_RD_ERR) { + return AES_KEYSTORE_READ_ERROR; + } + /* Read tag * Wait for the context ready bit */ while(!(REG(AES_AES_CTRL) & AES_AES_CTRL_SAVED_CONTEXT_READY)); diff --git a/cpu/cc2538/dev/ccm.h b/cpu/cc2538/dev/ccm.h index 65c4e36b3..1cab578af 100644 --- a/cpu/cc2538/dev/ccm.h +++ b/cpu/cc2538/dev/ccm.h @@ -57,7 +57,7 @@ /** \name AES-CCM driver return codes * @{ */ -#define CCM_AUTHENTICATION_FAILED 6 +#define CCM_AUTHENTICATION_FAILED 7 /** @} */ /*---------------------------------------------------------------------------*/ /** \name AES-CCM functions @@ -73,12 +73,14 @@ * \param pdata Pointer to message to authenticate and encrypt, or \c NULL * \param pdata_len Length of message to authenticate and encrypt in octets, or \c 0 * \param mic_len Number of octets in authentication field (even value between 0 and 16) + * \param process Process to be polled upon completion of the operation, or \c NULL * \return \c CRYPTO_SUCCESS if successful, or CRYPTO/AES/CCM error code */ uint8_t ccm_auth_encrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, const void *adata, uint16_t adata_len, void *pdata, - uint16_t pdata_len, uint8_t mic_len); + uint16_t pdata_len, uint8_t mic_len, + struct process *process); /** \brief Checks the status of the CCM authentication and encryption operation * \retval false Result not yet available, and no error occurred @@ -103,12 +105,14 @@ uint8_t ccm_auth_encrypt_get_result(void *mic, uint8_t mic_len); * \param cdata Pointer to encrypted and authenticated message * \param cdata_len Length of encrypted and authenticated message in octets * \param mic_len Number of octets in authentication field (even value between 0 and 16) + * \param process Process to be polled upon completion of the operation, or \c NULL * \return \c CRYPTO_SUCCESS if successful, or CRYPTO/AES/CCM error code */ uint8_t ccm_auth_decrypt_start(uint8_t len_len, uint8_t key_area, const void *nonce, const void *adata, uint16_t adata_len, void *cdata, - uint16_t cdata_len, uint8_t mic_len); + uint16_t cdata_len, uint8_t mic_len, + struct process *process); /** \brief Checks the status of the CCM authentication checking and decryption operation * \retval false Result not yet available, and no error occurred diff --git a/cpu/cc2538/dev/crypto.c b/cpu/cc2538/dev/crypto.c index faf3845b0..7dc5d3342 100644 --- a/cpu/cc2538/dev/crypto.c +++ b/cpu/cc2538/dev/crypto.c @@ -36,15 +36,55 @@ * Implementation of the cc2538 AES/SHA cryptoprocessor driver */ #include "contiki.h" +#include "sys/energest.h" #include "dev/sys-ctrl.h" +#include "dev/nvic.h" #include "dev/crypto.h" +#include "dev/aes.h" #include "reg.h" +#include "lpm.h" + +#include +/*---------------------------------------------------------------------------*/ +static volatile struct process *notification_process = NULL; +/*---------------------------------------------------------------------------*/ +/** \brief The AES/SHA cryptoprocessor ISR + * + * This is the interrupt service routine for the AES/SHA + * cryptoprocessor. + * + * This ISR is called at worst from PM0, so lpm_exit() does not need + * to be called. + */ +void +crypto_isr(void) +{ + ENERGEST_ON(ENERGEST_TYPE_IRQ); + + nvic_interrupt_unpend(NVIC_INT_AES); + nvic_interrupt_disable(NVIC_INT_AES); + + if(notification_process != NULL) { + process_poll((struct process *)notification_process); + notification_process = NULL; + } + + ENERGEST_OFF(ENERGEST_TYPE_IRQ); +} +/*---------------------------------------------------------------------------*/ +static bool +permit_pm1(void) +{ + return REG(AES_CTRL_ALG_SEL) == 0; +} /*---------------------------------------------------------------------------*/ void crypto_init(void) { volatile int i; + lpm_register_peripheral(permit_pm1); + crypto_enable(); /* Reset the AES/SHA cryptoprocessor */ @@ -70,5 +110,11 @@ crypto_disable(void) REG(SYS_CTRL_SCGCSEC) &= ~SYS_CTRL_SCGCSEC_AES; REG(SYS_CTRL_DCGCSEC) &= ~SYS_CTRL_DCGCSEC_AES; } +/*---------------------------------------------------------------------------*/ +void +crypto_register_process_notification(struct process *p) +{ + notification_process = p; +} /** @} */ diff --git a/cpu/cc2538/dev/crypto.h b/cpu/cc2538/dev/crypto.h index e51111602..ad06ef343 100644 --- a/cpu/cc2538/dev/crypto.h +++ b/cpu/cc2538/dev/crypto.h @@ -51,7 +51,8 @@ #define CRYPTO_SUCCESS 0 #define CRYPTO_INVALID_PARAM 1 #define CRYPTO_NULL_ERROR 2 -#define CRYPTO_DMA_BUS_ERROR 3 +#define CRYPTO_RESOURCE_IN_USE 3 +#define CRYPTO_DMA_BUS_ERROR 4 /** @} */ /*---------------------------------------------------------------------------*/ /** \name Crypto functions @@ -71,6 +72,13 @@ void crypto_enable(void); */ void crypto_disable(void); +/** \brief Registers a process to be notified of the completion of a crypto + * operation + * \param p Process to be polled upon IRQ + * \note This function is only supposed to be called by the crypto drivers. + */ +void crypto_register_process_notification(struct process *p); + /** @} */ #endif /* CRYPTO_H_ */ diff --git a/cpu/cc2538/dev/sha256.c b/cpu/cc2538/dev/sha256.c index 16067c2ce..347c54081 100644 --- a/cpu/cc2538/dev/sha256.c +++ b/cpu/cc2538/dev/sha256.c @@ -114,6 +114,8 @@ new_hash(sha256_state_t *state, const void *data, void *hash) if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_DMA_BUS_ERR) { /* Clear the DMA error */ REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR; + /* Disable master control / DMA clock */ + REG(AES_CTRL_ALG_SEL) = 0x00000000; return CRYPTO_DMA_BUS_ERROR; } @@ -194,6 +196,8 @@ resume_hash(sha256_state_t *state, const void *data, void *hash) if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_DMA_BUS_ERR) { /* Clear the DMA error */ REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR; + /* Disable master control / DMA clock */ + REG(AES_CTRL_ALG_SEL) = 0x00000000; return CRYPTO_DMA_BUS_ERROR; } @@ -249,6 +253,10 @@ sha256_process(sha256_state_t *state, const void *data, uint32_t len) return CRYPTO_INVALID_PARAM; } + if(REG(AES_CTRL_ALG_SEL) != 0x00000000) { + return CRYPTO_RESOURCE_IN_USE; + } + if(len > 0 && state->new_digest) { if(state->curlen == 0 && len > BLOCK_SIZE) { rom_util_memcpy(state->buf, data, BLOCK_SIZE); @@ -321,6 +329,10 @@ sha256_done(sha256_state_t *state, void *hash) return CRYPTO_INVALID_PARAM; } + if(REG(AES_CTRL_ALG_SEL) != 0x00000000) { + return CRYPTO_RESOURCE_IN_USE; + } + /* Increase the length of the message */ state->length += state->curlen << 3; state->final_digest = true; diff --git a/cpu/cc2538/lpm.c b/cpu/cc2538/lpm.c index abe75c02e..91d67acc9 100644 --- a/cpu/cc2538/lpm.c +++ b/cpu/cc2538/lpm.c @@ -101,7 +101,7 @@ static uint8_t max_pm; #ifdef LPM_CONF_PERIPH_PERMIT_PM1_FUNCS_MAX #define LPM_PERIPH_PERMIT_PM1_FUNCS_MAX LPM_CONF_PERIPH_PERMIT_PM1_FUNCS_MAX #else -#define LPM_PERIPH_PERMIT_PM1_FUNCS_MAX 2 +#define LPM_PERIPH_PERMIT_PM1_FUNCS_MAX 3 #endif static lpm_periph_permit_pm1_func_t diff --git a/cpu/cc2538/startup-gcc.c b/cpu/cc2538/startup-gcc.c index b4155fa29..2aa82894e 100644 --- a/cpu/cc2538/startup-gcc.c +++ b/cpu/cc2538/startup-gcc.c @@ -67,6 +67,7 @@ void udma_err_isr(void); void usb_isr(void) WEAK_ALIAS(default_handler); void uart0_isr(void) WEAK_ALIAS(default_handler); void uart1_isr(void) WEAK_ALIAS(default_handler); +void crypto_isr(void); /* Boot Loader Backdoor selection */ #if FLASH_CCA_CONF_BOOTLDR_BACKDOOR @@ -269,7 +270,7 @@ void(*const vectors[])(void) = usb_isr, /* 156 USB */ cc2538_rf_rx_tx_isr, /* 157 RFCORE RX/TX */ cc2538_rf_err_isr, /* 158 RFCORE Error */ - default_handler, /* 159 AES */ + crypto_isr, /* 159 AES */ default_handler, /* 160 PKA */ rtimer_isr, /* 161 SM Timer */ default_handler, /* 162 MACTimer */ diff --git a/examples/cc2538dk/crypto/ccm-test.c b/examples/cc2538dk/crypto/ccm-test.c index e303c77ef..c34965e5d 100644 --- a/examples/cc2538dk/crypto/ccm-test.c +++ b/examples/cc2538dk/crypto/ccm-test.c @@ -67,6 +67,7 @@ PROCESS_THREAD(ccm_test_process, ev, data) "success", "invalid param", "NULL error", + "resource in use", "DMA bus error", "keystore read error", "keystore write error", @@ -237,14 +238,13 @@ PROCESS_THREAD(ccm_test_process, ev, data) ret = ccm_auth_encrypt_start(vectors[i].len_len, vectors[i].key_area, vectors[i].nonce, vectors[i].adata, vectors[i].adata_len, vectors[i].mdata, - vectors[i].mdata_len, vectors[i].mic_len); + vectors[i].mdata_len, vectors[i].mic_len, + &ccm_test_process); time2 = RTIMER_NOW(); time = time2 - time; total_time += time; if(ret == CRYPTO_SUCCESS) { - do { - PROCESS_PAUSE(); - } while(!ccm_auth_encrypt_check_status()); + PROCESS_WAIT_EVENT_UNTIL(ccm_auth_encrypt_check_status()); time2 = RTIMER_NOW() - time2; total_time += time2; } @@ -286,14 +286,13 @@ PROCESS_THREAD(ccm_test_process, ev, data) ret = ccm_auth_decrypt_start(vectors[i].len_len, vectors[i].key_area, vectors[i].nonce, vectors[i].adata, vectors[i].adata_len, vectors[i].mdata, - vectors[i].mdata_len, vectors[i].mic_len); + vectors[i].mdata_len, vectors[i].mic_len, + &ccm_test_process); time2 = RTIMER_NOW(); time = time2 - time; total_time += time; if(ret == CRYPTO_SUCCESS) { - do { - PROCESS_PAUSE(); - } while(!ccm_auth_decrypt_check_status()); + PROCESS_WAIT_EVENT_UNTIL(ccm_auth_decrypt_check_status()); time2 = RTIMER_NOW() - time2; total_time += time2; } diff --git a/examples/cc2538dk/crypto/sha256-test.c b/examples/cc2538dk/crypto/sha256-test.c index dcdfd83de..f690ed27d 100644 --- a/examples/cc2538dk/crypto/sha256-test.c +++ b/examples/cc2538dk/crypto/sha256-test.c @@ -68,6 +68,7 @@ PROCESS_THREAD(sha256_test_process, ev, data) "success", "invalid param", "NULL error", + "resource in use", "DMA bus error" }; static const struct {