Add Broadcom / Netgear changes from RAXE 1.0.0.48
[project/bcm63xx/u-boot.git] / arch / arm / mach-bcmbca / otp_tk / sec_tk.c
diff --git a/arch/arm/mach-bcmbca/otp_tk/sec_tk.c b/arch/arm/mach-bcmbca/otp_tk/sec_tk.c
new file mode 100644 (file)
index 0000000..13bf807
--- /dev/null
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2020 Broadcom Ltd.
+ */
+#include <common.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include "linux/printk.h"
+#include <asm/arch/misc.h>
+#include "bcm_otp.h"
+#include <u-boot/rsa.h>
+#include <u-boot/sha256.h>
+#include <uboot_aes.h>
+#include "bcm_secure.h"
+#include "tk_ks.h"
+
+//#define DRY_RUN
+
+#define        TM_SAMPLE_RATE 10
+
+static char _get_char(void)
+{
+       return tstc() ? getc():'\0';
+}
+
+static inline int sec_tk_check_abort(int sec)
+{
+    char str[8],ch;
+    sec *= TM_SAMPLE_RATE;
+    while (sec > 0) {
+       ch = _get_char();
+        if (ch == 'c' || ch == 'C') {
+            break;
+        }
+       if (!(sec%TM_SAMPLE_RATE)) {
+               sprintf(str,"%3d",sec/TM_SAMPLE_RATE);
+       }
+               puts(str);
+        putc('\r');
+        memset(str, 0, 8);
+        mdelay(1000/TM_SAMPLE_RATE);
+        sec--;
+    }
+    return sec;
+}
+
+
+static inline void ntohl_array(u32* a, u32 length) 
+{
+    int i;
+    for (i = 0;i < length; i++)  {
+         a[i] = ntohl(a[i]);
+    }
+}
+
+
+static int sec_tk_fuse_verify(otp_map_feat_t id, 
+                       const u8* data, 
+                       u32 size)
+{
+       u32     *data_verify = NULL,
+               size_verify = 0;
+       otp_map_cmn_err_t rc = OTP_MAP_CMN_OK; 
+       rc = bcm_otp_read(id, &data_verify, &size_verify);
+       if (rc) {
+               if (rc != OTP_HW_CMN_ERR_KEY_EMPTY) {
+                       goto err;
+               }
+               rc = OTP_MAP_CMN_OK;
+       }
+#ifndef  DRY_RUN 
+       if (!data || !(*data)) {
+               printf("EINV\n");
+               goto err;
+       }
+       rc = bcm_otp_write(id, data, size);
+       if (rc) {
+               printf("EFSD\n");
+               goto err;
+       }
+#else 
+       do{
+               int i;
+               printf("Fusing with size %d data: \n\t",size);
+               for (i = 0; i < size; i++) {
+                       printf(" 0x%x ",data[i]);
+               }
+               printf("\n");
+       }while(0);
+#endif
+err:
+       return rc;
+}
+
+static inline int sec_tk_commit_req(ks_req_state_t req_state, 
+                                bcm_sec_state_t cur_state)
+{
+        int res, rc = 0;
+       
+        switch(cur_state) {
+                case SEC_STATE_UNSEC:
+                        if (req_state == KS_REQ_TRANSIT_FLD || 
+                                req_state == KS_REQ_TRANSIT_MFG){
+                                printf("MFG\n");
+                               u32 val = 0x1, size = 4;
+                               if (sec_tk_fuse_verify(OTP_MAP_BRCM_BTRM_BOOT_ENABLE, &val, size )) {
+                                       goto err;
+                               }
+                               val = 0x7;
+                               if (sec_tk_fuse_verify(OTP_MAP_CUST_BTRM_BOOT_ENABLE, &val, size )) {
+                                       goto err;
+                               }
+                        }
+                        break;
+                case SEC_STATE_GEN3_MFG:
+                        if (req_state == KS_REQ_TRANSIT_FLD) {
+                                int res;
+                               /*program otp bits accordingly */
+                                u8 ek_iv[KS_AES_128_CBC_SZ+KS_AES_128_CBC_SZ],
+                                                hash[KS_HASH_SZ]; 
+                                u32 mid;
+
+                                if (ks_get_data_info(KS_DATA_TYPE_KEY_AES_CBC_128_EK, 
+                                        KS_DATA_STATE_FLD_ENCR, ek_iv) != KS_ERR_SUCC) {
+                                        goto err;
+                                }
+                                if (ks_get_data_info(KS_DATA_TYPE_KEY_AES_CBC_128_IV, 
+                                        KS_DATA_STATE_FLD_ENCR, ek_iv+KS_AES_128_CBC_SZ) != KS_ERR_SUCC) {
+                                        goto err;
+                                }
+                                if (ks_get_data_info(KS_DATA_TYPE_HASH, 
+                                                KS_DATA_STATE_RAW, hash) != KS_ERR_SUCC) {
+                                        goto err;
+                                }
+                                if (ks_get_data_info(KS_DATA_TYPE_MID, 
+                                        KS_DATA_STATE_RAW, &mid) != KS_ERR_SUCC) {
+                                        goto err;
+                                }
+                                printf("FLD\n");
+                               /*
+                                 since sotp interface dealing with 32 bit integers - assumption is
+                                 that raw byte data from keystore are always honoring big endian 
+                                */
+                               mid = ntohl(mid);
+                                ntohl_array((u32*)ek_iv,(KS_AES_128_CBC_SZ*2)/sizeof(u32)); 
+                                ntohl_array((u32*)hash,(KS_HASH_SZ)/sizeof(u32)); 
+                               rc = sec_tk_fuse_verify(OTP_MAP_CUST_MFG_MRKTID, &mid, sizeof(u32));
+                               if (rc) {
+                                        goto err;
+                               }
+                               rc = sec_tk_fuse_verify(SOTP_MAP_FLD_HMID, hash, KS_HASH_SZ);
+                               if (rc) {
+                                        goto err;
+                               }
+                               rc = sec_tk_fuse_verify(SOTP_MAP_FLD_ROE, ek_iv, KS_AES_128_CBC_SZ*2);
+                               if (rc) {
+                                        goto err;
+                               }
+                        }
+                        break;
+                default:
+                        goto err;
+        }
+        return 0;
+err:    
+        return -1;
+}
+
+
+static inline int sec_tk_do_req(u32 sec_arch,
+                               bcm_sec_state_t sec_state,
+                                ks_req_info_t *req_info)
+{
+       /*
+        if (ks_get_req_info(&req_info) != KS_ERR_SUCC) {
+                goto err;
+        }*/
+        
+        switch(sec_arch) {
+                case SEC_ARCH_GEN3:
+                        sec_tk_commit_req(req_info->state, sec_state);
+                        break;
+                case SEC_ARCH_GEN2:
+                case SEC_ARCH_NONE:
+                case SEC_ARCH_GEN1:
+                default:
+                        goto err;
+        }
+        return 0;
+err:
+        printf("EREQ\n");
+        return -1;
+}
+
+static int sec_tk_allow_req(bcm_sec_state_t sec_state, 
+                        ks_req_state_t req_state)
+{
+        switch (sec_state) {
+                case SEC_STATE_UNSEC:
+                        if (req_state == KS_REQ_TRANSIT_MFG ||
+                                req_state == KS_REQ_TRANSIT_FLD) {
+                                return 1;       
+                        }
+                        break;
+                case SEC_STATE_GEN3_MFG:
+                        if (req_state == KS_REQ_TRANSIT_FLD) {
+                                return 1;       
+                        }
+                        break;
+                default:
+                        break;
+        }
+        return 0; 
+}
+
+int sec_tk()
+{      
+       char* msg = NULL;
+       u8* aes_key;
+        ks_req_info_t req_info;
+       bcm_sec_state_t state = bcm_sec()->state;
+        printf("SECE\n");
+        printf("GEN3\n");
+       bcm_sec_get_active_aes_key(&aes_key);
+        if (ks_init(state,
+               SEC_ARCH_GEN3, 
+               bcm_sec_get_active_pub_key(),
+               aes_key) != KS_ERR_SUCC) {
+                goto err;
+        }
+        if (ks_get_req_info(&req_info) != KS_ERR_SUCC) {
+                goto err;
+        }
+
+        if (!sec_tk_allow_req(state, req_info.state)) {
+                printf("FUSD\n");
+                goto done;
+        }
+        switch (state) {
+                case SEC_STATE_UNSEC:
+                        msg = "NSEC\n";
+                        break;
+                case SEC_STATE_GEN3_MFG:
+                        msg = "MFG\n";
+                        break;
+                default:
+                        goto err;
+        }
+               printf(msg);
+        printf("ABT?\n");
+        if (sec_tk_check_abort(req_info.abort_delay)) {
+                
+                printf("CNCL\n");
+                goto done;
+        }
+        if (sec_tk_do_req(SEC_ARCH_GEN3, state ,&req_info) == 0) {
+                printf("POR!\n");
+        }
+done:
+        return 0;
+err:
+        printf("SERR\n"); 
+        return -1;
+}
+