[Crash-utility] [PATCH 04/16] MIPS64: Make the crash tool successfully enter the crash command line

Youling Tang tangyouling at loongson.cn
Wed Mar 10 09:20:01 UTC 2021


On 03/10/2021 09:15 AM, HAGIO KAZUHITO(萩尾 一仁) wrote:
> -----Original Message-----
>> 1. Add mips64_init() implementation, do all necessary machine-specific setup,
>> which will be called multiple times during initialization.
>>
>> 2. Add the implementation of the vtop command, which is used to convert a
>> virtual address to a physical address. When entering the crash command line,
>> the corresponding symbols in the kernel will be read, and at the same time,
>> the conversion of virtual and real addresses will also be used, so the vtop
>> command is a prerequisite for entering the crash command line.
>>
>> 3. Add mips64_get_smp_cpus() implementation, get the number of online cpus.
>>
>> 4. Add mips64_get_page_size() implementation, get page size.
>>
>> The results after applying patch 01~04 are as follows:
>> ...
>>        KERNEL: /boot/vmlinux-4.19.161kexec+
>>      DUMPFILE: /home/tang/vmcore_4.19.161
>>          CPUS: 4
>>          DATE: Mon Jan 25 18:54:14 HKT 2021
>>        UPTIME: (cannot calculate: unknown HZ value)
>> LOAD AVERAGE: 0.24, 0.21, 0.09
>>         TASKS: 348
>>      NODENAME: bogon
>>       RELEASE: 4.19.161kexec+
>>       VERSION: #15 SMP PREEMPT Mon Jan 25 17:56:16 HKT 2021
>>       MACHINE: mips64  (unknown Mhz)
>>        MEMORY: 0
>>         PANIC: "CPU 3 Unable to handle kernel paging request at virtual address 0000000000000000, epc ==
>> ffffffff8085d318, ra == ffffffff8085d308"
>>           PID: 4768
>>       COMMAND: "bash"
>>          TASK: 9800000243bcf200  [THREAD_INFO: 980000024291c000]
>>           CPU: 3
>>         STATE: TASK_RUNNING (PANIC)
>>
>> crash>
>>
>> Signed-off-by: Huacai Chen <chenhuacai at loongson.cn>
>> Signed-off-by: Youling Tang <tangyouling at loongson.cn>
>> ---
>>   mips64.c | 308 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 308 insertions(+)
>>
>> diff --git a/mips64.c b/mips64.c
>> index c3eb03c..21a8206 100644
>> --- a/mips64.c
>> +++ b/mips64.c
>> @@ -17,11 +17,269 @@
>>   #include <elf.h>
>>   #include "defs.h"
>>
>> +static int mips64_pgd_vtop(ulong *pgd, ulong vaddr,
>> +			physaddr_t *paddr, int verbose);
>> +static int mips64_uvtop(struct task_context *tc, ulong vaddr,
>> +			physaddr_t *paddr, int verbose);
>> +static int mips64_kvtop(struct task_context *tc, ulong kvaddr,
>> +			physaddr_t *paddr, int verbose);
>> +
>> +/*
>> + * 3 Levels paging       PAGE_SIZE=16KB
>> + *  PGD  |  PMD  |  PTE  |  OFFSET  |
>> + *  11   |  11   |  11   |    14    |
>> + */
>> +/* From arch/mips/include/asm/pgtable{,-64}.h */
>> +typedef struct { ulong pgd; } pgd_t;
>> +typedef struct { ulong pmd; } pmd_t;
>> +typedef struct { ulong pte; } pte_t;
>> +
>> +#define PMD_ORDER	0
>> +#define PTE_ORDER	0
>> +
>> +#define PMD_SHIFT	(PAGESHIFT() + (PAGESHIFT() + PTE_ORDER - 3))
>> +#define PMD_SIZE	(1UL << PMD_SHIFT)
>> +#define PMD_MASK	(~(PMD_SIZE - 1))
>> +
>> +#define PGDIR_SHIFT	(PMD_SHIFT + (PAGESHIFT() + PMD_ORDER - 3))
>> +#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
>> +#define PGDIR_MASK	(~(PGDIR_SIZE - 1))
>> +
>> +#define PTRS_PER_PTE	(1UL << (PAGESHIFT() - 3))
>> +#define PTRS_PER_PMD	PTRS_PER_PTE
>> +#define PTRS_PER_PGD	PTRS_PER_PTE
>> +#define USER_PTRS_PER_PGD	(0x80000000UL/PGDIR_SIZE)
>> +
>> +#define pte_index(addr)	(((addr) >> PAGESHIFT()) & (PTRS_PER_PTE - 1))
>> +#define pmd_index(addr)	(((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
>> +#define pgd_index(addr)	(((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
>> +
>> +#define MIPS64_CPU_RIXI	(1UL << 23)	/* CPU has TLB Read/eXec Inhibit */
>> +
>> +/* From arch/mips/include/uapi/asm/reg.h */
>> +#define MIPS64_EF_R0		0
>> +#define MIPS64_EF_R29		29
>> +#define MIPS64_EF_R31		31
>> +#define MIPS64_EF_LO		32
>> +#define MIPS64_EF_HI		33
>> +#define MIPS64_EF_CP0_EPC	34
>> +#define MIPS64_EF_CP0_BADVADDR	35
>> +#define MIPS64_EF_CP0_STATUS	36
>> +#define MIPS64_EF_CP0_CAUSE	37
>> +
>> +static struct machine_specific mips64_machine_specific = { 0 };
>> +
>> +/*
>> + * Holds registers during the crash.
>> + */
>> +static struct mips64_register *panic_task_regs;
>> +
>> +/*
>> + * Virtual to physical memory translation. This function will be called
>> + * by both mips64_kvtop and mips64_uvtop.
>> + */
>> +static int
>> +mips64_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
>> +{
>> +	ulong *pgd_ptr, pgd_val;
>> +	ulong *pmd_ptr, pmd_val;
>> +	ulong *pte_ptr, pte_val;
>> +
>> +	if (verbose) {
>> +		const char *segment;
>> +
>> +		if (vaddr < 0x4000000000000000lu)
>> +			segment = "xuseg";
>> +		else if (vaddr < 0x8000000000000000lu)
>> +			segment = "xsseg";
>> +		else if (vaddr < 0xc000000000000000lu)
>> +			segment = "xkphys";
>> +		else if (vaddr < 0xffffffff80000000lu)
>> +			segment = "xkseg";
>> +		else if (vaddr < 0xffffffffa0000000lu)
>> +			segment = "kseg0";
>> +		else if (vaddr < 0xffffffffc0000000lu)
>> +			segment = "kseg1";
>> +		else if (vaddr < 0xffffffffe0000000lu)
>> +			segment = "sseg";
>> +		else
>> +			segment = "kseg3";
>> +
>> +		fprintf(fp, "SEGMENT: %s\n", segment);
>> +	}
>> +
>> +	if (IS_CKPHYS(vaddr) || IS_XKPHYS(vaddr)) {
>> +		*paddr = VTOP(vaddr);
>> +		return TRUE;
>> +	}
>> +
>> +	if (verbose)
>> +		fprintf(fp, "PAGE DIRECTORY: %016lx\n", (ulong)pgd);
>> +
>> +	pgd_ptr = pgd + pgd_index(vaddr);
>> +	FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
>> +	pgd_val = ULONG(machdep->pgd + PAGEOFFSET(pgd_ptr));
>> +	if (verbose)
>> +		fprintf(fp, "  PGD: %16lx => %16lx\n", (ulong)pgd_ptr, pgd_val);
>> +	if (!pgd_val)
>> +		goto no_page;
>> +
>> +	pmd_ptr = (ulong *)(VTOP(pgd_val) + sizeof(pmd_t) * pmd_index(vaddr));
>> +	FILL_PMD(PAGEBASE(pmd_ptr), PHYSADDR, PAGESIZE());
>> +	pmd_val = ULONG(machdep->pmd + PAGEOFFSET(pmd_ptr));
>> +	if (verbose)
>> +		fprintf(fp, "  PMD: %016lx => %016lx\n", (ulong)pmd_ptr, pmd_val);
>> +	if (!pmd_val)
>> +		goto no_page;
>> +
>> +	pte_ptr = (ulong *)(VTOP(pmd_val) + sizeof(pte_t) * pte_index(vaddr));
>> +	FILL_PTBL(PAGEBASE(pte_ptr), PHYSADDR, PAGESIZE());
>> +	pte_val = ULONG(machdep->ptbl + PAGEOFFSET(pte_ptr));
>> +	if (verbose)
>> +		fprintf(fp, "  PTE: %016lx => %016lx\n", (ulong)pte_ptr, pte_val);
>> +	if (!pte_val)
>> +		goto no_page;
>> +
>> +	return TRUE;
>> +no_page:
>> +	fprintf(fp, "invalid\n");
>> +	return FALSE;
>> +}
>> +
>> +/* Translates a user virtual address to its physical address. cmd_vtop() sets
>> + * the verbose flag so that the pte translation gets displayed; all other
>> + * callers quietly accept the translation.
>> + */
>> +static int
>> +mips64_uvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
>> +{
>> +	ulong mm, active_mm;
>> +	ulong *pgd;
>> +
>> +	if (!tc)
>> +		error(FATAL, "current context invalid\n");
>> +
>> +	*paddr = 0;
>> +
>> +	if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) {
>> +		if (VALID_MEMBER(thread_struct_pg_tables))
>> +			pgd = (ulong *)machdep->get_task_pgd(tc->task);
> The machdep->get_task_pgd is not set in this patchset?
>
> MIPS defines this:
> static ulong
> mips_get_task_pgd(ulong task)
> {
>          return error(FATAL, "%s: not implemented\n", __func__);
> }
There is no need to implement get_task_pgd() for the time being, I will
remove the use of machdep->get_task_pgd(), which directly obtains pgd
from mm_struct.

Thanks,
Youling
>
> Thanks,
> Kazu
>
>> +		else {
>> +			if (INVALID_MEMBER(task_struct_active_mm))
>> +				error(FATAL, "no pg_tables or active_mm?\n");
>> +
>> +			readmem(tc->task + OFFSET(task_struct_active_mm),
>> +				KVADDR, &active_mm, sizeof(void *),
>> +				"task active_mm contents", FAULT_ON_ERROR);
>> +
>> +			 if (!active_mm)
>> +				 error(FATAL,
>> +				       "no active_mm for this kernel thread\n");
>> +
>> +			readmem(active_mm + OFFSET(mm_struct_pgd),
>> +				KVADDR, &pgd, sizeof(long),
>> +				"mm_struct pgd", FAULT_ON_ERROR);
>> +		}
>> +	} else {
>> +		if ((mm = task_mm(tc->task, TRUE)))
>> +			pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd));
>> +		else
>> +			readmem(tc->mm_struct + OFFSET(mm_struct_pgd),
>> +			KVADDR, &pgd, sizeof(long), "mm_struct pgd",
>> +			FAULT_ON_ERROR);
>> +	}
>> +
>> +	return mips64_pgd_vtop(pgd, vaddr, paddr, verbose);;
>> +}
>> +
>> +/* Translates a user virtual address to its physical address. cmd_vtop() sets
>> + * the verbose flag so that the pte translation gets displayed; all other
>> + * callers quietly accept the translation.
>> + */
>> +static int
>> +mips64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
>> +{
>> +	if (!IS_KVADDR(kvaddr))
>> +		return FALSE;
>> +
>> +	if (!verbose) {
>> +		if (IS_CKPHYS(kvaddr) || IS_XKPHYS(kvaddr)) {
>> +			*paddr = VTOP(kvaddr);
>> +			return TRUE;
>> +		}
>> +	}
>> +
>> +	return mips64_pgd_vtop((ulong *)vt->kernel_pgd[0], kvaddr, paddr,
>> +			     verbose);
>> +}
>> +
>> +/*
>> + * Accept or reject a symbol from the kernel namelist.
>> + */
>> +static int
>> +mips64_verify_symbol(const char *name, ulong value, char type)
>> +{
>> +	return TRUE;
>> +}
>> +
>> +/*
>> + * Override smp_num_cpus if possible and necessary.
>> + */
>> +static int
>> +mips64_get_smp_cpus(void)
>> +{
>> +	return (get_cpus_online() > 0) ? get_cpus_online() : kt->cpus;
>> +}
>> +
>> +static ulong
>> +mips64_get_page_size(void)
>> +{
>> +	return memory_page_size();
>> +}
>> +
>> +/*
>> + * Determine where vmalloc'd memory starts.
>> + */
>> +static ulong
>> +mips64_vmalloc_start(void)
>> +{
>> +	return 0;
>> +}
>> +
>> +static ulong
>> +mips64_processor_speed(void)
>> +{
>> +	return 0;
>> +}
>> +
>> +/*
>> + * Checks whether given task is valid task address.
>> + */
>> +static int
>> +mips64_is_task_addr(ulong task)
>> +{
>> +	if (tt->flags & THREAD_INFO)
>> +		return IS_KVADDR(task);
>> +
>> +	return (IS_KVADDR(task) && ALIGNED_STACK_OFFSET(task) == 0);
>> +}
>> +
>>   void
>>   mips64_dump_machdep_table(ulong arg)
>>   {
>>   }
>>
>> +static void
>> +pt_level_alloc(char **lvl, char *name)
>> +{
>> +	size_t sz = PAGESIZE();
>> +	void *pointer = malloc(sz);
>> +
>> +	if (!pointer)
>> +	        error(FATAL, name);
>> +	*lvl = pointer;
>> +}
>> +
>>   /*
>>    * Do all necessary machine-specific setup here. This is called several
>>    * times during initialization.
>> @@ -33,6 +291,56 @@ mips64_init(int when)
>>   	case SETUP_ENV:
>>   		machdep->process_elf_notes = process_elf64_notes;
>>   		break;
>> +
>> +	case PRE_SYMTAB:
>> +		machdep->verify_symbol = mips64_verify_symbol;
>> +		machdep->machspec = &mips64_machine_specific;
>> +		if (pc->flags & KERNEL_DEBUG_QUERY)
>> +			return;
>> +		machdep->last_pgd_read = 0;
>> +		machdep->last_pmd_read = 0;
>> +		machdep->last_ptbl_read = 0;
>> +		machdep->verify_paddr = generic_verify_paddr;
>> +		machdep->ptrs_per_pgd = PTRS_PER_PGD;
>> +		break;
>> +
>> +	case PRE_GDB:
>> +		machdep->pagesize = mips64_get_page_size();
>> +		machdep->pageshift = ffs(machdep->pagesize) - 1;
>> +		machdep->pageoffset = machdep->pagesize - 1;
>> +		machdep->pagemask = ~((ulonglong)machdep->pageoffset);
>> +		if (machdep->pagesize >= 16384)
>> +			machdep->stacksize = machdep->pagesize;
>> +		else
>> +			machdep->stacksize = machdep->pagesize * 2;
>> +
>> +		pt_level_alloc(&machdep->pgd, "cannot malloc pgd space.");
>> +		pt_level_alloc(&machdep->pmd, "cannot malloc pmd space.");
>> +		pt_level_alloc(&machdep->ptbl, "cannot malloc ptbl space.");
>> +		machdep->kvbase = 0x8000000000000000lu;
>> +		machdep->identity_map_base = machdep->kvbase;
>> +		machdep->is_kvaddr = generic_is_kvaddr;
>> +		machdep->is_uvaddr = generic_is_uvaddr;
>> +		machdep->uvtop = mips64_uvtop;
>> +		machdep->kvtop = mips64_kvtop;
>> +		machdep->vmalloc_start = mips64_vmalloc_start;
>> +		machdep->processor_speed = mips64_processor_speed;
>> +		machdep->get_stackbase = generic_get_stackbase;
>> +		machdep->get_stacktop = generic_get_stacktop;
>> +		machdep->memory_size = generic_memory_size;
>> +		machdep->is_task_addr = mips64_is_task_addr;
>> +		machdep->get_smp_cpus = mips64_get_smp_cpus;
>> +		machdep->value_to_symbol = generic_machdep_value_to_symbol;
>> +		machdep->init_kernel_pgd = NULL;
>> +		break;
>> +
>> +	case POST_GDB:
>> +		machdep->section_size_bits = _SECTION_SIZE_BITS;
>> +		machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
>> +		break;
>> +
>> +	case POST_VM:
>> +		break;
>>   	}
>>   }
>>
>> --
>> 2.1.0




More information about the Crash-utility mailing list