Merge pull request #99 from ssvb/20170228-smc-workaround
fel: SMC workaround for the Allwinner SoCs with the secure bit set in eFUSE
This commit is contained in:
commit
d9b1d7e7df
36
fel.c
36
fel.c
@ -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;
|
||||
|
||||
@ -148,6 +148,8 @@ soc_info_t soc_info_table[] = {
|
||||
.sid_base = 0x01C14000,
|
||||
.sid_offset = 0x200,
|
||||
.rvbar_reg = 0x017000A0,
|
||||
/* Check L.NOP in the OpenRISC reset vector */
|
||||
.needs_smc_workaround_if_zero_word_at_addr = 0x40004,
|
||||
},{
|
||||
.soc_id = 0x1639, /* Allwinner A80 */
|
||||
.name = "A80",
|
||||
@ -175,6 +177,8 @@ soc_info_t soc_info_table[] = {
|
||||
.sid_base = 0x01C14000,
|
||||
.sid_offset = 0x200,
|
||||
.sid_fix = true,
|
||||
/* Check L.NOP in the OpenRISC reset vector */
|
||||
.needs_smc_workaround_if_zero_word_at_addr = 0x40004,
|
||||
},{
|
||||
.soc_id = 0x1681, /* Allwinner V3s */
|
||||
.name = "V3s",
|
||||
@ -193,6 +197,8 @@ soc_info_t soc_info_table[] = {
|
||||
.sid_base = 0x01C14000,
|
||||
.sid_offset = 0x200,
|
||||
.rvbar_reg = 0x017000A0,
|
||||
/* Check L.NOP in the OpenRISC reset vector */
|
||||
.needs_smc_workaround_if_zero_word_at_addr = 0x40004,
|
||||
},{
|
||||
.soc_id = 0x1701, /* Allwinner R40 */
|
||||
.name = "R40",
|
||||
|
||||
18
soc_info.h
18
soc_info.h
@ -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;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user