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(a)loongson.cn>
> Signed-off-by: Youling Tang <tangyouling(a)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