@@ -358,6 +358,14 @@ static uint32_t fel_to_spl_thunk[] = {
358358 #include "thunks/fel-to-spl-thunk.h"
359359};
360360
361+ static uint32_t fel_to_secure_svc_spl_thunk [] = {
362+ #include "thunks/fel-to-secure-svc-spl-thunk.h"
363+ };
364+
365+ static uint32_t fel_to_secure_svc_return_thunk [] = {
366+ #include "thunks/fel-to-secure-svc-return-thunk.h"
367+ };
368+
361369#define DRAM_BASE 0x40000000
362370#define DRAM_SIZE 0x80000000
363371
@@ -415,6 +423,8 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val)
415423 fel_writel_n (dev , addr , & val , 1 );
416424}
417425
426+ static void aw_apply_smc_workaround (feldev_handle * dev );
427+
418428void aw_fel_print_sid (feldev_handle * dev , bool force_workaround )
419429{
420430 uint32_t key [4 ];
@@ -426,6 +436,8 @@ void aw_fel_print_sid(feldev_handle *dev, bool force_workaround)
426436 return ;
427437 }
428438
439+ aw_apply_smc_workaround (dev );
440+
429441 if (soc_info -> sid_fix || force_workaround ) {
430442 pr_info ("Read SID key via registers, base = 0x%08X\n" ,
431443 soc_info -> sid_base );
@@ -451,6 +463,8 @@ void aw_fel_dump_sid(feldev_handle *dev)
451463 return ;
452464 }
453465
466+ aw_apply_smc_workaround (dev );
467+
454468 for (const sid_section * s = soc_info -> sid_sections ; s -> name ; s ++ ) {
455469 uint32_t count = s -> size_bits / 32 ;
456470
@@ -564,6 +578,29 @@ void aw_set_sctlr(feldev_handle *dev, soc_info_t *soc_info,
564578 aw_write_arm_cp_reg (dev , soc_info , 15 , 0 , 1 , 0 , 0 , sctlr );
565579}
566580
581+ static bool aw_fel_needs_smc_workaround (feldev_handle * dev )
582+ {
583+ soc_info_t * soc_info = dev -> soc_info ;
584+ uint32_t val ;
585+
586+ if (soc_info -> secure_boot_fuse_addr ) {
587+ aw_fel_read (dev , soc_info -> secure_boot_fuse_addr ,
588+ & val , sizeof (val ));
589+ if (!(le32toh (val ) & soc_info -> secure_boot_fuse_mask ))
590+ return false;
591+
592+ if (!soc_info -> needs_smc_workaround_if_zero_word_at_addr )
593+ return true;
594+ }
595+
596+ if (!soc_info -> needs_smc_workaround_if_zero_word_at_addr )
597+ return false;
598+ aw_fel_read (dev , soc_info -> needs_smc_workaround_if_zero_word_at_addr ,
599+ & val , sizeof (val ));
600+
601+ return le32toh (val ) == 0 ;
602+ }
603+
567604static void aw_fel_execute_raw_thunk (feldev_handle * dev ,
568605 const uint32_t * thunk ,
569606 size_t thunk_size )
@@ -622,36 +659,49 @@ static void aw_fel_execute_thunk(feldev_handle *dev,
622659}
623660
624661/*
625- * Issue a "smc #0" instruction . This brings a SoC booted in "secure boot"
626- * state from the default non-secure FEL into secure FEL .
662+ * Apply the "smc #0" workaround . This moves a secure-boot FEL session from
663+ * the default non-secure state into secure state .
627664 * This crashes on devices using "non-secure boot", as the BROM does not
628665 * provide a handler address in MVBAR. So we have a runtime check.
666+ * Some newer SoCs need to perform the SMC and return to FEL via a thunk,
667+ * which handles the monitor-to-SVC transition details.
629668 */
630- void aw_apply_smc_workaround (feldev_handle * dev )
669+ static void aw_apply_smc_workaround (feldev_handle * dev )
631670{
632671 soc_info_t * soc_info = dev -> soc_info ;
633- uint32_t val ;
634- uint32_t arm_code [] = {
635- htole32 (0xe1600070 ), /* smc #0 */
636- htole32 (0xe12fff1e ), /* bx lr */
637- };
672+ static bool applied ;
638673
639- /* Return if the SoC does not need this workaround */
640- if (! soc_info -> needs_smc_workaround_if_zero_word_at_addr )
674+ /* Return if the workaround is not needed or has been already applied */
675+ if (applied || ! aw_fel_needs_smc_workaround ( dev ) )
641676 return ;
642677
643- /* This has less overhead than fel_readl_n() and may be good enough */
644- aw_fel_read (dev , soc_info -> needs_smc_workaround_if_zero_word_at_addr ,
645- & val , sizeof (val ));
678+ if (soc_info -> smc_workaround == SMC_WORKAROUND_SECURE_SVC_THUNK ) {
679+ uint32_t arm_code [] = {
680+ htole32 (0xe12fff1e ), /* bx lr */
681+ };
646682
647- /* Return if the workaround is not needed or has been already applied */
648- if (val != 0 )
649- return ;
683+ pr_info ("Applying SMC workaround via secure-SVC return thunk... " );
684+ aw_fel_write (dev , arm_code , soc_info -> spl_addr ,
685+ sizeof (arm_code ));
686+ aw_fel_execute_thunk (dev , fel_to_secure_svc_return_thunk ,
687+ sizeof (fel_to_secure_svc_return_thunk ),
688+ soc_info -> spl_addr ,
689+ soc_info -> swap_buffers );
690+ pr_info (" done.\n" );
691+ } else {
692+ uint32_t arm_code [] = {
693+ htole32 (0xe1600070 ), /* smc #0 */
694+ htole32 (0xe12fff1e ), /* bx lr */
695+ };
650696
651- pr_info ("Applying SMC workaround... " );
652- aw_fel_write (dev , arm_code , soc_info -> scratch_addr , sizeof (arm_code ));
653- aw_fel_execute (dev , soc_info -> scratch_addr );
654- pr_info (" done.\n" );
697+ pr_info ("Applying SMC workaround... " );
698+ aw_fel_write (dev , arm_code , soc_info -> scratch_addr ,
699+ sizeof (arm_code ));
700+ aw_fel_execute (dev , soc_info -> scratch_addr );
701+ pr_info (" done.\n" );
702+ }
703+
704+ applied = true;
655705}
656706
657707/*
@@ -814,14 +864,17 @@ void aw_restore_and_enable_mmu(feldev_handle *dev,
814864/* Minimum offset of the main U-Boot image within u-boot-sunxi-with-spl.bin. */
815865#define SPL_MIN_OFFSET 0x8000
816866
817- uint32_t aw_fel_write_and_execute_spl (feldev_handle * dev , uint8_t * buf , size_t len )
867+ static uint32_t aw_fel_write_and_execute_spl (feldev_handle * dev , uint8_t * buf ,
868+ size_t len )
818869{
819870 soc_info_t * soc_info = dev -> soc_info ;
820871 sram_swap_buffers * swap_buffers ;
821872 char header_signature [9 ] = { 0 };
822873 size_t i ;
823874 uint32_t sp , sp_irq ;
824875 uint32_t spl_checksum , spl_len , spl_len_limit ;
876+ const uint32_t * thunk = fel_to_spl_thunk ;
877+ size_t thunk_code_size = sizeof (fel_to_spl_thunk );
825878 uint32_t * buf32 = (uint32_t * )buf ;
826879 uint32_t cur_addr = soc_info -> spl_addr ;
827880 uint32_t * tt = NULL ;
@@ -913,8 +966,15 @@ uint32_t aw_fel_write_and_execute_spl(feldev_handle *dev, uint8_t *buf, size_t l
913966 if (len > 0 )
914967 aw_fel_write (dev , buf , cur_addr , len );
915968
969+ if (soc_info -> smc_workaround == SMC_WORKAROUND_SECURE_SVC_THUNK &&
970+ aw_fel_needs_smc_workaround (dev )) {
971+ thunk = fel_to_secure_svc_spl_thunk ;
972+ thunk_code_size = sizeof (fel_to_secure_svc_spl_thunk );
973+ pr_info ("SPL: enabling secure-SVC transition workaround\n" );
974+ }
975+
916976 pr_info ("=> Executing the SPL..." );
917- aw_fel_execute_thunk (dev , fel_to_spl_thunk , sizeof ( fel_to_spl_thunk ) ,
977+ aw_fel_execute_thunk (dev , thunk , thunk_code_size ,
918978 soc_info -> spl_addr , swap_buffers );
919979 pr_info (" done.\n" );
920980
@@ -1414,8 +1474,15 @@ int main(int argc, char **argv)
14141474 */
14151475 handle = feldev_open (busnum , devnum , AW_USB_VENDOR_ID , AW_USB_PRODUCT_ID );
14161476
1417- /* Some SoCs need the SMC workaround to enter the secure boot mode */
1418- aw_apply_smc_workaround (handle );
1477+ /*
1478+ * Some SoCs need the SMC workaround to enter secure state. On H616,
1479+ * SMC returns through monitor mode, and the secure-SVC transition is
1480+ * only reliable when it is part of the operation that needs secure
1481+ * state. Keep the global workaround for older SoCs, and let the SID
1482+ * and SPL paths request the H616 thunk at their point of use.
1483+ */
1484+ if (handle -> soc_info -> smc_workaround != SMC_WORKAROUND_SECURE_SVC_THUNK )
1485+ aw_apply_smc_workaround (handle );
14191486
14201487 /* Handle command-style arguments, in order of appearance */
14211488 while (argc > 1 ) {
0 commit comments