arm64: Add TLB conflict fault handler

Add TLB conflict fault handler and try to handle
gracefully. Check whether TLB fault can be handled
by EL2 and cause panic if EL2 is not able to handle.

Change-Id: I276ec5413411932bd8a67ed4c85ebbf66f4affcf
Signed-off-by: Runmin Wang <runminw@codeaurora.org>
Signed-off-by: Prasad Sodagudi <psodagud@codeaurora.org>
Signed-off-by: Naina Mehta <nainmeht@codeaurora.org>
This commit is contained in:
Naina Mehta 2021-07-26 16:34:55 +05:30 committed by Gerrit - the friendly Code Review server
parent ca0d1e3eaf
commit 7769d7fea8
6 changed files with 63 additions and 0 deletions

View File

@ -1793,6 +1793,14 @@ config BUILD_ARM64_DT_OVERLAY
required flags to add DT overlay in the
compilation.
config TLB_CONF_HANDLER
bool "enable handler for TLB conflict"
help
This option enables graceful handling of TLB
conflict in EL2. Say yes here to enable TLB
conflict handler.
If unsure, Say n.
config SYSVIPC_COMPAT
def_bool y
depends on COMPAT && SYSVIPC

View File

@ -24,6 +24,10 @@
#include <linux/preempt.h>
#include <linux/hugetlb.h>
#ifdef CONFIG_TLB_CONF_HANDLER
#include <linux/qcom_scm.h>
#endif
#include <asm/acpi.h>
#include <asm/bug.h>
#include <asm/cmpxchg.h>
@ -691,6 +695,15 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
return 0;
}
#ifdef CONFIG_TLB_CONF_HANDLER
static int do_tlb_conf_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs)
{
if (qcom_scm_tlb_conf_handler(addr))
return 1;
return 0;
}
#endif
static const struct fault_info fault_info[] = {
{ do_bad, SIGKILL, SI_KERNEL, "ttbr address size fault" },
{ do_bad, SIGKILL, SI_KERNEL, "level 1 address size fault" },
@ -740,7 +753,11 @@ static const struct fault_info fault_info[] = {
{ do_bad, SIGKILL, SI_KERNEL, "unknown 45" },
{ do_bad, SIGKILL, SI_KERNEL, "unknown 46" },
{ do_bad, SIGKILL, SI_KERNEL, "unknown 47" },
#ifdef CONFIG_TLB_CONF_HANDLER
{ do_tlb_conf_fault, SIGKILL, SI_KERNEL, "TLB conflict abort" },
#else
{ do_bad, SIGKILL, SI_KERNEL, "TLB conflict abort" },
#endif
{ do_bad, SIGKILL, SI_KERNEL, "Unsupported atomic hardware update fault" },
{ do_bad, SIGKILL, SI_KERNEL, "unknown 50" },
{ do_bad, SIGKILL, SI_KERNEL, "unknown 51" },

View File

@ -1020,6 +1020,27 @@ int __qcom_scm_sec_wdog_trigger(struct device *dev)
return ret ? : desc.res[0];
}
#ifdef CONFIG_TLB_CONF_HANDLER
int __qcom_scm_tlb_conf_handler(struct device *dev, unsigned long addr)
{
int ret;
#define SCM_TLB_CONFLICT_CMD 0x1F
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_MP,
.cmd = SCM_TLB_CONFLICT_CMD,
.owner = ARM_SMCCC_OWNER_SIP,
};
desc.args[0] = addr;
desc.arginfo = QCOM_SCM_ARGS(1);
ret = qcom_scm_call_atomic(dev, &desc);
return ret ? : desc.res[0];
}
#endif
void __qcom_scm_disable_sdi(struct device *dev)
{
int ret;

View File

@ -160,6 +160,14 @@ int qcom_scm_sec_wdog_trigger(void)
}
EXPORT_SYMBOL(qcom_scm_sec_wdog_trigger);
#ifdef CONFIG_TLB_CONF_HANDLER
int qcom_scm_tlb_conf_handler(unsigned long addr)
{
return __qcom_scm_tlb_conf_handler(__scm->dev, addr);
}
EXPORT_SYMBOL(qcom_scm_tlb_conf_handler);
#endif
/**
* qcom_scm_disable_sdi() - Disable SDI
*/

View File

@ -28,6 +28,9 @@ extern void __qcom_scm_cpu_power_down(struct device *dev, u32 flags);
extern void __qcom_scm_cpu_hp(struct device *dev, u32 flags);
extern int __qcom_scm_sec_wdog_deactivate(struct device *dev);
extern int __qcom_scm_sec_wdog_trigger(struct device *dev);
#ifdef CONFIG_TLB_CONF_HANDLER
extern int __qcom_scm_tlb_conf_handler(struct device *dev, unsigned long addr);
#endif
extern void __qcom_scm_disable_sdi(struct device *dev);
extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
extern int __qcom_scm_spin_cpu(struct device *dev);

View File

@ -86,6 +86,9 @@ extern void qcom_scm_cpu_power_down(u32 flags);
extern void qcom_scm_cpu_hp(u32 flags);
extern int qcom_scm_sec_wdog_deactivate(void);
extern int qcom_scm_sec_wdog_trigger(void);
#ifdef CONFIG_TLB_CONF_HANDLER
extern int qcom_scm_tlb_conf_handler(unsigned long addr);
#endif
extern void qcom_scm_disable_sdi(void);
extern int qcom_scm_set_remote_state(u32 state, u32 id);
extern int qcom_scm_spin_cpu(void);
@ -231,6 +234,9 @@ static inline void qcom_scm_cpu_power_down(u32 flags) {}
static inline void qcom_scm_cpu_hp(u32 flags) {}
static inline int qcom_scm_sec_wdog_deactivate(void) { return -ENODEV; }
static inline int qcom_scm_sec_wdog_trigger(void) { return -ENODEV; }
#ifdef CONFIG_TLB_CONF_HANDLER
static inline int qcom_scm_tlb_conf_handler(unsigned long addr) { return -ENODEV; }
#endif
static inline void qcom_scm_disable_sdi(void) {}
static inline u32 qcom_scm_set_remote_state(u32 state, u32 id)
{ return -ENODEV; }