Commit d9b1d7e7 authored by Siarhei Siamashka's avatar Siarhei Siamashka Committed by GitHub
Browse files

Merge pull request #99 from ssvb/20170228-smc-workaround

fel: SMC workaround for the Allwinner SoCs with the secure bit set in eFUSE
parents 7128c73a 275827ad
......@@ -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",
......
......@@ -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