]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
ARM: tegra: Add LP0 support for ODM production
authorIon Agorria <ion@agorria.com>
Tue, 7 Jan 2025 00:53:19 +0000 (01:53 +0100)
committerSvyatoslav Ryhel <clamor95@gmail.com>
Fri, 1 Aug 2025 05:43:41 +0000 (08:43 +0300)
Now that we have working AES engine driver we can request the warmboot code
to be encrypted and signed  with SBK if the device requires so. This
unlocks LP0 support for most devices in the wild as they use ODM Production
Secure.

We are not aware of any "ODM Production Open" device nor have access to
thus this has not been tested on one, merely added for completeness.

Signed-off-by: Ion Agorria <ion@agorria.com>
arch/arm/include/asm/arch-tegra/warmboot.h
arch/arm/mach-tegra/tegra20/warmboot.c

index 402f93aac486e9c7c55653581f73ca21788f3a10..4352f1dc5e8e4671f2d97838fda51e5464fca2d8 100644 (file)
@@ -119,7 +119,6 @@ union scratch3_reg {
 int warmboot_save_sdram_params(void);
 
 int warmboot_prepare_code(u32 seg_address, u32 seg_length);
-int sign_data_block(u8 *source, u32 length, u8 *signature);
 void wb_start(void);   /* Start of WB assembly code */
 void wb_end(void);     /* End of WB assembly code */
 
index 059388f723186ced60f8b713c84ef294549af739..3fd39fe3c1a9b48b43445694c5de63f1cfad410d 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/arch-tegra/pmc.h>
 #include <asm/arch-tegra/fuse.h>
 #include <asm/arch-tegra/warmboot.h>
+#include <asm/arch-tegra/crypto.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -182,25 +183,36 @@ int warmboot_save_sdram_params(void)
        return 0;
 }
 
-static void determine_crypto_options(int *is_encrypted, int *is_signed,
-                                    int *use_zero_key)
+static void determine_crypto_options(int *is_encrypted, int *is_signed)
 {
        switch (tegra_fuse_get_operation_mode()) {
+       case MODE_ODM_PRODUCTION_SECURE:
+               *is_encrypted = 1;
+               *is_signed = 1;
+               break;
+       case MODE_ODM_PRODUCTION_OPEN:
        case MODE_PRODUCTION:
                *is_encrypted = 0;
                *is_signed = 1;
-               *use_zero_key = 1;
                break;
        case MODE_UNDEFINED:
        default:
                *is_encrypted = 0;
                *is_signed = 0;
-               *use_zero_key  = 0;
                break;
        }
 }
 
-static int sign_wb_code(u32 start, u32 length, int use_zero_key)
+static int encrypt_wb_code(u8 *source, u8 *destination, u32 length)
+{
+       source += offsetof(struct wb_header, random_aes_block);
+       destination += offsetof(struct wb_header, random_aes_block);
+       length -= offsetof(struct wb_header, random_aes_block);
+
+       return encrypt_data_block(source, destination, length);
+}
+
+static int sign_wb_code(u32 start, u32 length)
 {
        int err;
        u8 *source;             /* Pointer to source */
@@ -222,10 +234,9 @@ int warmboot_prepare_code(u32 seg_address, u32 seg_length)
        struct wb_header *dst_header;   /* Pointer to dest WB header */
        int is_encrypted;               /* Segment is encrypted */
        int is_signed;                  /* Segment is signed */
-       int use_zero_key;               /* Use key of all zeros */
 
        /* Determine crypto options. */
-       determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key);
+       determine_crypto_options(&is_encrypted, &is_signed);
 
        /* Get the actual code limits. */
        length = roundup(((u32)wb_end - (u32)wb_start), 16);
@@ -273,18 +284,15 @@ int warmboot_prepare_code(u32 seg_address, u32 seg_length)
        dst_header->entry_point = NV_WB_RUN_ADDRESS;
        dst_header->code_length = length;
 
-       if (is_encrypted) {
-               printf("!!!! Encryption is not supported !!!!\n");
-               dst_header->length_insecure = 0;
-               err = -EACCES;
-               goto fail;
-       } else
-               /* copy the wb code directly following dst_header. */
-               memcpy((char *)(dst_header+1), (char *)wb_start, length);
+       if (is_encrypted)
+               encrypt_wb_code((u8 *)wb_start, (u8 *)dst_header,
+                               length + sizeof(struct wb_header));
+       else
+               /* copy the wb code directly following dst_header */
+               memcpy((char *)(dst_header + 1), (char *)wb_start, length);
 
        if (is_signed)
-               err = sign_wb_code(seg_address, dst_header->length_insecure,
-                                  use_zero_key);
+               err = sign_wb_code(seg_address, dst_header->length_insecure);
 
 fail:
        if (err)