mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [patch 0/2] x86_64: preserve large page text mappings with CONFIG_DEBUG_RODATA
@ 2009-10-14 21:46 Suresh Siddha
  2009-10-14 21:46 ` [patch 1/2] x86_64: preserve large page mapping for 1st 2MB kernel txt " Suresh Siddha
  2009-10-14 21:46 ` [patch 2/2] x86_64: align RODATA kernel section to 2MB " Suresh Siddha
  0 siblings, 2 replies; 7+ messages in thread
From: Suresh Siddha @ 2009-10-14 21:46 UTC (permalink / raw)
  To: hpa, mingo, tglx, arjan; +Cc: linux-kernel, chinang.ma

Most of the distributions enable CONFIG_DEBUG_RODATA by default, with the
assumption that the debug protection checks come with no cost. Our OLTP tests
showed 1% improvement (with 2% reduction in system time and 1% increase in
iowait idle time) by disabling CONFIG_DEBUG_RODATA on a two socket
NHM-EP system.

CONFIG_DEBUG_RODATA breaks some of the kernel text/data large page
mappings to small pages, thus causing this regression. These two
patches address this issue.

Experiments with EL5 kernel and mainline show that the first patch in the series
(preserve large page mapping for 1st 2MB kernel txt with CONFIG_DEBUG_RODATA)
should recover most of the above mentioned regression. We are doing
couple of more OLTP tests for the confirmation.

thanks,
suresh


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [patch 1/2] x86_64: preserve large page mapping for 1st 2MB kernel txt with CONFIG_DEBUG_RODATA
  2009-10-14 21:46 [patch 0/2] x86_64: preserve large page text mappings with CONFIG_DEBUG_RODATA Suresh Siddha
@ 2009-10-14 21:46 ` Suresh Siddha
  2009-10-24  1:03   ` [tip:branch?] x86-64: " tip-bot for Suresh Siddha
  2009-10-14 21:46 ` [patch 2/2] x86_64: align RODATA kernel section to 2MB " Suresh Siddha
  1 sibling, 1 reply; 7+ messages in thread
From: Suresh Siddha @ 2009-10-14 21:46 UTC (permalink / raw)
  To: hpa, mingo, tglx, arjan; +Cc: linux-kernel, chinang.ma, Suresh Siddha

[-- Attachment #1: prevent_kernel_text_lp.patch --]
[-- Type: text/plain, Size: 2438 bytes --]

In the first 2MB, kernel text is co-located with kernel static
page tables setup by head_64.S.  CONFIG_DEBUG_RODATA chops this
2MB large page mapping to small 4KB pages as we mark the kernel text as RO,
leaving the static page tables as RW.

With CONFIG_DEBUG_RODATA disabled, OLTP run on NHM-EP shows 1% improvement
with 2% reduction in system time and 1% improvement in iowait idle time.

To recover this, move the kernel static page tables to .data section, so that
we don't have to break the first 2MB of kernel text to small pages with
CONFIG_DEBUG_RODATA.

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
---
 arch/x86/kernel/head_64.S |    3 ++-
 arch/x86/mm/init_64.c     |    6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)

Index: tree/arch/x86/kernel/head_64.S
===================================================================
--- tree.orig/arch/x86/kernel/head_64.S
+++ tree/arch/x86/kernel/head_64.S
@@ -262,11 +262,11 @@ ENTRY(secondary_startup_64)
 	.quad	x86_64_start_kernel
 	ENTRY(initial_gs)
 	.quad	INIT_PER_CPU_VAR(irq_stack_union)
-	__FINITDATA
 
 	ENTRY(stack_start)
 	.quad  init_thread_union+THREAD_SIZE-8
 	.word  0
+	__FINITDATA
 
 bad_address:
 	jmp bad_address
@@ -340,6 +340,7 @@ ENTRY(name)
 	i = i + 1 ;					\
 	.endr
 
+	.data
 	/*
 	 * This default setting generates an ident mapping at address 0x100000
 	 * and a mapping for the kernel that precisely maps virtual address
Index: tree/arch/x86/mm/init_64.c
===================================================================
--- tree.orig/arch/x86/mm/init_64.c
+++ tree/arch/x86/mm/init_64.c
@@ -698,7 +698,7 @@ static int kernel_set_to_readonly;
 
 void set_kernel_text_rw(void)
 {
-	unsigned long start = PFN_ALIGN(_stext);
+	unsigned long start = PFN_ALIGN(_text);
 	unsigned long end = PFN_ALIGN(__start_rodata);
 
 	if (!kernel_set_to_readonly)
@@ -712,7 +712,7 @@ void set_kernel_text_rw(void)
 
 void set_kernel_text_ro(void)
 {
-	unsigned long start = PFN_ALIGN(_stext);
+	unsigned long start = PFN_ALIGN(_text);
 	unsigned long end = PFN_ALIGN(__start_rodata);
 
 	if (!kernel_set_to_readonly)
@@ -726,7 +726,7 @@ void set_kernel_text_ro(void)
 
 void mark_rodata_ro(void)
 {
-	unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata);
+	unsigned long start = PFN_ALIGN(_text), end = PFN_ALIGN(__end_rodata);
 	unsigned long rodata_start =
 		((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
 



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [patch 2/2] x86_64: align RODATA kernel section to 2MB with CONFIG_DEBUG_RODATA
  2009-10-14 21:46 [patch 0/2] x86_64: preserve large page text mappings with CONFIG_DEBUG_RODATA Suresh Siddha
  2009-10-14 21:46 ` [patch 1/2] x86_64: preserve large page mapping for 1st 2MB kernel txt " Suresh Siddha
@ 2009-10-14 21:46 ` Suresh Siddha
  2009-10-15  3:24   ` Sam Ravnborg
  2009-10-24  1:03   ` [tip:branch?] x86-64: " tip-bot for Suresh Siddha
  1 sibling, 2 replies; 7+ messages in thread
From: Suresh Siddha @ 2009-10-14 21:46 UTC (permalink / raw)
  To: hpa, mingo, tglx, arjan; +Cc: linux-kernel, chinang.ma, Suresh Siddha

[-- Attachment #1: align_rodata_hpage.patch --]
[-- Type: text/plain, Size: 4819 bytes --]

CONFIG_DEBUG_RODATA chops the large pages spanning boundaries of kernel
text/rodata/data to small 4KB pages as they are mapped with different
attributes (text as RO, RODATA as RO and NX etc).

On x86_64, preserve the large page mappings for kernel text/rodata/data
boundaries when CONFIG_DEBUG_RODATA is enabled. This is done by allowing the
RODATA section to be hugepage aligned and having same RWX attributes
for the 2MB page boundaries

Extra Memory pages padding the sections will be freed during the end of the boot
and the kernel identity mappings will have different RWX permissions compared to
the kernel text mappings.

Kernel identity mappings to these physical pages will be mapped with smaller
pages but large page mappings are still retained for kernel text,rodata,data
mappings.

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
---
 arch/x86/include/asm/sections.h |    6 ++++++
 arch/x86/kernel/vmlinux.lds.S   |   17 +++++++++++++++++
 arch/x86/mm/init_64.c           |   14 +++++++++++++-
 arch/x86/mm/pageattr.c          |   14 ++++++++++++++
 4 files changed, 50 insertions(+), 1 deletion(-)

Index: tree/arch/x86/include/asm/sections.h
===================================================================
--- tree.orig/arch/x86/include/asm/sections.h
+++ tree/arch/x86/include/asm/sections.h
@@ -2,7 +2,13 @@
 #define _ASM_X86_SECTIONS_H
 
 #include <asm-generic/sections.h>
+#include <asm/uaccess.h>
 
 extern char __brk_base[], __brk_limit[];
+extern struct exception_table_entry __stop___ex_table[];
+
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+extern char __end_rodata_hpage_align[];
+#endif
 
 #endif	/* _ASM_X86_SECTIONS_H */
Index: tree/arch/x86/kernel/vmlinux.lds.S
===================================================================
--- tree.orig/arch/x86/kernel/vmlinux.lds.S
+++ tree/arch/x86/kernel/vmlinux.lds.S
@@ -41,6 +41,21 @@ ENTRY(phys_startup_64)
 jiffies_64 = jiffies;
 #endif
 
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+
+#define X64_ALIGN_DEBUG_RODATA_BEGIN	. = ALIGN(HPAGE_SIZE);
+
+#define X64_ALIGN_DEBUG_RODATA_END				\
+		. = ALIGN(HPAGE_SIZE);				\
+		__end_rodata_hpage_align = .;
+
+#else
+
+#define X64_ALIGN_DEBUG_RODATA_BEGIN
+#define X64_ALIGN_DEBUG_RODATA_END
+
+#endif
+
 PHDRS {
 	text PT_LOAD FLAGS(5);          /* R_E */
 	data PT_LOAD FLAGS(7);          /* RWE */
@@ -90,7 +105,9 @@ SECTIONS
 
 	EXCEPTION_TABLE(16) :text = 0x9090
 
+	X64_ALIGN_DEBUG_RODATA_BEGIN
 	RO_DATA(PAGE_SIZE)
+	X64_ALIGN_DEBUG_RODATA_END
 
 	/* Data */
 	.data : AT(ADDR(.data) - LOAD_OFFSET) {
Index: tree/arch/x86/mm/init_64.c
===================================================================
--- tree.orig/arch/x86/mm/init_64.c
+++ tree/arch/x86/mm/init_64.c
@@ -726,9 +726,13 @@ void set_kernel_text_ro(void)
 
 void mark_rodata_ro(void)
 {
-	unsigned long start = PFN_ALIGN(_text), end = PFN_ALIGN(__end_rodata);
+	unsigned long start = PFN_ALIGN(_text);
 	unsigned long rodata_start =
 		((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
+	unsigned long end = (unsigned long) &__end_rodata_hpage_align;
+	unsigned long text_end = PAGE_ALIGN((unsigned long) &__stop___ex_table);
+	unsigned long rodata_end = PAGE_ALIGN((unsigned long) &__end_rodata);
+	unsigned long data_start = (unsigned long) &_sdata;
 
 	printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
 	       (end - start) >> 10);
@@ -751,6 +755,14 @@ void mark_rodata_ro(void)
 	printk(KERN_INFO "Testing CPA: again\n");
 	set_memory_ro(start, (end-start) >> PAGE_SHIFT);
 #endif
+
+	free_init_pages("unused kernel memory",
+			(unsigned long) page_address(virt_to_page(text_end)),
+			(unsigned long)
+				 page_address(virt_to_page(rodata_start)));
+	free_init_pages("unused kernel memory",
+			(unsigned long) page_address(virt_to_page(rodata_end)),
+			(unsigned long) page_address(virt_to_page(data_start)));
 }
 
 #endif
Index: tree/arch/x86/mm/pageattr.c
===================================================================
--- tree.orig/arch/x86/mm/pageattr.c
+++ tree/arch/x86/mm/pageattr.c
@@ -279,6 +279,20 @@ static inline pgprot_t static_protection
 		   __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
 		pgprot_val(forbidden) |= _PAGE_RW;
 
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+	/*
+	 * Kernel text mappings for the large page aligned .rodata section
+	 * will be read-only. For the kernel identity mappings covering
+	 * the holes caused by this alignment can be anything.
+	 *
+	 * This will preserve the large page mappings for kernel text/data
+	 * at no extra cost.
+	 */
+	if (within(address, (unsigned long)_text,
+		   (unsigned long)__end_rodata_hpage_align))
+		pgprot_val(forbidden) |= _PAGE_RW;
+#endif
+
 	prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
 
 	return prot;



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch 2/2] x86_64: align RODATA kernel section to 2MB with CONFIG_DEBUG_RODATA
  2009-10-14 21:46 ` [patch 2/2] x86_64: align RODATA kernel section to 2MB " Suresh Siddha
