Commit 8c45b33e authored by Andre Przywara's avatar Andre Przywara Committed by Siarhei Siamashka
Browse files

fel: SMC workaround to enter "secure boot" FEL mode on some SoCs



If an SoC has the "secure boot" fuse burned, it will enter FEL mode in
non-secure state, so with the SCR.NS bit set. Since in this mode the
secure/non-secure state restrictions are actually observed, we suffer
from several restrictions:
- No access to the SID information (both via memory mapped and "register").
- No access to secure SRAM (SRAM A2 on H3/A64/H5).
- No access to the secure side of the GIC, so it can't be configured to
  be accessible from non-secure world.
- No RMR trigger on ARMv8 cores to bring the core into AArch64.
Those limitations make a board pretty useless for many applications.

However it has been found out that a simple "smc" call will immediately
return from monitor mode, but with the NS bit cleared, so access to all
secure peripherals is suddenly possible.

Add all the necessary support code for doing a runtime check and
activating this workaround. Affected SoCs need to have the "smc"
workaround enabled in their soc_info struct.
Signed-off-by: default avatarAndre Przywara <osp@andrep.de>
["sunxi-fel smc" command changed to automatic detection by Siarhei]
Signed-off-by: default avatarSiarhei Siamashka <siarhei.siamashka@gmail.com>
parent 7128c73a
......@@ -402,6 +402,39 @@ void aw_set_sctlr(feldev_handle *dev, soc_info_t *soc_info,
aw_write_arm_cp_reg(dev, soc_info, 15, 0, 1, 0, 0, sctlr);
}
/*
* Issue a "smc #0" instruction. This brings a SoC booted in "secure boot"
* state from the default non-secure FEL into secure FEL.
* This crashes on devices using "non-secure boot", as the BROM does not
* provide a handler address in MVBAR. So we have a runtime check.
*/
void aw_apply_smc_workaround(feldev_handle *dev)
{
soc_info_t *soc_info = dev->soc_info;
uint32_t val;
uint32_t arm_code[] = {
htole32(0xe1600070), /* smc #0 */
htole32(0xe12fff1e), /* bx lr */
};
/* Return if the SoC does not need this workaround */
if (!soc_info->needs_smc_workaround_if_zero_word_at_addr)
return;
/* This has less overhead than fel_readl_n() and may be good enough */
aw_fel_read(dev, soc_info->needs_smc_workaround_if_zero_word_at_addr,
&val, sizeof(val));
/* Return if the workaround is not needed or has been already applied */
if (val != 0)
return;
pr_info("Applying SMC workaround... ");
aw_fel_write(dev, arm_code, soc_info->scratch_addr, sizeof(arm_code));
aw_fel_execute(dev, soc_info->scratch_addr);
pr_info(" done.\n");
}
/*
* Reconstruct the same MMU translation table as used by the A20 BROM.
* We are basically reverting the changes, introduced in newer SoC
......@@ -1092,6 +1125,9 @@ int main(int argc, char **argv)
*/
handle = feldev_open(busnum, devnum, AW_USB_VENDOR_ID, AW_USB_PRODUCT_ID);
/* Some SoCs need the SMC workaround to enter the secure boot mode */
aw_apply_smc_workaround(handle);
/* Handle command-style arguments, in order of appearance */
while (argc > 1 ) {
int skip = 1;
......
......@@ -72,6 +72,22 @@ typedef struct {
* spare space in SRAM to place the translation table there and specify it as
* the 'mmu_tt_addr' field in the 'soc_sram_info' structure. The 'mmu_tt_addr'
* address must be 16K aligned.
*
* If an SoC has the "secure boot" fuse burned, it will enter FEL mode in
* non-secure state, so with the SCR.NS bit set. Since in this mode the
* secure/non-secure state restrictions are actually observed, we suffer
* from several restrictions:
* - No access to the SID information (both via memory mapped and "register").
* - No access to secure SRAM (SRAM A2 on H3/A64/H5).
* - No access to the secure side of the GIC, so it can't be configured to
* be accessible from non-secure world.
* - No RMR trigger on ARMv8 cores to bring the core into AArch64.
* However it has been found out that a simple "smc" call will immediately
* return from monitor mode, but with the NS bit cleared, so access to all
* secure peripherals is suddenly possible.
* The 'needs_smc_workaround_if_zero_word_at_addr' field can be used to
* have a check for this condition (reading from restricted addresses
* typically returns zero) and then activate the SMC workaround if needed.
*/
typedef struct {
uint32_t soc_id; /* ID of the SoC */
......@@ -86,6 +102,8 @@ typedef struct {
uint32_t sid_offset; /* offset for SID_KEY[0-3], "root key" */
uint32_t rvbar_reg; /* MMIO address of RVBARADDR0_L register */
bool sid_fix; /* Use SID workaround (read via register) */
/* Use SMC workaround (enter secure mode) if can't read from this address */
uint32_t needs_smc_workaround_if_zero_word_at_addr;
sram_swap_buffers *swap_buffers;
} soc_info_t;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment