diff options
Diffstat (limited to 'arch/x86/mm/dump_pagetables.c')
| -rw-r--r-- | arch/x86/mm/dump_pagetables.c | 118 | 
1 files changed, 82 insertions, 36 deletions
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index 0002a3a3308..167ffcac16e 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c @@ -30,11 +30,14 @@ struct pg_state {  	unsigned long start_address;  	unsigned long current_address;  	const struct addr_marker *marker; +	unsigned long lines; +	bool to_dmesg;  };  struct addr_marker {  	unsigned long start_address;  	const char *name; +	unsigned long max_lines;  };  /* indices for address_markers; keep sync'd w/ address_markers below */ @@ -45,6 +48,7 @@ enum address_markers_idx {  	LOW_KERNEL_NR,  	VMALLOC_START_NR,  	VMEMMAP_START_NR, +	ESPFIX_START_NR,  	HIGH_KERNEL_NR,  	MODULES_VADDR_NR,  	MODULES_END_NR, @@ -67,6 +71,7 @@ static struct addr_marker address_markers[] = {  	{ PAGE_OFFSET,		"Low Kernel Mapping" },  	{ VMALLOC_START,        "vmalloc() Area" },  	{ VMEMMAP_START,        "Vmemmap" }, +	{ ESPFIX_BASE_ADDR,	"ESPfix Area", 16 },  	{ __START_KERNEL_map,   "High Kernel Mapping" },  	{ MODULES_VADDR,        "Modules" },  	{ MODULES_END,          "End Modules" }, @@ -88,10 +93,28 @@ static struct addr_marker address_markers[] = {  #define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT)  #define PGD_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT) +#define pt_dump_seq_printf(m, to_dmesg, fmt, args...)		\ +({								\ +	if (to_dmesg)					\ +		printk(KERN_INFO fmt, ##args);			\ +	else							\ +		if (m)						\ +			seq_printf(m, fmt, ##args);		\ +}) + +#define pt_dump_cont_printf(m, to_dmesg, fmt, args...)		\ +({								\ +	if (to_dmesg)					\ +		printk(KERN_CONT fmt, ##args);			\ +	else							\ +		if (m)						\ +			seq_printf(m, fmt, ##args);		\ +}) +  /*   * Print a readable form of a pgprot_t to the seq_file   */ -static void printk_prot(struct seq_file *m, pgprot_t prot, int level) +static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)  {  	pgprotval_t pr = pgprot_val(prot);  	static const char * const level_name[] = @@ -99,47 +122,47 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level)  	if (!pgprot_val(prot)) {  		/* Not present */ -		seq_printf(m, "                          "); +		pt_dump_cont_printf(m, dmsg, "                          ");  	} else {  		if (pr & _PAGE_USER) -			seq_printf(m, "USR "); +			pt_dump_cont_printf(m, dmsg, "USR ");  		else -			seq_printf(m, "    "); +			pt_dump_cont_printf(m, dmsg, "    ");  		if (pr & _PAGE_RW) -			seq_printf(m, "RW "); +			pt_dump_cont_printf(m, dmsg, "RW ");  		else -			seq_printf(m, "ro "); +			pt_dump_cont_printf(m, dmsg, "ro ");  		if (pr & _PAGE_PWT) -			seq_printf(m, "PWT "); +			pt_dump_cont_printf(m, dmsg, "PWT ");  		else -			seq_printf(m, "    "); +			pt_dump_cont_printf(m, dmsg, "    ");  		if (pr & _PAGE_PCD) -			seq_printf(m, "PCD "); +			pt_dump_cont_printf(m, dmsg, "PCD ");  		else -			seq_printf(m, "    "); +			pt_dump_cont_printf(m, dmsg, "    ");  		/* Bit 9 has a different meaning on level 3 vs 4 */  		if (level <= 3) {  			if (pr & _PAGE_PSE) -				seq_printf(m, "PSE "); +				pt_dump_cont_printf(m, dmsg, "PSE ");  			else -				seq_printf(m, "    "); +				pt_dump_cont_printf(m, dmsg, "    ");  		} else {  			if (pr & _PAGE_PAT) -				seq_printf(m, "pat "); +				pt_dump_cont_printf(m, dmsg, "pat ");  			else -				seq_printf(m, "    "); +				pt_dump_cont_printf(m, dmsg, "    ");  		}  		if (pr & _PAGE_GLOBAL) -			seq_printf(m, "GLB "); +			pt_dump_cont_printf(m, dmsg, "GLB ");  		else -			seq_printf(m, "    "); +			pt_dump_cont_printf(m, dmsg, "    ");  		if (pr & _PAGE_NX) -			seq_printf(m, "NX "); +			pt_dump_cont_printf(m, dmsg, "NX ");  		else -			seq_printf(m, "x  "); +			pt_dump_cont_printf(m, dmsg, "x  ");  	} -	seq_printf(m, "%s\n", level_name[level]); +	pt_dump_cont_printf(m, dmsg, "%s\n", level_name[level]);  }  /* @@ -163,7 +186,7 @@ static void note_page(struct seq_file *m, struct pg_state *st,  		      pgprot_t new_prot, int level)  {  	pgprotval_t prot, cur; -	static const char units[] = "KMGTPE"; +	static const char units[] = "BKMGTPE";  	/*  	 * If we have a "break" in the series, we need to flush the state that @@ -178,7 +201,9 @@ static void note_page(struct seq_file *m, struct pg_state *st,  		st->current_prot = new_prot;  		st->level = level;  		st->marker = address_markers; -		seq_printf(m, "---[ %s ]---\n", st->marker->name); +		st->lines = 0; +		pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", +				   st->marker->name);  	} else if (prot != cur || level != st->level ||  		   st->current_address >= st->marker[1].start_address) {  		const char *unit = units; @@ -188,17 +213,24 @@ static void note_page(struct seq_file *m, struct pg_state *st,  		/*  		 * Now print the actual finished series  		 */ -		seq_printf(m, "0x%0*lx-0x%0*lx   ", -			   width, st->start_address, -			   width, st->current_address); - -		delta = (st->current_address - st->start_address) >> 10; -		while (!(delta & 1023) && unit[1]) { -			delta >>= 10; -			unit++; +		if (!st->marker->max_lines || +		    st->lines < st->marker->max_lines) { +			pt_dump_seq_printf(m, st->to_dmesg, +					   "0x%0*lx-0x%0*lx   ", +					   width, st->start_address, +					   width, st->current_address); + +			delta = st->current_address - st->start_address; +			while (!(delta & 1023) && unit[1]) { +				delta >>= 10; +				unit++; +			} +			pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ", +					    delta, *unit); +			printk_prot(m, st->current_prot, st->level, +				    st->to_dmesg);  		} -		seq_printf(m, "%9lu%c ", delta, *unit); -		printk_prot(m, st->current_prot, st->level); +		st->lines++;  		/*  		 * We print markers for special areas of address space, @@ -206,8 +238,19 @@ static void note_page(struct seq_file *m, struct pg_state *st,  		 * This helps in the interpretation.  		 */  		if (st->current_address >= st->marker[1].start_address) { +			if (st->marker->max_lines && +			    st->lines > st->marker->max_lines) { +				unsigned long nskip = +					st->lines - st->marker->max_lines; +				pt_dump_seq_printf(m, st->to_dmesg, +						   "... %lu entr%s skipped ... \n", +						   nskip, +						   nskip == 1 ? "y" : "ies"); +			}  			st->marker++; -			seq_printf(m, "---[ %s ]---\n", st->marker->name); +			st->lines = 0; +			pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", +					   st->marker->name);  		}  		st->start_address = st->current_address; @@ -296,7 +339,7 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,  #define pgd_none(a)  pud_none(__pud(pgd_val(a)))  #endif -static void walk_pgd_level(struct seq_file *m) +void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)  {  #ifdef CONFIG_X86_64  	pgd_t *start = (pgd_t *) &init_level4_pgt; @@ -304,9 +347,12 @@ static void walk_pgd_level(struct seq_file *m)  	pgd_t *start = swapper_pg_dir;  #endif  	int i; -	struct pg_state st; +	struct pg_state st = {}; -	memset(&st, 0, sizeof(st)); +	if (pgd) { +		start = pgd; +		st.to_dmesg = true; +	}  	for (i = 0; i < PTRS_PER_PGD; i++) {  		st.current_address = normalize_addr(i * PGD_LEVEL_MULT); @@ -331,7 +377,7 @@ static void walk_pgd_level(struct seq_file *m)  static int ptdump_show(struct seq_file *m, void *v)  { -	walk_pgd_level(m); +	ptdump_walk_pgd_level(m, NULL);  	return 0;  }  | 