@ 2009-10-15  3:24   ` Sam Ravnborg
  2009-10-15 20:23     ` Suresh Siddha
  2009-10-24  1:03   ` [tip:branch?] x86-64: " tip-bot for Suresh Siddha
  1 sibling, 1 reply; 7+ messages in thread
From: Sam Ravnborg @ 2009-10-15  3:24 UTC (permalink / raw)
  To: Suresh Siddha; +Cc: hpa, mingo, tglx, arjan, linux-kernel, chinang.ma

> Index: tree/arch/x86/include/asm/sections.h
> ===================================================================
> --- tree.orig/arch/x86/include/asm/sections.h
> +++ tree/arch/x86/include/asm/sections.h
> @@ -2,7 +2,13 @@
>  #define _ASM_X86_SECTIONS_H
>  
>  #include <asm-generic/sections.h>
> +#include <asm/uaccess.h>
>  
>  extern char __brk_base[], __brk_limit[];
> +extern struct exception_table_entry __stop___ex_table[];
> +
> +#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
> +extern char __end_rodata_hpage_align[];
> +#endif
>  
>  #endif	/* _ASM_X86_SECTIONS_H */
> Index: tree/arch/x86/kernel/vmlinux.lds.S
> ===================================================================
> --- tree.orig/arch/x86/kernel/vmlinux.lds.S
> +++ tree/arch/x86/kernel/vmlinux.lds.S
> @@ -41,6 +41,21 @@ ENTRY(phys_startup_64)
>  jiffies_64 = jiffies;
>  #endif
>  
> +#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
> +
> +#define X64_ALIGN_DEBUG_RODATA_BEGIN	. = ALIGN(HPAGE_SIZE);
> +
> +#define X64_ALIGN_DEBUG_RODATA_END				\
> +		. = ALIGN(HPAGE_SIZE);				\
> +		__end_rodata_hpage_align = .;
This symbol is only defined if CONFIG_DEBUG_RODATA is defined, but (see below).

> +
> +#else
> +
> +#define X64_ALIGN_DEBUG_RODATA_BEGIN
> +#define X64_ALIGN_DEBUG_RODATA_END
> +
> +#endif

A coment describing the purpose of
this would be nice.

> +
>  PHDRS {
>  	text PT_LOAD FLAGS(5);          /* R_E */
>  	data PT_LOAD FLAGS(7);          /* RWE */
> @@ -90,7 +105,9 @@ SECTIONS
>  
>  	EXCEPTION_TABLE(16) :text = 0x9090
>  
> +	X64_ALIGN_DEBUG_RODATA_BEGIN
>  	RO_DATA(PAGE_SIZE)
> +	X64_ALIGN_DEBUG_RODATA_END
>  
>  	/* Data */
>  	.data : AT(ADDR(.data) - LOAD_OFFSET) {
> Index: tree/arch/x86/mm/init_64.c
> ===================================================================
> --- tree.orig/arch/x86/mm/init_64.c
> +++ tree/arch/x86/mm/init_64.c
> @@ -726,9 +726,13 @@ void set_kernel_text_ro(void)
>  
>  void mark_rodata_ro(void)
>  {
> -	unsigned long start = PFN_ALIGN(_text), end = PFN_ALIGN(__end_rodata);
> +	unsigned long start = PFN_ALIGN(_text);
>  	unsigned long rodata_start =
>  		((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
> +	unsigned long end = (unsigned long) &__end_rodata_hpage_align;
Here the symbol seems to be referenced unconditionally.

	Sam

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch 2/2] x86_64: align RODATA kernel section to 2MB with CONFIG_DEBUG_RODATA
  2009-10-15  3:24   ` Sam Ravnborg
