1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * SEC Descriptor Construction Library
3*4882a593Smuzhiyun * Basic job descriptor construction
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright 2014 Freescale Semiconductor, Inc.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <common.h>
12*4882a593Smuzhiyun #include <fsl_sec.h>
13*4882a593Smuzhiyun #include "desc_constr.h"
14*4882a593Smuzhiyun #include "jobdesc.h"
15*4882a593Smuzhiyun #include "rsa_caam.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #if defined(CONFIG_MX6) || defined(CONFIG_MX7)
18*4882a593Smuzhiyun /*!
19*4882a593Smuzhiyun * Secure memory run command
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * @param sec_mem_cmd Secure memory command register
22*4882a593Smuzhiyun * @return cmd_status Secure memory command status register
23*4882a593Smuzhiyun */
secmem_set_cmd(uint32_t sec_mem_cmd)24*4882a593Smuzhiyun uint32_t secmem_set_cmd(uint32_t sec_mem_cmd)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun uint32_t temp_reg;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR;
29*4882a593Smuzhiyun uint32_t sm_vid = SM_VERSION(sec_in32(&sec->smvid));
30*4882a593Smuzhiyun uint32_t jr_id = 0;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun sec_out32(CAAM_SMCJR(sm_vid, jr_id), sec_mem_cmd);
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun do {
35*4882a593Smuzhiyun temp_reg = sec_in32(CAAM_SMCSJR(sm_vid, jr_id));
36*4882a593Smuzhiyun } while (temp_reg & CMD_COMPLETE);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun return temp_reg;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /*!
42*4882a593Smuzhiyun * CAAM page allocation:
43*4882a593Smuzhiyun * Allocates a partition from secure memory, with the id
44*4882a593Smuzhiyun * equal to partition_num. This will de-allocate the page
45*4882a593Smuzhiyun * if it is already allocated. The partition will have
46*4882a593Smuzhiyun * full access permissions. The permissions are set before,
47*4882a593Smuzhiyun * running a job descriptor. A memory page of secure RAM
48*4882a593Smuzhiyun * is allocated for the partition.
49*4882a593Smuzhiyun *
50*4882a593Smuzhiyun * @param page Number of the page to allocate.
51*4882a593Smuzhiyun * @param partition Number of the partition to allocate.
52*4882a593Smuzhiyun * @return 0 on success, ERROR_IN_PAGE_ALLOC otherwise
53*4882a593Smuzhiyun */
caam_page_alloc(uint8_t page_num,uint8_t partition_num)54*4882a593Smuzhiyun int caam_page_alloc(uint8_t page_num, uint8_t partition_num)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun uint32_t temp_reg;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR;
59*4882a593Smuzhiyun uint32_t sm_vid = SM_VERSION(sec_in32(&sec->smvid));
60*4882a593Smuzhiyun uint32_t jr_id = 0;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /*
63*4882a593Smuzhiyun * De-Allocate partition_num if already allocated to ARM core
64*4882a593Smuzhiyun */
65*4882a593Smuzhiyun if (sec_in32(CAAM_SMPO_0) & PARTITION_OWNER(partition_num)) {
66*4882a593Smuzhiyun temp_reg = secmem_set_cmd(PARTITION(partition_num) |
67*4882a593Smuzhiyun CMD_PART_DEALLOC);
68*4882a593Smuzhiyun if (temp_reg & SMCSJR_AERR) {
69*4882a593Smuzhiyun printf("Error: De-allocation status 0x%X\n", temp_reg);
70*4882a593Smuzhiyun return ERROR_IN_PAGE_ALLOC;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /* set the access rights to allow full access */
75*4882a593Smuzhiyun sec_out32(CAAM_SMAG1JR(sm_vid, jr_id, partition_num), 0xF);
76*4882a593Smuzhiyun sec_out32(CAAM_SMAG2JR(sm_vid, jr_id, partition_num), 0xF);
77*4882a593Smuzhiyun sec_out32(CAAM_SMAPJR(sm_vid, jr_id, partition_num), 0xFF);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* Now need to allocate partition_num of secure RAM. */
80*4882a593Smuzhiyun /* De-Allocate page_num by starting with a page inquiry command */
81*4882a593Smuzhiyun temp_reg = secmem_set_cmd(PAGE(page_num) | CMD_INQUIRY);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* if the page is owned, de-allocate it */
84*4882a593Smuzhiyun if ((temp_reg & SMCSJR_PO) == PAGE_OWNED) {
85*4882a593Smuzhiyun temp_reg = secmem_set_cmd(PAGE(page_num) | CMD_PAGE_DEALLOC);
86*4882a593Smuzhiyun if (temp_reg & SMCSJR_AERR) {
87*4882a593Smuzhiyun printf("Error: Allocation status 0x%X\n", temp_reg);
88*4882a593Smuzhiyun return ERROR_IN_PAGE_ALLOC;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun /* Allocate page_num to partition_num */
93*4882a593Smuzhiyun temp_reg = secmem_set_cmd(PAGE(page_num) | PARTITION(partition_num)
94*4882a593Smuzhiyun | CMD_PAGE_ALLOC);
95*4882a593Smuzhiyun if (temp_reg & SMCSJR_AERR) {
96*4882a593Smuzhiyun printf("Error: Allocation status 0x%X\n", temp_reg);
97*4882a593Smuzhiyun return ERROR_IN_PAGE_ALLOC;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun /* page inquiry command to ensure that the page was allocated */
100*4882a593Smuzhiyun temp_reg = secmem_set_cmd(PAGE(page_num) | CMD_INQUIRY);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /* if the page is not owned => problem */
103*4882a593Smuzhiyun if ((temp_reg & SMCSJR_PO) != PAGE_OWNED) {
104*4882a593Smuzhiyun printf("Allocation of page %d in partition %d failed 0x%X\n",
105*4882a593Smuzhiyun temp_reg, page_num, partition_num);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun return ERROR_IN_PAGE_ALLOC;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun return 0;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
inline_cnstr_jobdesc_blob_dek(uint32_t * desc,const uint8_t * plain_txt,uint8_t * dek_blob,uint32_t in_sz)113*4882a593Smuzhiyun int inline_cnstr_jobdesc_blob_dek(uint32_t *desc, const uint8_t *plain_txt,
114*4882a593Smuzhiyun uint8_t *dek_blob, uint32_t in_sz)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR;
117*4882a593Smuzhiyun uint32_t sm_vid = SM_VERSION(sec_in32(&sec->smvid));
118*4882a593Smuzhiyun uint32_t jr_id = 0;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun uint32_t ret = 0;
121*4882a593Smuzhiyun u32 aad_w1, aad_w2;
122*4882a593Smuzhiyun /* output blob will have 32 bytes key blob in beginning and
123*4882a593Smuzhiyun * 16 byte HMAC identifier at end of data blob */
124*4882a593Smuzhiyun uint32_t out_sz = in_sz + KEY_BLOB_SIZE + MAC_SIZE;
125*4882a593Smuzhiyun /* Setting HDR for blob */
126*4882a593Smuzhiyun uint8_t wrapped_key_hdr[8] = {HDR_TAG, 0x00, WRP_HDR_SIZE + out_sz,
127*4882a593Smuzhiyun HDR_PAR, HAB_MOD, HAB_ALG, in_sz, HAB_FLG};
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /* initialize the blob array */
130*4882a593Smuzhiyun memset(dek_blob, 0, out_sz + 8);
131*4882a593Smuzhiyun /* Copy the header into the DEK blob buffer */
132*4882a593Smuzhiyun memcpy(dek_blob, wrapped_key_hdr, sizeof(wrapped_key_hdr));
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* allocating secure memory */
135*4882a593Smuzhiyun ret = caam_page_alloc(PAGE_1, PARTITION_1);
136*4882a593Smuzhiyun if (ret)
137*4882a593Smuzhiyun return ret;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* Write DEK to secure memory */
140*4882a593Smuzhiyun memcpy((uint32_t *)SEC_MEM_PAGE1, (uint32_t *)plain_txt, in_sz);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun unsigned long start = (unsigned long)SEC_MEM_PAGE1 &
143*4882a593Smuzhiyun ~(ARCH_DMA_MINALIGN - 1);
144*4882a593Smuzhiyun unsigned long end = ALIGN(start + 0x1000, ARCH_DMA_MINALIGN);
145*4882a593Smuzhiyun flush_dcache_range(start, end);
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* Now configure the access rights of the partition */
148*4882a593Smuzhiyun sec_out32(CAAM_SMAG1JR(sm_vid, jr_id, PARTITION_1), KS_G1);
149*4882a593Smuzhiyun sec_out32(CAAM_SMAG2JR(sm_vid, jr_id, PARTITION_1), 0);
150*4882a593Smuzhiyun sec_out32(CAAM_SMAPJR(sm_vid, jr_id, PARTITION_1), PERM);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun /* construct aad for AES */
153*4882a593Smuzhiyun aad_w1 = (in_sz << OP_ALG_ALGSEL_SHIFT) | KEY_AES_SRC | LD_CCM_MODE;
154*4882a593Smuzhiyun aad_w2 = 0x0;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun init_job_desc(desc, 0);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun append_cmd(desc, CMD_LOAD | CLASS_2 | KEY_IMM | KEY_ENC |
159*4882a593Smuzhiyun (0x0c << LDST_OFFSET_SHIFT) | 0x08);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun append_u32(desc, aad_w1);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun append_u32(desc, aad_w2);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun append_cmd_ptr(desc, (dma_addr_t)SEC_MEM_PAGE1, in_sz, CMD_SEQ_IN_PTR);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun append_cmd_ptr(desc, (dma_addr_t)dek_blob + 8, out_sz, CMD_SEQ_OUT_PTR);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun append_operation(desc, OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB |
170*4882a593Smuzhiyun OP_PCLID_SECMEM);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun return ret;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun #endif
175*4882a593Smuzhiyun
inline_cnstr_jobdesc_hash(uint32_t * desc,const uint8_t * msg,uint32_t msgsz,uint8_t * digest,u32 alg_type,uint32_t alg_size,int sg_tbl)176*4882a593Smuzhiyun void inline_cnstr_jobdesc_hash(uint32_t *desc,
177*4882a593Smuzhiyun const uint8_t *msg, uint32_t msgsz, uint8_t *digest,
178*4882a593Smuzhiyun u32 alg_type, uint32_t alg_size, int sg_tbl)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun /* SHA 256 , output is of length 32 words */
181*4882a593Smuzhiyun uint32_t storelen = alg_size;
182*4882a593Smuzhiyun u32 options;
183*4882a593Smuzhiyun dma_addr_t dma_addr_in, dma_addr_out;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun dma_addr_in = virt_to_phys((void *)msg);
186*4882a593Smuzhiyun dma_addr_out = virt_to_phys((void *)digest);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun init_job_desc(desc, 0);
189*4882a593Smuzhiyun append_operation(desc, OP_TYPE_CLASS2_ALG |
190*4882a593Smuzhiyun OP_ALG_AAI_HASH | OP_ALG_AS_INITFINAL |
191*4882a593Smuzhiyun OP_ALG_ENCRYPT | OP_ALG_ICV_OFF | alg_type);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun options = LDST_CLASS_2_CCB | FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST2;
194*4882a593Smuzhiyun if (sg_tbl)
195*4882a593Smuzhiyun options |= FIFOLDST_SGF;
196*4882a593Smuzhiyun if (msgsz > 0xffff) {
197*4882a593Smuzhiyun options |= FIFOLDST_EXT;
198*4882a593Smuzhiyun append_fifo_load(desc, dma_addr_in, 0, options);
199*4882a593Smuzhiyun append_cmd(desc, msgsz);
200*4882a593Smuzhiyun } else {
201*4882a593Smuzhiyun append_fifo_load(desc, dma_addr_in, msgsz, options);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun append_store(desc, dma_addr_out, storelen,
205*4882a593Smuzhiyun LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun #ifndef CONFIG_SPL_BUILD
inline_cnstr_jobdesc_blob_encap(uint32_t * desc,uint8_t * key_idnfr,uint8_t * plain_txt,uint8_t * enc_blob,uint32_t in_sz)208*4882a593Smuzhiyun void inline_cnstr_jobdesc_blob_encap(uint32_t *desc, uint8_t *key_idnfr,
209*4882a593Smuzhiyun uint8_t *plain_txt, uint8_t *enc_blob,
210*4882a593Smuzhiyun uint32_t in_sz)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun dma_addr_t dma_addr_key_idnfr, dma_addr_in, dma_addr_out;
213*4882a593Smuzhiyun uint32_t key_sz = KEY_IDNFR_SZ_BYTES;
214*4882a593Smuzhiyun /* output blob will have 32 bytes key blob in beginning and
215*4882a593Smuzhiyun * 16 byte HMAC identifier at end of data blob */
216*4882a593Smuzhiyun uint32_t out_sz = in_sz + KEY_BLOB_SIZE + MAC_SIZE;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun dma_addr_key_idnfr = virt_to_phys((void *)key_idnfr);
219*4882a593Smuzhiyun dma_addr_in = virt_to_phys((void *)plain_txt);
220*4882a593Smuzhiyun dma_addr_out = virt_to_phys((void *)enc_blob);
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun init_job_desc(desc, 0);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun append_key(desc, dma_addr_key_idnfr, key_sz, CLASS_2);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun append_seq_in_ptr(desc, dma_addr_in, in_sz, 0);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun append_seq_out_ptr(desc, dma_addr_out, out_sz, 0);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun append_operation(desc, OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
inline_cnstr_jobdesc_blob_decap(uint32_t * desc,uint8_t * key_idnfr,uint8_t * enc_blob,uint8_t * plain_txt,uint32_t out_sz)233*4882a593Smuzhiyun void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr,
234*4882a593Smuzhiyun uint8_t *enc_blob, uint8_t *plain_txt,
235*4882a593Smuzhiyun uint32_t out_sz)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun dma_addr_t dma_addr_key_idnfr, dma_addr_in, dma_addr_out;
238*4882a593Smuzhiyun uint32_t key_sz = KEY_IDNFR_SZ_BYTES;
239*4882a593Smuzhiyun uint32_t in_sz = out_sz + KEY_BLOB_SIZE + MAC_SIZE;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun dma_addr_key_idnfr = virt_to_phys((void *)key_idnfr);
242*4882a593Smuzhiyun dma_addr_in = virt_to_phys((void *)enc_blob);
243*4882a593Smuzhiyun dma_addr_out = virt_to_phys((void *)plain_txt);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun init_job_desc(desc, 0);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun append_key(desc, dma_addr_key_idnfr, key_sz, CLASS_2);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun append_seq_in_ptr(desc, dma_addr_in, in_sz, 0);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun append_seq_out_ptr(desc, dma_addr_out, out_sz, 0);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun append_operation(desc, OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun #endif
256*4882a593Smuzhiyun /*
257*4882a593Smuzhiyun * Descriptor to instantiate RNG State Handle 0 in normal mode and
258*4882a593Smuzhiyun * load the JDKEK, TDKEK and TDSK registers
259*4882a593Smuzhiyun */
inline_cnstr_jobdesc_rng_instantiation(uint32_t * desc)260*4882a593Smuzhiyun void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun u32 *jump_cmd;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun init_job_desc(desc, 0);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* INIT RNG in non-test mode */
267*4882a593Smuzhiyun append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
268*4882a593Smuzhiyun OP_ALG_AS_INIT);
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /* wait for done */
271*4882a593Smuzhiyun jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1);
272*4882a593Smuzhiyun set_jump_tgt_here(desc, jump_cmd);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /*
275*4882a593Smuzhiyun * load 1 to clear written reg:
276*4882a593Smuzhiyun * resets the done interrrupt and returns the RNG to idle.
277*4882a593Smuzhiyun */
278*4882a593Smuzhiyun append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /* generate secure keys (non-test) */
281*4882a593Smuzhiyun append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
282*4882a593Smuzhiyun OP_ALG_RNG4_SK);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /* Change key size to bytes form bits in calling function*/
inline_cnstr_jobdesc_pkha_rsaexp(uint32_t * desc,struct pk_in_params * pkin,uint8_t * out,uint32_t out_siz)286*4882a593Smuzhiyun void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
287*4882a593Smuzhiyun struct pk_in_params *pkin, uint8_t *out,
288*4882a593Smuzhiyun uint32_t out_siz)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun dma_addr_t dma_addr_e, dma_addr_a, dma_addr_n, dma_addr_out;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun dma_addr_e = virt_to_phys((void *)pkin->e);
293*4882a593Smuzhiyun dma_addr_a = virt_to_phys((void *)pkin->a);
294*4882a593Smuzhiyun dma_addr_n = virt_to_phys((void *)pkin->n);
295*4882a593Smuzhiyun dma_addr_out = virt_to_phys((void *)out);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun init_job_desc(desc, 0);
298*4882a593Smuzhiyun append_key(desc, dma_addr_e, pkin->e_siz, KEY_DEST_PKHA_E | CLASS_1);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun append_fifo_load(desc, dma_addr_a,
301*4882a593Smuzhiyun pkin->a_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_A);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun append_fifo_load(desc, dma_addr_n,
304*4882a593Smuzhiyun pkin->n_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_N);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun append_operation(desc, OP_TYPE_PK | OP_ALG_PK | OP_ALG_PKMODE_MOD_EXPO);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun append_fifo_store(desc, dma_addr_out, out_siz,
309*4882a593Smuzhiyun LDST_CLASS_1_CCB | FIFOST_TYPE_PKHA_B);
310*4882a593Smuzhiyun }
311