ARM: tegra: Add LP0 support for ODM production

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>
This commit is contained in:
Ion Agorria
2025-08-01 08:43:41 +03:00
committed by Svyatoslav Ryhel
parent b01f0a7c1d
commit f230bc6cf7
2 changed files with 25 additions and 18 deletions
@@ -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 */
+25 -17
View 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)