@ 2009-10-15 20:23     ` Suresh Siddha
  0 siblings, 0 replies; 7+ messages in thread
From: Suresh Siddha @ 2009-10-15 20:23 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: hpa, mingo, tglx, arjan, linux-kernel, Ma, Chinang

On Wed, 2009-10-14 at 20:24 -0700, Sam Ravnborg wrote:
> > +#else
> > +
> > +#define X64_ALIGN_DEBUG_RODATA_BEGIN
> > +#define X64_ALIGN_DEBUG_RODATA_END
> > +
> > +#endif
> 
> A coment describing the purpose of
> this would be nice.

I will update this in the next version of the patch.

> > @@ -726,9 +726,13 @@ void set_kernel_text_ro(void)
> >  
> >  void mark_rodata_ro(void)
> >  {
> > -	unsigned long start = PFN_ALIGN(_text), end = PFN_ALIGN(__end_rodata);
> > +	unsigned long start = PFN_ALIGN(_text);
> >  	unsigned long rodata_start =
> >  		((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
> > +	unsigned long end = (unsigned long) &__end_rodata_hpage_align;
> Here the symbol seems to be referenced unconditionally.

This function is defined only for CONFIG_DEBUG_RODATA.

thanks,
suresh


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [tip:branch?] x86-64: preserve large page mapping for 1st 2MB kernel txt with CONFIG_DEBUG_RODATA
  2009-10-14 21:46 ` [patch 1/2] x86_64: preserve large page mapping for 1st 2MB kernel txt " Suresh Siddha
