Merge pull request #1131 from jeenu-arm/gic-migrate
Migrate upstream platforms to using interrupt properties
diff --git a/bl32/sp_min/aarch32/entrypoint.S b/bl32/sp_min/aarch32/entrypoint.S
index d868c53..cd9fe5c 100644
--- a/bl32/sp_min/aarch32/entrypoint.S
+++ b/bl32/sp_min/aarch32/entrypoint.S
@@ -162,6 +162,15 @@
stcopr r0, SCR
isb
+ /*
+ * Set PMCR.DP to 1 to prohibit cycle counting whilst in Secure Mode.
+ * Also, the PMCR.LC field has an architecturally UNKNOWN value on reset
+ * and so set to 1 as ARM has deprecated use of PMCR.LC=0.
+ */
+ ldcopr r0, PMCR
+ orr r0, r0, #(PMCR_LC_BIT | PMCR_DP_BIT)
+ stcopr r0, PMCR
+
ldr r0, [r2, #SMC_CTX_GPREG_R0] /* smc_fid */
/* Check whether an SMC64 is issued */
tst r0, #(FUNCID_CC_MASK << FUNCID_CC_SHIFT)
@@ -210,6 +219,15 @@
stcopr r0, SCR
isb
+ /*
+ * Set PMCR.DP to 1 to prohibit cycle counting whilst in Secure Mode.
+ * Also, the PMCR.LC field has an architecturally UNKNOWN value on reset
+ * and so set to 1 as ARM has deprecated use of PMCR.LC=0.
+ */
+ ldcopr r0, PMCR
+ orr r0, r0, #(PMCR_LC_BIT | PMCR_DP_BIT)
+ stcopr r0, PMCR
+
push {r2, r3}
bl sp_min_fiq
pop {r0, r3}
diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst
index aeb883a..0790597 100644
--- a/docs/firmware-design.rst
+++ b/docs/firmware-design.rst
@@ -886,10 +886,10 @@
TODO: Provide design walkthrough of PSCI implementation.
-The PSCI v1.0 specification categorizes APIs as optional and mandatory. All the
-mandatory APIs in PSCI v1.0 and all the APIs in PSCI v0.2 draft specification
+The PSCI v1.1 specification categorizes APIs as optional and mandatory. All the
+mandatory APIs in PSCI v1.1, PSCI v1.0 and in PSCI v0.2 draft specification
`Power State Coordination Interface PDD`_ are implemented. The table lists
-the PSCI v1.0 APIs and their support in generic code.
+the PSCI v1.1 APIs and their support in generic code.
An API implementation might have a dependency on platform code e.g. CPU\_SUSPEND
requires the platform to export a part of the implementation. Hence the level
@@ -898,9 +898,9 @@
required support.
+-----------------------------+-------------+-------------------------------+
-| PSCI v1.0 API | Supported | Comments |
+| PSCI v1.1 API | Supported | Comments |
+=============================+=============+===============================+
-| ``PSCI_VERSION`` | Yes | The version returned is 1.0 |
+| ``PSCI_VERSION`` | Yes | The version returned is 1.1 |
+-----------------------------+-------------+-------------------------------+
| ``CPU_SUSPEND`` | Yes\* | |
+-----------------------------+-------------+-------------------------------+
@@ -936,6 +936,12 @@
+-----------------------------+-------------+-------------------------------+
| ``PSCI_STAT_COUNT`` | Yes\* | |
+-----------------------------+-------------+-------------------------------+
+| ``SYSTEM_RESET2`` | Yes\* | |
++-----------------------------+-------------+-------------------------------+
+| ``MEM_PROTECT`` | Yes\* | |
++-----------------------------+-------------+-------------------------------+
+| ``MEM_PROTECT_CHECK_RANGE`` | Yes\* | |
++-----------------------------+-------------+-------------------------------+
\*Note : These PSCI APIs require platform power management hooks to be
registered with the generic PSCI code to be supported.
@@ -2475,7 +2481,7 @@
References
----------
-.. [#] Trusted Board Boot Requirements CLIENT PDD (ARM DEN 0006B-5). Available
+.. [#] Trusted Board Boot Requirements CLIENT PDD (ARM DEN0006C-1). Available
under NDA through your ARM account representative.
.. [#] `Power State Coordination Interface PDD`_
.. [#] `SMC Calling Convention PDD`_
diff --git a/docs/platform-migration-guide.rst b/docs/platform-migration-guide.rst
index 638033e..ca75546 100644
--- a/docs/platform-migration-guide.rst
+++ b/docs/platform-migration-guide.rst
@@ -158,6 +158,17 @@
int (*validate_ns_entrypoint)(unsigned long ns_entrypoint);
void (*get_sys_suspend_power_state)(
psci_power_state_t *req_state);
+ int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state,
+ int pwrlvl);
+ int (*translate_power_state_by_mpidr)(u_register_t mpidr,
+ unsigned int power_state,
+ psci_power_state_t *output_state);
+ int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
+ int (*mem_protect_chk)(uintptr_t base, u_register_t length);
+ int (*read_mem_protect)(int *val);
+ int (*write_mem_protect)(int val);
+ int (*system_reset2)(int is_vendor,
+ int reset_type, u_register_t cookie);
} plat_psci_ops_t;
The description of these handlers can be found in the `Porting Guide <porting-guide.rst#user-content-function--plat_setup_psci_ops-mandatory>`__.
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index c0b173c..6352bb9 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -2271,6 +2271,44 @@
Implementations are not expected to handle ``power_levels`` greater than
``PLAT_MAX_PWR_LVL``.
+plat\_psci\_ops.system\_reset2()
+................................
+
+This is an optional function. If implemented this function is
+called during the ``SYSTEM_RESET2`` call to perform a reset
+based on the first parameter ``reset_type`` as specified in
+`PSCI`_. The parameter ``cookie`` can be used to pass additional
+reset information. If the ``reset_type`` is not supported, the
+function must return ``PSCI_E_NOT_SUPPORTED``. For architectural
+resets, all failures must return ``PSCI_E_INVALID_PARAMETERS``
+and vendor reset can return other PSCI error codes as defined
+in `PSCI`_. On success this function will not return.
+
+plat\_psci\_ops.write\_mem\_protect()
+....................................
+
+This is an optional function. If implemented it enables or disables the
+``MEM_PROTECT`` functionality based on the value of ``val``.
+A non-zero value enables ``MEM_PROTECT`` and a value of zero
+disables it. Upon encountering failures it must return a negative value
+and on success it must return 0.
+
+plat\_psci\_ops.read\_mem\_protect()
+.....................................
+
+This is an optional function. If implemented it returns the current
+state of ``MEM_PROTECT`` via the ``val`` parameter. Upon encountering
+failures it must return a negative value and on success it must
+return 0.
+
+plat\_psci\_ops.mem\_protect\_chk()
+...................................
+
+This is an optional function. If implemented it checks if a memory
+region defined by a base address ``base`` and with a size of ``length``
+bytes is protected by ``MEM_PROTECT``. If the region is protected
+then it must return 0, otherwise it must return a negative number.
+
Interrupt Management framework (in BL31)
----------------------------------------
diff --git a/docs/user-guide.rst b/docs/user-guide.rst
index 80273be..28483f2 100644
--- a/docs/user-guide.rst
+++ b/docs/user-guide.rst
@@ -1392,10 +1392,10 @@
The latest version of the AArch64 build of ARM Trusted Firmware has been tested
on the following ARM FVPs (64-bit host machine only).
-NOTE: Unless otherwise stated, the model version is Version 11.0 Build 11.0.34.
+NOTE: Unless otherwise stated, the model version is Version 11.1 Build 11.1.22.
- ``Foundation_Platform``
-- ``FVP_Base_AEMv8A-AEMv8A`` (Version 8.5, Build 0.8.8502)
+- ``FVP_Base_AEMv8A-AEMv8A`` (Version 8.7, Build 0.8.8702)
- ``FVP_Base_Cortex-A35x4``
- ``FVP_Base_Cortex-A53x4``
- ``FVP_Base_Cortex-A57x4-A53x4``
@@ -1408,7 +1408,7 @@
The latest version of the AArch32 build of ARM Trusted Firmware has been tested
on the following ARM FVPs (64-bit host machine only).
-- ``FVP_Base_AEMv8A-AEMv8A`` (Version 8.5, Build 0.8.8502)
+- ``FVP_Base_AEMv8A-AEMv8A`` (Version 8.7, Build 0.8.8702)
- ``FVP_Base_Cortex-A32x4``
NOTE: The build numbers quoted above are those reported by launching the FVP
@@ -1427,7 +1427,7 @@
CADI-compliant debugger (for example, ARM DS-5) can connect to and control its
execution.
-NOTE: With FVP model Version 11.0 Build 11.0.34 and Version 8.5 Build 0.8.5202
+NOTE: Since FVP model Version 11.0 Build 11.0.34 and Version 8.5 Build 0.8.5202
the internal synchronisation timings changed compared to older versions of the
models. The models can be launched with ``-Q 100`` option if they are required
to match the run time characteristics of the older versions.
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index e2c5f24..3846bec 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -351,6 +351,8 @@
#define PMCR_N_SHIFT 11
#define PMCR_N_MASK 0x1f
#define PMCR_N_BITS (PMCR_N_MASK << PMCR_N_SHIFT)
+#define PMCR_LC_BIT (1 << 6)
+#define PMCR_DP_BIT (1 << 5)
/*******************************************************************************
* Definitions of register offsets, fields and macros for CPU system
diff --git a/include/lib/aarch32/smcc_helpers.h b/include/lib/aarch32/smcc_helpers.h
index 1bc8438..53f1aa4 100644
--- a/include/lib/aarch32/smcc_helpers.h
+++ b/include/lib/aarch32/smcc_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -21,7 +21,8 @@
#define SMC_CTX_SP_MON 0x7C
#define SMC_CTX_LR_MON 0x80
#define SMC_CTX_SCR 0x84
-#define SMC_CTX_SIZE 0x88
+#define SMC_CTX_PMCR 0x88
+#define SMC_CTX_SIZE 0x8C
#ifndef __ASSEMBLY__
#include <cassert.h>
@@ -73,6 +74,7 @@
u_register_t sp_mon;
u_register_t lr_mon;
u_register_t scr;
+ u_register_t pmcr;
} smc_ctx_t;
/*
diff --git a/include/lib/aarch32/smcc_macros.S b/include/lib/aarch32/smcc_macros.S
index 7edf410..cf26175 100644
--- a/include/lib/aarch32/smcc_macros.S
+++ b/include/lib/aarch32/smcc_macros.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,6 +13,8 @@
* spsr, lr, sp registers and the `scr` register to the SMC context on entry
* due a SMC call. The `lr` of the current mode (monitor) is expected to be
* already saved. The `sp` must point to the `smc_ctx_t` to save to.
+ * Additionally, also save the 'pmcr' register as this is updated whilst
+ * executing in the secure world.
*/
.macro smcc_save_gp_mode_regs
/* Save r0 - r12 in the SMC context */
@@ -46,6 +48,8 @@
/* lr_mon is already saved by caller */
ldcopr r4, SCR
str r4, [sp, #SMC_CTX_SCR]
+ ldcopr r4, PMCR
+ str r4, [sp, #SMC_CTX_PMCR]
.endm
/*
@@ -70,6 +74,12 @@
stcopr r1, SCR
isb
+ /*
+ * Restore the PMCR register.
+ */
+ ldr r1, [r0, #SMC_CTX_PMCR]
+ stcopr r1, PMCR
+
/* Restore the banked registers including the current SPSR */
add r1, r0, #SMC_CTX_SP_USR
ldm r1!, {r4-r12}
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index bbe1e4f..997e3a2 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -504,9 +504,14 @@
#define CNTACR_RWPT_SHIFT U(0x5)
/* PMCR_EL0 definitions */
+#define PMCR_EL0_RESET_VAL U(0x0)
#define PMCR_EL0_N_SHIFT U(11)
#define PMCR_EL0_N_MASK U(0x1f)
#define PMCR_EL0_N_BITS (PMCR_EL0_N_MASK << PMCR_EL0_N_SHIFT)
+#define PMCR_EL0_LC_BIT (U(1) << 6)
+#define PMCR_EL0_DP_BIT (U(1) << 5)
+#define PMCR_EL0_X_BIT (U(1) << 4)
+#define PMCR_EL0_D_BIT (U(1) << 3)
/*******************************************************************************
* Definitions of MAIR encodings for device and normal memory
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index 03110fd..9c022ab 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -31,11 +31,8 @@
__asm__ volatile ("msr " #_reg_name ", %0" : : "r" (v)); \
}
-#define _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _reg_name) \
-static inline void write_ ## _name(const uint64_t v) \
-{ \
- __asm__ volatile ("msr " #_reg_name ", %0" : : "i" (v)); \
-}
+#define SYSREG_WRITE_CONST(reg_name, v) \
+ __asm__ volatile ("msr " #reg_name ", %0" : : "i" (v))
/* Define read function for system register */
#define DEFINE_SYSREG_READ_FUNC(_name) \
@@ -59,11 +56,6 @@
#define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name) \
_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
-/* Define write function for special system registers */
-#define DEFINE_SYSREG_WRITE_CONST_FUNC(_name) \
- _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _name)
-
-
/**********************************************************************
* Macros to create inline functions for system instructions
*********************************************************************/
@@ -171,15 +163,17 @@
void dcsw_op_louis(u_register_t op_type);
void dcsw_op_all(u_register_t op_type);
+void disable_mmu_el1(void);
void disable_mmu_el3(void);
+void disable_mmu_icache_el1(void);
void disable_mmu_icache_el3(void);
/*******************************************************************************
* Misc. accessor prototypes
******************************************************************************/
-DEFINE_SYSREG_WRITE_CONST_FUNC(daifset)
-DEFINE_SYSREG_WRITE_CONST_FUNC(daifclr)
+#define write_daifclr(val) SYSREG_WRITE_CONST(daifclr, val)
+#define write_daifset(val) SYSREG_WRITE_CONST(daifset, val)
DEFINE_SYSREG_READ_FUNC(par_el1)
DEFINE_SYSREG_READ_FUNC(id_pfr1_el1)
@@ -308,7 +302,7 @@
DEFINE_SYSREG_RW_FUNCS(mdcr_el2)
DEFINE_SYSREG_RW_FUNCS(hstr_el2)
DEFINE_SYSREG_RW_FUNCS(cnthp_ctl_el2)
-DEFINE_SYSREG_READ_FUNC(pmcr_el0)
+DEFINE_SYSREG_RW_FUNCS(pmcr_el0)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2)
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index dcbf1c9..a89468d 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -87,22 +87,23 @@
#define CTX_AFSR1_EL1 U(0x98)
#define CTX_CONTEXTIDR_EL1 U(0xa0)
#define CTX_VBAR_EL1 U(0xa8)
+#define CTX_PMCR_EL0 U(0xb0)
/*
* If the platform is AArch64-only, there is no need to save and restore these
* AArch32 registers.
*/
#if CTX_INCLUDE_AARCH32_REGS
-#define CTX_SPSR_ABT U(0xb0)
-#define CTX_SPSR_UND U(0xb8)
-#define CTX_SPSR_IRQ U(0xc0)
-#define CTX_SPSR_FIQ U(0xc8)
-#define CTX_DACR32_EL2 U(0xd0)
-#define CTX_IFSR32_EL2 U(0xd8)
-#define CTX_FP_FPEXC32_EL2 U(0xe0)
-#define CTX_TIMER_SYSREGS_OFF U(0xf0) /* Align to the next 16 byte boundary */
+#define CTX_SPSR_ABT U(0xc0) /* Align to the next 16 byte boundary */
+#define CTX_SPSR_UND U(0xc8)
+#define CTX_SPSR_IRQ U(0xd0)
+#define CTX_SPSR_FIQ U(0xd8)
+#define CTX_DACR32_EL2 U(0xe0)
+#define CTX_IFSR32_EL2 U(0xe8)
+#define CTX_FP_FPEXC32_EL2 U(0xf0)
+#define CTX_TIMER_SYSREGS_OFF U(0x100) /* Align to the next 16 byte boundary */
#else
-#define CTX_TIMER_SYSREGS_OFF U(0xb0)
+#define CTX_TIMER_SYSREGS_OFF U(0xc0) /* Align to the next 16 byte boundary */
#endif /* __CTX_INCLUDE_AARCH32_REGS__ */
/*
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index 0b44ab2..06434f9 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -65,6 +65,8 @@
#define PSCI_STAT_RESIDENCY_AARCH64 U(0xc4000010)
#define PSCI_STAT_COUNT_AARCH32 U(0x84000011)
#define PSCI_STAT_COUNT_AARCH64 U(0xc4000011)
+#define PSCI_SYSTEM_RESET2_AARCH32 U(0x84000012)
+#define PSCI_SYSTEM_RESET2_AARCH64 U(0xc4000012)
#define PSCI_MEM_PROTECT U(0x84000013)
#define PSCI_MEM_CHK_RANGE_AARCH32 U(0x84000014)
#define PSCI_MEM_CHK_RANGE_AARCH64 U(0xc4000014)
@@ -149,7 +151,7 @@
* PSCI version
******************************************************************************/
#define PSCI_MAJOR_VER (U(1) << 16)
-#define PSCI_MINOR_VER U(0x0)
+#define PSCI_MINOR_VER U(0x1)
/*******************************************************************************
* PSCI error codes
@@ -167,6 +169,14 @@
#define PSCI_INVALID_MPIDR ~((u_register_t)0)
+/*
+ * SYSTEM_RESET2 macros
+ */
+#define PSCI_RESET2_TYPE_VENDOR_SHIFT 31
+#define PSCI_RESET2_TYPE_VENDOR (1U << PSCI_RESET2_TYPE_VENDOR_SHIFT)
+#define PSCI_RESET2_TYPE_ARCH (0U << PSCI_RESET2_TYPE_VENDOR_SHIFT)
+#define PSCI_RESET2_SYSTEM_WARM_RESET (PSCI_RESET2_TYPE_ARCH | 0)
+
#ifndef __ASSEMBLY__
#include <stdint.h>
@@ -294,6 +304,8 @@
int (*mem_protect_chk)(uintptr_t base, u_register_t length);
int (*read_mem_protect)(int *val);
int (*write_mem_protect)(int val);
+ int (*system_reset2)(int is_vendor,
+ int reset_type, u_register_t cookie);
} plat_psci_ops_t;
/*******************************************************************************
diff --git a/include/lib/xlat_tables/xlat_tables_defs.h b/include/lib/xlat_tables/xlat_tables_defs.h
index 7cb9d37..3a7f245 100644
--- a/include/lib/xlat_tables/xlat_tables_defs.h
+++ b/include/lib/xlat_tables/xlat_tables_defs.h
@@ -24,9 +24,19 @@
#define FOUR_KB_INDEX(x) ((x) >> FOUR_KB_SHIFT)
#define INVALID_DESC U(0x0)
+/*
+ * A block descriptor points to a region of memory bigger than the granule size
+ * (e.g. a 2MB region when the granule size is 4KB).
+ */
#define BLOCK_DESC U(0x1) /* Table levels 0-2 */
+/* A table descriptor points to the next level of translation table. */
#define TABLE_DESC U(0x3) /* Table levels 0-2 */
+/*
+ * A page descriptor points to a page, i.e. a memory region whose size is the
+ * translation granule size (e.g. 4KB).
+ */
#define PAGE_DESC U(0x3) /* Table level 3 */
+
#define DESC_MASK U(0x3)
#define FIRST_LEVEL_DESC_N ONE_GB_SHIFT
@@ -84,10 +94,22 @@
#define XLAT_BLOCK_MASK(level) (XLAT_BLOCK_SIZE(level) - 1)
/* Mask to get the address bits common to a block of a certain table level*/
#define XLAT_ADDR_MASK(level) (~XLAT_BLOCK_MASK(level))
+/*
+ * Extract from the given virtual address the index into the given lookup level.
+ * This macro assumes the system is using the 4KB translation granule.
+ */
+#define XLAT_TABLE_IDX(virtual_addr, level) \
+ (((virtual_addr) >> XLAT_ADDR_SHIFT(level)) & ULL(0x1FF))
/*
- * AP[1] bit is ignored by hardware and is
- * treated as if it is One in EL2/EL3
+ * The ARMv8 translation table descriptor format defines AP[2:1] as the Access
+ * Permissions bits, and does not define an AP[0] bit.
+ *
+ * AP[1] is valid only for a stage 1 translation that supports two VA ranges
+ * (i.e. in the ARMv8A.0 architecture, that is the S-EL1&0 regime).
+ *
+ * AP[1] is RES0 for stage 1 translations that support only one VA range
+ * (e.g. EL3).
*/
#define AP2_SHIFT U(0x7)
#define AP2_RO U(0x1)
@@ -122,6 +144,28 @@
#define ATTR_INDEX_GET(attr) (((attr) >> 2) & ATTR_INDEX_MASK)
/*
+ * Shift values for the attributes fields in a block or page descriptor.
+ * See section D4.3.3 in the ARMv8-A ARM (issue B.a).
+ */
+
+/* Memory attributes index field, AttrIndx[2:0]. */
+#define ATTR_INDEX_SHIFT 2
+/* Non-secure bit, NS. */
+#define NS_SHIFT 5
+/* Shareability field, SH[1:0] */
+#define SHAREABILITY_SHIFT 8
+/* The Access Flag, AF. */
+#define ACCESS_FLAG_SHIFT 10
+/* The not global bit, nG. */
+#define NOT_GLOBAL_SHIFT 11
+/* Contiguous hint bit. */
+#define CONT_HINT_SHIFT 52
+/* Execute-never bits, XN. */
+#define PXN_SHIFT 53
+#define XN_SHIFT 54
+#define UXN_SHIFT XN_SHIFT
+
+/*
* Flags to override default values used to program system registers while
* enabling the MMU.
*/
diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h
index 1a55fba..73a9c53 100644
--- a/include/lib/xlat_tables/xlat_tables_v2.h
+++ b/include/lib/xlat_tables/xlat_tables_v2.h
@@ -251,5 +251,66 @@
#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+/*
+ * Change the memory attributes of the memory region starting from a given
+ * virtual address in a set of translation tables.
+ *
+ * This function can only be used after the translation tables have been
+ * initialized.
+ *
+ * The base address of the memory region must be aligned on a page boundary.
+ * The size of this memory region must be a multiple of a page size.
+ * The memory region must be already mapped by the given translation tables
+ * and it must be mapped at the granularity of a page.
+ *
+ * Return 0 on success, a negative value on error.
+ *
+ * In case of error, the memory attributes remain unchanged and this function
+ * has no effect.
+ *
+ * ctx
+ * Translation context to work on.
+ * base_va:
+ * Virtual address of the 1st page to change the attributes of.
+ * size:
+ * Size in bytes of the memory region.
+ * attr:
+ * New attributes of the page tables. The attributes that can be changed are
+ * data access (MT_RO/MT_RW), instruction access (MT_EXECUTE_NEVER/MT_EXECUTE)
+ * and user/privileged access (MT_USER/MT_PRIVILEGED) in the case of contexts
+ * that are used in the EL1&0 translation regime. Also, note that this
+ * function doesn't allow to remap a region as RW and executable, or to remap
+ * device memory as executable.
+ *
+ * NOTE: The caller of this function must be able to write to the translation
+ * tables, i.e. the memory where they are stored must be mapped with read-write
+ * access permissions. This function assumes it is the case. If this is not
+ * the case then this function might trigger a data abort exception.
+ *
+ * NOTE2: The caller is responsible for making sure that the targeted
+ * translation tables are not modified by any other code while this function is
+ * executing.
+ */
+int change_mem_attributes(xlat_ctx_t *ctx, uintptr_t base_va, size_t size,
+ mmap_attr_t attr);
+
+/*
+ * Query the memory attributes of a memory page in a set of translation tables.
+ *
+ * Return 0 on success, a negative error code on error.
+ * On success, the attributes are stored into *attributes.
+ *
+ * ctx
+ * Translation context to work on.
+ * base_va
+ * Virtual address of the page to get the attributes of.
+ * There are no alignment restrictions on this address. The attributes of the
+ * memory page it lies within are returned.
+ * attributes
+ * Output parameter where to store the attributes of the targeted memory page.
+ */
+int get_mem_attributes(const xlat_ctx_t *ctx, uintptr_t base_va,
+ mmap_attr_t *attributes);
+
#endif /*__ASSEMBLY__*/
#endif /* __XLAT_TABLES_V2_H__ */
diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
index 0ebdc93..28228c4 100644
--- a/include/lib/xlat_tables/xlat_tables_v2_helpers.h
+++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
@@ -162,8 +162,12 @@
.initialized = 0, \
}
+#if AARCH64
-/* This IMAGE_EL macro must not to be used outside the library */
+/*
+ * This IMAGE_EL macro must not to be used outside the library, and it is only
+ * used in AArch64.
+ */
#if IMAGE_BL1 || IMAGE_BL31
# define IMAGE_EL 3
# define IMAGE_XLAT_DEFAULT_REGIME EL3_REGIME
@@ -172,6 +176,17 @@
# define IMAGE_XLAT_DEFAULT_REGIME EL1_EL0_REGIME
#endif
+#else /* if AARCH32 */
+
+/*
+ * The PL1&0 translation regime in AArch32 behaves like the EL1&0 regime in
+ * AArch64 except for the XN bits, but we set and unset them at the same time,
+ * so there's no difference in practice.
+ */
+#define IMAGE_XLAT_DEFAULT_REGIME EL1_EL0_REGIME
+
+#endif /* AARCH64 */
+
#endif /*__ASSEMBLY__*/
#endif /* __XLAT_TABLES_V2_HELPERS_H__ */
diff --git a/lib/aarch64/misc_helpers.S b/lib/aarch64/misc_helpers.S
index 78153bf..9dfe46a 100644
--- a/lib/aarch64/misc_helpers.S
+++ b/lib/aarch64/misc_helpers.S
@@ -18,7 +18,9 @@
.globl zeromem16
.globl memcpy16
+ .globl disable_mmu_el1
.globl disable_mmu_el3
+ .globl disable_mmu_icache_el1
.globl disable_mmu_icache_el3
#if SUPPORT_VFP
@@ -451,11 +453,11 @@
func disable_mmu_el3
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT)
-do_disable_mmu:
+do_disable_mmu_el3:
mrs x0, sctlr_el3
bic x0, x0, x1
msr sctlr_el3, x0
- isb // ensure MMU is off
+ isb /* ensure MMU is off */
dsb sy
ret
endfunc disable_mmu_el3
@@ -463,10 +465,32 @@
func disable_mmu_icache_el3
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
- b do_disable_mmu
+ b do_disable_mmu_el3
endfunc disable_mmu_icache_el3
/* ---------------------------------------------------------------------------
+ * Disable the MMU at EL1
+ * ---------------------------------------------------------------------------
+ */
+
+func disable_mmu_el1
+ mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT)
+do_disable_mmu_el1:
+ mrs x0, sctlr_el1
+ bic x0, x0, x1
+ msr sctlr_el1, x0
+ isb /* ensure MMU is off */
+ dsb sy
+ ret
+endfunc disable_mmu_el1
+
+
+func disable_mmu_icache_el1
+ mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
+ b do_disable_mmu_el1
+endfunc disable_mmu_icache_el1
+
+/* ---------------------------------------------------------------------------
* Enable the use of VFP at EL3
* ---------------------------------------------------------------------------
*/
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 8a6c11b..db16a9f 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -74,6 +74,9 @@
mrs x9, vbar_el1
stp x17, x9, [x0, #CTX_CONTEXTIDR_EL1]
+ mrs x10, pmcr_el0
+ str x10, [x0, #CTX_PMCR_EL0]
+
/* Save AArch32 system registers if the build has instructed so */
#if CTX_INCLUDE_AARCH32_REGS
mrs x11, spsr_abt
@@ -193,6 +196,9 @@
msr contextidr_el1, x17
msr vbar_el1, x9
+ ldr x10, [x0, #CTX_PMCR_EL0]
+ msr pmcr_el0, x10
+
/* Restore AArch32 system registers if the build has instructed so */
#if CTX_INCLUDE_AARCH32_REGS
ldp x11, x12, [x0, #CTX_SPSR_ABT]
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 3d26056..21e86de 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -58,7 +58,7 @@
static void cm_init_context_common(cpu_context_t *ctx, const entry_point_info_t *ep)
{
unsigned int security_state;
- uint32_t scr_el3;
+ uint32_t scr_el3, pmcr_el0;
el3_state_t *state;
gp_regs_t *gp_regs;
unsigned long sctlr_elx;
@@ -164,11 +164,35 @@
/*
* Store the initialised SCTLR_EL1 value in the cpu_context - SCTLR_EL2
- * and other EL2 resgisters are set up by cm_preapre_ns_entry() as they
+ * and other EL2 registers are set up by cm_preapre_ns_entry() as they
* are not part of the stored cpu_context.
*/
write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx);
+ if (security_state == SECURE) {
+ /*
+ * Initialise PMCR_EL0 for secure context only, setting all
+ * fields rather than relying on hw. Some fields are
+ * architecturally UNKNOWN on reset.
+ *
+ * PMCR_EL0.LC: Set to one so that cycle counter overflow, that
+ * is recorded in PMOVSCLR_EL0[31], occurs on the increment
+ * that changes PMCCNTR_EL0[63] from 1 to 0.
+ *
+ * PMCR_EL0.DP: Set to one so that the cycle counter,
+ * PMCCNTR_EL0 does not count when event counting is prohibited.
+ *
+ * PMCR_EL0.X: Set to zero to disable export of events.
+ *
+ * PMCR_EL0.D: Set to zero so that, when enabled, PMCCNTR_EL0
+ * counts on every clock cycle.
+ */
+ pmcr_el0 = ((PMCR_EL0_RESET_VAL | PMCR_EL0_LC_BIT
+ | PMCR_EL0_DP_BIT)
+ & ~(PMCR_EL0_X_BIT | PMCR_EL0_D_BIT));
+ write_ctx_reg(get_sysregs_ctx(ctx), CTX_PMCR_EL0, pmcr_el0);
+ }
+
/* Populate EL3 state so that we've the right context before doing ERET */
state = get_el3state_ctx(ctx);
write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index a5d707e..4105e63 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -414,6 +414,10 @@
case PSCI_MEM_CHK_RANGE_AARCH32:
return psci_mem_chk_range(x1, x2);
+ case PSCI_SYSTEM_RESET2_AARCH32:
+ /* We should never return from psci_system_reset2() */
+ return psci_system_reset2(x1, x2);
+
default:
break;
}
@@ -453,6 +457,9 @@
case PSCI_MEM_CHK_RANGE_AARCH64:
return psci_mem_chk_range(x1, x2);
+ case PSCI_SYSTEM_RESET2_AARCH64:
+ /* We should never return from psci_system_reset2() */
+ return psci_system_reset2(x1, x2);
default:
break;
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index facfacb..504fb9e 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -89,7 +89,9 @@
define_psci_cap(PSCI_NODE_HW_STATE_AARCH64) | \
define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) | \
define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) | \
- define_psci_cap(PSCI_STAT_COUNT_AARCH64))
+ define_psci_cap(PSCI_STAT_COUNT_AARCH64) | \
+ define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64) | \
+ define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64))
/*
* Helper macros to get/set the fields of PSCI per-cpu data.
@@ -258,6 +260,7 @@
/* Private exported functions from psci_system_off.c */
void __dead2 psci_system_off(void);
void __dead2 psci_system_reset(void);
+int psci_system_reset2(uint32_t reset_type, u_register_t cookie);
/* Private exported functions from psci_stat.c */
void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index 5ef49ac..a841dda 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -248,6 +248,8 @@
psci_caps |= define_psci_cap(PSCI_MEM_PROTECT);
if (psci_plat_pm_ops->mem_protect_chk)
psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64);
+ if (psci_plat_pm_ops->system_reset2)
+ psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64);
#if ENABLE_PSCI_STAT
psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
diff --git a/lib/psci/psci_system_off.c b/lib/psci/psci_system_off.c
index ef5d3d1..13e9f4a 100644
--- a/lib/psci/psci_system_off.c
+++ b/lib/psci/psci_system_off.c
@@ -49,3 +49,33 @@
/* This function does not return. We should never get here */
}
+
+int psci_system_reset2(uint32_t reset_type, u_register_t cookie)
+{
+ int is_vendor;
+
+ psci_print_power_domain_map();
+
+ assert(psci_plat_pm_ops->system_reset2);
+
+ is_vendor = (reset_type >> PSCI_RESET2_TYPE_VENDOR_SHIFT) & 1;
+ if (!is_vendor) {
+ /*
+ * Only WARM_RESET is allowed for architectural type resets.
+ */
+ if (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET)
+ return PSCI_E_INVALID_PARAMS;
+ if (psci_plat_pm_ops->write_mem_protect &&
+ psci_plat_pm_ops->write_mem_protect(0) < 0) {
+ return PSCI_E_NOT_SUPPORTED;
+ }
+ }
+
+ /* Notify the Secure Payload Dispatcher */
+ if (psci_spd_pm && psci_spd_pm->svc_system_reset) {
+ psci_spd_pm->svc_system_reset();
+ }
+ console_flush();
+
+ return psci_plat_pm_ops->system_reset2(is_vendor, reset_type, cookie);
+}
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
index cbc8685..642f799 100644
--- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -27,8 +27,6 @@
return (read_sctlr() & SCTLR_M_BIT) != 0;
}
-#if PLAT_XLAT_TABLES_DYNAMIC
-
void xlat_arch_tlbi_va(uintptr_t va)
{
/*
@@ -77,8 +75,6 @@
isb();
}
-#endif /* PLAT_XLAT_TABLES_DYNAMIC */
-
int xlat_arch_current_el(void)
{
/*
diff --git a/lib/xlat_tables_v2/xlat_tables_internal.c b/lib/xlat_tables_v2/xlat_tables_internal.c
index 9faeb7e..0acfacb 100644
--- a/lib/xlat_tables_v2/xlat_tables_internal.c
+++ b/lib/xlat_tables_v2/xlat_tables_internal.c
@@ -1022,7 +1022,7 @@
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
/* Print the attributes of the specified block descriptor. */
-static void xlat_desc_print(xlat_ctx_t *ctx, uint64_t desc)
+static void xlat_desc_print(const xlat_ctx_t *ctx, uint64_t desc)
{
int mem_type_index = ATTR_INDEX_GET(desc);
xlat_regime_t xlat_regime = ctx->xlat_regime;
@@ -1315,3 +1315,348 @@
}
#endif /* AARCH32 */
+
+/*
+ * Do a translation table walk to find the block or page descriptor that maps
+ * virtual_addr.
+ *
+ * On success, return the address of the descriptor within the translation
+ * table. Its lookup level is stored in '*out_level'.
+ * On error, return NULL.
+ *
+ * xlat_table_base
+ * Base address for the initial lookup level.
+ * xlat_table_base_entries
+ * Number of entries in the translation table for the initial lookup level.
+ * virt_addr_space_size
+ * Size in bytes of the virtual address space.
+ */
+static uint64_t *find_xlat_table_entry(uintptr_t virtual_addr,
+ void *xlat_table_base,
+ int xlat_table_base_entries,
+ unsigned long long virt_addr_space_size,
+ int *out_level)
+{
+ unsigned int start_level;
+ uint64_t *table;
+ int entries;
+
+ VERBOSE("%s(%p)\n", __func__, (void *)virtual_addr);
+
+ start_level = GET_XLAT_TABLE_LEVEL_BASE(virt_addr_space_size);
+ VERBOSE("Starting translation table walk from level %i\n", start_level);
+
+ table = xlat_table_base;
+ entries = xlat_table_base_entries;
+
+ for (unsigned int level = start_level;
+ level <= XLAT_TABLE_LEVEL_MAX;
+ ++level) {
+ int idx;
+ uint64_t desc;
+ uint64_t desc_type;
+
+ VERBOSE("Table address: %p\n", (void *)table);
+
+ idx = XLAT_TABLE_IDX(virtual_addr, level);
+ VERBOSE("Index into level %i table: %i\n", level, idx);
+ if (idx >= entries) {
+ VERBOSE("Invalid address\n");
+ return NULL;
+ }
+
+ desc = table[idx];
+ desc_type = desc & DESC_MASK;
+ VERBOSE("Descriptor at level %i: 0x%llx\n", level,
+ (unsigned long long)desc);
+
+ if (desc_type == INVALID_DESC) {
+ VERBOSE("Invalid entry (memory not mapped)\n");
+ return NULL;
+ }
+
+ if (level == XLAT_TABLE_LEVEL_MAX) {
+ /*
+ * There can't be table entries at the final lookup
+ * level.
+ */
+ assert(desc_type == PAGE_DESC);
+ VERBOSE("Descriptor mapping a memory page (size: 0x%llx)\n",
+ (unsigned long long)XLAT_BLOCK_SIZE(XLAT_TABLE_LEVEL_MAX));
+ *out_level = level;
+ return &table[idx];
+ }
+
+ if (desc_type == BLOCK_DESC) {
+ VERBOSE("Descriptor mapping a memory block (size: 0x%llx)\n",
+ (unsigned long long)XLAT_BLOCK_SIZE(level));
+ *out_level = level;
+ return &table[idx];
+ }
+
+ assert(desc_type == TABLE_DESC);
+ VERBOSE("Table descriptor, continuing xlat table walk...\n");
+ table = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK);
+ entries = XLAT_TABLE_ENTRIES;
+ }
+
+ /*
+ * This shouldn't be reached, the translation table walk should end at
+ * most at level XLAT_TABLE_LEVEL_MAX and return from inside the loop.
+ */
+ assert(0);
+
+ return NULL;
+}
+
+
+static int get_mem_attributes_internal(const xlat_ctx_t *ctx, uintptr_t base_va,
+ mmap_attr_t *attributes, uint64_t **table_entry,
+ unsigned long long *addr_pa, int *table_level)
+{
+ uint64_t *entry;
+ uint64_t desc;
+ int level;
+ unsigned long long virt_addr_space_size;
+
+ /*
+ * Sanity-check arguments.
+ */
+ assert(ctx != NULL);
+ assert(ctx->initialized);
+ assert(ctx->xlat_regime == EL1_EL0_REGIME || ctx->xlat_regime == EL3_REGIME);
+
+ virt_addr_space_size = (unsigned long long)ctx->va_max_address + 1;
+ assert(virt_addr_space_size > 0);
+
+ entry = find_xlat_table_entry(base_va,
+ ctx->base_table,
+ ctx->base_table_entries,
+ virt_addr_space_size,
+ &level);
+ if (entry == NULL) {
+ WARN("Address %p is not mapped.\n", (void *)base_va);
+ return -EINVAL;
+ }
+
+ if (addr_pa != NULL) {
+ *addr_pa = *entry & TABLE_ADDR_MASK;
+ }
+
+ if (table_entry != NULL) {
+ *table_entry = entry;
+ }
+
+ if (table_level != NULL) {
+ *table_level = level;
+ }
+
+ desc = *entry;
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ VERBOSE("Attributes: ");
+ xlat_desc_print(ctx, desc);
+ tf_printf("\n");
+#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */
+
+ assert(attributes != NULL);
+ *attributes = 0;
+
+ int attr_index = (desc >> ATTR_INDEX_SHIFT) & ATTR_INDEX_MASK;
+
+ if (attr_index == ATTR_IWBWA_OWBWA_NTR_INDEX) {
+ *attributes |= MT_MEMORY;
+ } else if (attr_index == ATTR_NON_CACHEABLE_INDEX) {
+ *attributes |= MT_NON_CACHEABLE;
+ } else {
+ assert(attr_index == ATTR_DEVICE_INDEX);
+ *attributes |= MT_DEVICE;
+ }
+
+ int ap2_bit = (desc >> AP2_SHIFT) & 1;
+
+ if (ap2_bit == AP2_RW)
+ *attributes |= MT_RW;
+
+ if (ctx->xlat_regime == EL1_EL0_REGIME) {
+ int ap1_bit = (desc >> AP1_SHIFT) & 1;
+ if (ap1_bit == AP1_ACCESS_UNPRIVILEGED)
+ *attributes |= MT_USER;
+ }
+
+ int ns_bit = (desc >> NS_SHIFT) & 1;
+
+ if (ns_bit == 1)
+ *attributes |= MT_NS;
+
+ uint64_t xn_mask = xlat_arch_regime_get_xn_desc(ctx->xlat_regime);
+
+ if ((desc & xn_mask) == xn_mask) {
+ *attributes |= MT_EXECUTE_NEVER;
+ } else {
+ assert((desc & xn_mask) == 0);
+ }
+
+ return 0;
+}
+
+
+int get_mem_attributes(const xlat_ctx_t *ctx, uintptr_t base_va,
+ mmap_attr_t *attributes)
+{
+ return get_mem_attributes_internal(ctx, base_va, attributes,
+ NULL, NULL, NULL);
+}
+
+
+int change_mem_attributes(xlat_ctx_t *ctx,
+ uintptr_t base_va,
+ size_t size,
+ mmap_attr_t attr)
+{
+ /* Note: This implementation isn't optimized. */
+
+ assert(ctx != NULL);
+ assert(ctx->initialized);
+
+ unsigned long long virt_addr_space_size =
+ (unsigned long long)ctx->va_max_address + 1;
+ assert(virt_addr_space_size > 0);
+
+ if (!IS_PAGE_ALIGNED(base_va)) {
+ WARN("%s: Address %p is not aligned on a page boundary.\n",
+ __func__, (void *)base_va);
+ return -EINVAL;
+ }
+
+ if (size == 0) {
+ WARN("%s: Size is 0.\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((size % PAGE_SIZE) != 0) {
+ WARN("%s: Size 0x%zx is not a multiple of a page size.\n",
+ __func__, size);
+ return -EINVAL;
+ }
+
+ if (((attr & MT_EXECUTE_NEVER) == 0) && ((attr & MT_RW) != 0)) {
+ WARN("%s() doesn't allow to remap memory as read-write and executable.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ int pages_count = size / PAGE_SIZE;
+
+ VERBOSE("Changing memory attributes of %i pages starting from address %p...\n",
+ pages_count, (void *)base_va);
+
+ uintptr_t base_va_original = base_va;
+
+ /*
+ * Sanity checks.
+ */
+ for (int i = 0; i < pages_count; ++i) {
+ uint64_t *entry;
+ uint64_t desc;
+ int level;
+
+ entry = find_xlat_table_entry(base_va,
+ ctx->base_table,
+ ctx->base_table_entries,
+ virt_addr_space_size,
+ &level);
+ if (entry == NULL) {
+ WARN("Address %p is not mapped.\n", (void *)base_va);
+ return -EINVAL;
+ }
+
+ desc = *entry;
+
+ /*
+ * Check that all the required pages are mapped at page
+ * granularity.
+ */
+ if (((desc & DESC_MASK) != PAGE_DESC) ||
+ (level != XLAT_TABLE_LEVEL_MAX)) {
+ WARN("Address %p is not mapped at the right granularity.\n",
+ (void *)base_va);
+ WARN("Granularity is 0x%llx, should be 0x%x.\n",
+ (unsigned long long)XLAT_BLOCK_SIZE(level), PAGE_SIZE);
+ return -EINVAL;
+ }
+
+ /*
+ * If the region type is device, it shouldn't be executable.
+ */
+ int attr_index = (desc >> ATTR_INDEX_SHIFT) & ATTR_INDEX_MASK;
+ if (attr_index == ATTR_DEVICE_INDEX) {
+ if ((attr & MT_EXECUTE_NEVER) == 0) {
+ WARN("Setting device memory as executable at address %p.",
+ (void *)base_va);
+ return -EINVAL;
+ }
+ }
+
+ base_va += PAGE_SIZE;
+ }
+
+ /* Restore original value. */
+ base_va = base_va_original;
+
+ VERBOSE("%s: All pages are mapped, now changing their attributes...\n",
+ __func__);
+
+ for (int i = 0; i < pages_count; ++i) {
+
+ mmap_attr_t old_attr, new_attr;
+ uint64_t *entry;
+ int level;
+ unsigned long long addr_pa;
+
+ get_mem_attributes_internal(ctx, base_va, &old_attr,
+ &entry, &addr_pa, &level);
+
+ VERBOSE("Old attributes: 0x%x\n", old_attr);
+
+ /*
+ * From attr, only MT_RO/MT_RW, MT_EXECUTE/MT_EXECUTE_NEVER and
+ * MT_USER/MT_PRIVILEGED are taken into account. Any other
+ * information is ignored.
+ */
+
+ /* Clean the old attributes so that they can be rebuilt. */
+ new_attr = old_attr & ~(MT_RW|MT_EXECUTE_NEVER|MT_USER);
+
+ /*
+ * Update attributes, but filter out the ones this function
+ * isn't allowed to change.
+ */
+ new_attr |= attr & (MT_RW|MT_EXECUTE_NEVER|MT_USER);
+
+ VERBOSE("New attributes: 0x%x\n", new_attr);
+
+ /*
+ * The break-before-make sequence requires writing an invalid
+ * descriptor and making sure that the system sees the change
+ * before writing the new descriptor.
+ */
+ *entry = INVALID_DESC;
+
+ /* Invalidate any cached copy of this mapping in the TLBs. */
+ xlat_arch_tlbi_va_regime(base_va, ctx->xlat_regime);
+
+ /* Ensure completion of the invalidation. */
+ xlat_arch_tlbi_va_sync();
+
+ /* Write new descriptor */
+ *entry = xlat_desc(ctx, new_attr, addr_pa, level);
+
+ base_va += PAGE_SIZE;
+ }
+
+ /* Ensure that the last descriptor writen is seen by the system. */
+ dsbish();
+
+ return 0;
+}
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index 93d51fe..39c02af 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -300,4 +300,7 @@
.read_mem_protect = arm_psci_read_mem_protect,
.write_mem_protect = arm_nor_psci_write_mem_protect,
#endif
+#if CSS_USE_SCMI_SDS_DRIVER
+ .system_reset2 = css_system_reset2,
+#endif
};
diff --git a/plat/arm/css/drivers/scp/css_pm_scmi.c b/plat/arm/css/drivers/scp/css_pm_scmi.c
index c39bc4b..e29cd86 100644
--- a/plat/arm/css/drivers/scp/css_pm_scmi.c
+++ b/plat/arm/css/drivers/scp/css_pm_scmi.c
@@ -259,10 +259,7 @@
return HW_OFF;
}
-/*
- * Helper function to shutdown the system via SCMI.
- */
-void __dead2 css_scp_sys_shutdown(void)
+void __dead2 css_scp_system_off(int state)
{
int ret;
@@ -273,52 +270,37 @@
plat_arm_gic_cpuif_disable();
/*
- * Issue SCMI command for SYSTEM_SHUTDOWN. First issue a graceful
+ * Issue SCMI command. First issue a graceful
* request and if that fails force the request.
*/
ret = scmi_sys_pwr_state_set(scmi_handle,
SCMI_SYS_PWR_FORCEFUL_REQ,
- SCMI_SYS_PWR_SHUTDOWN);
+ state);
+
if (ret != SCMI_E_SUCCESS) {
- ERROR("SCMI system power domain shutdown return 0x%x unexpected\n",
- ret);
+ ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n",
+ state, ret);
panic();
}
-
wfi();
- ERROR("CSS System Shutdown: operation not handled.\n");
+ ERROR("CSS set power state: operation not handled.\n");
panic();
}
/*
+ * Helper function to shutdown the system via SCMI.
+ */
+void __dead2 css_scp_sys_shutdown(void)
+{
+ css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN);
+}
+
+/*
* Helper function to reset the system via SCMI.
*/
void __dead2 css_scp_sys_reboot(void)
{
- int ret;
-
- /*
- * Disable GIC CPU interface to prevent pending interrupt from waking
- * up the AP from WFI.
- */
- plat_arm_gic_cpuif_disable();
-
- /*
- * Issue SCMI command for SYSTEM_REBOOT. First issue a graceful
- * request and if that fails force the request.
- */
- ret = scmi_sys_pwr_state_set(scmi_handle,
- SCMI_SYS_PWR_FORCEFUL_REQ,
- SCMI_SYS_PWR_COLD_RESET);
- if (ret != SCMI_E_SUCCESS) {
- ERROR("SCMI system power domain reset return 0x%x unexpected\n",
- ret);
- panic();
- }
-
- wfi();
- ERROR("CSS System Reset: operation not handled.\n");
- panic();
+ css_scp_system_off(SCMI_SYS_PWR_COLD_RESET);
}
scmi_channel_plat_info_t plat_css_scmi_plat_info = {
@@ -376,13 +358,35 @@
ops->system_off = NULL;
ops->system_reset = NULL;
ops->get_sys_suspend_power_state = NULL;
- } else if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) {
- /*
- * System power management protocol is available, but it does
- * not support SYSTEM SUSPEND.
- */
- ops->get_sys_suspend_power_state = NULL;
+ } else {
+ if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) {
+ /*
+ * System power management protocol is available, but
+ * it does not support SYSTEM SUSPEND.
+ */
+ ops->get_sys_suspend_power_state = NULL;
+ }
+ if (!(msg_attr & SCMI_SYS_PWR_WARM_RESET_SUPPORTED)) {
+ /*
+ * WARM reset is not available.
+ */
+ ops->system_reset2 = NULL;
+ }
}
return ops;
}
+
+int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
+{
+ if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET))
+ return PSCI_E_INVALID_PARAMS;
+
+ css_scp_system_off(SCMI_SYS_PWR_WARM_RESET);
+ /*
+ * css_scp_system_off cannot return (it is a __dead function),
+ * but css_system_reset2 has to return some value, even in
+ * this case.
+ */
+ return 0;
+}
diff --git a/plat/arm/css/drivers/scp/css_scp.h b/plat/arm/css/drivers/scp/css_scp.h
index 223e372..1f0cf8e 100644
--- a/plat/arm/css/drivers/scp/css_scp.h
+++ b/plat/arm/css/drivers/scp/css_scp.h
@@ -15,12 +15,14 @@
struct psci_power_state;
/* API for power management by SCP */
+int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie);
void css_scp_suspend(const struct psci_power_state *target_state);
void css_scp_off(const struct psci_power_state *target_state);
void css_scp_on(u_register_t mpidr);
int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level);
void __dead2 css_scp_sys_shutdown(void);
void __dead2 css_scp_sys_reboot(void);
+void __dead2 css_scp_system_off(int state);
/* API for SCP Boot Image transfer. Return 0 on success, -1 on error */
int css_scp_boot_image_xfer(void *image, unsigned int image_size);
diff --git a/plat/socionext/uniphier/uniphier_rotpk.S b/plat/socionext/uniphier/uniphier_rotpk.S
index 0045a34..21c44b6 100644
--- a/plat/socionext/uniphier/uniphier_rotpk.S
+++ b/plat/socionext/uniphier/uniphier_rotpk.S
@@ -6,6 +6,7 @@
.global uniphier_rotpk_hash
.global uniphier_rotpk_hash_end
+ .section .rodata.uniphier_rotpk_hash, "a"
uniphier_rotpk_hash:
/* DER header */
.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
diff --git a/tools/fiptool/fiptool_platform.h b/tools/fiptool/fiptool_platform.h
index bfdd1ef..fd0a120 100644
--- a/tools/fiptool/fiptool_platform.h
+++ b/tools/fiptool/fiptool_platform.h
@@ -23,6 +23,7 @@
# else
/* Visual Studio. */
+# include "win_posix.h"
# endif
diff --git a/tools/fiptool/win_posix.c b/tools/fiptool/win_posix.c
new file mode 100644
index 0000000..48feb16
--- /dev/null
+++ b/tools/fiptool/win_posix.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include "win_posix.h"
+
+/*
+ * This variable is set by getopt to the index of the next element of the
+ * argv array to be processed. Once getopt has found all of the option
+ * arguments, you can use this variable to determine where the remaining
+ * non-option arguments begin. The initial value of this variable is 1.
+ */
+int optind = 1;
+
+/*
+ * If the value of this variable is nonzero, then getopt prints an error
+ * message to the standard error stream if it encounters an unknown option
+ * default character or an option with a missing required argument.
+ * If you set this variable to zero, getopt does not print any messages,
+ * but it still returns the character ? to indicate an error.
+ */
+const int opterr; /* = 0; */
+/* const because we do not implement error printing.*/
+/* Not initialised to conform with the coding standard. */
+
+/*
+ * When getopt encounters an unknown option character or an option with a
+ * missing required argument, it stores that option character in this
+ * variable.
+ */
+int optopt; /* = 0; */
+
+/*
+ * This variable is set by getopt to point at the value of the option
+ * argument, for those options that accept arguments.
+ */
+char *optarg; /* = 0; */
+
+enum return_flags {
+ RET_ERROR = -1,
+ RET_END_OPT_LIST = -1,
+ RET_NO_PARAM = '?',
+ RET_NO_PARAM2 = ':',
+ RET_UNKNOWN_OPT = '?'
+};
+
+/*
+ * Common initialisation on entry.
+ */
+static
+void getopt_init(void)
+{
+ optarg = (char *)0;
+ optopt = 0;
+ /* optind may be zero with some POSIX uses.
+ * For our purposes we just change it to 1.
+ */
+ if (optind == 0)
+ optind = 1;
+}
+
+/*
+ * Common handling for a single letter option.
+ */
+static
+int getopt_1char(int argc,
+ char *const argv[],
+ const char *const opstring,
+ const int optchar)
+{
+ size_t nlen = (opstring == 0) ? 0 : strlen(opstring);
+ size_t loptn;
+
+ for (loptn = 0; loptn < nlen; loptn++) {
+ if (optchar == opstring[loptn]) {
+ if (opstring[loptn + 1] == ':') {
+ /* Option has argument */
+ if (optind < argc) {
+ /* Found argument. */
+ assert(argv != 0);
+ optind++;
+ optarg = argv[optind++];
+ return optchar;
+ }
+ /* Missing argument. */
+ if (opstring[loptn + 2] == ':') {
+ /* OK if optional "x::". */
+ optind++;
+ return optchar;
+ }
+ /* Actual missing value. */
+ optopt = optchar;
+ return ((opstring[0] == ':')
+ ? RET_NO_PARAM2
+ : RET_NO_PARAM);
+ }
+ /* No argument, just return option char */
+ optind++;
+ return optchar;
+ }
+ }
+ /*
+ * If getopt finds an option character in argv that was not included in
+ * options, ... it returns '?' and sets the external variable optopt to
+ * the actual option character.
+ */
+ optopt = optchar;
+ return RET_UNKNOWN_OPT;
+}
+
+int getopt(int argc,
+ char *argv[],
+ char *opstring)
+{
+ int result = RET_END_OPT_LIST;
+ size_t argn = 0;
+ size_t nlen = strlen(opstring);
+
+ getopt_init();
+ /* If we have an argument left to play with */
+ if ((argc > optind) && (argv != 0)) {
+ const char *arg = (const char *)argv[optind];
+
+ if ((arg != 0) && (arg[0] == '-'))
+ result = getopt_1char(argc, argv, opstring, arg[1]);
+ }
+
+ return result;
+}
+
+/*
+ * Match an argument value against an option name.
+ * Note that we only match over the shorter length of the pair, to allow
+ * for abbreviation or say --match=value
+ * Long option names may be abbreviated if the abbreviation is unique or an
+ * exact match for some defined option.
+ * A long option may take a parameter, of the form --opt=param or --opt param.
+*/
+static
+int optmatch(const char *argval, const char *optname)
+{
+ int result = 0;
+
+ while ((result == 0) && (*optname != 0) && (*argval != 0))
+ result = (*argval++) - (*optname++);
+ return result;
+}
+
+/* Handling for a single long option. */
+static
+int getopt_1long(const int argc,
+ char *const argv[],
+ const struct option *const longopts,
+ const char *const optname,
+ int *const indexptr)
+{
+ int result = RET_UNKNOWN_OPT;
+ size_t loptn = 0;
+
+ while (longopts[loptn].name != 0) {
+ if (optmatch(optname, longopts[loptn].name) == 0) {
+ /* We found a match. */
+ result = longopts[loptn].val;
+ if (indexptr != 0)
+ *indexptr = loptn;
+ switch (longopts[loptn].has_arg) {
+ case required_argument:
+ if ((optind + 1) >= argc) {
+ /* Missing argument. */
+ optopt = result;
+ return RET_NO_PARAM;
+ }
+ /* Fallthrough to get option value. */
+
+ case optional_argument:
+ if ((argc - optind) > 0) {
+ /* Found argument. */
+ optarg = argv[++optind];
+ }
+ /* Fallthrough to handle flag. */
+
+ case no_argument:
+ optind++;
+ if (longopts[loptn].flag != 0) {
+ *longopts[loptn].flag = result;
+ result = 0;
+ }
+ break;
+
+ }
+ return result;
+ }
+ ++loptn;
+ }
+ /*
+ * If getopt finds an option character in argv that was not included
+ * in options, ... it returns '?' and sets the external variable
+ * optopt to the actual option character.
+ */
+ return RET_UNKNOWN_OPT;
+}
+
+/*
+ * getopt_long gets the next option argument from the argument list
+ * specified by the argv and argc arguments. Options may be either short
+ * (single letter) as for getopt, or longer names (preceded by --).
+ */
+int getopt_long(int argc,
+ char *argv[],
+ const char *shortopts,
+ const struct option *longopts,
+ int *indexptr)
+{
+ int result = RET_END_OPT_LIST;
+
+ getopt_init();
+ /* If we have an argument left to play with */
+ if ((argc > optind) && (argv != 0)) {
+ const char *arg = argv[optind];
+
+ if ((arg != 0) && (arg[0] == '-')) {
+ if (arg[1] == '-') {
+ /* Looks like a long option. */
+ result = getopt_1long(argc,
+ argv,
+ longopts,
+ &arg[2],
+ indexptr);
+ } else {
+ result = getopt_1char(argc,
+ argv,
+ shortopts,
+ arg[1]);
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ * getopt_long_only gets the next option argument from the argument list
+ * specified by the argv and argc arguments. Options may be either short
+ * or long as for getopt_long, but the long names may have a single '-'
+ * prefix too.
+ */
+int getopt_long_only(int argc,
+ char *argv[],
+ const char *shortopts,
+ const struct option *longopts,
+ int *indexptr)
+{
+ int result = RET_END_OPT_LIST;
+
+ getopt_init();
+ /* If we have an argument left to play with */
+ if ((argc > optind) && (argv != 0)) {
+ const char *arg = argv[optind];
+
+ if ((arg != 0) && (arg[0] == '-')) {
+ if (arg[1] == '-') {
+ /* Looks like a long option. */
+ result = getopt_1long(argc,
+ argv,
+ longopts,
+ &arg[2],
+ indexptr);
+ } else {
+ result = getopt_1long(argc,
+ argv,
+ longopts,
+ &arg[1],
+ indexptr);
+ if (result == RET_UNKNOWN_OPT) {
+ result = getopt_1char(argc,
+ argv,
+ shortopts,
+ arg[1]);
+ }
+ }
+ }
+ }
+ return result;
+}
diff --git a/tools/fiptool/win_posix.h b/tools/fiptool/win_posix.h
new file mode 100644
index 0000000..c3fc399
--- /dev/null
+++ b/tools/fiptool/win_posix.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __WINPOSIX_H__
+# define __WINPOSIX_H__
+
+# define _CRT_SECURE_NO_WARNINGS
+
+# include <direct.h>
+# include <io.h>
+# include <stdint.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/stat.h>
+
+# include "uuid.h"
+
+
+/* Derive or provide Windows equivalents of Posix/GCC/Unix stuff. */
+# ifndef PATH_MAX
+# ifdef MAX_PATH
+# define PATH_MAX MAX_PATH
+# else
+# ifdef _MAX_PATH
+# define MAX_PATH _MAX_PATH
+# define PATH_MAX _MAX_PATH
+# else
+# define PATH_MAX 260
+# endif
+# endif
+# endif
+
+# ifndef _CRT_SECURE_NO_WARNINGS
+# define _CRT_SECURE_NO_WARNINGS 1
+# endif
+
+/*
+ * Platform specific names.
+ *
+ * Visual Studio deprecates a number of POSIX functions and only provides
+ * ISO C++ compliant alternatives (distinguished by their '_' prefix).
+ * These macros help provide a stopgap for that.
+ */
+
+/* fileno cannot be an inline function, because _fileno is a macro. */
+# define fileno(fileptr) _fileno(fileptr)
+
+/* _fstat uses the _stat structure, not stat. */
+# define BLD_PLAT_STAT _stat
+
+/* Define flag values for _access. */
+# define F_OK 0
+
+
+/* getopt implementation for Windows: Data. */
+
+/* Legitimate values for option.has_arg. */
+enum has_arg_values {
+ no_argument, /* No argument value required */
+ required_argument, /* value must be specified. */
+ optional_argument /* value may be specified. */
+};
+
+/* Long option table entry for get_opt_long. */
+struct option {
+ /* The name of the option. */
+ const char *name;
+
+ /*
+ * Indicates whether the option takes an argument.
+ * Possible values: see has_arg_values above.
+ */
+ int has_arg;
+
+ /* If not null, when option present, *flag is set to val. */
+ int *flag;
+
+ /*
+ * The value associated with this option to return
+ * (and save in *flag when not null)
+ */
+ int val;
+};
+
+/*
+ * This variable is set by getopt to point at the value of the option
+ * argument, for those options that accept arguments.
+ */
+extern char *optarg;
+
+/*
+ * When this variable is not zero, getopt emits an error message to stderr
+ * if it encounters an unspecified option, or a missing argument.
+ * Otherwise no message is reported.
+ */
+extern const int opterr; /* const as NOT used in this implementation. */
+
+/*
+ * This variable is set by getopt to the index of the next element of the
+ * argv array to be processed. Once getopt has found all of the option
+ * arguments, you can use this variable to determine where the remaining
+ * non-option arguments begin. The initial value of this variable is 1.
+ */
+extern int optind;
+
+/*
+ * When getopt encounters an unknown option character or an option with a
+ * missing required argument, it stores that option character in this
+ * variable.
+ */
+extern int optopt;
+
+
+/*
+ * Platform specific names.
+ *
+ * Visual Studio deprecates a number of POSIX functions and only provides
+ * ISO C++ compliant alternatives (distinguished by their '_' prefix).
+ * These inline functions provide a stopgap for that.
+ */
+
+inline int access(const char *path, int mode)
+{
+ return _access(path, mode);
+}
+
+inline int chdir(const char *s)
+{
+ return _chdir(s);
+}
+
+inline int fstat(int fd, struct _stat *buffer)
+{
+ return _fstat(fd, buffer);
+}
+
+inline char *strdup(const char *s)
+{
+ return _strdup(s);
+}
+
+/*
+ * getopt implementation for Windows: Functions.
+ *
+ * Windows does not have the getopt family of functions, as it normally
+ * uses '/' instead of '-' as the command line option delimiter.
+ * These functions provide a Windows version that uses '-', which precludes
+ * using '-' as the intial letter of a program argument.
+ * This is not seen as a problem in the specific instance of fiptool,
+ * and enables existing makefiles to work on a Windows build environment.
+ */
+
+/*
+ * The getopt function gets the next option argument from the argument list
+ * specified by the argv and argc arguments.
+ */
+int getopt(int argc,
+ char *argv[],
+ char *options);
+
+/*
+ * getopt_long gets the next option argument from the argument list
+ * specified by the argv and argc arguments. Options may be either short
+ * (single letter) as for getopt, or longer names (preceded by --).
+ */
+int getopt_long(int argc,
+ char *argv[],
+ const char *shortopts,
+ const struct option *longopts,
+ int *indexptr);
+
+/*
+ * getopt_long_only gets the next option argument from the argument list
+ * specified by the argv and argc arguments. Options may be either short
+ * or long as for getopt_long, but the long names may have a single '-'
+ * prefix, too.
+ */
+int getopt_long_only(int argc,
+ char *argv[],
+ const char *shortopts,
+ const struct option *longopts,
+ int *indexptr);
+
+#endif /* __WINPOSIX_H__ */