[Crash-utility] [PATCH v4 2/4] [ppc] Support for platform based Virtual address translation

Toshikazu Nakayama nakayama.ts at ncos.nec.co.jp
Tue Feb 21 01:31:04 UTC 2012


(2012/02/20 20:06), Suzuki K. Poulose wrote:
> This patch adds infrastructure for defining Virtual address translation bits
> for each platform and use the specific definition for the platform depending on
> the 'powerpc_base_platform' variable. If a matching platform is not found,
> fallbacks to the default definition.
> 
> Each platform can define a probe function which can identify the 'kernel
> platform string' to one of its variant. It can then update PGDIR_SHIFT,
> PTRS_PER_PGD, PTRS_PER_PTE, the size of a PTE and also the various Page flags.
> 
> This patch also changes the pte to ulonglong type.
> 
> mach command now displays the platform string read from the kernel.
> 
> crash>  mach
>         MACHINE TYPE: ppc
>             PLATFORM: ppc440gp
>          MEMORY SIZE: 128 MB
> 	...
> 
> Signed-off-by: Suzuki K. Poulose<suzuki at in.ibm.com>
> ---
> 
>   defs.h |   82 ++++++++++++++++++++++++++++++++++---------
>   ppc.c  |  123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
>   2 files changed, 171 insertions(+), 34 deletions(-)
> 
> diff --git a/defs.h b/defs.h
> index a942dbb..0c5558e 100755
> --- a/defs.h
> +++ b/defs.h
> @@ -2635,27 +2635,50 @@ struct load_module {
>   #define _32BIT_
>   #define MACHINE_TYPE       "PPC"
> 
> -#define PAGEBASE(X)  (((ulong)(X))&  (ulong)machdep->pagemask)
> +#define PAGEBASE(X) 		((X)&  machdep->pagemask)
> 
>   #define PTOV(X)            ((unsigned long)(X)+(machdep->kvbase))
>   #define VTOP(X)            ((unsigned long)(X)-(machdep->kvbase))
>   #define IS_VMALLOC_ADDR(X) (vt->vmalloc_start&&  (ulong)(X)>= vt->vmalloc_start)
> 
> -#define PGDIR_SHIFT   (22)
> -#define PTRS_PER_PTE  (1024)
> -#define PTRS_PER_PGD  (1024)
> -
> -#define _PAGE_PRESENT   0x001   /* software: pte contains a translation */
> -#define _PAGE_USER      0x002   /* matches one of the PP bits */
> -#define _PAGE_RW        0x004   /* software: user write access allowed */
> -#define _PAGE_GUARDED   0x008
> -#define _PAGE_COHERENT  0x010   /* M: enforce memory coherence (SMP systems) */
> -#define _PAGE_NO_CACHE  0x020   /* I: cache inhibit */
> -#define _PAGE_WRITETHRU 0x040   /* W: cache write-through */
> -#define _PAGE_DIRTY     0x080   /* C: page changed */
> -#define _PAGE_ACCESSED  0x100   /* R: page referenced */
> -#define _PAGE_HWWRITE   0x200   /* software: _PAGE_RW&  _PAGE_DIRTY */
> -#define _PAGE_SHARED    0
> +/* Page translation bits */
> +#define PPC_PLATFORM		(machdep->machspec->platform)
> +#define PGDIR_SHIFT		(machdep->machspec->pgdir_shift)
> +#define PTRS_PER_PTE		(machdep->machspec->ptrs_per_pte)
> +#define PTRS_PER_PGD		(machdep->machspec->ptrs_per_pgd)
> +#define PTE_SIZE		(machdep->machspec->pte_size)
> +
> +/* Default values for Page translation */
> +#define DEFAULT_PGDIR_SHIFT	(22)
> +#define DEFAULT_PTRS_PER_PTE	(1024)
> +#define DEFAULT_PTRS_PER_PGD	(1024)
> +#define DEFAULT_PTE_SIZE	sizeof(ulong)
> +
> +/* PAGE flags */
> +#define _PAGE_PRESENT   (machdep->machspec->_page_present)	/* software: pte contains a translation */
> +#define _PAGE_USER      (machdep->machspec->_page_user)		/* matches one of the PP bits */
> +#define _PAGE_RW        (machdep->machspec->_page_rw)		/* software: user write access allowed */
> +#define _PAGE_GUARDED   (machdep->machspec->_page_guarded)
> +#define _PAGE_COHERENT  (machdep->machspec->_page_coherent	/* M: enforce memory coherence (SMP systems) */)
> +#define _PAGE_NO_CACHE  (machdep->machspec->_page_no_cache)	/* I: cache inhibit */
> +#define _PAGE_WRITETHRU (machdep->machspec->_page_writethru)	/* W: cache write-through */
> +#define _PAGE_DIRTY     (machdep->machspec->_page_dirty)	/* C: page changed */
> +#define _PAGE_ACCESSED  (machdep->machspec->_page_accessed)	/* R: page referenced */
> +#define _PAGE_HWWRITE   (machdep->machspec->_page_hwwrite)	/* software: _PAGE_RW&  _PAGE_DIRTY */
> +#define _PAGE_SHARED    (machdep->machspec->_page_shared)
> +
> +/* Default values for PAGE flags */
> +#define DEFAULT_PAGE_PRESENT   0x001
> +#define DEFAULT_PAGE_USER      0x002
> +#define DEFAULT_PAGE_RW        0x004
> +#define DEFAULT_PAGE_GUARDED   0x008
> +#define DEFAULT_PAGE_COHERENT  0x010
> +#define DEFAULT_PAGE_NO_CACHE  0x020
> +#define DEFAULT_PAGE_WRITETHRU 0x040
> +#define DEFAULT_PAGE_DIRTY     0x080
> +#define DEFAULT_PAGE_ACCESSED  0x100
> +#define DEFAULT_PAGE_HWWRITE   0x200
> +#define DEFAULT_PAGE_SHARED    0
> 
>   #define SWP_TYPE(entry) (((entry)>>  1)&  0x7f)
>   #define SWP_OFFSET(entry) ((entry)>>  8)
> @@ -4533,6 +4556,33 @@ void ppc64_dump_machdep_table(ulong);
>    *  ppc.c
>    */
>   #ifdef PPC
> +
> +/* Holds the platform specific info for page translation */
> +struct machine_specific {
> +
> +	char *platform;
> +
> +	/* page address translation bits */
> +	int pgdir_shift;
> +	int ptrs_per_pgd;
> +	int ptrs_per_pte;
> +	int pte_size;
> +
> +	/* page flags */
> +	ulong _page_present;
> +	ulong _page_user;
> +	ulong _page_rw;
> +	ulong _page_guarded;
> +	ulong _page_coherent;
> +	ulong _page_no_cache;
> +	ulong _page_writethru;
> +	ulong _page_dirty;
> +	ulong _page_accessed;
> +	ulong _page_hwwrite;
> +	ulong _page_shared;
> +
> +};
> +	
>   void ppc_init(int);
>   void ppc_dump_machdep_table(ulong);
>   #define display_idt_table() \
> diff --git a/ppc.c b/ppc.c
> index 3834e7f..9f765b6 100755
> --- a/ppc.c
> +++ b/ppc.c
> @@ -17,6 +17,9 @@
>   #ifdef PPC
>   #include "defs.h"
> 
> +
> +#define MAX_PLATFORM_LEN	32	/* length for platform string */
> +
>   /*
>    *  This structure was copied from kernel source
>    *  in include/asm-ppc/ptrace.h
> @@ -67,6 +70,71 @@ static void ppc_display_machine_stats(void);
>   static void ppc_dump_line_number(ulong);
>   static struct line_number_hook ppc_line_number_hooks[];
> 
> +
> +static struct machine_specific ppc_machine_specific = { 0 };
> +static int probe_default_platform(char *);
> +static void ppc_probe_base_platform(void);
> +
> +typedef int (*probe_func_t) (char *);
> +
> +probe_func_t probe_platforms[] = {
> +	probe_default_platform, /* This should be at the end */
> +	NULL
> +};
> +
> +static int
> +probe_default_platform(char *name)
> +{
> +	struct machine_specific *machspec = machdep->machspec;
> +
> +	/* Use the default definitions */
> +	machspec->platform = strdup(name);
> +
> +	machspec->pgdir_shift 	= DEFAULT_PGDIR_SHIFT;
> +	machspec->ptrs_per_pgd 	= DEFAULT_PTRS_PER_PGD;
> +	machspec->ptrs_per_pte 	= DEFAULT_PTRS_PER_PTE;
> +	machspec->pte_size 	= DEFAULT_PTE_SIZE;
> +
> +	machspec->_page_present		= DEFAULT_PAGE_PRESENT;
> +	machspec->_page_user 		= DEFAULT_PAGE_USER;
> +	machspec->_page_rw 		= DEFAULT_PAGE_RW;
> +	machspec->_page_guarded 	= DEFAULT_PAGE_GUARDED;
> +	machspec->_page_coherent 	= DEFAULT_PAGE_COHERENT;
> +	machspec->_page_no_cache 	= DEFAULT_PAGE_NO_CACHE;
> +	machspec->_page_writethru 	= DEFAULT_PAGE_WRITETHRU;
> +	machspec->_page_dirty 		= DEFAULT_PAGE_DIRTY;
> +	machspec->_page_accessed 	= DEFAULT_PAGE_ACCESSED;
> +	machspec->_page_hwwrite 	= DEFAULT_PAGE_HWWRITE;
> +	machspec->_page_shared 		= DEFAULT_PAGE_SHARED;
> +	
> +
> +	return TRUE;
> +}
> +
> +/*
> + * Find the platform of the crashing system and set the
> + * base_platform accordingly.
> + */
> +void
> +ppc_probe_base_platform(void)
> +{
> +	probe_func_t probe;
> +	char platform_name[MAX_PLATFORM_LEN];
> +	ulong ptr;
> +	int i;
> +
> +	if(!try_get_symbol_data("powerpc_base_platform", sizeof(ulong),&ptr) ||
> +		read_string(ptr, platform_name, MAX_PLATFORM_LEN - 1) == 0)
> +		/* Let us fallback to default definitions */
> +		platform_name[0] = '\0';

Could you give some fallback message at PLATFORM: via 'mach' command
like "undetectable" or any good phrase?

> +	for (i = 0; probe_platforms[i] != NULL; i++) {
> +		probe = probe_platforms[i];
> +		if (probe(platform_name))
> +			break;
> +	}
> +}
> +
>   /*
>    *  Do all necessary machine-specific setup here.  This is called twice,
>    *  before and after GDB has been initialized.
> @@ -80,6 +148,7 @@ ppc_init(int when)
>   	switch (when)
>   	{
>   	case SETUP_ENV:
> +		machdep->machspec =&ppc_machine_specific;
>   		machdep->process_elf_notes = process_elf32_notes;
>   		break;
> 
> @@ -101,7 +170,6 @@ ppc_init(int when)
>                   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:
> @@ -127,6 +195,11 @@ ppc_init(int when)
>   		machdep->line_number_hooks = ppc_line_number_hooks;
>   		machdep->value_to_symbol = generic_machdep_value_to_symbol;
>                   machdep->init_kernel_pgd = NULL;
> +
> +		/* Find the platform where we crashed */
> +		ppc_probe_base_platform();
> +		machdep->ptrs_per_pgd = PTRS_PER_PGD;
> +
>   		break;
> 
>   	case POST_GDB:
> @@ -201,6 +274,7 @@ ppc_dump_machdep_table(ulong arg)
>           int others;
> 
>           others = 0;
> +	fprintf(fp, "           platform: %s\n", PPC_PLATFORM);
>           fprintf(fp, "              flags: %lx (", machdep->flags);
>   	if (machdep->flags&  KSYMS_START)
>   		fprintf(fp, "%sKSYMS_START", others++ ? "|" : "");
> @@ -212,6 +286,10 @@ ppc_dump_machdep_table(ulong arg)
>           fprintf(fp, "          pageshift: %d\n", machdep->pageshift);
>           fprintf(fp, "           pagemask: %llx\n", machdep->pagemask);
>           fprintf(fp, "         pageoffset: %lx\n", machdep->pageoffset);
> +	fprintf(fp, "        pgdir_shift: %d\n", PGDIR_SHIFT);
> +	fprintf(fp, "       ptrs_per_pgd: %d\n", PTRS_PER_PGD);
> +	fprintf(fp, "       ptrs_per_pte: %d\n", PTRS_PER_PTE);
> +	fprintf(fp, "           pte_size: %d\n", PTE_SIZE);
>   	fprintf(fp, "          stacksize: %ld\n", machdep->stacksize);
>           fprintf(fp, "                 hz: %d\n", machdep->hz);
>           fprintf(fp, "                mhz: %ld\n", machdep->mhz);
> @@ -252,7 +330,6 @@ ppc_dump_machdep_table(ulong arg)
>           fprintf(fp, "                pgd: %lx\n", (ulong)machdep->pgd);
>           fprintf(fp, "                pmd: %lx\n", (ulong)machdep->pmd);
>           fprintf(fp, "               ptbl: %lx\n", (ulong)machdep->ptbl);
> -	fprintf(fp, "       ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd);
>           fprintf(fp, "  section_size_bits: %ld\n", machdep->section_size_bits);
>           fprintf(fp, "   max_physmem_bits: %ld\n", machdep->max_physmem_bits);
>           fprintf(fp, "  sections_per_root: %ld\n", machdep->sections_per_root);
> @@ -266,15 +343,20 @@ ppc_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
>   	ulong *page_middle;
>   	ulong *page_table;
>   	ulong pgd_pte;
> -	ulong pte;
> +	ulonglong pte;
> 
> -	if (verbose)
> +	if (verbose)
>   		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
> 
>   	page_dir = pgd + (vaddr>>  PGDIR_SHIFT);
> 
> -        FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
> -        pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
> +	/*
> + 	 * Size of a pgd could be more than a PAGE.
> + 	 * So use PAGEBASE(page_dir), instead of
> + 	 * PAGEBASE(pgd) for FILL_PGD()
> + 	 */
> +        FILL_PGD(PAGEBASE((ulong)page_dir), KVADDR, PAGESIZE());
> +        pgd_pte = ULONG(machdep->pgd + PAGEOFFSET((ulong)page_dir));
> 
>   	if (verbose)
>   		fprintf(fp, "  PGD: %lx =>  %lx\n", (ulong)page_dir, pgd_pte);
> @@ -285,33 +367,37 @@ ppc_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
>   	page_middle = (ulong *)pgd_pte;
> 
>   	if (machdep->flags&  CPU_BOOKE)
> -		page_table = page_middle + (BTOP(vaddr)&  (PTRS_PER_PTE - 1));
> +		page_table = (ulong *)((ulong)page_middle + ((ulong)BTOP(vaddr)&  (PTRS_PER_PTE - 1)) * PTE_SIZE);
>   	else {
>   		page_table = (ulong *)((pgd_pte&  (ulong)machdep->pagemask) + machdep->kvbase);
> -		page_table += ((ulong)BTOP(vaddr)&  (PTRS_PER_PTE-1));
> +		page_table = (ulong *)((ulong)page_table + ((ulong)BTOP(vaddr)&  (PTRS_PER_PTE-1)) * PTE_SIZE);
>   	}
> 
>   	if (verbose)
>   		fprintf(fp, "  PMD: %lx =>  %lx\n", (ulong)page_middle,
>   			(ulong)page_table);
> 
> -        FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
> -        pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
> +        FILL_PTBL(PAGEBASE((ulong)page_table), KVADDR, PAGESIZE());
> +	if (PTE_SIZE == sizeof(ulonglong))
> +		pte = ULONGLONG(machdep->ptbl + PAGEOFFSET((ulong)page_table));
> +
> +	else	/* Defaults to ulong */
> +	        pte = ULONG(machdep->ptbl + PAGEOFFSET((ulong)page_table));
> 
>   	if (verbose)
> -		fprintf(fp, "  PTE: %lx =>  %lx\n", (ulong)page_table, pte);
> +		fprintf(fp, "  PTE: %lx =>  %llx\n", (ulong)page_table, pte);
> 
>   	if (!(pte&  _PAGE_PRESENT)) {
>   		if (pte&&  verbose) {
>   			fprintf(fp, "\n");
> -			ppc_translate_pte(pte, 0, 0);
> +			ppc_translate_pte(0, 0, pte);
>   		}
>   		goto no_page;
>   	}
> 
>   	if (verbose) {
> -		fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(pte));
> -		ppc_translate_pte(pte, 0, 0);
> +		fprintf(fp, " PAGE: %llx\n\n", PAGEBASE(pte));
> +		ppc_translate_pte(0, 0, pte);
>   	}
> 
>   	*paddr = PAGEBASE(pte) + PAGEOFFSET(vaddr);
> @@ -623,7 +709,7 @@ ppc_get_task_pgd(ulong task)
>    *  If a physaddr pointer is passed in, don't print anything.
>    */
>   static int
> -ppc_translate_pte(ulong pte, void *physaddr, ulonglong unused)
> +ppc_translate_pte(ulong unused, void *physaddr, ulonglong pte)