@ 2009-10-24  1:03   ` tip-bot for Suresh Siddha
  0 siblings, 0 replies; 7+ messages in thread
From: tip-bot for Suresh Siddha @ 2009-10-24  1:03 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, suresh.b.siddha, tglx

Commit-ID:  b9af7c0d44b8bb71e3af5e94688d076414aa8c87
Gitweb:     http://git.kernel.org/tip/b9af7c0d44b8bb71e3af5e94688d076414aa8c87
Author:     Suresh Siddha <suresh.b.siddha@intel.com>
AuthorDate: Wed, 14 Oct 2009 14:46:55 -0700
Committer:  H. Peter Anvin <hpa@zytor.com>
CommitDate: Tue, 20 Oct 2009 14:46:00 +0900

x86-64: preserve large page mapping for 1st 2MB kernel txt with CONFIG_DEBUG_RODATA

In the first 2MB, kernel text is co-located with kernel static
page tables setup by head_64.S.  CONFIG_DEBUG_RODATA chops this
2MB large page mapping to small 4KB pages as we mark the kernel text as RO,
leaving the static page tables as RW.

With CONFIG_DEBUG_RODATA disabled, OLTP run on NHM-EP shows 1% improvement
with 2% reduction in system time and 1% improvement in iowait idle time.

To recover this, move the kernel static page tables to .data section, so that
we don't have to break the first 2MB of kernel text to small pages with
CONFIG_DEBUG_RODATA.

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
LKML-Reference: <20091014220254.063193621@sbs-t61.sc.intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
---
 arch/x86/kernel/head_64.S |    3 ++-
 arch/x86/mm/init_64.c     |    6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 780cd92..b55ee4f 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -262,11 +262,11 @@ ENTRY(secondary_startup_64)
 	.quad	x86_64_start_kernel
 	ENTRY(initial_gs)
 	.quad	INIT_PER_CPU_VAR(irq_stack_union)
-	__FINITDATA
 
 	ENTRY(stack_start)
 	.quad  init_thread_union+THREAD_SIZE-8
 	.word  0
+	__FINITDATA
 
 bad_address:
 	jmp bad_address
@@ -340,6 +340,7 @@ ENTRY(name)
 	i = i + 1 ;					\
 	.endr
 
+	.data
 	/*
 	 * This default setting generates an ident mapping at address 0x100000
 	 * and a mapping for the kernel that precisely maps virtual address
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index c20d30b..7dafd41 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -699,7 +699,7 @@ static int kernel_set_to_readonly;
 
 void set_kernel_text_rw(void)
 {
-	unsigned long start = PFN_ALIGN(_stext);
+	unsigned long start = PFN_ALIGN(_text);
 	unsigned long end = PFN_ALIGN(__start_rodata);
 
 	if (!kernel_set_to_readonly)
@@ -713,7 +713,7 @@ void set_kernel_text_rw(void)
 
 void set_kernel_text_ro(void)
 {
-	unsigned long start = PFN_ALIGN(_stext);
+	unsigned long start = PFN_ALIGN(_text);
 	unsigned long end = PFN_ALIGN(__start_rodata);
 
 	if (!kernel_set_to_readonly)
@@ -727,7 +727,7 @@ void set_kernel_text_ro(void)
 
 void mark_rodata_ro(void)
 {
-	unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata);
+	unsigned long start = PFN_ALIGN(_text), end = PFN_ALIGN(__end_rodata);
 	unsigned long rodata_start =
 		((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [tip:branch?] x86-64: align RODATA kernel section to 2MB with CONFIG_DEBUG_RODATA
  2009-10-14 21:46 ` [patch 2/2] x86_64: align RODATA kernel section to 2MB " Suresh Siddha
  2009-10-15  3:24   ` Sam Ravnborg
@ 2009-10-24  1:03   ` tip-bot for Suresh Siddha
  1 sibling, 0 replies; 7+ messages in thread
