Merge remote-tracking branch 'uniarch/master' into multiarch
[fw/altos] / src / ao_aes.c
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19
20 #if !HAS_AES
21 #error Must define HAS_AES 1
22 #endif
23
24 __xdata uint8_t ao_aes_mutex;
25 __xdata uint8_t ao_aes_done;
26 __xdata uint8_t ao_aes_dma_in, ao_aes_dma_out;
27 __xdata uint8_t ao_aes_dma_in_done, ao_aes_dma_out_done;
28 __pdata enum ao_aes_mode ao_aes_current_mode;
29
30 void
31 ao_aes_isr(void) __interrupt 4
32 {
33         S0CON = 0;
34         if (ENCCCS & ENCCCS_RDY) {
35                 ao_aes_done = 1;
36                 ao_wakeup(&ao_aes_done);
37         }
38 }
39
40 void
41 ao_aes_set_mode(enum ao_aes_mode mode)
42 {
43         ao_aes_current_mode = mode;
44 }
45
46 void
47 ao_aes_set_key(__xdata uint8_t *in)
48 {
49         ao_dma_set_transfer(ao_aes_dma_in,
50                             in,
51                             &ENCDIXADDR,
52                             AO_AES_LEN,
53                             DMA_CFG0_WORDSIZE_8 |
54                             DMA_CFG0_TMODE_SINGLE |
55                             DMA_CFG0_TRIGGER_ENC_DW,
56                             DMA_CFG1_SRCINC_1 |
57                             DMA_CFG1_DESTINC_0 |
58                             DMA_CFG1_PRIORITY_LOW);
59         ao_dma_start(ao_aes_dma_in);
60         ao_aes_done = 0;
61         ENCCCS = ENCCCS_MODE_CBC_MAC |
62                 ENCCCS_CMD_LOAD_KEY;
63         ENCCCS |= ENCCCS_START;
64         __critical while (!ao_aes_done)
65                 ao_sleep(&ao_aes_done);
66 }
67
68 void
69 ao_aes_zero_iv(void)
70 {
71         uint8_t b;
72
73         ENCCCS = ENCCCS_MODE_CBC_MAC | ENCCCS_CMD_LOAD_IV | ENCCCS_START;
74         for (b = 0; b < AO_AES_LEN; b++)
75                 ENCDI = 0;
76 }
77
78 void
79 ao_aes_run(__xdata uint8_t *in,
80            __xdata uint8_t *out)
81 {
82         uint8_t b;
83         if (in) {
84                 ao_dma_set_transfer(ao_aes_dma_in,
85                                     in,
86                                     &ENCDIXADDR,
87                                     AO_AES_LEN,
88                                     DMA_CFG0_WORDSIZE_8 |
89                                     DMA_CFG0_TMODE_SINGLE |
90                                     DMA_CFG0_TRIGGER_ENC_DW,
91                                     DMA_CFG1_SRCINC_1 |
92                                     DMA_CFG1_DESTINC_0 |
93                                     DMA_CFG1_PRIORITY_LOW);
94         }
95         if (out) {
96                 ao_dma_set_transfer(ao_aes_dma_out,
97                                     &ENCDOXADDR,
98                                     out,
99                                     AO_AES_LEN,
100                                     DMA_CFG0_WORDSIZE_8 |
101                                     DMA_CFG0_TMODE_SINGLE |
102                                     DMA_CFG0_TRIGGER_ENC_UP,
103                                     DMA_CFG1_SRCINC_0 |
104                                     DMA_CFG1_DESTINC_1 |
105                                     DMA_CFG1_PRIORITY_LOW);
106         }
107         switch (ao_aes_current_mode) {
108         case ao_aes_mode_cbc_mac:
109                 if (out)
110                         b = (ENCCCS_MODE_CBC |
111                              ENCCCS_CMD_ENCRYPT);
112                 else
113                         b = (ENCCCS_MODE_CBC_MAC |
114                              ENCCCS_CMD_ENCRYPT);
115                 break;
116         default:
117                 return;
118         }
119         ao_aes_done = 0;
120         if (in)
121                 ao_dma_start(ao_aes_dma_in);
122         if (out)
123                 ao_dma_start(ao_aes_dma_out);
124         ENCCCS = b;
125         ENCCCS |= ENCCCS_START;
126         if (out) {
127                 __critical while (!ao_aes_dma_out_done)
128                         ao_sleep(&ao_aes_dma_out_done);
129         } else {
130                 __critical while (!ao_aes_done)
131                         ao_sleep(&ao_aes_done);
132         }
133 }
134
135 void
136 ao_aes_init(void)
137 {
138         ao_aes_dma_in = ao_dma_alloc(&ao_aes_dma_in_done);
139         ao_aes_dma_out = ao_dma_alloc(&ao_aes_dma_out_done);
140         S0CON = 0;
141         ENCIE = 1;
142 }