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

HAGIO KAZUHITO(萩尾 一仁) k-hagio-ab at nec.com
Wed Mar 10 01:15:28 UTC 2021


-----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__);
}

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