From: tip-bot for Suresh Siddha @ 2009-10-24  1:03 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, suresh.b.siddha, tglx

Commit-ID:  74e081797bd9d2a7d8005fe519e719df343a2ba8
Gitweb:     http://git.kernel.org/tip/74e081797bd9d2a7d8005fe519e719df343a2ba8
Author:     Suresh Siddha <suresh.b.siddha@intel.com>
AuthorDate: Wed, 14 Oct 2009 14:46:56 -0700
Committer:  H. Peter Anvin <hpa@zytor.com>
CommitDate: Tue, 20 Oct 2009 14:46:00 +0900

x86-64: align RODATA kernel section to 2MB with CONFIG_DEBUG_RODATA

CONFIG_DEBUG_RODATA chops the large pages spanning boundaries of kernel
text/rodata/data to small 4KB pages as they are mapped with different
attributes (text as RO, RODATA as RO and NX etc).

On x86_64, preserve the large page mappings for kernel text/rodata/data
boundaries when CONFIG_DEBUG_RODATA is enabled. This is done by allowing the
RODATA section to be hugepage aligned and having same RWX attributes
for the 2MB page boundaries

Extra Memory pages padding the sections will be freed during the end of the boot
and the kernel identity mappings will have different RWX permissions compared to
the kernel text mappings.

Kernel identity mappings to these physical pages will be mapped with smaller
pages but large page mappings are still retained for kernel text,rodata,data
mappings.

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
LKML-Reference: <20091014220254.190119924@sbs-t61.sc.intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
---
 arch/x86/include/asm/sections.h |    6 ++++++
 arch/x86/kernel/vmlinux.lds.S   |   17 +++++++++++++++++
 arch/x86/mm/init_64.c           |   14 +++++++++++++-
 arch/x86/mm/pageattr.c          |   14 ++++++++++++++
 4 files changed, 50 insertions(+), 1 deletions(-)

diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h
index 1b7ee5d..0a52424 100644
--- a/arch/x86/include/asm/sections.h
+++ b/arch/x86/include/asm/sections.h
@@ -2,7 +2,13 @@
 #define _ASM_X86_SECTIONS_H
 
 #include <asm-generic/sections.h>
+#include <asm/uaccess.h>
 
 extern char __brk_base[], __brk_limit[];
