mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
debug: add more strict checking for show_regs [2/2]
PD#SWPL-7711 Problem: Executing echo l > /proc/sysrq-trigger each 5 seconds for about 15 minius will trigger hardlockup Solution: Add more strict checking for show_regs to filter out addresses in secure monitor region and ioremap region, deferencing which triggers external abort on none-linefetch, and finally leading to hardlockup Verify: Locally pass on U200 Change-Id: I6bd219e7dc3ad29904e6bd1b7d2f4cfb3928d8ed Signed-off-by: Jiamin Ma <jiamin.ma@amlogic.com>
This commit is contained in:
@@ -47,6 +47,10 @@ unsigned long __stack_chk_guard __read_mostly;
|
||||
EXPORT_SYMBOL(__stack_chk_guard);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_MODIFY
|
||||
#include <linux/amlogic/secmon.h>
|
||||
#endif
|
||||
|
||||
static const char *processor_modes[] __maybe_unused = {
|
||||
"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
|
||||
"UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
|
||||
@@ -119,6 +123,34 @@ static void show_data(unsigned long addr, int nbytes, const char *name)
|
||||
if (addr < PAGE_OFFSET || addr > -256UL)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_MODIFY
|
||||
/*
|
||||
* Treating data in general purpose register as an address
|
||||
* and dereferencing it is quite a dangerous behaviour,
|
||||
* especially when it is an address belonging to secure
|
||||
* region or ioremap region, which can lead to external
|
||||
* abort on non-linefetch and can not be protected by
|
||||
* probe_kernel_address.
|
||||
* We need more strict filtering rules
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_SEC
|
||||
/*
|
||||
* filter out secure monitor region
|
||||
*/
|
||||
if (addr <= (unsigned long)high_memory)
|
||||
if (within_secmon_region(addr))
|
||||
return;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* filter out ioremap region
|
||||
*/
|
||||
if ((addr >= VMALLOC_START) && (addr <= VMALLOC_END))
|
||||
if (!pfn_valid(vmalloc_to_pfn((void *)addr)))
|
||||
return;
|
||||
#endif
|
||||
|
||||
printk("\n%s: %#lx:\n", name, addr);
|
||||
|
||||
/*
|
||||
|
||||
@@ -62,6 +62,10 @@ unsigned long __stack_chk_guard __read_mostly;
|
||||
EXPORT_SYMBOL(__stack_chk_guard);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_MODIFY
|
||||
#include <linux/amlogic/secmon.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Function pointers to optional machine specific functions
|
||||
*/
|
||||
@@ -195,6 +199,27 @@ static void show_data(unsigned long addr, int nbytes, const char *name)
|
||||
if (addr < PAGE_OFFSET || addr > -256UL)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_MODIFY
|
||||
/*
|
||||
* Treating data in general purpose register as an address
|
||||
* and dereferencing it is quite a dangerous behaviour,
|
||||
* especially when it belongs to secure monotor region or
|
||||
* ioremap region(for arm64 vmalloc region is already filtered
|
||||
* out), which can lead to external abort on non-linefetch and
|
||||
* can not be protected by probe_kernel_address.
|
||||
* We need more strict filtering rules
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_SEC
|
||||
/*
|
||||
* filter out secure monitor region
|
||||
*/
|
||||
if (addr <= (unsigned long)high_memory)
|
||||
if (within_secmon_region(addr))
|
||||
return;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
printk("\n%s: %#lx:\n", name, addr);
|
||||
|
||||
/*
|
||||
|
||||
@@ -35,6 +35,8 @@ static void __iomem *sharemem_in_base;
|
||||
static void __iomem *sharemem_out_base;
|
||||
static long phy_in_base;
|
||||
static long phy_out_base;
|
||||
static unsigned long secmon_start_virt;
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
#define IN_SIZE 0x1000
|
||||
#else
|
||||
@@ -55,6 +57,19 @@ static long get_sharemem_info(unsigned int function_id)
|
||||
}
|
||||
|
||||
#define RESERVE_MEM_SIZE 0x300000
|
||||
|
||||
int within_secmon_region(unsigned long addr)
|
||||
{
|
||||
if (!secmon_start_virt)
|
||||
return 0;
|
||||
|
||||
if ((addr >= secmon_start_virt) &&
|
||||
(addr <= (secmon_start_virt + RESERVE_MEM_SIZE)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int secmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
@@ -87,6 +102,7 @@ static int secmon_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
pr_info("get page:%p, %lx\n", page, page_to_pfn(page));
|
||||
secmon_start_virt = (unsigned long)page_to_virt(page);
|
||||
|
||||
if (pfn_valid(__phys_to_pfn(phy_in_base)))
|
||||
sharemem_in_base = (void __iomem *)__phys_to_virt(phy_in_base);
|
||||
|
||||
@@ -27,4 +27,6 @@ void sharemem_mutex_lock(void);
|
||||
void sharemem_mutex_unlock(void);
|
||||
void secmon_clear_cma_mmu(void);
|
||||
|
||||
int within_secmon_region(unsigned long addr);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -93,9 +93,19 @@ bool nmi_cpu_backtrace(struct pt_regs *regs)
|
||||
cpu, instruction_pointer(regs));
|
||||
} else {
|
||||
pr_warn("NMI backtrace for cpu %d\n", cpu);
|
||||
/*
|
||||
* two reasons for not calling show_regs here
|
||||
* 1. two many logs(100 lines per second) are
|
||||
* introduced, which makes the wanted stack
|
||||
* infos missed
|
||||
* 2. leads to potential external abort on
|
||||
* non-linefetch issue
|
||||
*/
|
||||
#ifndef CONFIG_AMLOGIC_MODIFY
|
||||
if (regs)
|
||||
show_regs(regs);
|
||||
else
|
||||
#endif
|
||||
dump_stack();
|
||||
}
|
||||
cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
|
||||
|
||||
@@ -254,10 +254,14 @@ struct page *vmalloc_to_page(const void *vmalloc_addr)
|
||||
*/
|
||||
if (!pgd_none(*pgd)) {
|
||||
pud_t *pud = pud_offset(pgd, addr);
|
||||
#ifndef CONFIG_AMLOGIC_MODIFY
|
||||
WARN_ON_ONCE(pud_bad(*pud));
|
||||
#endif
|
||||
if (!pud_none(*pud) && !pud_bad(*pud)) {
|
||||
pmd_t *pmd = pmd_offset(pud, addr);
|
||||
#ifndef CONFIG_AMLOGIC_MODIFY
|
||||
WARN_ON_ONCE(pmd_bad(*pmd));
|
||||
#endif
|
||||
if (!pmd_none(*pmd) && !pmd_bad(*pmd)) {
|
||||
pte_t *ptep, pte;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user