This change may gives impacts for existing machdep->translate_pte() users
whose external modules are possible to call with legacy prototype
machdep->translate_pte(pte, physaddr, unused) for 32bit pte.
A "unused" should be used for extended 64bit pte support in addition to
first 32bit pte support.

I think it is better for everyone to mark machdep->flags with PAE at PATCH3/4.
Maybe PAE is named for x86 but there are no differences in terms of flag 
handling.

Then declare ppc_translate_pte(ulong pte32, void *physaddr, ulonglong pte64)
so that ppc_pgd_vtop() can call with ppc_translate_pte((ulong)pte, NULL, pte)
and external users can also select similar way.

Thanks,
Toshi

>   {
>   	int c, len1, len2, len3, others, page_present;
>   	char buf[BUFSIZE];
> @@ -632,7 +718,7 @@ ppc_translate_pte(ulong pte, void *physaddr, ulonglong unused)
>   	char ptebuf[BUFSIZE];
>   	char physbuf[BUFSIZE];
>           char *arglist[MAXARGS];
> -	ulong paddr;
> +	ulonglong paddr;
> 
>           paddr = PAGEBASE(pte);
>   	page_present = (pte&  _PAGE_PRESENT);
> @@ -642,7 +728,7 @@ ppc_translate_pte(ulong pte, void *physaddr, ulonglong unused)
>   		return page_present;
>   	}
> 
> -	sprintf(ptebuf, "%lx", pte);
> +	sprintf(ptebuf, "%llx", pte);
>   	len1 = MAX(strlen(ptebuf), strlen("PTE"));
>   	fprintf(fp, "%s  ", mkstring(buf, len1, CENTER|LJUST, "PTE"));
> 
> @@ -668,7 +754,7 @@ ppc_translate_pte(ulong pte, void *physaddr, ulonglong unused)
>                   return page_present;
>           }
> 
> -	sprintf(physbuf, "%lx", paddr);
> +	sprintf(physbuf, "%llx", paddr);
>   	len2 = MAX(strlen(physbuf), strlen("PHYSICAL"));
>   	fprintf(fp, "%s  ", mkstring(buf, len2, CENTER|LJUST, "PHYSICAL"));
> 
> @@ -1509,6 +1595,7 @@ ppc_display_machine_stats(void)
>           uts =&kt->utsname;
> 
>           fprintf(fp, "       MACHINE TYPE: %s\n", uts->machine);
> +        fprintf(fp, "           PLATFORM: %s\n", PPC_PLATFORM);
>           fprintf(fp, "        MEMORY SIZE: %s\n", get_memory_size(buf));
>           fprintf(fp, "               CPUS: %d\n", kt->cpus);
>           fprintf(fp, "    PROCESSOR SPEED: ");
> 
> 




More information about the Crash-utility mailing list