+extern struct exception_table_entry __stop___ex_table[];
+
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+extern char __end_rodata_hpage_align[];
+#endif
 
 #endif	/* _ASM_X86_SECTIONS_H */
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 92929fb..1476379 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -41,6 +41,21 @@ ENTRY(phys_startup_64)
 jiffies_64 = jiffies;
 #endif
 
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+
+#define X64_ALIGN_DEBUG_RODATA_BEGIN	. = ALIGN(HPAGE_SIZE);
+
+#define X64_ALIGN_DEBUG_RODATA_END				\
+		. = ALIGN(HPAGE_SIZE);				\
+		__end_rodata_hpage_align = .;
+
+#else
+
+#define X64_ALIGN_DEBUG_RODATA_BEGIN
+#define X64_ALIGN_DEBUG_RODATA_END
+
+#endif
+
 PHDRS {
 	text PT_LOAD FLAGS(5);          /* R_E */
 	data PT_LOAD FLAGS(7);          /* RWE */
@@ -90,7 +105,9 @@ SECTIONS
 
 	EXCEPTION_TABLE(16) :text = 0x9090
 
+	X64_ALIGN_DEBUG_RODATA_BEGIN
 	RO_DATA(PAGE_SIZE)
+	X64_ALIGN_DEBUG_RODATA_END
 
 	/* Data */
 	.data : AT(ADDR(.data) - LOAD_OFFSET) {
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 7dafd41..0ed09fa 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -727,9 +727,13 @@ void set_kernel_text_ro(void)
 
 void mark_rodata_ro(void)
 {
-	unsigned long start = PFN_ALIGN(_text), end = PFN_ALIGN(__end_rodata);
+	unsigned long start = PFN_ALIGN(_text);
 	unsigned long rodata_start =
 		((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
+	unsigned long end = (unsigned long) &__end_rodata_hpage_align;
+	unsigned long text_end = PAGE_ALIGN((unsigned long) &__stop___ex_table);
+	unsigned long rodata_end = PAGE_ALIGN((unsigned long) &__end_rodata);
+	unsigned long data_start = (unsigned long) &_sdata;
 
 	printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
 	       (end - start) >> 10);
@@ -752,6 +756,14 @@ void mark_rodata_ro(void)
 	printk(KERN_INFO "Testing CPA: again\n");
 	set_memory_ro(start, (end-start) >> PAGE_SHIFT);
 #endif
+
+	free_init_pages("unused kernel memory",
+			(unsigned long) page_address(virt_to_page(text_end)),
+			(unsigned long)
+				 page_address(virt_to_page(rodata_start)));
+	free_init_pages("unused kernel memory",
+			(unsigned long) page_address(virt_to_page(rodata_end)),
+			(unsigned long) page_address(virt_to_page(data_start)));
 }
 
 #endif
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index dd38bfb..b494fc4 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -279,6 +279,20 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
 		   __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
 		pgprot_val(forbidden) |= _PAGE_RW;
 
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+	/*
+	 * Kernel text mappings for the large page aligned .rodata section
+	 * will be read-only. For the kernel identity mappings covering
+	 * the holes caused by this alignment can be anything.
+	 *
+	 * This will preserve the large page mappings for kernel text/data
+	 * at no extra cost.
+	 */
+	if (within(address, (unsigned long)_text,
+		   (unsigned long)__end_rodata_hpage_align))
+		pgprot_val(forbidden) |= _PAGE_RW;
+#endif
+
 	prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
 
 	return prot;

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2009-10-24  1:04 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-10-14 21:46 [patch 0/2] x86_64: preserve large page text mappings with CONFIG_DEBUG_RODATA Suresh Siddha
2009-10-14 21:46 ` [patch 1/2] x86_64: preserve large page mapping for 1st 2MB kernel txt " Suresh Siddha
2009-10-24  1:03   ` [tip:branch?] x86-64: " tip-bot for Suresh Siddha
2009-10-14 21:46 ` [patch 2/2] x86_64: align RODATA kernel section to 2MB " Suresh Siddha
2009-10-15  3:24   ` Sam Ravnborg
2009-10-15 20:23     ` Suresh Siddha
2009-10-24  1:03   ` [tip:branch?] x86-64: " tip-bot for Suresh Siddha

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome