Skip to contentSkip to conversation

objtool/x86: noinstr vs PARAVIRT

PATCH Applied Peter Zijlstra 7 participants 101 messages Jun 24, 2021 – Sep 17, 2021 1 message not in the archive

Subsystems (14)
x86 Kbuild Kselftest Library code +10 more subsystems
lore
Share & tools
lore

Peter Zijlstra

author maintainer
#0 lore raw

v2 cover objtool/x86: noinstr vs PARAVIRT

Hi,

Per long standing request from Thomas, this makes the noinstr validation work with PARAVIRT=y.

It isn't exactly pretty, but it does work.

With all this on top of tip/master (which includes some of the previous round), all (*) the robots seem to get is endless garbage like:

vmlinux.o: warning: objtool: __rdgsbase_inactive()+0x24: call to ftrace_likely_update() leaves .noinstr.text section

And my secret plan is to pull the KPTI CR3 swizzling into C such that all that will insta explode and become unfixable.

Steve, can I please delete TRACE_BRANCH_PROFILING and PROFILE_ALL_BRANCHES already?

(*) there were also a few reports from 0day running out of memory.

author maintainer
#1 lore raw

PATCH v2 1/24 x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

The asm_cpu_bringup_and_idle() function is required to push the return value on the stack in order to make ORC happy, but the only reason objtool doesn't complain is because of a happy accident.

The thing is that asm_cpu_bringup_and_idle() doesn't return, so validate_branch() never terminates and falls through to the next function, which in the normal case is the hypercall_page. And that, as it happens, is 4095 NOPs and a RET.

Make asm_cpu_bringup_and_idle() terminate on it's own, by making the function it calls as a dead-end. This way we no longer rely on what code happens to come after.

Fixes c3881eb58d56 ("x86/xen: Make the secondary CPU idle tasks reliable")
---
 tools/objtool/check.c |    1 +
 1 file changed, 1 insertion(+)
tools/objtool/check.c +1 -0
@@ -177,6 +177,7 @@ static bool __dead_end_function(struct o
 		"rewind_stack_do_exit",
 		"kunit_try_catch_throw",
 		"xen_start_kernel",
+		"cpu_bringup_and_idle",
 	};
 
 	if (!func)
maintainer Reviewed-by on v2 1/24
#2 lore raw

Re: [PATCH v2 01/24] x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

Quoted 9 lines · Peter Zijlstra

The asm_cpu_bringup_and_idle() function is required to push the return value on the stack in order to make ORC happy, but the only reason objtool doesn't complain is because of a happy accident.

The thing is that asm_cpu_bringup_and_idle() doesn't return, so validate_branch() never terminates and falls through to the next function, which in the normal case is the hypercall_page. And that, as it happens, is 4095 NOPs and a RET.

Quoted 6 lines

Make asm_cpu_bringup_and_idle() terminate on it's own, by making the function it calls as a dead-end. This way we no longer rely on what code happens to come after.

Fixes c3881eb58d56 ("x86/xen: Make the secondary CPU idle tasks reliable")

Juergen

Reviewed-by on v2 1/24
#3 lore raw

Re: [PATCH v2 01/24] x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

In reply to Peter Zijlstra
Quoted 9 lines · Peter Zijlstra

The asm_cpu_bringup_and_idle() function is required to push the return value on the stack in order to make ORC happy, but the only reason objtool doesn't complain is because of a happy accident.

The thing is that asm_cpu_bringup_and_idle() doesn't return, so validate_branch() never terminates and falls through to the next function, which in the normal case is the hypercall_page. And that, as it happens, is 4095 NOPs and a RET.

Quoted 6 lines

Make asm_cpu_bringup_and_idle() terminate on it's own, by making the function it calls as a dead-end. This way we no longer rely on what code happens to come after.

Fixes c3881eb58d56 ("x86/xen: Make the secondary CPU idle tasks reliable")

M

#4 lore raw

Re: [PATCH v2 01/24] x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

In reply to Peter Zijlstra
Quoted 9 lines · Peter Zijlstra

The asm_cpu_bringup_and_idle() function is required to push the return value on the stack in order to make ORC happy, but the only reason objtool doesn't complain is because of a happy accident.

The thing is that asm_cpu_bringup_and_idle() doesn't return, so validate_branch() never terminates and falls through to the next function, which in the normal case is the hypercall_page. And that, as it happens, is 4095 NOPs and a RET.

Quoted 6 lines

Make asm_cpu_bringup_and_idle() terminate on it's own, by making the function it calls as a dead-end. This way we no longer rely on what code happens to come after.

Fixes c3881eb58d56 ("x86/xen: Make the secondary CPU idle tasks reliable")

Looks right. Only problem is, with my assembler I get this:

arch/x86/kernel/head_64.o: warning: objtool: .text+0x5: unreachable instruction

Because gas insists on jumping over the page of nops...

0000000000000000 <asm_cpu_bringup_and_idle>:

       0:	e8 00 00 00 00       	callq  5 <asm_cpu_bringup_and_idle+0x5>
			1: R_X86_64_PLT32	cpu_bringup_and_idle-0x4
       5:	e9 f6 0f 00 00       	jmpq   1000 <xen_hypercall_set_trap_table>
       a:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      11:	00 00 00 00 
      15:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      1c:	00 00 00 00 
      20:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      27:	00 00 00 00 
      2b:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      32:	00 00 00 00 
      36:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      3d:	00 00 00 00 
Signature · 1 line
Josh
#5 lore raw

Re: [PATCH v2 01/24] x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

Quoted 24 lines · Josh Poimboeuf
Quoted 9 lines · Peter Zijlstra

The asm_cpu_bringup_and_idle() function is required to push the return value on the stack in order to make ORC happy, but the only reason objtool doesn't complain is because of a happy accident.

The thing is that asm_cpu_bringup_and_idle() doesn't return, so validate_branch() never terminates and falls through to the next function, which in the normal case is the hypercall_page. And that, as it happens, is 4095 NOPs and a RET.

Quoted 6 lines

Make asm_cpu_bringup_and_idle() terminate on it's own, by making the function it calls as a dead-end. This way we no longer rely on what code happens to come after.

Fixes c3881eb58d56 ("x86/xen: Make the secondary CPU idle tasks reliable")

Looks right. Only problem is, with my assembler I get this:

arch/x86/kernel/head_64.o: warning: objtool: .text+0x5: unreachable instruction

Because gas insists on jumping over the page of nops...

0000000000000000 <asm_cpu_bringup_and_idle>:

Quoted 13 lines
       0:	e8 00 00 00 00       	callq  5 <asm_cpu_bringup_and_idle+0x5>
			1: R_X86_64_PLT32	cpu_bringup_and_idle-0x4
       5:	e9 f6 0f 00 00       	jmpq   1000 <xen_hypercall_set_trap_table>
       a:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      11:	00 00 00 00 
      15:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      1c:	00 00 00 00 
      20:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      27:	00 00 00 00 
      2b:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      32:	00 00 00 00 
      36:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
      3d:	00 00 00 00 

Here's a fix:

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] x86/xen: Move hypercall_page to top of the file

Because hypercall_page is page-aligned, the assembler inexplicably adds an unreachable jump from after the end of the previous code to the beginning of hypercall_page.

That confuses objtool, understandably. It also creates significant text fragmentation. As a result, much of the object file is wasted text (nops).

Move hypercall_page to the beginning of the file to both prevent the text fragmentation and avoid the dead jump instruction.

$ size /tmp/head_64.before.o /tmp/head_64.after.o
   text	   data	    bss	    dec	    hex	filename
  10924	 307252	   4096	 322272	  4eae0	/tmp/head_64.before.o
   6823	 307252	   4096	 318171	  4dadb	/tmp/head_64.after.o
---
 arch/x86/xen/xen-head.S | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)
arch/x86/xen/xen-head.S +17 -17
index cb6538ae2fe0..488944d6d430 100644
@@ -20,6 +20,23 @@
 #include <xen/interface/xen-mca.h>
 #include <asm/xen/interface.h>
 
+.pushsection .text
+	.balign PAGE_SIZE
+SYM_CODE_START(hypercall_page)
+	.rept (PAGE_SIZE / 32)
+		UNWIND_HINT_FUNC
+		.skip 31, 0x90
+		ret
+	.endr
+
+#define HYPERCALL(n) \
+	.equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
+	.type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
+#include <asm/xen-hypercalls.h>
+#undef HYPERCALL
+SYM_CODE_END(hypercall_page)
+.popsection
+
 #ifdef CONFIG_XEN_PV
 	__INIT
 SYM_CODE_START(startup_xen)
@@ -64,23 +81,6 @@ SYM_CODE_END(asm_cpu_bringup_and_idle)
 #endif
 #endif
 
-.pushsection .text
-	.balign PAGE_SIZE
-SYM_CODE_START(hypercall_page)
-	.rept (PAGE_SIZE / 32)
-		UNWIND_HINT_FUNC
-		.skip 31, 0x90
-		ret
-	.endr
-
-#define HYPERCALL(n) \
-	.equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
-	.type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
-#include <asm/xen-hypercalls.h>
-#undef HYPERCALL
-SYM_CODE_END(hypercall_page)
-.popsection
-
 	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
 	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION,  .asciz "2.6")
 	ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION,    .asciz "xen-3.0")
Signature · 1 line
2.31.1
maintainer Reviewed-by
#6 lore raw

Re: [PATCH v2 01/24] x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

Quoted 55 lines · Josh Poimboeuf
Quoted 24 lines · Josh Poimboeuf
Quoted 9 lines · Peter Zijlstra

The asm_cpu_bringup_and_idle() function is required to push the return value on the stack in order to make ORC happy, but the only reason objtool doesn't complain is because of a happy accident.

The thing is that asm_cpu_bringup_and_idle() doesn't return, so validate_branch() never terminates and falls through to the next function, which in the normal case is the hypercall_page. And that, as it happens, is 4095 NOPs and a RET.

Quoted 6 lines

Make asm_cpu_bringup_and_idle() terminate on it's own, by making the function it calls as a dead-end. This way we no longer rely on what code happens to come after.

Fixes c3881eb58d56 ("x86/xen: Make the secondary CPU idle tasks reliable")

Looks right. Only problem is, with my assembler I get this:

   arch/x86/kernel/head_64.o: warning: objtool: .text+0x5: unreachable instruction

Because gas insists on jumping over the page of nops...

0000000000000000 <asm_cpu_bringup_and_idle>:

Quoted 13 lines
        0:	e8 00 00 00 00       	callq  5 <asm_cpu_bringup_and_idle+0x5>
			1: R_X86_64_PLT32	cpu_bringup_and_idle-0x4
        5:	e9 f6 0f 00 00       	jmpq   1000 <xen_hypercall_set_trap_table>
        a:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
       11:	00 00 00 00
       15:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
       1c:	00 00 00 00
       20:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
       27:	00 00 00 00
       2b:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
       32:	00 00 00 00
       36:	66 66 2e 0f 1f 84 00 	data16 nopw %cs:0x0(%rax,%rax,1)
       3d:	00 00 00 00

Here's a fix:

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] x86/xen: Move hypercall_page to top of the file

Because hypercall_page is page-aligned, the assembler inexplicably adds an unreachable jump from after the end of the previous code to the beginning of hypercall_page.

That confuses objtool, understandably. It also creates significant text fragmentation. As a result, much of the object file is wasted text (nops).

Move hypercall_page to the beginning of the file to both prevent the text fragmentation and avoid the dead jump instruction.

Quoted 6 lines
$ size /tmp/head_64.before.o /tmp/head_64.after.o
    text	   data	    bss	    dec	    hex	filename
   10924	 307252	   4096	 322272	  4eae0	/tmp/head_64.before.o
    6823	 307252	   4096	 318171	  4dadb	/tmp/head_64.after.o

Juergen

Quoted 57 lines
---
  arch/x86/xen/xen-head.S | 34 +++++++++++++++++-----------------
  1 file changed, 17 insertions(+), 17 deletions(-)
arch/x86/xen/xen-head.S +17 -17
index cb6538ae2fe0..488944d6d430 100644
@@ -20,6 +20,23 @@
  #include <xen/interface/xen-mca.h>
  #include <asm/xen/interface.h>
 
+.pushsection .text
+	.balign PAGE_SIZE
+SYM_CODE_START(hypercall_page)
+	.rept (PAGE_SIZE / 32)
+		UNWIND_HINT_FUNC
+		.skip 31, 0x90
+		ret
+	.endr
+
+#define HYPERCALL(n) \
+	.equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
+	.type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
+#include <asm/xen-hypercalls.h>
+#undef HYPERCALL
+SYM_CODE_END(hypercall_page)
+.popsection
+
  #ifdef CONFIG_XEN_PV
  	__INIT
  SYM_CODE_START(startup_xen)
@@ -64,23 +81,6 @@ SYM_CODE_END(asm_cpu_bringup_and_idle)
  #endif
  #endif
 
-.pushsection .text
-	.balign PAGE_SIZE
-SYM_CODE_START(hypercall_page)
-	.rept (PAGE_SIZE / 32)
-		UNWIND_HINT_FUNC
-		.skip 31, 0x90
-		ret
-	.endr
-
-#define HYPERCALL(n) \
-	.equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
-	.type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
-#include <asm/xen-hypercalls.h>
-#undef HYPERCALL
-SYM_CODE_END(hypercall_page)
-.popsection
-
  	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
  	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION,  .asciz "2.6")
  	ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION,    .asciz "xen-3.0")
maintainer
#7 lore raw

Re: [PATCH v2 01/24] x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

Quoted 56 lines · Juergen Gross
Quoted 55 lines · Josh Poimboeuf
Quoted 23 lines · Josh Poimboeuf
Quoted 9 lines · Peter Zijlstra

The asm_cpu_bringup_and_idle() function is required to push the return value on the stack in order to make ORC happy, but the only reason objtool doesn't complain is because of a happy accident.

The thing is that asm_cpu_bringup_and_idle() doesn't return, so validate_branch() never terminates and falls through to the next function, which in the normal case is the hypercall_page. And that, as it happens, is 4095 NOPs and a RET.

Quoted 6 lines

Make asm_cpu_bringup_and_idle() terminate on it's own, by making the function it calls as a dead-end. This way we no longer rely on what code happens to come after.

Fixes c3881eb58d56 ("x86/xen: Make the secondary CPU idle tasks reliable")

Looks right.  Only problem is, with my assembler I get this:

   arch/x86/kernel/head_64.o: warning: objtool: .text+0x5: unreachable instruction

Because gas insists on jumping over the page of nops...

Quoted 14 lines

0000000000000000 <asm_cpu_bringup_and_idle>:
        0:    e8 00 00 00 00           callq  5 <asm_cpu_bringup_and_idle+0x5> 1: R_X86_64_PLT32    cpu_bringup_and_idle-0x4
        5:    e9 f6 0f 00 00           jmpq   1000 <xen_hypercall_set_trap_table> a:    66 66 2e 0f 1f 84 00     data16 nopw %cs:0x0(%rax,%rax,1) 11:    00 00 00 00
       15:    66 66 2e 0f 1f 84 00     data16 nopw %cs:0x0(%rax,%rax,1) 1c:    00 00 00 00
       20:    66 66 2e 0f 1f 84 00     data16 nopw %cs:0x0(%rax,%rax,1) 27:    00 00 00 00
       2b:    66 66 2e 0f 1f 84 00     data16 nopw %cs:0x0(%rax,%rax,1) 32:    00 00 00 00
       36:    66 66 2e 0f 1f 84 00     data16 nopw %cs:0x0(%rax,%rax,1) 3d:    00 00 00 00

Here's a fix:

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] x86/xen: Move hypercall_page to top of the file

Because hypercall_page is page-aligned, the assembler inexplicably adds an unreachable jump from after the end of the previous code to the beginning of hypercall_page.

That confuses objtool, understandably.  It also creates significant text fragmentation.  As a result, much of the object file is wasted text (nops).

Move hypercall_page to the beginning of the file to both prevent the text fragmentation and avoid the dead jump instruction.

Quoted 8 lines
Quoted 6 lines
$ size /tmp/head_64.before.o /tmp/head_64.after.o
    text       data        bss        dec        hex    filename
   10924     307252       4096     322272      4eae0    /tmp/head_64.before.o
    6823     307252       4096     318171      4dadb    /tmp/head_64.after.o

Umm, will this be carried through the tip tree, or shall I take it in the xen tree?

Juergen

Quoted 60 lines

Juergen

Quoted 55 lines

---
  arch/x86/xen/xen-head.S | 34 +++++++++++++++++-----------------

  1 file changed, 17 insertions(+), 17 deletions(-)
arch/x86/xen/xen-head.S +17 -0
index cb6538ae2fe0..488944d6d430 100644
@@ -20,6 +20,23 @@
   #include <xen/interface/xen-mca.h>
   #include <asm/xen/interface.h>
+.pushsection .text
+    .balign PAGE_SIZE
+SYM_CODE_START(hypercall_page)
+    .rept (PAGE_SIZE / 32)
+        UNWIND_HINT_FUNC
+        .skip 31, 0x90
+        ret
+    .endr
+
+#define HYPERCALL(n) \
+    .equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
+    .type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
+#include <asm/xen-hypercalls.h>
+#undef HYPERCALL
+SYM_CODE_END(hypercall_page)
+.popsection
+
   #ifdef CONFIG_XEN_PV

      __INIT
  SYM_CODE_START(startup_xen)

arch/x86/xen/xen-head.S +0 -17
@@ -64,23 +81,6 @@ SYM_CODE_END(asm_cpu_bringup_and_idle)
   #endif
   #endif
-.pushsection .text
-    .balign PAGE_SIZE
-SYM_CODE_START(hypercall_page)
-    .rept (PAGE_SIZE / 32)
-        UNWIND_HINT_FUNC
-        .skip 31, 0x90
-        ret
-    .endr
-
-#define HYPERCALL(n) \
-    .equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
-    .type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
-#include <asm/xen-hypercalls.h>
-#undef HYPERCALL
-SYM_CODE_END(hypercall_page)
-.popsection
-
       ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
       ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION,  .asciz "2.6")
       ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION,    .asciz "xen-3.0")
 
author maintainer
#8 lore raw

Re: [PATCH v2 01/24] x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

Quoted 21 lines · Juergen Gross
Quoted 21 lines
Quoted 21 lines

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] x86/xen: Move hypercall_page to top of the file

Because hypercall_page is page-aligned, the assembler inexplicably adds an unreachable jump from after the end of the previous code to the beginning of hypercall_page.

That confuses objtool, understandably.  It also creates significant text fragmentation.  As a result, much of the object file is wasted text (nops).

Move hypercall_page to the beginning of the file to both prevent the text fragmentation and avoid the dead jump instruction.

$ size /tmp/head_64.before.o /tmp/head_64.after.o
    text       data        bss        dec        hex    filename
   10924     307252       4096     322272      4eae0
/tmp/head_64.before.o
    6823     307252       4096     318171      4dadb
/tmp/head_64.after.o
Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Umm, will this be carried through the tip tree, or shall I take it in the xen tree?

I have it in the whole x86/objtool/paravirt series. I you want it in the Xen tree, I'll be happy to drop it from there, although I hope to get all that merged this cycles somewhere.

maintainer
#9 lore raw

Re: [PATCH v2 01/24] x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

Quoted 24 lines · Peter Zijlstra
Quoted 23 lines · Juergen Gross
Quoted 23 lines
Quoted 22 lines

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] x86/xen: Move hypercall_page to top of the file

Because hypercall_page is page-aligned, the assembler inexplicably adds an unreachable jump from after the end of the previous code to the beginning of hypercall_page.

That confuses objtool, understandably.  It also creates significant text fragmentation.  As a result, much of the object file is wasted text (nops).

Move hypercall_page to the beginning of the file to both prevent the text fragmentation and avoid the dead jump instruction.

$ size /tmp/head_64.before.o /tmp/head_64.after.o
     text       data        bss        dec        hex    filename
    10924     307252       4096     322272      4eae0
/tmp/head_64.before.o
     6823     307252       4096     318171      4dadb
/tmp/head_64.after.o
Quoted 9 lines
Quoted 4 lines
Quoted 1 line

Umm, will this be carried through the tip tree, or shall I take it in the xen tree?

I have it in the whole x86/objtool/paravirt series. I you want it in the Xen tree, I'll be happy to drop it from there, although I hope to get all that merged this cycles somewhere.

Okay, I think it is better kept in your series then.

Juergen

merge bot Applied
#10 lore raw

[tip: objtool/core] x86/xen: Move hypercall_page to top of the file

In reply to Josh Poimboeuf
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     b7b205c3a0bc2b51f83cb793178ccbc12addf275
Gitweb:        https://git.kernel.org/tip/b7b205c3a0bc2b51f83cb793178ccbc12addf275
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Fri, 20 Aug 2021 12:31:07 -07:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:44 +02:00

x86/xen: Move hypercall_page to top of the file

Because hypercall_page is page-aligned, the assembler inexplicably adds an unreachable jump from after the end of the previous code to the beginning of hypercall_page.

That confuses objtool, understandably. It also creates significant text fragmentation. As a result, much of the object file is wasted text (nops).

Move hypercall_page to the beginning of the file to both prevent the text fragmentation and avoid the dead jump instruction.

$ size /tmp/head_64.before.o /tmp/head_64.after.o
   text	   data	    bss	    dec	    hex	filename
  10924	 307252	   4096	 322272	  4eae0	/tmp/head_64.before.o
   6823	 307252	   4096	 318171	  4dadb	/tmp/head_64.after.o
---
 arch/x86/xen/xen-head.S | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)
arch/x86/xen/xen-head.S +17 -17
index cb6538a..488944d 100644
@@ -20,6 +20,23 @@
 #include <xen/interface/xen-mca.h>
 #include <asm/xen/interface.h>
 
+.pushsection .text
+	.balign PAGE_SIZE
+SYM_CODE_START(hypercall_page)
+	.rept (PAGE_SIZE / 32)
+		UNWIND_HINT_FUNC
+		.skip 31, 0x90
+		ret
+	.endr
+
+#define HYPERCALL(n) \
+	.equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
+	.type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
+#include <asm/xen-hypercalls.h>
+#undef HYPERCALL
+SYM_CODE_END(hypercall_page)
+.popsection
+
 #ifdef CONFIG_XEN_PV
 	__INIT
 SYM_CODE_START(startup_xen)
@@ -64,23 +81,6 @@ SYM_CODE_END(asm_cpu_bringup_and_idle)
 #endif
 #endif
 
-.pushsection .text
-	.balign PAGE_SIZE
-SYM_CODE_START(hypercall_page)
-	.rept (PAGE_SIZE / 32)
-		UNWIND_HINT_FUNC
-		.skip 31, 0x90
-		ret
-	.endr
-
-#define HYPERCALL(n) \
-	.equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
-	.type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
-#include <asm/xen-hypercalls.h>
-#undef HYPERCALL
-SYM_CODE_END(hypercall_page)
-.popsection
-
 	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
 	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION,  .asciz "2.6")
 	ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION,    .asciz "xen-3.0")
merge bot Applied
#11 lore raw

[tip: objtool/core] x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     9af9dcf11bda3e2c0e24c1acaacb8685ad974e93
Gitweb:        https://git.kernel.org/tip/9af9dcf11bda3e2c0e24c1acaacb8685ad974e93
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:00 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:44 +02:00

x86/xen: Mark cpu_bringup_and_idle() as dead_end_function

The asm_cpu_bringup_and_idle() function is required to push the return value on the stack in order to make ORC happy, but the only reason objtool doesn't complain is because of a happy accident.

The thing is that asm_cpu_bringup_and_idle() doesn't return, so validate_branch() never terminates and falls through to the next function, which in the normal case is the hypercall_page. And that, as it happens, is 4095 NOPs and a RET.

Make asm_cpu_bringup_and_idle() terminate on it's own, by making the function it calls as a dead-end. This way we no longer rely on what code happens to come after.

Fixes c3881eb58d56 ("x86/xen: Make the secondary CPU idle tasks reliable")
---
 tools/objtool/check.c | 1 +
 1 file changed, 1 insertion(+)
tools/objtool/check.c +1 -0
index e5947fb..0e3981d 100644
@@ -173,6 +173,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
 		"rewind_stack_do_exit",
 		"kunit_try_catch_throw",
 		"xen_start_kernel",
+		"cpu_bringup_and_idle",
 	};
 
 	if (!func)
author maintainer
#12 lore raw

PATCH v2 2/24 objtool: Introduce CFI hash

In reply to Peter Zijlstra

Andi reported that objtool on vmlinux.o consumes more memory than his system has, leading to horrific performance.

This is in part because we keep a struct instruction for every instruction in the file in-memory. Shrink struct instruction by removing the CFI state (which includes full register state) from it and demand allocating it.

Given most instructions don't actually change CFI state, there's lots of repetition there, so add a hash table to find previous CFI instances.

Reduces memory consumption (and runtime) for processing an x86_64-allyesconfig:

  pre:  4:40.84 real,   143.99 user,    44.18 sys,      30624988 mem
  post: 2:14.61 real,   108.58 user,    25.04 sys,      16396184 mem
---
 tools/objtool/arch/x86/decode.c       |    2 
 tools/objtool/check.c                 |  155 ++++++++++++++++++++++++++++++----
 tools/objtool/include/objtool/cfi.h   |    2 
 tools/objtool/include/objtool/check.h |    4 
 tools/objtool/orc_gen.c               |   15 ++-
 5 files changed, 154 insertions(+), 24 deletions(-)
tools/objtool/arch/x86/decode.c +1 -1
@@ -781,7 +781,7 @@ int arch_rewrite_retpolines(struct objto
 
 int arch_decode_hint_reg(struct instruction *insn, u8 sp_reg)
 {
-	struct cfi_reg *cfa = &insn->cfi.cfa;
+	struct cfi_reg *cfa = &insn->cfip->cfa;
 
 	switch (sp_reg) {
 	case ORC_REG_UNDEFINED:
tools/objtool/check.c +137 -18

273 lines not on this page · raw message

tools/objtool/include/objtool/cfi.h +2 -0
@@ -7,6 +7,7 @@
 #define _OBJTOOL_CFI_H
 
 #include <arch/cfi_regs.h>
+#include <linux/list.h>
 
 #define CFI_UNDEFINED		-1
 #define CFI_CFA			-2
@@ -24,6 +25,7 @@ struct cfi_init_state {
 };
 
 struct cfi_state {
+	struct hlist_node hash; /* must be first, cficmp() */
 	struct cfi_reg regs[CFI_NUM_REGS];
 	struct cfi_reg vals[CFI_NUM_REGS];
 	struct cfi_reg cfa;
tools/objtool/include/objtool/check.h +3 -1
@@ -60,9 +60,11 @@ struct instruction {
 	struct list_head alts;
 	struct symbol *func;
 	struct list_head stack_ops;
-	struct cfi_state cfi;
+	struct cfi_state *cfip;
 };
 
+extern struct cfi_state *insn_get_cfi(struct instruction *);
+
 static inline bool is_static_jump(struct instruction *insn)
 {
 	return insn->type == INSN_JUMP_CONDITIONAL ||
tools/objtool/orc_gen.c +11 -4
@@ -13,13 +13,19 @@
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
 
-static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi)
+static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
+			  struct instruction *insn)
 {
-	struct instruction *insn = container_of(cfi, struct instruction, cfi);
 	struct cfi_reg *bp = &cfi->regs[CFI_BP];
 
 	memset(orc, 0, sizeof(*orc));
 
+	if (!cfi) {
+		orc->end = 0;
+		orc->sp_reg = ORC_REG_UNDEFINED;
+		return 0;
+	}
+
 	orc->end = cfi->end;
 
 	if (cfi->cfa.base == CFI_UNDEFINED) {
@@ -162,7 +168,7 @@ int orc_create(struct objtool_file *file
 			int i;
 
 			if (!alt_group) {
-				if (init_orc_entry(&orc, &insn->cfi))
+				if (init_orc_entry(&orc, insn->cfip, insn))
 					return -1;
 				if (!memcmp(&prev_orc, &orc, sizeof(orc)))
 					continue;
@@ -186,7 +192,8 @@ int orc_create(struct objtool_file *file
 				struct cfi_state *cfi = alt_group->cfi[i];
 				if (!cfi)
 					continue;
-				if (init_orc_entry(&orc, cfi))
+				/* errors are reported on the original insn */
+				if (init_orc_entry(&orc, cfi, insn))
 					return -1;
 				if (!memcmp(&prev_orc, &orc, sizeof(orc)))
 					continue;
#13 lore raw

Re: [PATCH v2 02/24] objtool: Introduce CFI hash

tools/objtool/check.c static int validate_branch(struct objtoo · line 2824

Quoted 7 lines
tools/objtool/check.c +2 -1
@@ -2725,15 +2820,24 @@ static int validate_branch(struct objtoo
 
 			if (insn->visited & visited)
 				return 0;
-		}
+		} else
+			nr_visited++;

just a coding style

	} else {
		nr_visited++;
	}

tools/objtool/check.c int check(struct objtool_file *file) · line 3308

Quoted 6 lines
tools/objtool/check.c +2 -0
@@ -3192,6 +3304,13 @@ int check(struct objtool_file *file)
 		warnings += ret;
 	}
 
+	if (stats) {
+		printf("nr_visited: %ld\n", nr_visited);

Could we make this nr_insns_visited?

Quoted 15 lines
tools/objtool/check.c +8 -2
+		printf("nr_cfi: %ld\n", nr_cfi);
+		printf("nr_cfi_reused: %ld\n", nr_cfi_reused);
+		printf("nr_cfi_cache: %ld\n", nr_cfi_cache);
+	}
+
+++ b/tools/objtool/orc_gen.c
@@ -13,13 +13,19 @@
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
 
-static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi)
+static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
+			  struct instruction *insn)
 {
-	struct instruction *insn = container_of(cfi, struct instruction, cfi);

tools/objtool/check.c line 28

Quoted 10 lines
tools/objtool/check.c +6 -0
 	struct cfi_reg *bp = &cfi->regs[CFI_BP];
 
 	memset(orc, 0, sizeof(*orc));
 
+	if (!cfi) {
+		orc->end = 0;
+		orc->sp_reg = ORC_REG_UNDEFINED;
+		return 0;
+	}
+

This looks strange. You access cfi a couple of lines earlier (bp cfi_reg initialization).

Is it even possible to have cfi == NULL here? The second call site below has a check and the first one should not happen (insn->cfip should be always set if I am not missing something).

Quoted 13 lines
tools/objtool/orc_gen.c +1 -1
 	orc->end = cfi->end;
 
 	if (cfi->cfa.base == CFI_UNDEFINED) {
@@ -162,7 +168,7 @@ int orc_create(struct objtool_file *file
 			int i;
 
 			if (!alt_group) {
-				if (init_orc_entry(&orc, &insn->cfi))
+				if (init_orc_entry(&orc, insn->cfip, insn))
 					return -1;
 				if (!memcmp(&prev_orc, &orc, sizeof(orc)))
 					continue;

tools/objtool/orc_gen.c int orc_create(struct objtool_file *file · line 199

Quoted 9 lines
tools/objtool/orc_gen.c +2 -1
@@ -186,7 +192,8 @@ int orc_create(struct objtool_file *file
 				struct cfi_state *cfi = alt_group->cfi[i];
 				if (!cfi)
 					continue;
-				if (init_orc_entry(&orc, cfi))
+				/* errors are reported on the original insn */
+				if (init_orc_entry(&orc, cfi, insn))
 					return -1;
 				if (!memcmp(&prev_orc, &orc, sizeof(orc)))
 					continue;

Anyway, this is a nice improvement.

Miroslav

author maintainer
#14 lore raw

Re: [PATCH v2 02/24] objtool: Introduce CFI hash

Quoted 14 lines · Miroslav Benes

tools/objtool/check.c static int validate_branch(struct objtoo · line 2824

Quoted 7 lines
tools/objtool/check.c +2 -1
@@ -2725,15 +2820,24 @@ static int validate_branch(struct objtoo
 
 			if (insn->visited & visited)
 				return 0;
-		}
+		} else
+			nr_visited++;

just a coding style

	} else {
		nr_visited++;
	}
Quoted 8 lines

tools/objtool/check.c int check(struct objtool_file *file) · line 3308

Quoted 6 lines
tools/objtool/check.c +2 -0
@@ -3192,6 +3304,13 @@ int check(struct objtool_file *file)
 		warnings += ret;
 	}
 
+	if (stats) {
+		printf("nr_visited: %ld\n", nr_visited);

Could we make this nr_insns_visited?

Both done.

Quoted 19 lines
Quoted 19 lines
tools/objtool/check.c +8 -2
+		printf("nr_cfi: %ld\n", nr_cfi);
+		printf("nr_cfi_reused: %ld\n", nr_cfi_reused);
+		printf("nr_cfi_cache: %ld\n", nr_cfi_cache);
+	}
+
+++ b/tools/objtool/orc_gen.c
@@ -13,13 +13,19 @@
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
 
-static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi)
+static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
+			  struct instruction *insn)
 {
-	struct instruction *insn = container_of(cfi, struct instruction, cfi);
 	struct cfi_reg *bp = &cfi->regs[CFI_BP];
 
 	memset(orc, 0, sizeof(*orc));
 
Quoted 9 lines

tools/objtool/orc_gen.c line 28

Quoted 6 lines
tools/objtool/orc_gen.c +6 -0
+	if (!cfi) {
+		orc->end = 0;
+		orc->sp_reg = ORC_REG_UNDEFINED;
+		return 0;
+	}
+

This looks strange. You access cfi a couple of lines earlier (bp cfi_reg initialization).

That's a relative address compute, it doesn't actually dereference the pointer.

Quoted 3 lines

Is it even possible to have cfi == NULL here? The second call site below has a check and the first one should not happen (insn->cfip should be always set if I am not missing something).

I can happen for instructions that are not visited, like NOP fillers between functions. Remove the check and try to build a file :-)

#15 lore raw

Re: [PATCH v2 02/24] objtool: Introduce CFI hash

Quoted 24 lines
Quoted 14 lines
Quoted 14 lines

+++ b/tools/objtool/orc_gen.c

tools/objtool/orc_gen.c +2 -2
@@ -13,13 +13,19 @@
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
 
-static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi)
+static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
+			  struct instruction *insn)
 {
-	struct instruction *insn = container_of(cfi, struct instruction, cfi);
 	struct cfi_reg *bp = &cfi->regs[CFI_BP];
 
 	memset(orc, 0, sizeof(*orc));
 
Quoted 9 lines

tools/objtool/orc_gen.c line 28

Quoted 6 lines
tools/objtool/orc_gen.c +6 -0
+	if (!cfi) {
+		orc->end = 0;
+		orc->sp_reg = ORC_REG_UNDEFINED;
+		return 0;
+	}
+

This looks strange. You access cfi a couple of lines earlier (bp cfi_reg initialization).

Quoted 2 lines

That's a relative address compute, it doesn't actually dereference the pointer.

Right, I misread the line.

Quoted 6 lines
Quoted 3 lines

Is it even possible to have cfi == NULL here? The second call site below has a check and the first one should not happen (insn->cfip should be always set if I am not missing something).

I can happen for instructions that are not visited, like NOP fillers between functions. Remove the check and try to build a file :-)

Doh, I should have done that. Of course there must be unvisited instructions. Sorry for the noise.

Miroslav

#16 lore raw

Re: [PATCH v2 02/24] objtool: Introduce CFI hash

In reply to Peter Zijlstra
Quoted 12 lines · Peter Zijlstra

Andi reported that objtool on vmlinux.o consumes more memory than his system has, leading to horrific performance.

This is in part because we keep a struct instruction for every instruction in the file in-memory. Shrink struct instruction by removing the CFI state (which includes full register state) from it and demand allocating it.

Given most instructions don't actually change CFI state, there's lots of repetition there, so add a hash table to find previous CFI instances.

Quoted 5 lines

Reduces memory consumption (and runtime) for processing an x86_64-allyesconfig:

  pre:  4:40.84 real,   143.99 user,    44.18 sys,      30624988 mem
  post: 2:14.61 real,   108.58 user,    25.04 sys,      16396184 mem

Excellent.

tools/objtool/check.c static void init_insn_state(struct insn_ · line 282

Quoted 11 lines
tools/objtool/check.c +11 -0
+static struct cfi_state *cfi_alloc(void)
+{
+	struct cfi_state *cfi = calloc(sizeof(struct cfi_state), 1);
+	if (!cfi) {
+		WARN("calloc failed");
+		exit(1);
+	}
+	nr_cfi++;
+	init_cfi_state(cfi);
+	return cfi;
+}

I'm thinking this should also add it to the hash. i.e. I don't think there's a scenario where you'd alloc a cfi and not want to add it to the hash. The more sharing the better.

tools/objtool/check.c static void init_insn_state(struct insn_ · line 290

Quoted 8 lines
tools/objtool/check.c +8 -0
+
+struct cfi_state *insn_get_cfi(struct instruction *insn)
+{
+	if (!insn->cfip)
+		insn->cfip = cfi_alloc();
+
+	return insn->cfip;
+}

Call it something like insn_get_or_alloc_cfi()?

Also, the function can be static.

Quoted 7 lines
tools/objtool/check.c +7 -0
+static struct cfi_state *cfi_hash_find(struct cfi_state *cfi)
+{
+	struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
+	struct cfi_state *obj;
+
+	hlist_for_each_entry(obj, head, hash) {
+		if (!cficmp(cfi, obj)) {

tools/objtool/check.c static void init_insn_state(struct insn_ · line 324

Quoted 10 lines
tools/objtool/check.c +10 -0
+			nr_cfi_cache++;
+			return obj;
+		}
+	}
+
+	obj = cfi_alloc();
+	*obj = *cfi;
+	hlist_add_head(&obj->hash, head);
+
+	return obj;

cfi_hash_find_or_alloc_cfi()?

Quoted 9 lines
tools/objtool/check.c +2 -1
@@ -2725,15 +2820,24 @@ static int validate_branch(struct objtoo
 
 			if (insn->visited & visited)
 				return 0;
-		}
+		} else
+			nr_visited++;
 
 		if (state.noinstr)

tools/objtool/check.c static int validate_branch(struct objtoo · line 2832

Quoted 10 lines
tools/objtool/check.c +4 -4
 			state.instr += insn->instr;
 
-		if (insn->hint)
-			state.cfi = insn->cfi;
-		else
-			insn->cfi = state.cfi;
+		if (insn->hint) {
+			state.cfi = *insn->cfip;
+		} else {
+			/* XXX track if we actually changed state.cfi */

Why would we do that?

tools/objtool/include/objtool/check.h struct instruction { · line 63

Quoted 7 lines
tools/objtool/include/objtool/check.h +2 -1
+++ b/tools/objtool/include/objtool/check.h
@@ -60,9 +60,11 @@ struct instruction {
 	struct list_head alts;
 	struct symbol *func;
 	struct list_head stack_ops;
-	struct cfi_state cfi;
+	struct cfi_state *cfip;

Not sure about this rename. Pointers generally don't need a 'p' postfix.

Signature · 1 line
Josh
author maintainer
#17 lore raw

Re: [PATCH v2 02/24] objtool: Introduce CFI hash

Quoted 7 lines · Josh Poimboeuf
Quoted 7 lines
(quoted diff) +7 -0
+static struct cfi_state *cfi_alloc(void)
+{
+	struct cfi_state *cfi = calloc(sizeof(struct cfi_state), 1);
+	if (!cfi) {
+		WARN("calloc failed");
+		exit(1);
+	}
Quoted 8 lines

Review

Quoted 4 lines
(quoted diff) +4 -0
+	nr_cfi++;
+	init_cfi_state(cfi);
+	return cfi;
+}

I'm thinking this should also add it to the hash. i.e. I don't think there's a scenario where you'd alloc a cfi and not want to add it to the hash. The more sharing the better.

Right, changed it like below.

Quoted 11 lines

Review

Quoted 8 lines
(quoted diff) +8 -0
+
+struct cfi_state *insn_get_cfi(struct instruction *insn)
+{
+	if (!insn->cfip)
+		insn->cfip = cfi_alloc();
+
+	return insn->cfip;
+}

Call it something like insn_get_or_alloc_cfi()?

Quoted 1 line

Also, the function can be static.

It's gone now.

Quoted 11 lines
Quoted 11 lines
(quoted diff) +11 -0
+static struct cfi_state *cfi_hash_find(struct cfi_state *cfi)
+{
+	struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
+	struct cfi_state *obj;
+
+	hlist_for_each_entry(obj, head, hash) {
+		if (!cficmp(cfi, obj)) {
+			nr_cfi_cache++;
+			return obj;
+		}
+	}
Quoted 8 lines

Review

Quoted 6 lines
(quoted diff) +6 -0
+
+	obj = cfi_alloc();
+	*obj = *cfi;
+	hlist_add_head(&obj->hash, head);
+
+	return obj;

cfi_hash_find_or_alloc_cfi()?

Made that cfi_hash_find_or_add()

tools/objtool/check.c +10 -7
@@ -30,6 +30,7 @@ struct alternative {
 static unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache;
 
 static struct cfi_init_state initial_func_cfi;
+static struct cfi_state init_cfi;
 static struct cfi_state func_cfi;
 
 struct instruction *find_insn(struct objtool_file *file,
@@ -278,7 +279,6 @@ static struct cfi_state *cfi_alloc(void)
 		exit(1);
 	}
 	nr_cfi++;
-	init_cfi_state(cfi);
 	return cfi;
 }
 
@@ -298,7 +298,7 @@ static inline u32 cfi_key(struct cfi_sta
 		     sizeof(*cfi) - sizeof(cfi->hash), 0);
 }
 
-static struct cfi_state *cfi_hash_find(struct cfi_state *cfi)
+static struct cfi_state *cfi_hash_find_or_add(struct cfi_state *cfi)
 {
 	struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
 	struct cfi_state *obj;
@@ -1620,10 +1620,10 @@ static void set_func_state(struct cfi_st
 
 static int read_unwind_hints(struct objtool_file *file)
 {
+	struct cfi_state cfi = init_cfi;
 	struct section *sec, *relocsec;
 	struct unwind_hint *hint;
 	struct instruction *insn;
-	struct cfi_state *cfi;
 	struct reloc *reloc;
 	int i;
 
@@ -1666,9 +1666,8 @@ static int read_unwind_hints(struct objt
 			continue;
 		}
 
-		cfi = insn->cfip;
-		if (!cfi)
-			cfi = insn->cfip = cfi_alloc();
+		if (insn->cfip)
+			cfi = *(insn->cfip);
 
 		if (arch_decode_hint_reg(insn, hint->sp_reg)) {
 			WARN_FUNC("unsupported unwind_hint sp base reg %d",
@@ -1679,6 +1678,8 @@ static int read_unwind_hints(struct objt
 		cfi->cfa.offset = bswap_if_needed(hint->sp_offset);
 		cfi->type = hint->type;
 		cfi->end = hint->end;
+
+		insn->cfip = cfi_hash_find_or_add(&cfi);
 	}
 
 	return 0;
@@ -2831,7 +2832,7 @@ static int validate_branch(struct objtoo
 				insn->cfip = prev_insn->cfip;
 				nr_cfi_reused++;
 			} else {
-				insn->cfip = cfi_hash_find(&state.cfi);
+				insn->cfip = cfi_hash_find_or_add(&state.cfi);
 			}
 		}
 
@@ -3239,6 +3240,7 @@ int check(struct objtool_file *file)
 	int ret, warnings = 0;
 
 	arch_initial_func_cfi_state(&initial_func_cfi);
+	init_cfi_state(&init_cfi);
 	init_cfi_state(&func_cfi);
 	set_func_state(&func_cfi);
 
@@ -3250,6 +3252,7 @@ int check(struct objtool_file *file)
 	if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3)))
 		goto out;
 
+	cfi_hash_add(&init_cfi);
 	cfi_hash_add(&func_cfi);
 
 	if (list_empty(&file->insn_list))
author maintainer
#18 lore raw

Re: [PATCH v2 02/24] objtool: Introduce CFI hash

Quoted 19 lines · Peter Zijlstra
Quoted 15 lines · Josh Poimboeuf

Review

Quoted 11 lines
(quoted diff) +11 -0
+static struct cfi_state *cfi_alloc(void)
+{
+	struct cfi_state *cfi = calloc(sizeof(struct cfi_state), 1);
+	if (!cfi) {
+		WARN("calloc failed");
+		exit(1);
+	}
+	nr_cfi++;
+	init_cfi_state(cfi);
+	return cfi;
+}

I'm thinking this should also add it to the hash. i.e. I don't think there's a scenario where you'd alloc a cfi and not want to add it to the hash. The more sharing the better.

tools/objtool/check.c static int read_unwind_hints(struct objt · line 1671

Quoted 6 lines
tools/objtool/check.c +0 -3
@@ -1666,9 +1666,8 @@ static int read_unwind_hints(struct objt
 			continue;
 		}
 
-		cfi = insn->cfip;
-		if (!cfi)
-			cfi = insn->cfip = cfi_alloc();

Urgh, the problem is that this runs before we allocate the hash-table! Lemme try and re-order thing.

author maintainer
#19 lore raw

Re: [PATCH v2 02/24] objtool: Introduce CFI hash

In reply to Josh Poimboeuf
Quoted 11 lines · Josh Poimboeuf
Quoted 11 lines
tools/objtool/check.c +2 -1
@@ -2725,15 +2820,24 @@ static int validate_branch(struct objtoo
 
 			if (insn->visited & visited)
 				return 0;
-		}
+		} else
+			nr_visited++;
 
 		if (state.noinstr)
 			state.instr += insn->instr;
 
Quoted 10 lines

tools/objtool/check.c static int validate_branch(struct objtoo · line 2832

Quoted 8 lines
tools/objtool/check.c +4 -4
-		if (insn->hint)
-			state.cfi = insn->cfi;
-		else
-			insn->cfi = state.cfi;
+		if (insn->hint) {
+			state.cfi = *insn->cfip;
+		} else {
+			/* XXX track if we actually changed state.cfi */

Why would we do that?

Saves on the memcmp()..

Quoted 9 lines

tools/objtool/include/objtool/check.h struct instruction { · line 63

Quoted 7 lines
tools/objtool/include/objtool/check.h +2 -1
+++ b/tools/objtool/include/objtool/check.h
@@ -60,9 +60,11 @@ struct instruction {
 	struct list_head alts;
 	struct symbol *func;
 	struct list_head stack_ops;
-	struct cfi_state cfi;
+	struct cfi_state *cfip;

Not sure about this rename. Pointers generally don't need a 'p' postfix.

It was a dev thing, meant I typically rename a member when I change type; easy for compiler and grep.

I can s/cfip/cfi/ on the patch, no biggie.

merge bot Applied
#20 lore raw

[tip: objtool/core] objtool: Introduce CFI hash

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     8b946cc38e063f0f7bb67789478c38f6d7d457c9
Gitweb:        https://git.kernel.org/tip/8b946cc38e063f0f7bb67789478c38f6d7d457c9
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:01 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:45 +02:00

objtool: Introduce CFI hash

Andi reported that objtool on vmlinux.o consumes more memory than his system has, leading to horrific performance.

This is in part because we keep a struct instruction for every instruction in the file in-memory. Shrink struct instruction by removing the CFI state (which includes full register state) from it and demand allocating it.

Given most instructions don't actually change CFI state, there's lots of repetition there, so add a hash table to find previous CFI instances.

Reduces memory consumption (and runtime) for processing an x86_64-allyesconfig:

  pre:  4:40.84 real,   143.99 user,    44.18 sys,      30624988 mem
  post: 2:14.61 real,   108.58 user,    25.04 sys,      16396184 mem
---
 tools/objtool/arch/x86/decode.c       |  20 +--
 tools/objtool/check.c                 | 154 ++++++++++++++++++++++---
 tools/objtool/include/objtool/arch.h  |   2 +-
 tools/objtool/include/objtool/cfi.h   |   2 +-
 tools/objtool/include/objtool/check.h |   2 +-
 tools/objtool/orc_gen.c               |  15 +-
 6 files changed, 160 insertions(+), 35 deletions(-)
tools/objtool/arch/x86/decode.c +9 -11
index bc82105..3435a32 100644
@@ -779,34 +779,32 @@ int arch_rewrite_retpolines(struct objtool_file *file)
 	return 0;
 }
 
-int arch_decode_hint_reg(struct instruction *insn, u8 sp_reg)
+int arch_decode_hint_reg(u8 sp_reg, int *base)
 {
-	struct cfi_reg *cfa = &insn->cfi.cfa;
-
 	switch (sp_reg) {
 	case ORC_REG_UNDEFINED:
-		cfa->base = CFI_UNDEFINED;
+		*base = CFI_UNDEFINED;
 		break;
 	case ORC_REG_SP:
-		cfa->base = CFI_SP;
+		*base = CFI_SP;
 		break;
 	case ORC_REG_BP:
-		cfa->base = CFI_BP;
+		*base = CFI_BP;
 		break;
 	case ORC_REG_SP_INDIRECT:
-		cfa->base = CFI_SP_INDIRECT;
+		*base = CFI_SP_INDIRECT;
 		break;
 	case ORC_REG_R10:
-		cfa->base = CFI_R10;
+		*base = CFI_R10;
 		break;
 	case ORC_REG_R13:
-		cfa->base = CFI_R13;
+		*base = CFI_R13;
 		break;
 	case ORC_REG_DI:
-		cfa->base = CFI_DI;
+		*base = CFI_DI;
 		break;
 	case ORC_REG_DX:
-		cfa->base = CFI_DX;
+		*base = CFI_DX;
 		break;
 	default:
 		return -1;
tools/objtool/check.c +136 -18

271 lines not on this page · raw message

tools/objtool/include/objtool/arch.h +1 -1
index 062bb6e..a5ab682 100644
@@ -83,7 +83,7 @@ unsigned long arch_dest_reloc_offset(int addend);
 
 const char *arch_nop_insn(int len);
 
-int arch_decode_hint_reg(struct instruction *insn, u8 sp_reg);
+int arch_decode_hint_reg(u8 sp_reg, int *base);
 
 bool arch_is_retpoline(struct symbol *sym);
 
tools/objtool/include/objtool/cfi.h +2 -0
index fd5cb0b..f11d1ac 100644
@@ -7,6 +7,7 @@
 #define _OBJTOOL_CFI_H
 
 #include <arch/cfi_regs.h>
+#include <linux/list.h>
 
 #define CFI_UNDEFINED		-1
 #define CFI_CFA			-2
@@ -24,6 +25,7 @@ struct cfi_init_state {
 };
 
 struct cfi_state {
+	struct hlist_node hash; /* must be first, cficmp() */
 	struct cfi_reg regs[CFI_NUM_REGS];
 	struct cfi_reg vals[CFI_NUM_REGS];
 	struct cfi_reg cfa;
tools/objtool/include/objtool/check.h +1 -1
index 56d50bc..07e99c2 100644
@@ -60,7 +60,7 @@ struct instruction {
 	struct list_head alts;
 	struct symbol *func;
 	struct list_head stack_ops;
-	struct cfi_state cfi;
+	struct cfi_state *cfi;
 };
 
 static inline bool is_static_jump(struct instruction *insn)
tools/objtool/orc_gen.c +11 -4
index dc9b7dd..ddacb42 100644
@@ -13,13 +13,19 @@
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
 
-static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi)
+static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
+			  struct instruction *insn)
 {
-	struct instruction *insn = container_of(cfi, struct instruction, cfi);
 	struct cfi_reg *bp = &cfi->regs[CFI_BP];
 
 	memset(orc, 0, sizeof(*orc));
 
+	if (!cfi) {
+		orc->end = 0;
+		orc->sp_reg = ORC_REG_UNDEFINED;
+		return 0;
+	}
+
 	orc->end = cfi->end;
 
 	if (cfi->cfa.base == CFI_UNDEFINED) {
@@ -162,7 +168,7 @@ int orc_create(struct objtool_file *file)
 			int i;
 
 			if (!alt_group) {
-				if (init_orc_entry(&orc, &insn->cfi))
+				if (init_orc_entry(&orc, insn->cfi, insn))
 					return -1;
 				if (!memcmp(&prev_orc, &orc, sizeof(orc)))
 					continue;
@@ -186,7 +192,8 @@ int orc_create(struct objtool_file *file)
 				struct cfi_state *cfi = alt_group->cfi[i];
 				if (!cfi)
 					continue;
-				if (init_orc_entry(&orc, cfi))
+				/* errors are reported on the original insn */
+				if (init_orc_entry(&orc, cfi, insn))
 					return -1;
 				if (!memcmp(&prev_orc, &orc, sizeof(orc)))
 					continue;
author maintainer
#21 lore raw

PATCH v2 3/24 objtool: Handle __sanitize_cov*() tail calls

In reply to Peter Zijlstra

Turns out the compilers also generate tail calls to __sanitize_cov*(), make sure to also patch those out in noinstr code.

Fixes 0f1441b44e82 ("objtool: Fix noinstr vs KCOV")
---
 tools/objtool/arch/x86/decode.c      |   20 ++++
 tools/objtool/check.c                |  153 ++++++++++++++++++-----------------
 tools/objtool/include/objtool/arch.h |    1 
 3 files changed, 100 insertions(+), 74 deletions(-)
tools/objtool/arch/x86/decode.c +20 -0
@@ -659,6 +659,26 @@ const char *arch_nop_insn(int len)
 	return nops[len-1];
 }
 
+#define BYTE_RET	0xC3
+
+const char *arch_ret_insn(int len)
+{
+	static const char ret[5][5] = {
+		{ BYTE_RET },
+		{ BYTE_RET, BYTES_NOP1 },
+		{ BYTE_RET, BYTES_NOP2 },
+		{ BYTE_RET, BYTES_NOP3 },
+		{ BYTE_RET, BYTES_NOP4 },
+	};
+
+	if (len < 1 || len > 5) {
+		WARN("invalid RET size: %d\n", len);
+		return NULL;
+	}
+
+	return ret[len-1];
+}
+
 /* asm/alternative.h ? */
 
 #define ALTINSTR_FLAG_INV	(1 << 15)
tools/objtool/check.c +79 -74

208 lines not on this page · raw message

tools/objtool/include/objtool/arch.h +1 -0
@@ -82,6 +82,7 @@ unsigned long arch_jump_destination(stru
 unsigned long arch_dest_reloc_offset(int addend);
 
 const char *arch_nop_insn(int len);
+const char *arch_ret_insn(int len);
 
 int arch_decode_hint_reg(struct instruction *insn, u8 sp_reg);
 
Acked-by on v2 3/24
#22 lore raw

Re: [PATCH v2 03/24] objtool: Handle __sanitize_cov*() tail calls

Quoted 5 lines · Peter Zijlstra

Turns out the compilers also generate tail calls to __sanitize_cov*(), make sure to also patch those out in noinstr code.

Fixes 0f1441b44e82 ("objtool: Fix noinstr vs KCOV")

Thanks! More reason to not even try to do the same for other architectures, and the compiler needing the attribute...

Quoted 266 lines
---
 tools/objtool/arch/x86/decode.c      |   20 ++++
 tools/objtool/check.c                |  153 ++++++++++++++++++-----------------
 tools/objtool/include/objtool/arch.h |    1 
 3 files changed, 100 insertions(+), 74 deletions(-)
tools/objtool/arch/x86/decode.c +20 -0
@@ -659,6 +659,26 @@ const char *arch_nop_insn(int len)
 	return nops[len-1];
 }
 
+#define BYTE_RET	0xC3
+
+const char *arch_ret_insn(int len)
+{
+	static const char ret[5][5] = {
+		{ BYTE_RET },
+		{ BYTE_RET, BYTES_NOP1 },
+		{ BYTE_RET, BYTES_NOP2 },
+		{ BYTE_RET, BYTES_NOP3 },
+		{ BYTE_RET, BYTES_NOP4 },
+	};
+
+	if (len < 1 || len > 5) {
+		WARN("invalid RET size: %d\n", len);
+		return NULL;
+	}
+
+	return ret[len-1];
+}
+
 /* asm/alternative.h ? */
 
 #define ALTINSTR_FLAG_INV	(1 << 15)
tools/objtool/check.c +79 -74
@@ -828,6 +828,74 @@ static struct reloc *insn_reloc(struct o
 	return insn->reloc;
 }
 
+static void remove_insn_ops(struct instruction *insn)
+{
+	struct stack_op *op, *tmp;
+
+	list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) {
+		list_del(&op->list);
+		free(op);
+	}
+}
+
+static void add_call_dest(struct objtool_file *file, struct instruction *insn,
+			  struct symbol *dest, bool sibling)
+{
+	struct reloc *reloc = insn_reloc(file, insn);
+
+	insn->call_dest = dest;
+	if (!dest)
+		return;
+
+	if (insn->call_dest->static_call_tramp) {
+		list_add_tail(&insn->call_node,
+			      &file->static_call_list);
+	}
+
+	if (insn->sec->noinstr &&
+	    !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
+		if (reloc) {
+			reloc->type = R_NONE;
+			elf_write_reloc(file->elf, reloc);
+		}
+
+		elf_write_insn(file->elf, insn->sec,
+			       insn->offset, insn->len,
+			       sibling ? arch_ret_insn(insn->len)
+			               : arch_nop_insn(insn->len));
+
+		insn->type = sibling ? INSN_RETURN : INSN_NOP;
+	}
+
+	if (mcount && !strcmp(insn->call_dest->name, "__fentry__")) {
+		if (sibling)
+			WARN_FUNC("Tail call to __fentry__ !?!?", insn->sec, insn->offset);
+
+		if (reloc) {
+			reloc->type = R_NONE;
+			elf_write_reloc(file->elf, reloc);
+		}
+
+		elf_write_insn(file->elf, insn->sec,
+			       insn->offset, insn->len,
+			       arch_nop_insn(insn->len));
+
+		insn->type = INSN_NOP;
+
+		list_add_tail(&insn->mcount_loc_node,
+			      &file->mcount_loc_list);
+	}
+
+	/*
+	 * Whatever stack impact regular CALLs have, should be undone
+	 * by the RETURN of the called function.
+	 *
+	 * Annotated intra-function calls retain the stack_ops but
+	 * are converted to JUMP, see read_intra_function_calls().
+	 */
+	remove_insn_ops(insn);
+}
+
 /*
  * Find the destination instructions for all jumps.
  */
@@ -866,11 +934,7 @@ static int add_jump_destinations(struct
 			continue;
 		} else if (insn->func) {
 			/* internal or external sibling call (with reloc) */
-			insn->call_dest = reloc->sym;
-			if (insn->call_dest->static_call_tramp) {
-				list_add_tail(&insn->call_node,
-					      &file->static_call_list);
-			}
+			add_call_dest(file, insn, reloc->sym, true);
 			continue;
 		} else if (reloc->sym->sec->idx) {
 			dest_sec = reloc->sym->sec;
@@ -926,13 +990,8 @@ static int add_jump_destinations(struct
 
 			} else if (insn->jump_dest->func->pfunc != insn->func->pfunc &&
 				   insn->jump_dest->offset == insn->jump_dest->func->offset) {
-
 				/* internal sibling call (without reloc) */
-				insn->call_dest = insn->jump_dest->func;
-				if (insn->call_dest->static_call_tramp) {
-					list_add_tail(&insn->call_node,
-						      &file->static_call_list);
-				}
+				add_call_dest(file, insn, insn->jump_dest->func, true);
 			}
 		}
 	}
@@ -940,16 +999,6 @@ static int add_jump_destinations(struct
 	return 0;
 }
 
-static void remove_insn_ops(struct instruction *insn)
-{
-	struct stack_op *op, *tmp;
-
-	list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) {
-		list_del(&op->list);
-		free(op);
-	}
-}
-
 static struct symbol *find_call_destination(struct section *sec, unsigned long offset)
 {
 	struct symbol *call_dest;
@@ -968,6 +1017,7 @@ static int add_call_destinations(struct
 {
 	struct instruction *insn;
 	unsigned long dest_off;
+	struct symbol *dest;
 	struct reloc *reloc;
 
 	for_each_insn(file, insn) {
@@ -977,7 +1027,9 @@ static int add_call_destinations(struct
 		reloc = insn_reloc(file, insn);
 		if (!reloc) {
 			dest_off = arch_jump_destination(insn);
-			insn->call_dest = find_call_destination(insn->sec, dest_off);
+			dest = find_call_destination(insn->sec, dest_off);
+
+			add_call_dest(file, insn, dest, false);
 
 			if (insn->ignore)
 				continue;
@@ -995,9 +1047,8 @@ static int add_call_destinations(struct
 
 		} else if (reloc->sym->type == STT_SECTION) {
 			dest_off = arch_dest_reloc_offset(reloc->addend);
-			insn->call_dest = find_call_destination(reloc->sym->sec,
-								dest_off);
-			if (!insn->call_dest) {
+			dest = find_call_destination(reloc->sym->sec, dest_off);
+			if (!dest) {
 				WARN_FUNC("can't find call dest symbol at %s+0x%lx",
 					  insn->sec, insn->offset,
 					  reloc->sym->sec->name,
@@ -1005,6 +1056,8 @@ static int add_call_destinations(struct
 				return -1;
 			}
 
+			add_call_dest(file, insn, dest, false);
+
 		} else if (arch_is_retpoline(reloc->sym)) {
 			/*
 			 * Retpoline calls are really dynamic calls in
@@ -1020,55 +1073,7 @@ static int add_call_destinations(struct
 			continue;
 
 		} else
-			insn->call_dest = reloc->sym;
-
-		if (insn->call_dest && insn->call_dest->static_call_tramp) {
-			list_add_tail(&insn->call_node,
-				      &file->static_call_list);
-		}
-
-		/*
-		 * Many compilers cannot disable KCOV with a function attribute
-		 * so they need a little help, NOP out any KCOV calls from noinstr
-		 * text.
-		 */
-		if (insn->sec->noinstr &&
-		    !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
-			if (reloc) {
-				reloc->type = R_NONE;
-				elf_write_reloc(file->elf, reloc);
-			}
-
-			elf_write_insn(file->elf, insn->sec,
-				       insn->offset, insn->len,
-				       arch_nop_insn(insn->len));
-			insn->type = INSN_NOP;
-		}
-
-		if (mcount && !strcmp(insn->call_dest->name, "__fentry__")) {
-			if (reloc) {
-				reloc->type = R_NONE;
-				elf_write_reloc(file->elf, reloc);
-			}
-
-			elf_write_insn(file->elf, insn->sec,
-				       insn->offset, insn->len,
-				       arch_nop_insn(insn->len));
-
-			insn->type = INSN_NOP;
-
-			list_add_tail(&insn->mcount_loc_node,
-				      &file->mcount_loc_list);
-		}
-
-		/*
-		 * Whatever stack impact regular CALLs have, should be undone
-		 * by the RETURN of the called function.
-		 *
-		 * Annotated intra-function calls retain the stack_ops but
-		 * are converted to JUMP, see read_intra_function_calls().
-		 */
-		remove_insn_ops(insn);
+			add_call_dest(file, insn, reloc->sym, false);
 	}
 
 	return 0;
tools/objtool/include/objtool/arch.h +1 -0
@@ -82,6 +82,7 @@ unsigned long arch_jump_destination(stru
 unsigned long arch_dest_reloc_offset(int addend);
 
 const char *arch_nop_insn(int len);
+const char *arch_ret_insn(int len);
 
 int arch_decode_hint_reg(struct instruction *insn, u8 sp_reg);
 
author maintainer
#23 lore raw

Re: [PATCH v2 03/24] objtool: Handle __sanitize_cov*() tail calls

Quoted 11 lines · Marco Elver
Quoted 5 lines · Peter Zijlstra

Turns out the compilers also generate tail calls to __sanitize_cov*(), make sure to also patch those out in noinstr code.

Fixes 0f1441b44e82 ("objtool: Fix noinstr vs KCOV")

Thanks! More reason to not even try to do the same for other architectures, and the compiler needing the attribute...

Agreed!

#24 lore raw

Re: [PATCH v2 03/24] objtool: Handle __sanitize_cov*() tail calls

In reply to Peter Zijlstra
Quoted 22 lines · On Thu, 24 Jun 2021 11:41:02 +0200 Peter Zijlstra <[email protected]> wrote:
tools/objtool/check.c +22 -0
+static void add_call_dest(struct objtool_file *file, struct instruction *insn,
+			  struct symbol *dest, bool sibling)
+{
+	struct reloc *reloc = insn_reloc(file, insn);
+
+	insn->call_dest = dest;
+	if (!dest)
+		return;
+
+	if (insn->call_dest->static_call_tramp) {
+		list_add_tail(&insn->call_node,
+			      &file->static_call_list);
+	}
+
+	if (insn->sec->noinstr &&
+	    !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
+		if (reloc) {
+			reloc->type = R_NONE;
+			elf_write_reloc(file->elf, reloc);
+		}
+
+		elf_write_insn(file->elf, insn->sec,

tools/objtool/check.c static struct reloc *insn_reloc(struct o · line 872

Quoted 10 lines
tools/objtool/check.c +10 -0
+			       insn->offset, insn->len,
+			       sibling ? arch_ret_insn(insn->len)
+			               : arch_nop_insn(insn->len));
+
+		insn->type = sibling ? INSN_RETURN : INSN_NOP;
+	}
+
+	if (mcount && !strcmp(insn->call_dest->name, "__fentry__")) {
+		if (sibling)
+			WARN_FUNC("Tail call to __fentry__ !?!?", insn->sec, insn->offset);

Have you ever triggered the above?

-- Steve

Quoted 6 lines
tools/objtool/check.c +6 -0
+
+		if (reloc) {
+			reloc->type = R_NONE;
+			elf_write_reloc(file->elf, reloc);
+		}
+
author maintainer
#25 lore raw

Re: [PATCH v2 03/24] objtool: Handle __sanitize_cov*() tail calls

Quoted 29 lines · Steven Rostedt
Quoted 26 lines · On Thu, 24 Jun 2021 11:41:02 +0200 Peter Zijlstra <[email protected]> wrote:
tools/objtool/check.c +26 -0
+static void add_call_dest(struct objtool_file *file, struct instruction *insn,
+			  struct symbol *dest, bool sibling)
+{
+	struct reloc *reloc = insn_reloc(file, insn);
+
+	insn->call_dest = dest;
+	if (!dest)
+		return;
+
+	if (insn->call_dest->static_call_tramp) {
+		list_add_tail(&insn->call_node,
+			      &file->static_call_list);
+	}
+
+	if (insn->sec->noinstr &&
+	    !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
+		if (reloc) {
+			reloc->type = R_NONE;
+			elf_write_reloc(file->elf, reloc);
+		}
+
+		elf_write_insn(file->elf, insn->sec,
+			       insn->offset, insn->len,
+			       sibling ? arch_ret_insn(insn->len)
+			               : arch_nop_insn(insn->len));
+
Quoted 8 lines

tools/objtool/check.c static struct reloc *insn_reloc(struct o · line 872

Quoted 6 lines
tools/objtool/check.c +6 -0
+		insn->type = sibling ? INSN_RETURN : INSN_NOP;
+	}
+
+	if (mcount && !strcmp(insn->call_dest->name, "__fentry__")) {
+		if (sibling)
+			WARN_FUNC("Tail call to __fentry__ !?!?", insn->sec, insn->offset);

Have you ever triggered the above?

No, that would be really daft. But since this function is to be called for both regular and tail calls, I figured I'd at least pretend to handle the case.

#26 lore raw

Re: [PATCH v2 03/24] objtool: Handle __sanitize_cov*() tail calls

Quoted 9 lines · On Sat, 26 Jun 2021 10:18:12 +0200 Peter Zijlstra <[email protected]> wrote:
Quoted 5 lines

tools/objtool/check.c static struct reloc *insn_reloc(struct o · line 872

Quoted 3 lines
tools/objtool/check.c +3 -0
+	if (mcount && !strcmp(insn->call_dest->name, "__fentry__")) {
+		if (sibling)
+			WARN_FUNC("Tail call to __fentry__ !?!?", insn->sec, insn->offset);  

Have you ever triggered the above?

No, that would be really daft. But since this function is to be called for both regular and tail calls, I figured I'd at least pretend to handle the case.

OK. I thought this was like one of those weird laws that were made because you know that someone did something really stupid once.

-- Steve

#27 lore raw

Re: [PATCH v2 03/24] objtool: Handle __sanitize_cov*() tail calls

In reply to Peter Zijlstra
Quoted 4 lines · Peter Zijlstra
tools/objtool/check.c +4 -0
+	if (insn->sec->noinstr &&
+	    !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
+		if (reloc) {
+			reloc->type = R_NONE;

tools/objtool/check.c static struct reloc *insn_reloc(struct o · line 868

Quoted 10 lines
tools/objtool/check.c +10 -0
+			elf_write_reloc(file->elf, reloc);
+		}
+
+		elf_write_insn(file->elf, insn->sec,
+			       insn->offset, insn->len,
+			       sibling ? arch_ret_insn(insn->len)
+			               : arch_nop_insn(insn->len));
+
+		insn->type = sibling ? INSN_RETURN : INSN_NOP;
+	}

It'd be nice to keep the comment for this case that was in add_call_destinations().

Signature · 1 line
Josh
author maintainer
#28 lore raw

Re: [PATCH v2 03/24] objtool: Handle __sanitize_cov*() tail calls

Quoted 10 lines · Josh Poimboeuf
Quoted 9 lines · Peter Zijlstra
tools/objtool/check.c +9 -0
+	if (insn->sec->noinstr &&
+	    !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
+		if (reloc) {
+			reloc->type = R_NONE;
+			elf_write_reloc(file->elf, reloc);
+		}
+
+		elf_write_insn(file->elf, insn->sec,
+			       insn->offset, insn->len,
Quoted 8 lines

tools/objtool/check.c static struct reloc *insn_reloc(struct o · line 868

Quoted 5 lines
tools/objtool/check.c +5 -0
+			       sibling ? arch_ret_insn(insn->len)
+			               : arch_nop_insn(insn->len));
+
+		insn->type = sibling ? INSN_RETURN : INSN_NOP;
+	}

It'd be nice to keep the comment for this case that was in add_call_destinations().

Done!

merge bot Applied
#29 lore raw

[tip: objtool/core] objtool: Handle __sanitize_cov*() tail calls

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     f56dae88a81fded66adf2bea9922d1d98d1da14f
Gitweb:        https://git.kernel.org/tip/f56dae88a81fded66adf2bea9922d1d98d1da14f
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:02 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:45 +02:00

objtool: Handle __sanitize_cov*() tail calls

Turns out the compilers also generate tail calls to __sanitize_cov*(), make sure to also patch those out in noinstr code.

---
 tools/objtool/arch/x86/decode.c      |  20 +++-
 tools/objtool/check.c                | 158 +++++++++++++-------------
 tools/objtool/include/objtool/arch.h |   1 +-
 3 files changed, 105 insertions(+), 74 deletions(-)
tools/objtool/arch/x86/decode.c +20 -0
index 3435a32..340a3dc 100644
@@ -659,6 +659,26 @@ const char *arch_nop_insn(int len)
 	return nops[len-1];
 }
 
+#define BYTE_RET	0xC3
+
+const char *arch_ret_insn(int len)
+{
+	static const char ret[5][5] = {
+		{ BYTE_RET },
+		{ BYTE_RET, BYTES_NOP1 },
+		{ BYTE_RET, BYTES_NOP2 },
+		{ BYTE_RET, BYTES_NOP3 },
+		{ BYTE_RET, BYTES_NOP4 },
+	};
+
+	if (len < 1 || len > 5) {
+		WARN("invalid RET size: %d\n", len);
+		return NULL;
+	}
+
+	return ret[len-1];
+}
+
 /* asm/alternative.h ? */
 
 #define ALTINSTR_FLAG_INV	(1 << 15)
tools/objtool/check.c +84 -74

213 lines not on this page · raw message

tools/objtool/include/objtool/arch.h +1 -0
index a5ab682..6f482ae 100644
@@ -82,6 +82,7 @@ unsigned long arch_jump_destination(struct instruction *insn);
 unsigned long arch_dest_reloc_offset(int addend);
 
 const char *arch_nop_insn(int len);
+const char *arch_ret_insn(int len);
 
 int arch_decode_hint_reg(u8 sp_reg, int *base);
 
author maintainer
#30 lore raw

PATCH v2 4/24 x86/kvm: Always inline sev_*guest()

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0x4d: call to sev_es_guest() leaves .noinstr.text section vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0x50: call to sev_guest() leaves .noinstr.text section

---
 arch/x86/kvm/svm/svm.h |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kvm/svm/svm.h +3 -3
@@ -204,12 +204,12 @@ DECLARE_PER_CPU(struct svm_cpu_data *, s
 
 void recalc_intercepts(struct vcpu_svm *svm);
 
-static inline struct kvm_svm *to_kvm_svm(struct kvm *kvm)
+static __always_inline struct kvm_svm *to_kvm_svm(struct kvm *kvm)
 {
 	return container_of(kvm, struct kvm_svm, kvm);
 }
 
-static inline bool sev_guest(struct kvm *kvm)
+static __always_inline bool sev_guest(struct kvm *kvm)
 {
 #ifdef CONFIG_KVM_AMD_SEV
 	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
@@ -220,7 +220,7 @@ static inline bool sev_guest(struct kvm
 #endif
 }
 
-static inline bool sev_es_guest(struct kvm *kvm)
+static __always_inline bool sev_es_guest(struct kvm *kvm)
 {
 #ifdef CONFIG_KVM_AMD_SEV
 	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
merge bot Applied
#31 lore raw

[tip: objtool/core] x86/kvm: Always inline sev_*guest()

The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     2b2f72d4d81936bc08c18c426f40b7df70e2f8e7
Gitweb:        https://git.kernel.org/tip/2b2f72d4d81936bc08c18c426f40b7df70e2f8e7
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:03 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:45 +02:00

x86/kvm: Always inline sev_*guest()

vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0x4d: call to sev_es_guest() leaves .noinstr.text section vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0x50: call to sev_guest() leaves .noinstr.text section

---
 arch/x86/kvm/svm/svm.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kvm/svm/svm.h +3 -3
index 524d943..408031a 100644
@@ -218,12 +218,12 @@ DECLARE_PER_CPU(struct svm_cpu_data *, svm_data);
 
 void recalc_intercepts(struct vcpu_svm *svm);
 
-static inline struct kvm_svm *to_kvm_svm(struct kvm *kvm)
+static __always_inline struct kvm_svm *to_kvm_svm(struct kvm *kvm)
 {
 	return container_of(kvm, struct kvm_svm, kvm);
 }
 
-static inline bool sev_guest(struct kvm *kvm)
+static __always_inline bool sev_guest(struct kvm *kvm)
 {
 #ifdef CONFIG_KVM_AMD_SEV
 	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
@@ -234,7 +234,7 @@ static inline bool sev_guest(struct kvm *kvm)
 #endif
 }
 
-static inline bool sev_es_guest(struct kvm *kvm)
+static __always_inline bool sev_es_guest(struct kvm *kvm)
 {
 #ifdef CONFIG_KVM_AMD_SEV
 	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
author maintainer
#32 lore raw

PATCH v2 5/24 x86/kvm: Always inline vmload() / vmsave()

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0xea: call to vmload() leaves .noinstr.text section vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0x133: call to vmsave() leaves .noinstr.text section

---
 arch/x86/kvm/svm/svm_ops.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kvm/svm/svm_ops.h +2 -2
@@ -56,12 +56,12 @@ static inline void invlpga(unsigned long
  * VMSAVE, VMLOAD, etc... is still controlled by the effective address size,
  * hence 'unsigned long' instead of 'hpa_t'.
  */
-static inline void vmsave(unsigned long pa)
+static __always_inline void vmsave(unsigned long pa)
 {
 	svm_asm1(vmsave, "a" (pa), "memory");
 }
 
-static inline void vmload(unsigned long pa)
+static __always_inline void vmload(unsigned long pa)
 {
 	svm_asm1(vmload, "a" (pa), "memory");
 }
merge bot Applied
#33 lore raw

[tip: objtool/core] x86/kvm: Always inline vmload() / vmsave()

The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     a168233a440d01d60ca65ea41e876661466f108b
Gitweb:        https://git.kernel.org/tip/a168233a440d01d60ca65ea41e876661466f108b
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:04 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:45 +02:00

x86/kvm: Always inline vmload() / vmsave()

vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0xea: call to vmload() leaves .noinstr.text section vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0x133: call to vmsave() leaves .noinstr.text section

---
 arch/x86/kvm/svm/svm_ops.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kvm/svm/svm_ops.h +2 -2
index 22e2b01..9430d64 100644
@@ -56,12 +56,12 @@ static inline void invlpga(unsigned long addr, u32 asid)
  * VMSAVE, VMLOAD, etc... is still controlled by the effective address size,
  * hence 'unsigned long' instead of 'hpa_t'.
  */
-static inline void vmsave(unsigned long pa)
+static __always_inline void vmsave(unsigned long pa)
 {
 	svm_asm1(vmsave, "a" (pa), "memory");
 }
 
-static inline void vmload(unsigned long pa)
+static __always_inline void vmload(unsigned long pa)
 {
 	svm_asm1(vmload, "a" (pa), "memory");
 }
author maintainer
#34 lore raw

PATCH v2 6/24 x86: Always inline context_tracking_guest_enter()

In reply to Peter Zijlstra

Yes, it really did out-of-line this....

vmlinux.o: warning: objtool: vmx_vcpu_enter_exit()+0x31: call to context_tracking_guest_enter() leaves .noinstr.text section

000000000019f660 <context_tracking_guest_enter>:

  19f660:	e8 00 00 00 00       	callq  19f665 <context_tracking_guest_enter+0x5>	19f661: R_X86_64_PLT32	__sanitizer_cov_trace_pc-0x4
  19f665:	31 c0                	xor    %eax,%eax
  19f667:	c3                   	retq   
---
 include/linux/context_tracking.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/context_tracking.h +1 -1
@@ -105,7 +105,7 @@ static inline void user_exit_irqoff(void
 static inline enum ctx_state exception_enter(void) { return 0; }
 static inline void exception_exit(enum ctx_state prev_ctx) { }
 static inline enum ctx_state ct_state(void) { return CONTEXT_DISABLED; }
-static inline bool context_tracking_guest_enter(void) { return false; }
+static __always_inline bool context_tracking_guest_enter(void) { return false; }
 static inline void context_tracking_guest_exit(void) { }
 
 #endif /* !CONFIG_CONTEXT_TRACKING */
#35 lore raw

Re: [PATCH v2 06/24] x86: Always inline context_tracking_guest_enter()

Quoted 10 lines · Peter Zijlstra

Yes, it really did out-of-line this....

vmlinux.o: warning: objtool: vmx_vcpu_enter_exit()+0x31: call to context_tracking_guest_enter() leaves .noinstr.text section

000000000019f660 <context_tracking_guest_enter>:

  19f660:	e8 00 00 00 00       	callq  19f665 <context_tracking_guest_enter+0x5>	19f661: R_X86_64_PLT32	__sanitizer_cov_trace_pc-0x4
  19f665:	31 c0                	xor    %eax,%eax
  19f667:	c3                   	retq   

Ha. I'm guessing this was from CONFIG_DEBUG_SECTION_MISMATCH, which is only good for triggering a lot of these useless __always_inline patches.

I have a patch somewhere to get rid of it.

Signature · 1 line
Josh
#36 lore raw

Re: [PATCH v2 06/24] x86: Always inline context_tracking_guest_enter()

Quoted 10 lines · Josh Poimboeuf
Quoted 9 lines · Peter Zijlstra

Yes, it really did out-of-line this....

vmlinux.o: warning: objtool: vmx_vcpu_enter_exit()+0x31: call to context_tracking_guest_enter() leaves .noinstr.text section

000000000019f660 <context_tracking_guest_enter>:

  19f660:	e8 00 00 00 00       	callq  19f665 <context_tracking_guest_enter+0x5>	19f661: R_X86_64_PLT32	__sanitizer_cov_trace_pc-0x4
  19f665:	31 c0                	xor    %eax,%eax
  19f667:	c3                   	retq   
Quoted 6 lines
Quoted 1 line

Ha. I'm guessing this was from CONFIG_DEBUG_SECTION_MISMATCH, which is only good for triggering a lot of these useless __always_inline patches.

I have a patch somewhere to get rid of it.

Found it.

WARNING: This patch may shrink your patch set and improve your sanity.

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] kbuild: Remove CONFIG_DEBUG_SECTION_MISMATCH

Modpost's section mismatch detection warns when a non-init function references an __init function. The warning is needed because __init memory is freed during boot, so the non-init function might end up calling into some random memory.

CONFIG_DEBUG_SECTION_MISMATCH is intended to root out more of these issues by adding the -fno-inline-functions-called-once compiler flag, which forces once-called static functions to not be inlined. As described in the option's help description:

- Add the option -fno-inline-functions-called-once to gcc commands. When inlining a function annotated with __init in a non-init function, we would lose the section information and thus the analysis would not catch the illegal reference. This option tells gcc to inline less (but it does result in a larger kernel).

It's true that if an __init function is inlined in a non-init function, it's no longer __init. But that's not actually a problem.

If an inlined __init function doesn't access any other __init functions or data, the inlining is harmless.

If the inlined __init function does access other __init functions/data, __init relocations will be generated for a non-init section, and modpost's section mismatch detection will discover it.

So the option isn't actually useful. It's not even useful for finding issues on other configs, which might have different inlining decisions, because with -O2, once-called static functions are always inlined. And anyway, nowadays we have build bots everywhere, which are great at finding such edge cases.

I get the feeling this option has been responsible for dozens of "convert inline to __always_inline" patches over the years. Such patches usually complain about the compiler's inlining decisions being unpredictable. Turns out the culprit is this CONFIG_DEBUG_SECTION_MISMATCH option, at least for once-called functions.

This option really has no benefits, and only drawbacks, causing needless churn. Remove it.

---
 Makefile                                      |  5 -----
 arch/arc/configs/tb10x_defconfig              |  1 -
 arch/nds32/configs/defconfig                  |  1 -
 arch/s390/configs/debug_defconfig             |  1 -
 arch/s390/configs/defconfig                   |  1 -
 lib/Kconfig.debug                             | 21 -------------------
 .../selftests/wireguard/qemu/debug.config     |  1 -
 7 files changed, 31 deletions(-)
Makefile +0 -5
index c19d1638da25..195d4f4914e3 100644
@@ -913,11 +913,6 @@ KBUILD_CFLAGS	+= $(CC_FLAGS_FTRACE) $(CC_FLAGS_USING)
 KBUILD_AFLAGS	+= $(CC_FLAGS_USING)
 endif
 
-# We trigger additional mismatches with less inlining
-ifdef CONFIG_DEBUG_SECTION_MISMATCH
-KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once)
-endif
-
 ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
 KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
 LDFLAGS_vmlinux += --gc-sections
arch/arc/configs/tb10x_defconfig +0 -1
index a12656ec0072..5acf8cc3e7b0 100644
@@ -96,7 +96,6 @@ CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
 CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_STACKOVERFLOW=y
arch/nds32/configs/defconfig +0 -1
index f9a89cf00aa6..61b5b83bd20e 100644
@@ -93,7 +93,6 @@ CONFIG_GDB_SCRIPTS=y
 CONFIG_READABLE_ASM=y
 CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_PANIC_ON_OOPS=y
arch/s390/configs/debug_defconfig +0 -1
index b88184019af9..68104f82cc9d 100644
@@ -782,7 +782,6 @@ CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_INFO_DWARF4=y
 CONFIG_GDB_SCRIPTS=y
 CONFIG_HEADERS_INSTALL=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_PAGE_OWNER=y
arch/s390/configs/defconfig +0 -1
index 1667a3cdcf0a..a5e7eb0276c6 100644
@@ -767,7 +767,6 @@ CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_INFO_DWARF4=y
 CONFIG_GDB_SCRIPTS=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_WX=y
 CONFIG_PTDUMP_DEBUGFS=y
lib/Kconfig.debug +0 -21
index e5cdf98f50c2..93f9c00783b2 100644
@@ -381,27 +381,6 @@ config HEADERS_INSTALL
 	  user-space program samples. It is also needed by some features such
 	  as uapi header sanity checks.
 
-config DEBUG_SECTION_MISMATCH
-	bool "Enable full Section mismatch analysis"
-	help
-	  The section mismatch analysis checks if there are illegal
-	  references from one section to another section.
-	  During linktime or runtime, some sections are dropped;
-	  any use of code/data previously in these sections would
-	  most likely result in an oops.
-	  In the code, functions and variables are annotated with
-	  __init,, etc. (see the full list in include/linux/init.h),
-	  which results in the code/data being placed in specific sections.
-	  The section mismatch analysis is always performed after a full
-	  kernel build, and enabling this option causes the following
-	  additional step to occur:
-	  - Add the option -fno-inline-functions-called-once to gcc commands.
-	    When inlining a function annotated with __init in a non-init
-	    function, we would lose the section information and thus
-	    the analysis would not catch the illegal reference.
-	    This option tells gcc to inline less (but it does result in
-	    a larger kernel).
-
 config SECTION_MISMATCH_WARN_ONLY
 	bool "Make section mismatch errors non-fatal"
 	default y
tools/testing/selftests/wireguard/qemu/debug.config +0 -1
index fe07d97df9fa..83588bb08fde 100644
@@ -57,7 +57,6 @@ CONFIG_USER_STACKTRACE_SUPPORT=y
 CONFIG_DEBUG_SG=y
 CONFIG_DEBUG_NOTIFIERS=y
 CONFIG_X86_DEBUG_FPU=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
 CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
Signature · 1 line
2.31.1
author maintainer
#37 lore raw

Re: [PATCH v2 06/24] x86: Always inline context_tracking_guest_enter()

Quoted 1 line · Josh Poimboeuf

WARNING: This patch may shrink your patch set and improve your sanity.

I'll go rebuild me some kernels to see how many __always_inline things I can drop.

Lets add a few Cc's though.

Quoted 168 lines

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] kbuild: Remove CONFIG_DEBUG_SECTION_MISMATCH

Modpost's section mismatch detection warns when a non-init function references an __init function. The warning is needed because __init memory is freed during boot, so the non-init function might end up calling into some random memory.

CONFIG_DEBUG_SECTION_MISMATCH is intended to root out more of these issues by adding the -fno-inline-functions-called-once compiler flag, which forces once-called static functions to not be inlined. As described in the option's help description:

- Add the option -fno-inline-functions-called-once to gcc commands. When inlining a function annotated with __init in a non-init function, we would lose the section information and thus the analysis would not catch the illegal reference. This option tells gcc to inline less (but it does result in a larger kernel).

It's true that if an __init function is inlined in a non-init function, it's no longer __init. But that's not actually a problem.

If an inlined __init function doesn't access any other __init functions or data, the inlining is harmless.

If the inlined __init function does access other __init functions/data, __init relocations will be generated for a non-init section, and modpost's section mismatch detection will discover it.

So the option isn't actually useful. It's not even useful for finding issues on other configs, which might have different inlining decisions, because with -O2, once-called static functions are always inlined. And anyway, nowadays we have build bots everywhere, which are great at finding such edge cases.

I get the feeling this option has been responsible for dozens of "convert inline to __always_inline" patches over the years. Such patches usually complain about the compiler's inlining decisions being unpredictable. Turns out the culprit is this CONFIG_DEBUG_SECTION_MISMATCH option, at least for once-called functions.

This option really has no benefits, and only drawbacks, causing needless churn. Remove it.

---
 Makefile                                      |  5 -----
 arch/arc/configs/tb10x_defconfig              |  1 -
 arch/nds32/configs/defconfig                  |  1 -
 arch/s390/configs/debug_defconfig             |  1 -
 arch/s390/configs/defconfig                   |  1 -
 lib/Kconfig.debug                             | 21 -------------------
 .../selftests/wireguard/qemu/debug.config     |  1 -
 7 files changed, 31 deletions(-)
Makefile +0 -5
index c19d1638da25..195d4f4914e3 100644
@@ -913,11 +913,6 @@ KBUILD_CFLAGS	+= $(CC_FLAGS_FTRACE) $(CC_FLAGS_USING)
 KBUILD_AFLAGS	+= $(CC_FLAGS_USING)
 endif
 
-# We trigger additional mismatches with less inlining
-ifdef CONFIG_DEBUG_SECTION_MISMATCH
-KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once)
-endif
-
 ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
 KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
 LDFLAGS_vmlinux += --gc-sections
arch/arc/configs/tb10x_defconfig +0 -1
index a12656ec0072..5acf8cc3e7b0 100644
@@ -96,7 +96,6 @@ CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
 CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_STACKOVERFLOW=y
arch/nds32/configs/defconfig +0 -1
index f9a89cf00aa6..61b5b83bd20e 100644
@@ -93,7 +93,6 @@ CONFIG_GDB_SCRIPTS=y
 CONFIG_READABLE_ASM=y
 CONFIG_HEADERS_INSTALL=y
 CONFIG_HEADERS_CHECK=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_PANIC_ON_OOPS=y
arch/s390/configs/debug_defconfig +0 -1
index b88184019af9..68104f82cc9d 100644
@@ -782,7 +782,6 @@ CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_INFO_DWARF4=y
 CONFIG_GDB_SCRIPTS=y
 CONFIG_HEADERS_INSTALL=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_PAGE_OWNER=y
arch/s390/configs/defconfig +0 -1
index 1667a3cdcf0a..a5e7eb0276c6 100644
@@ -767,7 +767,6 @@ CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_INFO_DWARF4=y
 CONFIG_GDB_SCRIPTS=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_WX=y
 CONFIG_PTDUMP_DEBUGFS=y
lib/Kconfig.debug +0 -21
index e5cdf98f50c2..93f9c00783b2 100644
@@ -381,27 +381,6 @@ config HEADERS_INSTALL
 	  user-space program samples. It is also needed by some features such
 	  as uapi header sanity checks.
 
-config DEBUG_SECTION_MISMATCH
-	bool "Enable full Section mismatch analysis"
-	help
-	  The section mismatch analysis checks if there are illegal
-	  references from one section to another section.
-	  During linktime or runtime, some sections are dropped;
-	  any use of code/data previously in these sections would
-	  most likely result in an oops.
-	  In the code, functions and variables are annotated with
-	  __init,, etc. (see the full list in include/linux/init.h),
-	  which results in the code/data being placed in specific sections.
-	  The section mismatch analysis is always performed after a full
-	  kernel build, and enabling this option causes the following
-	  additional step to occur:
-	  - Add the option -fno-inline-functions-called-once to gcc commands.
-	    When inlining a function annotated with __init in a non-init
-	    function, we would lose the section information and thus
-	    the analysis would not catch the illegal reference.
-	    This option tells gcc to inline less (but it does result in
-	    a larger kernel).
-
 config SECTION_MISMATCH_WARN_ONLY
 	bool "Make section mismatch errors non-fatal"
 	default y
tools/testing/selftests/wireguard/qemu/debug.config +0 -1
index fe07d97df9fa..83588bb08fde 100644
@@ -57,7 +57,6 @@ CONFIG_USER_STACKTRACE_SUPPORT=y
 CONFIG_DEBUG_SG=y
 CONFIG_DEBUG_NOTIFIERS=y
 CONFIG_X86_DEBUG_FPU=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
 CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
Signature · 1 line
2.31.1

A message that is not in the archive (sent off-list or not yet received): [email protected]

#39 lore raw

Re: [PATCH v2 06/24] x86: Always inline context_tracking_guest_enter()

Quoted 28 lines · Sam Ravnborg

Hi Josh,

Quoted 15 lines · Peter Zijlstra
Quoted 1 line · Josh Poimboeuf

WARNING: This patch may shrink your patch set and improve your sanity.

I'll go rebuild me some kernels to see how many __always_inline things I can drop.

Lets add a few Cc's though.

Quoted 6 lines

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] kbuild: Remove CONFIG_DEBUG_SECTION_MISMATCH

So the option isn't actually useful. It's not even useful for finding issues on other configs, which might have different inlining decisions, because with -O2, once-called static functions are always inlined.

We have following -O possibilities:

    ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
    KBUILD_CFLAGS += -O2
    else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
    KBUILD_CFLAGS += -O3
    else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
    KBUILD_CFLAGS += -Os
    endif
Quoted 3 lines

We always built with -Os or -O2 (and ARC supports -O3).
Do we know that gcc and clang will always inline once-called functions with -O2 and -Os for the relevant architectures?

Hm, I should have read the GCC manual a little closer:

-finline-functions-called-once
Consider all "static" functions called once for inlining into their caller even if they are not marked "inline".

So it's not necessarily a guarantee that once-called functions will always be inlined. Looking at GCC code, there at least some theoretical edge cases involving optimization mismatches between caller and callee, though as a rule the kernel avoids function-specific optimizations.

Still, I think the patch is a net benefit. I'll update the patch description and post it again separately since Peter doesn't seem to need it here.

Quoted 5 lines

If you can answer yes to this with some confidence then you can add my:

Note: I added this option long time ago and is unhappy if this only have resulted in useless code changes.

It might have been useful in the days before we had all the automated build bots doing randconfigs. Nowadays any __init mismatch issues which would only be seen in obscure config/compiler combinations will be rooted out by the bots reporting modpost section mismatch warnings.

Signature · 1 line
Josh
author maintainer
#40 lore raw

Re: [PATCH v2 06/24] x86: Always inline context_tracking_guest_enter()

In reply to Josh Poimboeuf
Quoted 11 lines · Josh Poimboeuf
Quoted 10 lines · Josh Poimboeuf
Quoted 9 lines · Peter Zijlstra

Yes, it really did out-of-line this....

vmlinux.o: warning: objtool: vmx_vcpu_enter_exit()+0x31: call to context_tracking_guest_enter() leaves .noinstr.text section

000000000019f660 <context_tracking_guest_enter>:

  19f660:	e8 00 00 00 00       	callq  19f665 <context_tracking_guest_enter+0x5>	19f661: R_X86_64_PLT32	__sanitizer_cov_trace_pc-0x4
  19f665:	31 c0                	xor    %eax,%eax
  19f667:	c3                   	retq   
Quoted 8 lines
Quoted 6 lines
Quoted 1 line

Ha. I'm guessing this was from CONFIG_DEBUG_SECTION_MISMATCH, which is only good for triggering a lot of these useless __always_inline patches.

I have a patch somewhere to get rid of it.

Found it.

Even with your patch applied, x86_64-allyesconfig still gives me the above. In fact, I had to re-instate 4 of the 6 __always_inline patches, so I've kept them all for now.

merge bot Applied
#41 lore raw

[tip: objtool/core] x86: Always inline context_tracking_guest_enter()

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     e25b694bf1d9ef4a3f36c0b85348f8e780f22139
Gitweb:        https://git.kernel.org/tip/e25b694bf1d9ef4a3f36c0b85348f8e780f22139
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:05 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:46 +02:00

x86: Always inline context_tracking_guest_enter()

Yes, it really did out-of-line this....

vmlinux.o: warning: objtool: vmx_vcpu_enter_exit()+0x31: call to context_tracking_guest_enter() leaves .noinstr.text section

000000000019f660 <context_tracking_guest_enter>:

  19f660:	e8 00 00 00 00       	callq  19f665 <context_tracking_guest_enter+0x5>	19f661: R_X86_64_PLT32	__sanitizer_cov_trace_pc-0x4
  19f665:	31 c0                	xor    %eax,%eax
  19f667:	c3                   	retq
---
 include/linux/context_tracking.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/context_tracking.h +1 -1
index 4d7fced..7a14807 100644
@@ -105,7 +105,7 @@ static inline void user_exit_irqoff(void) { }
 static inline enum ctx_state exception_enter(void) { return 0; }
 static inline void exception_exit(enum ctx_state prev_ctx) { }
 static inline enum ctx_state ct_state(void) { return CONTEXT_DISABLED; }
-static inline bool context_tracking_guest_enter(void) { return false; }
+static __always_inline bool context_tracking_guest_enter(void) { return false; }
 static inline void context_tracking_guest_exit(void) { }
 
 #endif /* !CONFIG_CONTEXT_TRACKING */
author maintainer
#42 lore raw

PATCH v2 7/24 x86/kvm: Always inline to_svm()

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0x13: call to to_svm() leaves .noinstr.text section

---
 arch/x86/kvm/svm/svm.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/svm/svm.h +1 -1
@@ -252,7 +252,7 @@ static inline bool vmcb_is_dirty(struct
         return !test_bit(bit, (unsigned long *)&vmcb->control.clean);
 }
 
-static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
+static __always_inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
 {
 	return container_of(vcpu, struct vcpu_svm, vcpu);
 }
merge bot Applied
#43 lore raw

[tip: objtool/core] x86/kvm: Always inline to_svm()

The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     aee045ed0a6b22100f4d5945ee2deb75db6a0dd5
Gitweb:        https://git.kernel.org/tip/aee045ed0a6b22100f4d5945ee2deb75db6a0dd5
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:06 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:46 +02:00

x86/kvm: Always inline to_svm()

vmlinux.o: warning: objtool: svm_vcpu_enter_exit()+0x13: call to to_svm() leaves .noinstr.text section

---
 arch/x86/kvm/svm/svm.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/svm/svm.h +1 -1
index 408031a..38f12a6 100644
@@ -271,7 +271,7 @@ static inline bool vmcb_is_dirty(struct vmcb *vmcb, int bit)
         return !test_bit(bit, (unsigned long *)&vmcb->control.clean);
 }
 
-static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
+static __always_inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
 {
 	return container_of(vcpu, struct vcpu_svm, vcpu);
 }
author maintainer
#44 lore raw

PATCH v2 8/24 x86/kvm: Always inline evmcs_write64()

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: vmx_update_host_rsp()+0x64: call to evmcs_write64() leaves .noinstr.text section

---
 arch/x86/kvm/vmx/evmcs.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx/evmcs.h +2 -2
@@ -97,7 +97,7 @@ static __always_inline int get_evmcs_off
 
 #undef ROL16
 
-static inline void evmcs_write64(unsigned long field, u64 value)
+static __always_inline void evmcs_write64(unsigned long field, u64 value)
 {
 	u16 clean_field;
 	int offset = get_evmcs_offset(field, &clean_field);
@@ -187,7 +187,7 @@ static inline void evmcs_load(u64 phys_a
 
 __init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
 #else /* !IS_ENABLED(CONFIG_HYPERV) */
-static inline void evmcs_write64(unsigned long field, u64 value) {}
+static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
 static inline void evmcs_write32(unsigned long field, u32 value) {}
 static inline void evmcs_write16(unsigned long field, u16 value) {}
 static inline u64 evmcs_read64(unsigned long field) { return 0; }
merge bot Applied
#45 lore raw

[tip: objtool/core] x86/kvm: Always inline evmcs_write64()

The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     010050a86393703f43859a4704d2193be49126d6
Gitweb:        https://git.kernel.org/tip/010050a86393703f43859a4704d2193be49126d6
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:07 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:46 +02:00

x86/kvm: Always inline evmcs_write64()

vmlinux.o: warning: objtool: vmx_update_host_rsp()+0x64: call to evmcs_write64() leaves .noinstr.text section

---
 arch/x86/kvm/vmx/evmcs.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx/evmcs.h +2 -2
index 152ab0a..16731d2 100644
@@ -93,7 +93,7 @@ static __always_inline int get_evmcs_offset(unsigned long field,
 	return evmcs_field->offset;
 }
 
-static inline void evmcs_write64(unsigned long field, u64 value)
+static __always_inline void evmcs_write64(unsigned long field, u64 value)
 {
 	u16 clean_field;
 	int offset = get_evmcs_offset(field, &clean_field);
@@ -183,7 +183,7 @@ static inline void evmcs_load(u64 phys_addr)
 
 __init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
 #else /* !IS_ENABLED(CONFIG_HYPERV) */
-static inline void evmcs_write64(unsigned long field, u64 value) {}
+static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
 static inline void evmcs_write32(unsigned long field, u32 value) {}
 static inline void evmcs_write16(unsigned long field, u16 value) {}
 static inline u64 evmcs_read64(unsigned long field) { return 0; }
author maintainer
#46 lore raw

PATCH v2 9/24 x86: Always inline ip_within_syscall_gap()

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: vc_switch_off_ist()+0x20: call to ip_within_syscall_gap.isra.0() leaves .noinstr.text section

---
 arch/x86/include/asm/ptrace.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/ptrace.h +1 -1
@@ -181,7 +181,7 @@ static inline bool any_64bit_mode(struct
 #define current_user_stack_pointer()	current_pt_regs()->sp
 #define compat_user_stack_pointer()	current_pt_regs()->sp
 
-static inline bool ip_within_syscall_gap(struct pt_regs *regs)
+static __always_inline bool ip_within_syscall_gap(struct pt_regs *regs)
 {
 	bool ret = (regs->ip >= (unsigned long)entry_SYSCALL_64 &&
 		    regs->ip <  (unsigned long)entry_SYSCALL_64_safe_stack);
merge bot Applied
#47 lore raw

[tip: objtool/core] x86: Always inline ip_within_syscall_gap()

The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     c6b01dace2cd7f6b3e9174d4d1411755608486f1
Gitweb:        https://git.kernel.org/tip/c6b01dace2cd7f6b3e9174d4d1411755608486f1
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:08 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:47 +02:00

x86: Always inline ip_within_syscall_gap()

vmlinux.o: warning: objtool: vc_switch_off_ist()+0x20: call to ip_within_syscall_gap.isra.0() leaves .noinstr.text section

---
 arch/x86/include/asm/ptrace.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/ptrace.h +1 -1
index b94f615..7036631 100644
@@ -181,7 +181,7 @@ static inline bool any_64bit_mode(struct pt_regs *regs)
 #define current_user_stack_pointer()	current_pt_regs()->sp
 #define compat_user_stack_pointer()	current_pt_regs()->sp
 
-static inline bool ip_within_syscall_gap(struct pt_regs *regs)
+static __always_inline bool ip_within_syscall_gap(struct pt_regs *regs)
 {
 	bool ret = (regs->ip >= (unsigned long)entry_SYSCALL_64 &&
 		    regs->ip <  (unsigned long)entry_SYSCALL_64_safe_stack);
author maintainer
#48 lore raw

PATCH v2 10/24 x86/sev: Fix noinstr for vc_ghcb_invalidate()

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: __sev_put_ghcb()+0x88: call to __memset() leaves .noinstr.text section vmlinux.o: warning: objtool: __sev_es_nmi_complete()+0x39: call to __memset() leaves .noinstr.text section

---
 arch/x86/kernel/sev-shared.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/sev-shared.c +1 -1
@@ -64,7 +64,7 @@ static bool sev_es_negotiate_protocol(vo
 static __always_inline void vc_ghcb_invalidate(struct ghcb *ghcb)
 {
 	ghcb->save.sw_exit_code = 0;
-	memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
+	__builtin_memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
 }
 
 static bool vc_decoding_needed(unsigned long exit_code)
merge bot Applied
#49 lore raw

[tip: objtool/core] x86/sev: Fix noinstr for vc_ghcb_invalidate()

The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     2c36d87be49355931da5b29ef7621505e0e46ce9
Gitweb:        https://git.kernel.org/tip/2c36d87be49355931da5b29ef7621505e0e46ce9
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:09 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:47 +02:00

x86/sev: Fix noinstr for vc_ghcb_invalidate()

vmlinux.o: warning: objtool: __sev_put_ghcb()+0x88: call to __memset() leaves .noinstr.text section vmlinux.o: warning: objtool: __sev_es_nmi_complete()+0x39: call to __memset() leaves .noinstr.text section

---
 arch/x86/kernel/sev-shared.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/sev-shared.c +1 -1
index 9f90f46..34f20e0 100644
@@ -64,7 +64,7 @@ static bool sev_es_negotiate_protocol(void)
 static __always_inline void vc_ghcb_invalidate(struct ghcb *ghcb)
 {
 	ghcb->save.sw_exit_code = 0;
-	memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
+	__builtin_memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
 }
 
 static bool vc_decoding_needed(unsigned long exit_code)
author maintainer
#50 lore raw

PATCH v2 11/24 locking/lockdep: Avoid RCU-induced noinstr fail

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: look_up_lock_class()+0xc7: call to rcu_read_lock_any_held() leaves .noinstr.text section

---
 kernel/locking/lockdep.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/locking/lockdep.c +1 -1
@@ -888,7 +888,7 @@ look_up_lock_class(const struct lockdep_
 	if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
 		return NULL;
 
-	hlist_for_each_entry_rcu(class, hash_head, hash_entry) {
+	hlist_for_each_entry_rcu_notrace(class, hash_head, hash_entry) {
 		if (class->key == key) {
 			/*
 			 * Huh! same key, different name? Did someone trample
merge bot Applied
#51 lore raw

[tip: objtool/core] locking/lockdep: Avoid RCU-induced noinstr fail

The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     ce0b9c805dd66d5e49fd53ec5415ae398f4c56e6
Gitweb:        https://git.kernel.org/tip/ce0b9c805dd66d5e49fd53ec5415ae398f4c56e6
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:10 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:47 +02:00

locking/lockdep: Avoid RCU-induced noinstr fail

vmlinux.o: warning: objtool: look_up_lock_class()+0xc7: call to rcu_read_lock_any_held() leaves .noinstr.text section

---
 kernel/locking/lockdep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/locking/lockdep.c +1 -1
index bf1c00c..8a50967 100644
@@ -888,7 +888,7 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
 	if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
 		return NULL;
 
-	hlist_for_each_entry_rcu(class, hash_head, hash_entry) {
+	hlist_for_each_entry_rcu_notrace(class, hash_head, hash_entry) {
 		if (class->key == key) {
 			/*
 			 * Huh! same key, different name? Did someone trample
author maintainer
#52 lore raw

PATCH v2 12/24 x86/paravirt: Mark arch_local_irq_*() __always_inline

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: lockdep_hardirqs_on()+0x72: call to arch_local_save_flags() leaves .noinstr.text section vmlinux.o: warning: objtool: lockdep_hardirqs_off()+0x73: call to arch_local_save_flags() leaves .noinstr.text section vmlinux.o: warning: objtool: match_held_lock()+0x11f: call to arch_local_save_flags() leaves .noinstr.text section

vmlinux.o: warning: objtool: lock_is_held_type()+0x4e: call to arch_local_irq_save() leaves .noinstr.text section

vmlinux.o: warning: objtool: lock_is_held_type()+0x65: call to arch_local_irq_disable() leaves .noinstr.text section

vmlinux.o: warning: objtool: lock_is_held_type()+0xfe: call to arch_local_irq_enable() leaves .noinstr.text section

It makes no sense to not inline these things.

---
 arch/x86/include/asm/paravirt.h |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/include/asm/paravirt.h +4 -4
@@ -681,23 +681,23 @@ bool __raw_callee_save___native_vcpu_is_
 	((struct paravirt_callee_save) { func })
 
 #ifdef CONFIG_PARAVIRT_XXL
-static inline notrace unsigned long arch_local_save_flags(void)
+static __always_inline unsigned long arch_local_save_flags(void)
 {
 	return PVOP_ALT_CALLEE0(unsigned long, irq.save_fl, "pushf; pop %%rax;",
 				ALT_NOT(X86_FEATURE_XENPV));
 }
 
-static inline notrace void arch_local_irq_disable(void)
+static __always_inline void arch_local_irq_disable(void)
 {
 	PVOP_ALT_VCALLEE0(irq.irq_disable, "cli;", ALT_NOT(X86_FEATURE_XENPV));
 }
 
-static inline notrace void arch_local_irq_enable(void)
+static __always_inline void arch_local_irq_enable(void)
 {
 	PVOP_ALT_VCALLEE0(irq.irq_enable, "sti;", ALT_NOT(X86_FEATURE_XENPV));
 }
 
-static inline notrace unsigned long arch_local_irq_save(void)
+static __always_inline unsigned long arch_local_irq_save(void)
 {
 	unsigned long f;
 
maintainer Reviewed-by on v2 12/24
#53 lore raw

Re: [PATCH v2 12/24] x86/paravirt: Mark arch_local_irq_*() __always_inline

Quoted 6 lines · Peter Zijlstra

vmlinux.o: warning: objtool: lockdep_hardirqs_on()+0x72: call to arch_local_save_flags() leaves .noinstr.text section vmlinux.o: warning: objtool: lockdep_hardirqs_off()+0x73: call to arch_local_save_flags() leaves .noinstr.text section vmlinux.o: warning: objtool: match_held_lock()+0x11f: call to arch_local_save_flags() leaves .noinstr.text section

vmlinux.o: warning: objtool: lock_is_held_type()+0x4e: call to arch_local_irq_save() leaves .noinstr.text section

Quoted 7 lines

vmlinux.o: warning: objtool: lock_is_held_type()+0x65: call to arch_local_irq_disable() leaves .noinstr.text section

vmlinux.o: warning: objtool: lock_is_held_type()+0xfe: call to arch_local_irq_enable() leaves .noinstr.text section

It makes no sense to not inline these things.

Juergen

merge bot Applied
#54 lore raw

[tip: objtool/core] x86/paravirt: Mark arch_local_irq_*() __always_inline

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     e9382440de18718fb6f878986c0844c30abc6f99
Gitweb:        https://git.kernel.org/tip/e9382440de18718fb6f878986c0844c30abc6f99
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:11 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:47 +02:00

x86/paravirt: Mark arch_local_irq_*() __always_inline

vmlinux.o: warning: objtool: lockdep_hardirqs_on()+0x72: call to arch_local_save_flags() leaves .noinstr.text section vmlinux.o: warning: objtool: lockdep_hardirqs_off()+0x73: call to arch_local_save_flags() leaves .noinstr.text section vmlinux.o: warning: objtool: match_held_lock()+0x11f: call to arch_local_save_flags() leaves .noinstr.text section

vmlinux.o: warning: objtool: lock_is_held_type()+0x4e: call to arch_local_irq_save() leaves .noinstr.text section

vmlinux.o: warning: objtool: lock_is_held_type()+0x65: call to arch_local_irq_disable() leaves .noinstr.text section

vmlinux.o: warning: objtool: lock_is_held_type()+0xfe: call to arch_local_irq_enable() leaves .noinstr.text section

It makes no sense to not inline these things.

---
 arch/x86/include/asm/paravirt.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/include/asm/paravirt.h +4 -4
index da3a1ac..89a5322 100644
@@ -678,23 +678,23 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
 	((struct paravirt_callee_save) { func })
 
 #ifdef CONFIG_PARAVIRT_XXL
-static inline notrace unsigned long arch_local_save_flags(void)
+static __always_inline unsigned long arch_local_save_flags(void)
 {
 	return PVOP_ALT_CALLEE0(unsigned long, irq.save_fl, "pushf; pop %%rax;",
 				ALT_NOT(X86_FEATURE_XENPV));
 }
 
-static inline notrace void arch_local_irq_disable(void)
+static __always_inline void arch_local_irq_disable(void)
 {
 	PVOP_ALT_VCALLEE0(irq.irq_disable, "cli;", ALT_NOT(X86_FEATURE_XENPV));
 }
 
-static inline notrace void arch_local_irq_enable(void)
+static __always_inline void arch_local_irq_enable(void)
 {
 	PVOP_ALT_VCALLEE0(irq.irq_enable, "sti;", ALT_NOT(X86_FEATURE_XENPV));
 }
 
-static inline notrace unsigned long arch_local_irq_save(void)
+static __always_inline unsigned long arch_local_irq_save(void)
 {
 	unsigned long f;
 
author maintainer
#55 lore raw

PATCH v2 13/24 x86/paravirt: Use PVOP_* for paravirt calls

In reply to Peter Zijlstra

Doing unconditional indirect calls through the pv_ops vector is weird.

---
 arch/x86/include/asm/paravirt.h |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/include/asm/paravirt.h +4 -4
@@ -52,11 +52,11 @@ void __init paravirt_set_cap(void);
 /* The paravirtualized I/O functions */
 static inline void slow_down_io(void)
 {
-	pv_ops.cpu.io_delay();
+	PVOP_VCALL0(cpu.io_delay);
 #ifdef REALLY_SLOW_IO
-	pv_ops.cpu.io_delay();
-	pv_ops.cpu.io_delay();
-	pv_ops.cpu.io_delay();
+	PVOP_VCALL0(cpu.io_delay);
+	PVOP_VCALL0(cpu.io_delay);
+	PVOP_VCALL0(cpu.io_delay);
 #endif
 }
 
merge bot Applied
#57 lore raw

[tip: objtool/core] x86/paravirt: Use PVOP_* for paravirt calls

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     eac46b323b28215ad19d53390737df4aa336ac14
Gitweb:        https://git.kernel.org/tip/eac46b323b28215ad19d53390737df4aa336ac14
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:12 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:48 +02:00

x86/paravirt: Use PVOP_* for paravirt calls

Doing unconditional indirect calls through the pv_ops vector is weird.

---
 arch/x86/include/asm/paravirt.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/include/asm/paravirt.h +4 -4
index 89a5322..a13a9a3 100644
@@ -52,11 +52,11 @@ void __init paravirt_set_cap(void);
 /* The paravirtualized I/O functions */
 static inline void slow_down_io(void)
 {
-	pv_ops.cpu.io_delay();
+	PVOP_VCALL0(cpu.io_delay);
 #ifdef REALLY_SLOW_IO
-	pv_ops.cpu.io_delay();
-	pv_ops.cpu.io_delay();
-	pv_ops.cpu.io_delay();
+	PVOP_VCALL0(cpu.io_delay);
+	PVOP_VCALL0(cpu.io_delay);
+	PVOP_VCALL0(cpu.io_delay);
 #endif
 }
 
author maintainer
#58 lore raw

PATCH v2 14/24 x86/xen: Make read_cr2() noinstr

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[41]: native_read_cr2
vmlinux.o: warning: objtool: pv_ops[41]: xen_read_cr2
vmlinux.o: warning: objtool: pv_ops[41]: xen_read_cr2_direct
vmlinux.o: warning: objtool: exc_double_fault()+0x15: call to pv_ops[41]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h |    2 +-
 arch/x86/kernel/paravirt.c      |    7 ++++++-
 arch/x86/xen/xen-asm.S          |    2 ++
 3 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
@@ -133,7 +133,7 @@ static inline void write_cr0(unsigned lo
 	PVOP_VCALL1(cpu.write_cr0, x);
 }
 
-static inline unsigned long read_cr2(void)
+static __always_inline unsigned long read_cr2(void)
 {
 	return PVOP_ALT_CALLEE0(unsigned long, mmu.read_cr2,
 				"mov %%cr2, %%rax;",
arch/x86/kernel/paravirt.c +6 -1
@@ -238,6 +238,11 @@ struct pv_info pv_info = {
 /* 64-bit pagetable entries */
 #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_64)
 
+static noinstr unsigned long pv_native_read_cr2(void)
+{
+	return native_read_cr2();
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -298,7 +303,7 @@ struct paravirt_patch_template pv_ops =
 	.mmu.exit_mmap		= paravirt_nop,
 
 #ifdef CONFIG_PARAVIRT_XXL
-	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(native_read_cr2),
+	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(pv_native_read_cr2),
 	.mmu.write_cr2		= native_write_cr2,
 	.mmu.read_cr3		= __native_read_cr3,
 	.mmu.write_cr3		= native_write_cr3,
arch/x86/xen/xen-asm.S +2 -0
@@ -102,6 +102,7 @@ SYM_FUNC_START(check_events)
 	ret
 SYM_FUNC_END(check_events)
 
+.pushsection .noinstr.text, "ax"
 SYM_FUNC_START(xen_read_cr2)
 	FRAME_BEGIN
 	_ASM_MOV PER_CPU_VAR(xen_vcpu), %_ASM_AX
@@ -116,6 +117,7 @@ SYM_FUNC_START(xen_read_cr2_direct)
 	FRAME_END
 	ret
 SYM_FUNC_END(xen_read_cr2_direct);
+.popsection
 
 .macro xen_pv_trap name
 SYM_CODE_START(xen_\name)
maintainer Reviewed-by on v2 14/24
#59 lore raw

Re: [PATCH v2 14/24] x86/xen: Make read_cr2() noinstr

Quoted 6 lines · Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[41]: native_read_cr2
vmlinux.o: warning: objtool: pv_ops[41]: xen_read_cr2
vmlinux.o: warning: objtool: pv_ops[41]: xen_read_cr2_direct
vmlinux.o: warning: objtool: exc_double_fault()+0x15: call to pv_ops[41]() leaves .noinstr.text section

Juergen

merge bot Applied
#60 lore raw

[tip: objtool/core] x86/xen: Make read_cr2() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     ee6781aba03fc3040e3dfaa57fe8c2cea751ee35
Gitweb:        https://git.kernel.org/tip/ee6781aba03fc3040e3dfaa57fe8c2cea751ee35
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:13 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:48 +02:00

x86/xen: Make read_cr2() noinstr

vmlinux.o: warning: objtool: pv_ops[41]: native_read_cr2
vmlinux.o: warning: objtool: pv_ops[41]: xen_read_cr2
vmlinux.o: warning: objtool: pv_ops[41]: xen_read_cr2_direct
vmlinux.o: warning: objtool: exc_double_fault()+0x15: call to pv_ops[41]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h | 2 +-
 arch/x86/kernel/paravirt.c      | 7 ++++++-
 arch/x86/xen/xen-asm.S          | 2 ++
 3 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
index a13a9a3..8878065 100644
@@ -133,7 +133,7 @@ static inline void write_cr0(unsigned long x)
 	PVOP_VCALL1(cpu.write_cr0, x);
 }
 
-static inline unsigned long read_cr2(void)
+static __always_inline unsigned long read_cr2(void)
 {
 	return PVOP_ALT_CALLEE0(unsigned long, mmu.read_cr2,
 				"mov %%cr2, %%rax;",
arch/x86/kernel/paravirt.c +6 -1
index 04cafc0..ff4ade8 100644
@@ -238,6 +238,11 @@ struct pv_info pv_info = {
 /* 64-bit pagetable entries */
 #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_64)
 
+static noinstr unsigned long pv_native_read_cr2(void)
+{
+	return native_read_cr2();
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -298,7 +303,7 @@ struct paravirt_patch_template pv_ops = {
 	.mmu.exit_mmap		= paravirt_nop,
 
 #ifdef CONFIG_PARAVIRT_XXL
-	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(native_read_cr2),
+	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(pv_native_read_cr2),
 	.mmu.write_cr2		= native_write_cr2,
 	.mmu.read_cr3		= __native_read_cr3,
 	.mmu.write_cr3		= native_write_cr3,
arch/x86/xen/xen-asm.S +2 -0
index 1e62644..aef4a1e 100644
@@ -102,6 +102,7 @@ SYM_FUNC_START(check_events)
 	ret
 SYM_FUNC_END(check_events)
 
+.pushsection .noinstr.text, "ax"
 SYM_FUNC_START(xen_read_cr2)
 	FRAME_BEGIN
 	_ASM_MOV PER_CPU_VAR(xen_vcpu), %_ASM_AX
@@ -116,6 +117,7 @@ SYM_FUNC_START(xen_read_cr2_direct)
 	FRAME_END
 	ret
 SYM_FUNC_END(xen_read_cr2_direct);
+.popsection
 
 .macro xen_pv_trap name
 SYM_CODE_START(xen_\name)
merge bot Applied
#61 lore raw

[tip: objtool/core] x86/xen: Make read_cr2() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     0a53c9acf4da51a75392b0b543ce5eaae78a567f
Gitweb:        https://git.kernel.org/tip/0a53c9acf4da51a75392b0b543ce5eaae78a567f
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:13 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:11:50 +02:00

x86/xen: Make read_cr2() noinstr

vmlinux.o: warning: objtool: pv_ops[41]: native_read_cr2
vmlinux.o: warning: objtool: pv_ops[41]: xen_read_cr2
vmlinux.o: warning: objtool: pv_ops[41]: xen_read_cr2_direct
vmlinux.o: warning: objtool: exc_double_fault()+0x15: call to pv_ops[41]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h | 2 +-
 arch/x86/kernel/paravirt.c      | 7 ++++++-
 arch/x86/xen/xen-asm.S          | 2 ++
 3 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
index a13a9a3..8878065 100644
@@ -133,7 +133,7 @@ static inline void write_cr0(unsigned long x)
 	PVOP_VCALL1(cpu.write_cr0, x);
 }
 
-static inline unsigned long read_cr2(void)
+static __always_inline unsigned long read_cr2(void)
 {
 	return PVOP_ALT_CALLEE0(unsigned long, mmu.read_cr2,
 				"mov %%cr2, %%rax;",
arch/x86/kernel/paravirt.c +6 -1
index 04cafc0..e351014 100644
@@ -218,6 +218,11 @@ void paravirt_end_context_switch(struct task_struct *next)
 	if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
 		arch_enter_lazy_mmu_mode();
 }
+
+static noinstr unsigned long pv_native_read_cr2(void)
+{
+	return native_read_cr2();
+}
 #endif
 
 enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
@@ -298,7 +303,7 @@ struct paravirt_patch_template pv_ops = {
 	.mmu.exit_mmap		= paravirt_nop,
 
 #ifdef CONFIG_PARAVIRT_XXL
-	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(native_read_cr2),
+	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(pv_native_read_cr2),
 	.mmu.write_cr2		= native_write_cr2,
 	.mmu.read_cr3		= __native_read_cr3,
 	.mmu.write_cr3		= native_write_cr3,
arch/x86/xen/xen-asm.S +2 -0
index 1e62644..aef4a1e 100644
@@ -102,6 +102,7 @@ SYM_FUNC_START(check_events)
 	ret
 SYM_FUNC_END(check_events)
 
+.pushsection .noinstr.text, "ax"
 SYM_FUNC_START(xen_read_cr2)
 	FRAME_BEGIN
 	_ASM_MOV PER_CPU_VAR(xen_vcpu), %_ASM_AX
@@ -116,6 +117,7 @@ SYM_FUNC_START(xen_read_cr2_direct)
 	FRAME_END
 	ret
 SYM_FUNC_END(xen_read_cr2_direct);
+.popsection
 
 .macro xen_pv_trap name
 SYM_CODE_START(xen_\name)
author maintainer
#62 lore raw

PATCH v2 15/24 x86/xen: Make write_cr2() noinstr

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[42]: native_write_cr2
vmlinux.o: warning: objtool: pv_ops[42]: xen_write_cr2
vmlinux.o: warning: objtool: exc_nmi()+0x127: call to pv_ops[42]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h |    2 +-
 arch/x86/kernel/paravirt.c      |    7 ++++++-
 arch/x86/xen/mmu_pv.c           |    3 ++-
 3 files changed, 9 insertions(+), 3 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
@@ -140,7 +140,7 @@ static __always_inline unsigned long rea
 				ALT_NOT(X86_FEATURE_XENPV));
 }
 
-static inline void write_cr2(unsigned long x)
+static __always_inline void write_cr2(unsigned long x)
 {
 	PVOP_VCALL1(mmu.write_cr2, x);
 }
arch/x86/kernel/paravirt.c +6 -1
@@ -243,6 +243,11 @@ static noinstr unsigned long pv_native_r
 	return native_read_cr2();
 }
 
+static noinstr void pv_native_write_cr2(unsigned long val)
+{
+	native_write_cr2(val);
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -304,7 +309,7 @@ struct paravirt_patch_template pv_ops =
 
 #ifdef CONFIG_PARAVIRT_XXL
 	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(pv_native_read_cr2),
-	.mmu.write_cr2		= native_write_cr2,
+	.mmu.write_cr2		= pv_native_write_cr2,
 	.mmu.read_cr3		= __native_read_cr3,
 	.mmu.write_cr3		= native_write_cr3,
 
arch/x86/xen/mmu_pv.c +2 -1
@@ -1204,7 +1204,8 @@ static void __init xen_pagetable_init(vo
 	xen_remap_memory();
 	xen_setup_mfn_list_list();
 }
-static void xen_write_cr2(unsigned long cr2)
+
+static noinstr void xen_write_cr2(unsigned long cr2)
 {
 	this_cpu_read(xen_vcpu)->arch.cr2 = cr2;
 }
merge bot Applied
#64 lore raw

[tip: objtool/core] x86/xen: Make write_cr2() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     80de642654653a8f86b34e9072a4d2fb95c32683
Gitweb:        https://git.kernel.org/tip/80de642654653a8f86b34e9072a4d2fb95c32683
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:14 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:48 +02:00

x86/xen: Make write_cr2() noinstr

vmlinux.o: warning: objtool: pv_ops[42]: native_write_cr2
vmlinux.o: warning: objtool: pv_ops[42]: xen_write_cr2
vmlinux.o: warning: objtool: exc_nmi()+0x127: call to pv_ops[42]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h | 2 +-
 arch/x86/kernel/paravirt.c      | 7 ++++++-
 arch/x86/xen/mmu_pv.c           | 3 ++-
 3 files changed, 9 insertions(+), 3 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
index 8878065..be82b52 100644
@@ -140,7 +140,7 @@ static __always_inline unsigned long read_cr2(void)
 				ALT_NOT(X86_FEATURE_XENPV));
 }
 
-static inline void write_cr2(unsigned long x)
+static __always_inline void write_cr2(unsigned long x)
 {
 	PVOP_VCALL1(mmu.write_cr2, x);
 }
arch/x86/kernel/paravirt.c +6 -1
index ff4ade8..78f08e1 100644
@@ -243,6 +243,11 @@ static noinstr unsigned long pv_native_read_cr2(void)
 	return native_read_cr2();
 }
 
+static noinstr void pv_native_write_cr2(unsigned long val)
+{
+	native_write_cr2(val);
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -304,7 +309,7 @@ struct paravirt_patch_template pv_ops = {
 
 #ifdef CONFIG_PARAVIRT_XXL
 	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(pv_native_read_cr2),
-	.mmu.write_cr2		= native_write_cr2,
+	.mmu.write_cr2		= pv_native_write_cr2,
 	.mmu.read_cr3		= __native_read_cr3,
 	.mmu.write_cr3		= native_write_cr3,
 
arch/x86/xen/mmu_pv.c +2 -1
index 1df5f01..f3cafe5 100644
@@ -1204,7 +1204,8 @@ static void __init xen_pagetable_init(void)
 	xen_remap_memory();
 	xen_setup_mfn_list_list();
 }
-static void xen_write_cr2(unsigned long cr2)
+
+static noinstr void xen_write_cr2(unsigned long cr2)
 {
 	this_cpu_read(xen_vcpu)->arch.cr2 = cr2;
 }
merge bot Applied
#65 lore raw

[tip: objtool/core] x86/xen: Make write_cr2() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     209cfd0cbb6722d3461e4f928dc150e4c3811948
Gitweb:        https://git.kernel.org/tip/209cfd0cbb6722d3461e4f928dc150e4c3811948
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:14 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:12:16 +02:00

x86/xen: Make write_cr2() noinstr

vmlinux.o: warning: objtool: pv_ops[42]: native_write_cr2
vmlinux.o: warning: objtool: pv_ops[42]: xen_write_cr2
vmlinux.o: warning: objtool: exc_nmi()+0x127: call to pv_ops[42]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h | 2 +-
 arch/x86/kernel/paravirt.c      | 7 ++++++-
 arch/x86/xen/mmu_pv.c           | 3 ++-
 3 files changed, 9 insertions(+), 3 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
index 8878065..be82b52 100644
@@ -140,7 +140,7 @@ static __always_inline unsigned long read_cr2(void)
 				ALT_NOT(X86_FEATURE_XENPV));
 }
 
-static inline void write_cr2(unsigned long x)
+static __always_inline void write_cr2(unsigned long x)
 {
 	PVOP_VCALL1(mmu.write_cr2, x);
 }
arch/x86/kernel/paravirt.c +6 -1
index e351014..fc2cf2b 100644
@@ -223,6 +223,11 @@ static noinstr unsigned long pv_native_read_cr2(void)
 {
 	return native_read_cr2();
 }
+
+static noinstr void pv_native_write_cr2(unsigned long val)
+{
+	native_write_cr2(val);
+}
 #endif
 
 enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
@@ -304,7 +309,7 @@ struct paravirt_patch_template pv_ops = {
 
 #ifdef CONFIG_PARAVIRT_XXL
 	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(pv_native_read_cr2),
-	.mmu.write_cr2		= native_write_cr2,
+	.mmu.write_cr2		= pv_native_write_cr2,
 	.mmu.read_cr3		= __native_read_cr3,
 	.mmu.write_cr3		= native_write_cr3,
 
arch/x86/xen/mmu_pv.c +2 -1
index 1df5f01..f3cafe5 100644
@@ -1204,7 +1204,8 @@ static void __init xen_pagetable_init(void)
 	xen_remap_memory();
 	xen_setup_mfn_list_list();
 }
-static void xen_write_cr2(unsigned long cr2)
+
+static noinstr void xen_write_cr2(unsigned long cr2)
 {
 	this_cpu_read(xen_vcpu)->arch.cr2 = cr2;
 }
author maintainer
#66 lore raw

PATCH v2 16/24 x86/xen: Make get_debugreg() noinstr

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[1]: xen_get_debugreg
vmlinux.o: warning: objtool: pv_ops[1]: native_get_debugreg
vmlinux.o: warning: objtool: exc_debug()+0x25: call to pv_ops[1]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h      |    2 +-
 arch/x86/include/asm/xen/hypercall.h |    2 +-
 arch/x86/kernel/paravirt.c           |    8 ++++++--
 arch/x86/xen/enlighten_pv.c          |    2 +-
 4 files changed, 9 insertions(+), 5 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
@@ -113,7 +113,7 @@ static inline void __cpuid(unsigned int
 /*
  * These special macros can be used to get or set a debugging register
  */
-static inline unsigned long paravirt_get_debugreg(int reg)
+static __always_inline unsigned long paravirt_get_debugreg(int reg)
 {
 	return PVOP_CALL1(unsigned long, cpu.get_debugreg, reg);
 }
arch/x86/include/asm/xen/hypercall.h +1 -1
@@ -314,7 +314,7 @@ HYPERVISOR_set_debugreg(int reg, unsigne
 	return _hypercall2(int, set_debugreg, reg, value);
 }
 
-static inline unsigned long
+static __always_inline unsigned long
 HYPERVISOR_get_debugreg(int reg)
 {
 	return _hypercall1(unsigned long, get_debugreg, reg);
arch/x86/kernel/paravirt.c +6 -2
@@ -248,13 +248,18 @@ static noinstr void pv_native_write_cr2(
 	native_write_cr2(val);
 }
 
+static noinstr unsigned long pv_native_get_debugreg(int regno)
+{
+	return native_get_debugreg(regno);
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
 
 #ifdef CONFIG_PARAVIRT_XXL
 	.cpu.cpuid		= native_cpuid,
-	.cpu.get_debugreg	= native_get_debugreg,
+	.cpu.get_debugreg	= pv_native_get_debugreg,
 	.cpu.set_debugreg	= native_set_debugreg,
 	.cpu.read_cr0		= native_read_cr0,
 	.cpu.write_cr0		= native_write_cr0,
@@ -382,7 +387,6 @@ struct paravirt_patch_template pv_ops =
 
 #ifdef CONFIG_PARAVIRT_XXL
 /* At this point, native_get/set_debugreg has real function entries */
-NOKPROBE_SYMBOL(native_get_debugreg);
 NOKPROBE_SYMBOL(native_set_debugreg);
 NOKPROBE_SYMBOL(native_load_idt);
 
arch/x86/xen/enlighten_pv.c +1 -1
@@ -317,7 +317,7 @@ static void xen_set_debugreg(int reg, un
 	HYPERVISOR_set_debugreg(reg, val);
 }
 
-static unsigned long xen_get_debugreg(int reg)
+static noinstr unsigned long xen_get_debugreg(int reg)
 {
 	return HYPERVISOR_get_debugreg(reg);
 }
merge bot Applied
#68 lore raw

[tip: objtool/core] x86/xen: Make get_debugreg() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     737196b197f21326b96ba969a5b1205c90f25cdc
Gitweb:        https://git.kernel.org/tip/737196b197f21326b96ba969a5b1205c90f25cdc
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:15 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:49 +02:00

x86/xen: Make get_debugreg() noinstr

vmlinux.o: warning: objtool: pv_ops[1]: xen_get_debugreg
vmlinux.o: warning: objtool: pv_ops[1]: native_get_debugreg
vmlinux.o: warning: objtool: exc_debug()+0x25: call to pv_ops[1]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h      | 2 +-
 arch/x86/include/asm/xen/hypercall.h | 2 +-
 arch/x86/kernel/paravirt.c           | 8 ++++++--
 arch/x86/xen/enlighten_pv.c          | 2 +-
 4 files changed, 9 insertions(+), 5 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
index be82b52..f48465c 100644
@@ -113,7 +113,7 @@ static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
 /*
  * These special macros can be used to get or set a debugging register
  */
-static inline unsigned long paravirt_get_debugreg(int reg)
+static __always_inline unsigned long paravirt_get_debugreg(int reg)
 {
 	return PVOP_CALL1(unsigned long, cpu.get_debugreg, reg);
 }
arch/x86/include/asm/xen/hypercall.h +1 -1
index 454b208..af92202 100644
@@ -314,7 +314,7 @@ HYPERVISOR_set_debugreg(int reg, unsigned long value)
 	return _hypercall2(int, set_debugreg, reg, value);
 }
 
-static inline unsigned long
+static __always_inline unsigned long
 HYPERVISOR_get_debugreg(int reg)
 {
 	return _hypercall1(unsigned long, get_debugreg, reg);
arch/x86/kernel/paravirt.c +6 -2
index 78f08e1..9188ae1 100644
@@ -248,13 +248,18 @@ static noinstr void pv_native_write_cr2(unsigned long val)
 	native_write_cr2(val);
 }
 
+static noinstr unsigned long pv_native_get_debugreg(int regno)
+{
+	return native_get_debugreg(regno);
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
 
 #ifdef CONFIG_PARAVIRT_XXL
 	.cpu.cpuid		= native_cpuid,
-	.cpu.get_debugreg	= native_get_debugreg,
+	.cpu.get_debugreg	= pv_native_get_debugreg,
 	.cpu.set_debugreg	= native_set_debugreg,
 	.cpu.read_cr0		= native_read_cr0,
 	.cpu.write_cr0		= native_write_cr0,
@@ -382,7 +387,6 @@ struct paravirt_patch_template pv_ops = {
 
 #ifdef CONFIG_PARAVIRT_XXL
 /* At this point, native_get/set_debugreg has real function entries */
-NOKPROBE_SYMBOL(native_get_debugreg);
 NOKPROBE_SYMBOL(native_set_debugreg);
 NOKPROBE_SYMBOL(native_load_idt);
 
arch/x86/xen/enlighten_pv.c +1 -1
index 753f637..273e1fa 100644
@@ -316,7 +316,7 @@ static void xen_set_debugreg(int reg, unsigned long val)
 	HYPERVISOR_set_debugreg(reg, val);
 }
 
-static unsigned long xen_get_debugreg(int reg)
+static noinstr unsigned long xen_get_debugreg(int reg)
 {
 	return HYPERVISOR_get_debugreg(reg);
 }
merge bot Applied
#69 lore raw

[tip: objtool/core] x86/xen: Make get_debugreg() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     f4afb713e5c3a4419ba7aaecc31a8c8bd91d13fb
Gitweb:        https://git.kernel.org/tip/f4afb713e5c3a4419ba7aaecc31a8c8bd91d13fb
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:15 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:12:34 +02:00

x86/xen: Make get_debugreg() noinstr

vmlinux.o: warning: objtool: pv_ops[1]: xen_get_debugreg
vmlinux.o: warning: objtool: pv_ops[1]: native_get_debugreg
vmlinux.o: warning: objtool: exc_debug()+0x25: call to pv_ops[1]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h      | 2 +-
 arch/x86/include/asm/xen/hypercall.h | 2 +-
 arch/x86/kernel/paravirt.c           | 8 ++++++--
 arch/x86/xen/enlighten_pv.c          | 2 +-
 4 files changed, 9 insertions(+), 5 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
index be82b52..f48465c 100644
@@ -113,7 +113,7 @@ static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
 /*
  * These special macros can be used to get or set a debugging register
  */
-static inline unsigned long paravirt_get_debugreg(int reg)
+static __always_inline unsigned long paravirt_get_debugreg(int reg)
 {
 	return PVOP_CALL1(unsigned long, cpu.get_debugreg, reg);
 }
arch/x86/include/asm/xen/hypercall.h +1 -1
index 454b208..af92202 100644
@@ -314,7 +314,7 @@ HYPERVISOR_set_debugreg(int reg, unsigned long value)
 	return _hypercall2(int, set_debugreg, reg, value);
 }
 
-static inline unsigned long
+static __always_inline unsigned long
 HYPERVISOR_get_debugreg(int reg)
 {
 	return _hypercall1(unsigned long, get_debugreg, reg);
arch/x86/kernel/paravirt.c +6 -2
index fc2cf2b..8af526c 100644
@@ -228,6 +228,11 @@ static noinstr void pv_native_write_cr2(unsigned long val)
 {
 	native_write_cr2(val);
 }
+
+static noinstr unsigned long pv_native_get_debugreg(int regno)
+{
+	return native_get_debugreg(regno);
+}
 #endif
 
 enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
@@ -254,7 +259,7 @@ struct paravirt_patch_template pv_ops = {
 
 #ifdef CONFIG_PARAVIRT_XXL
 	.cpu.cpuid		= native_cpuid,
-	.cpu.get_debugreg	= native_get_debugreg,
+	.cpu.get_debugreg	= pv_native_get_debugreg,
 	.cpu.set_debugreg	= native_set_debugreg,
 	.cpu.read_cr0		= native_read_cr0,
 	.cpu.write_cr0		= native_write_cr0,
@@ -382,7 +387,6 @@ struct paravirt_patch_template pv_ops = {
 
 #ifdef CONFIG_PARAVIRT_XXL
 /* At this point, native_get/set_debugreg has real function entries */
-NOKPROBE_SYMBOL(native_get_debugreg);
 NOKPROBE_SYMBOL(native_set_debugreg);
 NOKPROBE_SYMBOL(native_load_idt);
 
arch/x86/xen/enlighten_pv.c +1 -1
index 753f637..273e1fa 100644
@@ -316,7 +316,7 @@ static void xen_set_debugreg(int reg, unsigned long val)
 	HYPERVISOR_set_debugreg(reg, val);
 }
 
-static unsigned long xen_get_debugreg(int reg)
+static noinstr unsigned long xen_get_debugreg(int reg)
 {
 	return HYPERVISOR_get_debugreg(reg);
 }
author maintainer
#70 lore raw

PATCH v2 17/24 x86/xen: Make set_debugreg() noinstr

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[2]: xen_set_debugreg
vmlinux.o: warning: objtool: pv_ops[2]: native_set_debugreg
vmlinux.o: warning: objtool: exc_debug()+0x3b: call to pv_ops[2]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h      |    2 +-
 arch/x86/include/asm/xen/hypercall.h |    2 +-
 arch/x86/kernel/paravirt.c           |    9 ++++++---
 arch/x86/xen/enlighten_pv.c          |    2 +-
 4 files changed, 9 insertions(+), 6 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
@@ -118,7 +118,7 @@ static __always_inline unsigned long par
 	return PVOP_CALL1(unsigned long, cpu.get_debugreg, reg);
 }
 #define get_debugreg(var, reg) var = paravirt_get_debugreg(reg)
-static inline void set_debugreg(unsigned long val, int reg)
+static __always_inline void set_debugreg(unsigned long val, int reg)
 {
 	PVOP_VCALL2(cpu.set_debugreg, reg, val);
 }
arch/x86/include/asm/xen/hypercall.h +1 -1
@@ -308,7 +308,7 @@ HYPERVISOR_platform_op(struct xen_platfo
 	return _hypercall1(int, platform_op, op);
 }
 
-static inline int
+static __always_inline int
 HYPERVISOR_set_debugreg(int reg, unsigned long value)
 {
 	return _hypercall2(int, set_debugreg, reg, value);
arch/x86/kernel/paravirt.c +6 -3
@@ -253,6 +253,11 @@ static noinstr unsigned long pv_native_g
 	return native_get_debugreg(regno);
 }
 
+static noinstr void pv_native_set_debugreg(int regno, unsigned long val)
+{
+	native_set_debugreg(regno, val);
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -260,7 +265,7 @@ struct paravirt_patch_template pv_ops =
 #ifdef CONFIG_PARAVIRT_XXL
 	.cpu.cpuid		= native_cpuid,
 	.cpu.get_debugreg	= pv_native_get_debugreg,
-	.cpu.set_debugreg	= native_set_debugreg,
+	.cpu.set_debugreg	= pv_native_set_debugreg,
 	.cpu.read_cr0		= native_read_cr0,
 	.cpu.write_cr0		= native_write_cr0,
 	.cpu.write_cr4		= native_write_cr4,
@@ -386,8 +391,6 @@ struct paravirt_patch_template pv_ops =
 };
 
 #ifdef CONFIG_PARAVIRT_XXL
-/* At this point, native_get/set_debugreg has real function entries */
-NOKPROBE_SYMBOL(native_set_debugreg);
 NOKPROBE_SYMBOL(native_load_idt);
 
 void (*paravirt_iret)(void) = native_iret;
arch/x86/xen/enlighten_pv.c +1 -1
@@ -312,7 +312,7 @@ static void __init xen_init_capabilities
 	}
 }
 
-static void xen_set_debugreg(int reg, unsigned long val)
+static noinstr void xen_set_debugreg(int reg, unsigned long val)
 {
 	HYPERVISOR_set_debugreg(reg, val);
 }
merge bot Applied
#72 lore raw

[tip: objtool/core] x86/xen: Make set_debugreg() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     9da62cacc7ed17e2186f82273762fe850078c8c3
Gitweb:        https://git.kernel.org/tip/9da62cacc7ed17e2186f82273762fe850078c8c3
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:16 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:49 +02:00

x86/xen: Make set_debugreg() noinstr

vmlinux.o: warning: objtool: pv_ops[2]: xen_set_debugreg
vmlinux.o: warning: objtool: pv_ops[2]: native_set_debugreg
vmlinux.o: warning: objtool: exc_debug()+0x3b: call to pv_ops[2]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h      |  2 +-
 arch/x86/include/asm/xen/hypercall.h |  2 +-
 arch/x86/kernel/paravirt.c           |  9 ++++++---
 arch/x86/xen/enlighten_pv.c          |  2 +-
 4 files changed, 9 insertions(+), 6 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
index f48465c..34da790 100644
@@ -118,7 +118,7 @@ static __always_inline unsigned long paravirt_get_debugreg(int reg)
 	return PVOP_CALL1(unsigned long, cpu.get_debugreg, reg);
 }
 #define get_debugreg(var, reg) var = paravirt_get_debugreg(reg)
-static inline void set_debugreg(unsigned long val, int reg)
+static __always_inline void set_debugreg(unsigned long val, int reg)
 {
 	PVOP_VCALL2(cpu.set_debugreg, reg, val);
 }
arch/x86/include/asm/xen/hypercall.h +1 -1
index af92202..990b8aa 100644
@@ -308,7 +308,7 @@ HYPERVISOR_platform_op(struct xen_platform_op *op)
 	return _hypercall1(int, platform_op, op);
 }
 
-static inline int
+static __always_inline int
 HYPERVISOR_set_debugreg(int reg, unsigned long value)
 {
 	return _hypercall2(int, set_debugreg, reg, value);
arch/x86/kernel/paravirt.c +6 -3
index 9188ae1..4d98791 100644
@@ -253,6 +253,11 @@ static noinstr unsigned long pv_native_get_debugreg(int regno)
 	return native_get_debugreg(regno);
 }
 
+static noinstr void pv_native_set_debugreg(int regno, unsigned long val)
+{
+	native_set_debugreg(regno, val);
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -260,7 +265,7 @@ struct paravirt_patch_template pv_ops = {
 #ifdef CONFIG_PARAVIRT_XXL
 	.cpu.cpuid		= native_cpuid,
 	.cpu.get_debugreg	= pv_native_get_debugreg,
-	.cpu.set_debugreg	= native_set_debugreg,
+	.cpu.set_debugreg	= pv_native_set_debugreg,
 	.cpu.read_cr0		= native_read_cr0,
 	.cpu.write_cr0		= native_write_cr0,
 	.cpu.write_cr4		= native_write_cr4,
@@ -386,8 +391,6 @@ struct paravirt_patch_template pv_ops = {
 };
 
 #ifdef CONFIG_PARAVIRT_XXL
-/* At this point, native_get/set_debugreg has real function entries */
-NOKPROBE_SYMBOL(native_set_debugreg);
 NOKPROBE_SYMBOL(native_load_idt);
 
 void (*paravirt_iret)(void) = native_iret;
arch/x86/xen/enlighten_pv.c +1 -1
index 273e1fa..2b1a8ba 100644
@@ -311,7 +311,7 @@ static void __init xen_init_capabilities(void)
 	}
 }
 
-static void xen_set_debugreg(int reg, unsigned long val)
+static noinstr void xen_set_debugreg(int reg, unsigned long val)
 {
 	HYPERVISOR_set_debugreg(reg, val);
 }
merge bot Applied
#73 lore raw

[tip: objtool/core] x86/xen: Make set_debugreg() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     7361fac0465ba96ec8f7559459e3c70818ba6c78
Gitweb:        https://git.kernel.org/tip/7361fac0465ba96ec8f7559459e3c70818ba6c78
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:16 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:14:39 +02:00

x86/xen: Make set_debugreg() noinstr

vmlinux.o: warning: objtool: pv_ops[2]: xen_set_debugreg
vmlinux.o: warning: objtool: pv_ops[2]: native_set_debugreg
vmlinux.o: warning: objtool: exc_debug()+0x3b: call to pv_ops[2]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h      |  2 +-
 arch/x86/include/asm/xen/hypercall.h |  2 +-
 arch/x86/kernel/paravirt.c           |  9 ++++++---
 arch/x86/xen/enlighten_pv.c          |  2 +-
 4 files changed, 9 insertions(+), 6 deletions(-)
arch/x86/include/asm/paravirt.h +1 -1
index f48465c..34da790 100644
@@ -118,7 +118,7 @@ static __always_inline unsigned long paravirt_get_debugreg(int reg)
 	return PVOP_CALL1(unsigned long, cpu.get_debugreg, reg);
 }
 #define get_debugreg(var, reg) var = paravirt_get_debugreg(reg)
-static inline void set_debugreg(unsigned long val, int reg)
+static __always_inline void set_debugreg(unsigned long val, int reg)
 {
 	PVOP_VCALL2(cpu.set_debugreg, reg, val);
 }
arch/x86/include/asm/xen/hypercall.h +1 -1
index af92202..990b8aa 100644
@@ -308,7 +308,7 @@ HYPERVISOR_platform_op(struct xen_platform_op *op)
 	return _hypercall1(int, platform_op, op);
 }
 
-static inline int
+static __always_inline int
 HYPERVISOR_set_debugreg(int reg, unsigned long value)
 {
 	return _hypercall2(int, set_debugreg, reg, value);
arch/x86/kernel/paravirt.c +6 -3
index 8af526c..cdaf862 100644
@@ -233,6 +233,11 @@ static noinstr unsigned long pv_native_get_debugreg(int regno)
 {
 	return native_get_debugreg(regno);
 }
+
+static noinstr void pv_native_set_debugreg(int regno, unsigned long val)
+{
+	native_set_debugreg(regno, val);
+}
 #endif
 
 enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
@@ -260,7 +265,7 @@ struct paravirt_patch_template pv_ops = {
 #ifdef CONFIG_PARAVIRT_XXL
 	.cpu.cpuid		= native_cpuid,
 	.cpu.get_debugreg	= pv_native_get_debugreg,
-	.cpu.set_debugreg	= native_set_debugreg,
+	.cpu.set_debugreg	= pv_native_set_debugreg,
 	.cpu.read_cr0		= native_read_cr0,
 	.cpu.write_cr0		= native_write_cr0,
 	.cpu.write_cr4		= native_write_cr4,
@@ -386,8 +391,6 @@ struct paravirt_patch_template pv_ops = {
 };
 
 #ifdef CONFIG_PARAVIRT_XXL
-/* At this point, native_get/set_debugreg has real function entries */
-NOKPROBE_SYMBOL(native_set_debugreg);
 NOKPROBE_SYMBOL(native_load_idt);
 
 void (*paravirt_iret)(void) = native_iret;
arch/x86/xen/enlighten_pv.c +1 -1
index 273e1fa..2b1a8ba 100644
@@ -311,7 +311,7 @@ static void __init xen_init_capabilities(void)
 	}
 }
 
-static void xen_set_debugreg(int reg, unsigned long val)
+static noinstr void xen_set_debugreg(int reg, unsigned long val)
 {
 	HYPERVISOR_set_debugreg(reg, val);
 }
author maintainer
#74 lore raw

PATCH v2 18/24 x86/xen: Make save_fl() noinstr

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[30]: native_save_fl
vmlinux.o: warning: objtool: pv_ops[30]: __raw_callee_save_xen_save_fl
vmlinux.o: warning: objtool: pv_ops[30]: xen_save_fl_direct
vmlinux.o: warning: objtool: lockdep_hardirqs_off()+0x73: call to pv_ops[30]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h |    7 +++++--
 arch/x86/kernel/irqflags.S      |    2 ++
 arch/x86/xen/irq.c              |    4 ++--
 arch/x86/xen/xen-asm.S          |   32 ++++++++++++++++----------------
 4 files changed, 25 insertions(+), 20 deletions(-)
arch/x86/include/asm/paravirt.h +5 -2
@@ -653,10 +653,10 @@ bool __raw_callee_save___native_vcpu_is_
  * functions.
  */
 #define PV_THUNK_NAME(func) "__raw_callee_save_" #func
-#define PV_CALLEE_SAVE_REGS_THUNK(func)					\
+#define __PV_CALLEE_SAVE_REGS_THUNK(func, section)			\
 	extern typeof(func) __raw_callee_save_##func;			\
 									\
-	asm(".pushsection .text;"					\
+	asm(".pushsection " section ", \"ax\";"				\
 	    ".globl " PV_THUNK_NAME(func) ";"				\
 	    ".type " PV_THUNK_NAME(func) ", @function;"			\
 	    PV_THUNK_NAME(func) ":"					\
@@ -669,6 +669,9 @@ bool __raw_callee_save___native_vcpu_is_
 	    ".size " PV_THUNK_NAME(func) ", .-" PV_THUNK_NAME(func) ";"	\
 	    ".popsection")
 
+#define PV_CALLEE_SAVE_REGS_THUNK(func)			\
+	__PV_CALLEE_SAVE_REGS_THUNK(func, ".text")
+
 /* Get a reference to a callee-save function */
 #define PV_CALLEE_SAVE(func)						\
 	((struct paravirt_callee_save) { __raw_callee_save_##func })
arch/x86/kernel/irqflags.S +2 -0
@@ -7,9 +7,11 @@
 /*
  * unsigned long native_save_fl(void)
  */
+.pushsection .noinstr.text, "ax"
 SYM_FUNC_START(native_save_fl)
 	pushf
 	pop %_ASM_AX
 	ret
 SYM_FUNC_END(native_save_fl)
+.popsection
 EXPORT_SYMBOL(native_save_fl)
arch/x86/xen/irq.c +2 -2
@@ -24,7 +24,7 @@ void xen_force_evtchn_callback(void)
 	(void)HYPERVISOR_xen_version(0, NULL);
 }
 
-asmlinkage __visible unsigned long xen_save_fl(void)
+asmlinkage __visible noinstr unsigned long xen_save_fl(void)
 {
 	struct vcpu_info *vcpu;
 	unsigned long flags;
@@ -40,7 +40,7 @@ asmlinkage __visible unsigned long xen_s
 	*/
 	return (-flags) & X86_EFLAGS_IF;
 }
-PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl);
+__PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl, ".noinstr.text");
 
 asmlinkage __visible void xen_irq_disable(void)
 {
arch/x86/xen/xen-asm.S +16 -16
@@ -58,22 +58,6 @@ SYM_FUNC_START(xen_irq_disable_direct)
 SYM_FUNC_END(xen_irq_disable_direct)
 
 /*
- * (xen_)save_fl is used to get the current interrupt enable status.
- * Callers expect the status to be in X86_EFLAGS_IF, and other bits
- * may be set in the return value.  We take advantage of this by
- * making sure that X86_EFLAGS_IF has the right value (and other bits
- * in that byte are 0), but other bits in the return value are
- * undefined.  We need to toggle the state of the bit, because Xen and
- * x86 use opposite senses (mask vs enable).
- */
-SYM_FUNC_START(xen_save_fl_direct)
-	testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask
-	setz %ah
-	addb %ah, %ah
-	ret
-SYM_FUNC_END(xen_save_fl_direct)
-
-/*
  * Force an event check by making a hypercall, but preserve regs
  * before making the call.
  */
@@ -103,6 +87,22 @@ SYM_FUNC_START(check_events)
 SYM_FUNC_END(check_events)
 
 .pushsection .noinstr.text, "ax"
+/*
+ * (xen_)save_fl is used to get the current interrupt enable status.
+ * Callers expect the status to be in X86_EFLAGS_IF, and other bits
+ * may be set in the return value.  We take advantage of this by
+ * making sure that X86_EFLAGS_IF has the right value (and other bits
+ * in that byte are 0), but other bits in the return value are
+ * undefined.  We need to toggle the state of the bit, because Xen and
+ * x86 use opposite senses (mask vs enable).
+ */
+SYM_FUNC_START(xen_save_fl_direct)
+	testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask
+	setz %ah
+	addb %ah, %ah
+	ret
+SYM_FUNC_END(xen_save_fl_direct)
+
 SYM_FUNC_START(xen_read_cr2)
 	FRAME_BEGIN
 	_ASM_MOV PER_CPU_VAR(xen_vcpu), %_ASM_AX
maintainer Reviewed-by on v2 18/24
#75 lore raw

Re: [PATCH v2 18/24] x86/xen: Make save_fl() noinstr

Quoted 6 lines · Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[30]: native_save_fl
vmlinux.o: warning: objtool: pv_ops[30]: __raw_callee_save_xen_save_fl
vmlinux.o: warning: objtool: pv_ops[30]: xen_save_fl_direct
vmlinux.o: warning: objtool: lockdep_hardirqs_off()+0x73: call to pv_ops[30]() leaves .noinstr.text section

Juergen

merge bot Applied
#76 lore raw

[tip: objtool/core] x86/xen: Make save_fl() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     1126696d60d04b844be88db50099f8fdb43d8166
Gitweb:        https://git.kernel.org/tip/1126696d60d04b844be88db50099f8fdb43d8166
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:17 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:49 +02:00

x86/xen: Make save_fl() noinstr

vmlinux.o: warning: objtool: pv_ops[30]: native_save_fl
vmlinux.o: warning: objtool: pv_ops[30]: __raw_callee_save_xen_save_fl
vmlinux.o: warning: objtool: pv_ops[30]: xen_save_fl_direct
vmlinux.o: warning: objtool: lockdep_hardirqs_off()+0x73: call to pv_ops[30]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h |  7 +++++--
 arch/x86/kernel/irqflags.S      |  2 ++-
 arch/x86/xen/irq.c              |  4 ++--
 arch/x86/xen/xen-asm.S          | 32 ++++++++++++++++----------------
 4 files changed, 25 insertions(+), 20 deletions(-)
arch/x86/include/asm/paravirt.h +5 -2
index 34da790..cebec95 100644
@@ -653,10 +653,10 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
  * functions.
  */
 #define PV_THUNK_NAME(func) "__raw_callee_save_" #func
-#define PV_CALLEE_SAVE_REGS_THUNK(func)					\
+#define __PV_CALLEE_SAVE_REGS_THUNK(func, section)			\
 	extern typeof(func) __raw_callee_save_##func;			\
 									\
-	asm(".pushsection .text;"					\
+	asm(".pushsection " section ", \"ax\";"				\
 	    ".globl " PV_THUNK_NAME(func) ";"				\
 	    ".type " PV_THUNK_NAME(func) ", @function;"			\
 	    PV_THUNK_NAME(func) ":"					\
@@ -669,6 +669,9 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
 	    ".size " PV_THUNK_NAME(func) ", .-" PV_THUNK_NAME(func) ";"	\
 	    ".popsection")
 
+#define PV_CALLEE_SAVE_REGS_THUNK(func)			\
+	__PV_CALLEE_SAVE_REGS_THUNK(func, ".text")
+
 /* Get a reference to a callee-save function */
 #define PV_CALLEE_SAVE(func)						\
 	((struct paravirt_callee_save) { __raw_callee_save_##func })
arch/x86/kernel/irqflags.S +2 -0
index 8ef3506..760e1f2 100644
@@ -7,9 +7,11 @@
 /*
  * unsigned long native_save_fl(void)
  */
+.pushsection .noinstr.text, "ax"
 SYM_FUNC_START(native_save_fl)
 	pushf
 	pop %_ASM_AX
 	ret
 SYM_FUNC_END(native_save_fl)
+.popsection
 EXPORT_SYMBOL(native_save_fl)
arch/x86/xen/irq.c +2 -2
index dfa091d..9c71f43 100644
@@ -24,7 +24,7 @@ void xen_force_evtchn_callback(void)
 	(void)HYPERVISOR_xen_version(0, NULL);
 }
 
-asmlinkage __visible unsigned long xen_save_fl(void)
+asmlinkage __visible noinstr unsigned long xen_save_fl(void)
 {
 	struct vcpu_info *vcpu;
 	unsigned long flags;
@@ -40,7 +40,7 @@ asmlinkage __visible unsigned long xen_save_fl(void)
 	*/
 	return (-flags) & X86_EFLAGS_IF;
 }
-PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl);
+__PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl, ".noinstr.text");
 
 asmlinkage __visible void xen_irq_disable(void)
 {
arch/x86/xen/xen-asm.S +16 -16
index aef4a1e..0883e39 100644
@@ -58,22 +58,6 @@ SYM_FUNC_START(xen_irq_disable_direct)
 SYM_FUNC_END(xen_irq_disable_direct)
 
 /*
- * (xen_)save_fl is used to get the current interrupt enable status.
- * Callers expect the status to be in X86_EFLAGS_IF, and other bits
- * may be set in the return value.  We take advantage of this by
- * making sure that X86_EFLAGS_IF has the right value (and other bits
- * in that byte are 0), but other bits in the return value are
- * undefined.  We need to toggle the state of the bit, because Xen and
- * x86 use opposite senses (mask vs enable).
- */
-SYM_FUNC_START(xen_save_fl_direct)
-	testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask
-	setz %ah
-	addb %ah, %ah
-	ret
-SYM_FUNC_END(xen_save_fl_direct)
-
-/*
  * Force an event check by making a hypercall, but preserve regs
  * before making the call.
  */
@@ -103,6 +87,22 @@ SYM_FUNC_START(check_events)
 SYM_FUNC_END(check_events)
 
 .pushsection .noinstr.text, "ax"
+/*
+ * (xen_)save_fl is used to get the current interrupt enable status.
+ * Callers expect the status to be in X86_EFLAGS_IF, and other bits
+ * may be set in the return value.  We take advantage of this by
+ * making sure that X86_EFLAGS_IF has the right value (and other bits
+ * in that byte are 0), but other bits in the return value are
+ * undefined.  We need to toggle the state of the bit, because Xen and
+ * x86 use opposite senses (mask vs enable).
+ */
+SYM_FUNC_START(xen_save_fl_direct)
+	testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask
+	setz %ah
+	addb %ah, %ah
+	ret
+SYM_FUNC_END(xen_save_fl_direct)
+
 SYM_FUNC_START(xen_read_cr2)
 	FRAME_BEGIN
 	_ASM_MOV PER_CPU_VAR(xen_vcpu), %_ASM_AX
merge bot Applied
#77 lore raw

[tip: objtool/core] x86/xen: Make save_fl() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     20125c872a3f129cef7fdec2b7681da98502a55d
Gitweb:        https://git.kernel.org/tip/20125c872a3f129cef7fdec2b7681da98502a55d
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:17 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:14:44 +02:00

x86/xen: Make save_fl() noinstr

vmlinux.o: warning: objtool: pv_ops[30]: native_save_fl
vmlinux.o: warning: objtool: pv_ops[30]: __raw_callee_save_xen_save_fl
vmlinux.o: warning: objtool: pv_ops[30]: xen_save_fl_direct
vmlinux.o: warning: objtool: lockdep_hardirqs_off()+0x73: call to pv_ops[30]() leaves .noinstr.text section

---
 arch/x86/include/asm/paravirt.h |  7 +++++--
 arch/x86/kernel/irqflags.S      |  2 ++-
 arch/x86/xen/irq.c              |  4 ++--
 arch/x86/xen/xen-asm.S          | 32 ++++++++++++++++----------------
 4 files changed, 25 insertions(+), 20 deletions(-)
arch/x86/include/asm/paravirt.h +5 -2
index 34da790..cebec95 100644
@@ -653,10 +653,10 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
  * functions.
  */
 #define PV_THUNK_NAME(func) "__raw_callee_save_" #func
-#define PV_CALLEE_SAVE_REGS_THUNK(func)					\
+#define __PV_CALLEE_SAVE_REGS_THUNK(func, section)			\
 	extern typeof(func) __raw_callee_save_##func;			\
 									\
-	asm(".pushsection .text;"					\
+	asm(".pushsection " section ", \"ax\";"				\
 	    ".globl " PV_THUNK_NAME(func) ";"				\
 	    ".type " PV_THUNK_NAME(func) ", @function;"			\
 	    PV_THUNK_NAME(func) ":"					\
@@ -669,6 +669,9 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
 	    ".size " PV_THUNK_NAME(func) ", .-" PV_THUNK_NAME(func) ";"	\
 	    ".popsection")
 
+#define PV_CALLEE_SAVE_REGS_THUNK(func)			\
+	__PV_CALLEE_SAVE_REGS_THUNK(func, ".text")
+
 /* Get a reference to a callee-save function */
 #define PV_CALLEE_SAVE(func)						\
 	((struct paravirt_callee_save) { __raw_callee_save_##func })
arch/x86/kernel/irqflags.S +2 -0
index 8ef3506..760e1f2 100644
@@ -7,9 +7,11 @@
 /*
  * unsigned long native_save_fl(void)
  */
+.pushsection .noinstr.text, "ax"
 SYM_FUNC_START(native_save_fl)
 	pushf
 	pop %_ASM_AX
 	ret
 SYM_FUNC_END(native_save_fl)
+.popsection
 EXPORT_SYMBOL(native_save_fl)
arch/x86/xen/irq.c +2 -2
index dfa091d..9c71f43 100644
@@ -24,7 +24,7 @@ void xen_force_evtchn_callback(void)
 	(void)HYPERVISOR_xen_version(0, NULL);
 }
 
-asmlinkage __visible unsigned long xen_save_fl(void)
+asmlinkage __visible noinstr unsigned long xen_save_fl(void)
 {
 	struct vcpu_info *vcpu;
 	unsigned long flags;
@@ -40,7 +40,7 @@ asmlinkage __visible unsigned long xen_save_fl(void)
 	*/
 	return (-flags) & X86_EFLAGS_IF;
 }
-PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl);
+__PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl, ".noinstr.text");
 
 asmlinkage __visible void xen_irq_disable(void)
 {
arch/x86/xen/xen-asm.S +16 -16
index aef4a1e..0883e39 100644
@@ -58,22 +58,6 @@ SYM_FUNC_START(xen_irq_disable_direct)
 SYM_FUNC_END(xen_irq_disable_direct)
 
 /*
- * (xen_)save_fl is used to get the current interrupt enable status.
- * Callers expect the status to be in X86_EFLAGS_IF, and other bits
- * may be set in the return value.  We take advantage of this by
- * making sure that X86_EFLAGS_IF has the right value (and other bits
- * in that byte are 0), but other bits in the return value are
- * undefined.  We need to toggle the state of the bit, because Xen and
- * x86 use opposite senses (mask vs enable).
- */
-SYM_FUNC_START(xen_save_fl_direct)
-	testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask
-	setz %ah
-	addb %ah, %ah
-	ret
-SYM_FUNC_END(xen_save_fl_direct)
-
-/*
  * Force an event check by making a hypercall, but preserve regs
  * before making the call.
  */
@@ -103,6 +87,22 @@ SYM_FUNC_START(check_events)
 SYM_FUNC_END(check_events)
 
 .pushsection .noinstr.text, "ax"
+/*
+ * (xen_)save_fl is used to get the current interrupt enable status.
+ * Callers expect the status to be in X86_EFLAGS_IF, and other bits
+ * may be set in the return value.  We take advantage of this by
+ * making sure that X86_EFLAGS_IF has the right value (and other bits
+ * in that byte are 0), but other bits in the return value are
+ * undefined.  We need to toggle the state of the bit, because Xen and
+ * x86 use opposite senses (mask vs enable).
+ */
+SYM_FUNC_START(xen_save_fl_direct)
+	testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask
+	setz %ah
+	addb %ah, %ah
+	ret
+SYM_FUNC_END(xen_save_fl_direct)
+
 SYM_FUNC_START(xen_read_cr2)
 	FRAME_BEGIN
 	_ASM_MOV PER_CPU_VAR(xen_vcpu), %_ASM_AX
author maintainer
#78 lore raw

PATCH v2 19/24 x86/xen: Make hypercall_page noinstr

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: xen_set_debugreg()+0x3: call to hypercall_page() leaves .noinstr.text section vmlinux.o: warning: objtool: xen_get_debugreg()+0x3: call to hypercall_page() leaves .noinstr.text section vmlinux.o: warning: objtool: xen_irq_enable()+0x24: call to hypercall_page() leaves .noinstr.text section

---
 arch/x86/xen/xen-head.S |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/xen/xen-head.S +1 -1
@@ -64,7 +64,7 @@ SYM_CODE_END(asm_cpu_bringup_and_idle)
 #endif
 #endif
 
-.pushsection .text
+.pushsection .noinstr.text, "ax"
 	.balign PAGE_SIZE
 SYM_CODE_START(hypercall_page)
 	.rept (PAGE_SIZE / 32)
maintainer Reviewed-by on v2 19/24
#79 lore raw

Re: [PATCH v2 19/24] x86/xen: Make hypercall_page noinstr

Quoted 5 lines · Peter Zijlstra

vmlinux.o: warning: objtool: xen_set_debugreg()+0x3: call to hypercall_page() leaves .noinstr.text section vmlinux.o: warning: objtool: xen_get_debugreg()+0x3: call to hypercall_page() leaves .noinstr.text section vmlinux.o: warning: objtool: xen_irq_enable()+0x24: call to hypercall_page() leaves .noinstr.text section

Juergen

merge bot Applied
#80 lore raw

[tip: objtool/core] x86/xen: Make hypercall_page noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     9f38b2a0baf1e5c7a1d1231cd8fe706c6f769a73
Gitweb:        https://git.kernel.org/tip/9f38b2a0baf1e5c7a1d1231cd8fe706c6f769a73
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:18 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:50 +02:00

x86/xen: Make hypercall_page noinstr

vmlinux.o: warning: objtool: xen_set_debugreg()+0x3: call to hypercall_page() leaves .noinstr.text section vmlinux.o: warning: objtool: xen_get_debugreg()+0x3: call to hypercall_page() leaves .noinstr.text section vmlinux.o: warning: objtool: xen_irq_enable()+0x24: call to hypercall_page() leaves .noinstr.text section

---
 arch/x86/xen/xen-head.S | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/xen/xen-head.S +1 -1
index 488944d..9e27b86 100644
@@ -20,7 +20,7 @@
 #include <xen/interface/xen-mca.h>
 #include <asm/xen/interface.h>
 
-.pushsection .text
+.pushsection .noinstr.text, "ax"
 	.balign PAGE_SIZE
 SYM_CODE_START(hypercall_page)
 	.rept (PAGE_SIZE / 32)
merge bot Applied
#81 lore raw

[tip: objtool/core] x86/xen: Make hypercall_page noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     74ea805b79d2b6eb472daa2540ed35ccb4ed23e7
Gitweb:        https://git.kernel.org/tip/74ea805b79d2b6eb472daa2540ed35ccb4ed23e7
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:18 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:14:44 +02:00

x86/xen: Make hypercall_page noinstr

vmlinux.o: warning: objtool: xen_set_debugreg()+0x3: call to hypercall_page() leaves .noinstr.text section vmlinux.o: warning: objtool: xen_get_debugreg()+0x3: call to hypercall_page() leaves .noinstr.text section vmlinux.o: warning: objtool: xen_irq_enable()+0x24: call to hypercall_page() leaves .noinstr.text section

---
 arch/x86/xen/xen-head.S | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/xen/xen-head.S +1 -1
index 488944d..9e27b86 100644
@@ -20,7 +20,7 @@
 #include <xen/interface/xen-mca.h>
 #include <asm/xen/interface.h>
 
-.pushsection .text
+.pushsection .noinstr.text, "ax"
 	.balign PAGE_SIZE
 SYM_CODE_START(hypercall_page)
 	.rept (PAGE_SIZE / 32)
author maintainer
#82 lore raw

PATCH v2 20/24 x86/xen: Make irq_enable() noinstr

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[32]: native_irq_enable
vmlinux.o: warning: objtool: pv_ops[32]: __raw_callee_save_xen_irq_enable
vmlinux.o: warning: objtool: pv_ops[32]: xen_irq_enable_direct
vmlinux.o: warning: objtool: lock_is_held_type()+0xfe: call to pv_ops[32]() leaves .noinstr.text section

---
 arch/x86/kernel/paravirt.c |    7 ++++-
 arch/x86/xen/irq.c         |    4 +--
 arch/x86/xen/xen-asm.S     |   56 ++++++++++++++++++++++-----------------------
 3 files changed, 36 insertions(+), 31 deletions(-)
arch/x86/kernel/paravirt.c +6 -1
@@ -258,6 +258,11 @@ static noinstr void pv_native_set_debugr
 	native_set_debugreg(regno, val);
 }
 
+static noinstr void pv_native_irq_enable(void)
+{
+	native_irq_enable();
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -302,7 +307,7 @@ struct paravirt_patch_template pv_ops =
 	/* Irq ops. */
 	.irq.save_fl		= __PV_IS_CALLEE_SAVE(native_save_fl),
 	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(native_irq_disable),
-	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(native_irq_enable),
+	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(pv_native_irq_enable),
 	.irq.safe_halt		= native_safe_halt,
 	.irq.halt		= native_halt,
 #endif /* CONFIG_PARAVIRT_XXL */
arch/x86/xen/irq.c +2 -2
@@ -53,7 +53,7 @@ asmlinkage __visible void xen_irq_disabl
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable);
 
-asmlinkage __visible void xen_irq_enable(void)
+asmlinkage __visible noinstr void xen_irq_enable(void)
 {
 	struct vcpu_info *vcpu;
 
@@ -76,7 +76,7 @@ asmlinkage __visible void xen_irq_enable
 
 	preempt_enable();
 }
-PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable);
+__PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable, ".noinstr.text");
 
 static void xen_safe_halt(void)
 {
arch/x86/xen/xen-asm.S +28 -28

74 lines not on this page · raw message

maintainer Reviewed-by on v2 20/24
#83 lore raw

Re: [PATCH v2 20/24] x86/xen: Make irq_enable() noinstr

Quoted 6 lines · Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[32]: native_irq_enable
vmlinux.o: warning: objtool: pv_ops[32]: __raw_callee_save_xen_irq_enable
vmlinux.o: warning: objtool: pv_ops[32]: xen_irq_enable_direct
vmlinux.o: warning: objtool: lock_is_held_type()+0xfe: call to pv_ops[32]() leaves .noinstr.text section

Juergen

merge bot Applied
#84 lore raw

[tip: objtool/core] x86/xen: Make irq_enable() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     92e34bb9bdc242045b29269fc93942ee9befc521
Gitweb:        https://git.kernel.org/tip/92e34bb9bdc242045b29269fc93942ee9befc521
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:19 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:50 +02:00

x86/xen: Make irq_enable() noinstr

vmlinux.o: warning: objtool: pv_ops[32]: native_irq_enable
vmlinux.o: warning: objtool: pv_ops[32]: __raw_callee_save_xen_irq_enable
vmlinux.o: warning: objtool: pv_ops[32]: xen_irq_enable_direct
vmlinux.o: warning: objtool: lock_is_held_type()+0xfe: call to pv_ops[32]() leaves .noinstr.text section

---
 arch/x86/kernel/paravirt.c |  7 ++++-
 arch/x86/xen/irq.c         |  4 +--
 arch/x86/xen/xen-asm.S     | 56 ++++++++++++++++++-------------------
 3 files changed, 36 insertions(+), 31 deletions(-)
arch/x86/kernel/paravirt.c +6 -1
index 4d98791..a9b97a9 100644
@@ -258,6 +258,11 @@ static noinstr void pv_native_set_debugreg(int regno, unsigned long val)
 	native_set_debugreg(regno, val);
 }
 
+static noinstr void pv_native_irq_enable(void)
+{
+	native_irq_enable();
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -302,7 +307,7 @@ struct paravirt_patch_template pv_ops = {
 	/* Irq ops. */
 	.irq.save_fl		= __PV_IS_CALLEE_SAVE(native_save_fl),
 	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(native_irq_disable),
-	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(native_irq_enable),
+	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(pv_native_irq_enable),
 	.irq.safe_halt		= native_safe_halt,
 	.irq.halt		= native_halt,
 #endif /* CONFIG_PARAVIRT_XXL */
arch/x86/xen/irq.c +2 -2
index 9c71f43..7fb4cf2 100644
@@ -53,7 +53,7 @@ asmlinkage __visible void xen_irq_disable(void)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable);
 
-asmlinkage __visible void xen_irq_enable(void)
+asmlinkage __visible noinstr void xen_irq_enable(void)
 {
 	struct vcpu_info *vcpu;
 
@@ -76,7 +76,7 @@ asmlinkage __visible void xen_irq_enable(void)
 
 	preempt_enable();
 }
-PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable);
+__PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable, ".noinstr.text");
 
 static void xen_safe_halt(void)
 {
arch/x86/xen/xen-asm.S +28 -28

74 lines not on this page · raw message

merge bot Applied
#85 lore raw

[tip: objtool/core] x86/xen: Make irq_enable() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     d7bfc7d57cbe13382fd3eb739667fd0e2f74122b
Gitweb:        https://git.kernel.org/tip/d7bfc7d57cbe13382fd3eb739667fd0e2f74122b
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:19 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:17:12 +02:00

x86/xen: Make irq_enable() noinstr

vmlinux.o: warning: objtool: pv_ops[32]: native_irq_enable
vmlinux.o: warning: objtool: pv_ops[32]: __raw_callee_save_xen_irq_enable
vmlinux.o: warning: objtool: pv_ops[32]: xen_irq_enable_direct
vmlinux.o: warning: objtool: lock_is_held_type()+0xfe: call to pv_ops[32]() leaves .noinstr.text section

---
 arch/x86/kernel/paravirt.c |  7 ++++-
 arch/x86/xen/irq.c         |  4 +--
 arch/x86/xen/xen-asm.S     | 56 ++++++++++++++++++-------------------
 3 files changed, 36 insertions(+), 31 deletions(-)
arch/x86/kernel/paravirt.c +6 -1
index cdaf862..75f0d24 100644
@@ -238,6 +238,11 @@ static noinstr void pv_native_set_debugreg(int regno, unsigned long val)
 {
 	native_set_debugreg(regno, val);
 }
+
+static noinstr void pv_native_irq_enable(void)
+{
+	native_irq_enable();
+}
 #endif
 
 enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
@@ -302,7 +307,7 @@ struct paravirt_patch_template pv_ops = {
 	/* Irq ops. */
 	.irq.save_fl		= __PV_IS_CALLEE_SAVE(native_save_fl),
 	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(native_irq_disable),
-	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(native_irq_enable),
+	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(pv_native_irq_enable),
 	.irq.safe_halt		= native_safe_halt,
 	.irq.halt		= native_halt,
 #endif /* CONFIG_PARAVIRT_XXL */
arch/x86/xen/irq.c +2 -2
index 9c71f43..7fb4cf2 100644
@@ -53,7 +53,7 @@ asmlinkage __visible void xen_irq_disable(void)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable);
 
-asmlinkage __visible void xen_irq_enable(void)
+asmlinkage __visible noinstr void xen_irq_enable(void)
 {
 	struct vcpu_info *vcpu;
 
@@ -76,7 +76,7 @@ asmlinkage __visible void xen_irq_enable(void)
 
 	preempt_enable();
 }
-PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable);
+__PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable, ".noinstr.text");
 
 static void xen_safe_halt(void)
 {
arch/x86/xen/xen-asm.S +28 -28

74 lines not on this page · raw message

author maintainer
#86 lore raw

PATCH v2 21/24 x86/xen: Make irq_disable() noinstr

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[31]: native_irq_disable
vmlinux.o: warning: objtool: pv_ops[31]: __raw_callee_save_xen_irq_disable
vmlinux.o: warning: objtool: pv_ops[31]: xen_irq_disable_direct
vmlinux.o: warning: objtool: lock_is_held_type()+0x5b: call to pv_ops[31]() leaves .noinstr.text section

---
 arch/x86/kernel/paravirt.c |    7 ++++++-
 arch/x86/xen/irq.c         |    4 ++--
 arch/x86/xen/xen-asm.S     |    3 +--
 3 files changed, 9 insertions(+), 5 deletions(-)
arch/x86/kernel/paravirt.c +6 -1
@@ -263,6 +263,11 @@ static noinstr void pv_native_irq_enable
 	native_irq_enable();
 }
 
+static noinstr void pv_native_irq_disable(void)
+{
+	native_irq_disable();
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -306,7 +311,7 @@ struct paravirt_patch_template pv_ops =
 
 	/* Irq ops. */
 	.irq.save_fl		= __PV_IS_CALLEE_SAVE(native_save_fl),
-	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(native_irq_disable),
+	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(pv_native_irq_disable),
 	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(pv_native_irq_enable),
 	.irq.safe_halt		= native_safe_halt,
 	.irq.halt		= native_halt,
arch/x86/xen/irq.c +2 -2
@@ -42,7 +42,7 @@ asmlinkage __visible noinstr unsigned lo
 }
 __PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl, ".noinstr.text");
 
-asmlinkage __visible void xen_irq_disable(void)
+asmlinkage __visible noinstr void xen_irq_disable(void)
 {
 	/* There's a one instruction preempt window here.  We need to
 	   make sure we're don't switch CPUs between getting the vcpu
@@ -51,7 +51,7 @@ asmlinkage __visible void xen_irq_disabl
 	this_cpu_read(xen_vcpu)->evtchn_upcall_mask = 1;
 	preempt_enable_no_resched();
 }
-PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable);
+__PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable, ".noinstr.text");
 
 asmlinkage __visible noinstr void xen_irq_enable(void)
 {
arch/x86/xen/xen-asm.S +1 -2
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/linkage.h>
 
+.pushsection .noinstr.text, "ax"
 /*
  * Disabling events is simply a matter of making the event mask
  * non-zero.
@@ -30,8 +31,6 @@ SYM_FUNC_START(xen_irq_disable_direct)
 	ret
 SYM_FUNC_END(xen_irq_disable_direct)
 
-.pushsection .noinstr.text, "ax"
-
 /*
  * Force an event check by making a hypercall, but preserve regs
  * before making the call.
maintainer Reviewed-by on v2 21/24
#87 lore raw

Re: [PATCH v2 21/24] x86/xen: Make irq_disable() noinstr

Quoted 6 lines · Peter Zijlstra

vmlinux.o: warning: objtool: pv_ops[31]: native_irq_disable
vmlinux.o: warning: objtool: pv_ops[31]: __raw_callee_save_xen_irq_disable
vmlinux.o: warning: objtool: pv_ops[31]: xen_irq_disable_direct
vmlinux.o: warning: objtool: lock_is_held_type()+0x5b: call to pv_ops[31]() leaves .noinstr.text section

Juergen

merge bot Applied
#88 lore raw

[tip: objtool/core] x86/xen: Make irq_disable() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     bf10b01f581231dc9d25a12dcfec272b981745dc
Gitweb:        https://git.kernel.org/tip/bf10b01f581231dc9d25a12dcfec272b981745dc
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:20 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:50 +02:00

x86/xen: Make irq_disable() noinstr

vmlinux.o: warning: objtool: pv_ops[31]: native_irq_disable
vmlinux.o: warning: objtool: pv_ops[31]: __raw_callee_save_xen_irq_disable
vmlinux.o: warning: objtool: pv_ops[31]: xen_irq_disable_direct
vmlinux.o: warning: objtool: lock_is_held_type()+0x5b: call to pv_ops[31]() leaves .noinstr.text section

---
 arch/x86/kernel/paravirt.c | 7 ++++++-
 arch/x86/xen/irq.c         | 4 ++--
 arch/x86/xen/xen-asm.S     | 3 +--
 3 files changed, 9 insertions(+), 5 deletions(-)
arch/x86/kernel/paravirt.c +6 -1
index a9b97a9..5a804de 100644
@@ -263,6 +263,11 @@ static noinstr void pv_native_irq_enable(void)
 	native_irq_enable();
 }
 
+static noinstr void pv_native_irq_disable(void)
+{
+	native_irq_disable();
+}
+
 struct paravirt_patch_template pv_ops = {
 	/* Cpu ops. */
 	.cpu.io_delay		= native_io_delay,
@@ -306,7 +311,7 @@ struct paravirt_patch_template pv_ops = {
 
 	/* Irq ops. */
 	.irq.save_fl		= __PV_IS_CALLEE_SAVE(native_save_fl),
-	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(native_irq_disable),
+	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(pv_native_irq_disable),
 	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(pv_native_irq_enable),
 	.irq.safe_halt		= native_safe_halt,
 	.irq.halt		= native_halt,
arch/x86/xen/irq.c +2 -2
index 7fb4cf2..f52b60d 100644
@@ -42,7 +42,7 @@ asmlinkage __visible noinstr unsigned long xen_save_fl(void)
 }
 __PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl, ".noinstr.text");
 
-asmlinkage __visible void xen_irq_disable(void)
+asmlinkage __visible noinstr void xen_irq_disable(void)
 {
 	/* There's a one instruction preempt window here.  We need to
 	   make sure we're don't switch CPUs between getting the vcpu
@@ -51,7 +51,7 @@ asmlinkage __visible void xen_irq_disable(void)
 	this_cpu_read(xen_vcpu)->evtchn_upcall_mask = 1;
 	preempt_enable_no_resched();
 }
-PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable);
+__PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable, ".noinstr.text");
 
 asmlinkage __visible noinstr void xen_irq_enable(void)
 {
arch/x86/xen/xen-asm.S +1 -2
index 2225195..220dd96 100644
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/linkage.h>
 
+.pushsection .noinstr.text, "ax"
 /*
  * Disabling events is simply a matter of making the event mask
  * non-zero.
@@ -30,8 +31,6 @@ SYM_FUNC_START(xen_irq_disable_direct)
 	ret
 SYM_FUNC_END(xen_irq_disable_direct)
 
-.pushsection .noinstr.text, "ax"
-
 /*
  * Force an event check by making a hypercall, but preserve regs
  * before making the call.
merge bot Applied
#89 lore raw

[tip: objtool/core] x86/xen: Make irq_disable() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     09c413071e2de71d1f28813c560ae0c06b344520
Gitweb:        https://git.kernel.org/tip/09c413071e2de71d1f28813c560ae0c06b344520
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:20 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:20:23 +02:00

x86/xen: Make irq_disable() noinstr

vmlinux.o: warning: objtool: pv_ops[31]: native_irq_disable
vmlinux.o: warning: objtool: pv_ops[31]: __raw_callee_save_xen_irq_disable
vmlinux.o: warning: objtool: pv_ops[31]: xen_irq_disable_direct
vmlinux.o: warning: objtool: lock_is_held_type()+0x5b: call to pv_ops[31]() leaves .noinstr.text section

---
 arch/x86/kernel/paravirt.c | 7 ++++++-
 arch/x86/xen/irq.c         | 4 ++--
 arch/x86/xen/xen-asm.S     | 3 +--
 3 files changed, 9 insertions(+), 5 deletions(-)
arch/x86/kernel/paravirt.c +6 -1
index 75f0d24..ebc4536 100644
@@ -243,6 +243,11 @@ static noinstr void pv_native_irq_enable(void)
 {
 	native_irq_enable();
 }
+
+static noinstr void pv_native_irq_disable(void)
+{
+	native_irq_disable();
+}
 #endif
 
 enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
@@ -306,7 +311,7 @@ struct paravirt_patch_template pv_ops = {
 
 	/* Irq ops. */
 	.irq.save_fl		= __PV_IS_CALLEE_SAVE(native_save_fl),
-	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(native_irq_disable),
+	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(pv_native_irq_disable),
 	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(pv_native_irq_enable),
 	.irq.safe_halt		= native_safe_halt,
 	.irq.halt		= native_halt,
arch/x86/xen/irq.c +2 -2
index 7fb4cf2..f52b60d 100644
@@ -42,7 +42,7 @@ asmlinkage __visible noinstr unsigned long xen_save_fl(void)
 }
 __PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl, ".noinstr.text");
 
-asmlinkage __visible void xen_irq_disable(void)
+asmlinkage __visible noinstr void xen_irq_disable(void)
 {
 	/* There's a one instruction preempt window here.  We need to
 	   make sure we're don't switch CPUs between getting the vcpu
@@ -51,7 +51,7 @@ asmlinkage __visible void xen_irq_disable(void)
 	this_cpu_read(xen_vcpu)->evtchn_upcall_mask = 1;
 	preempt_enable_no_resched();
 }
-PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable);
+__PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable, ".noinstr.text");
 
 asmlinkage __visible noinstr void xen_irq_enable(void)
 {
arch/x86/xen/xen-asm.S +1 -2
index 2225195..220dd96 100644
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/linkage.h>
 
+.pushsection .noinstr.text, "ax"
 /*
  * Disabling events is simply a matter of making the event mask
  * non-zero.
@@ -30,8 +31,6 @@ SYM_FUNC_START(xen_irq_disable_direct)
 	ret
 SYM_FUNC_END(xen_irq_disable_direct)
 
-.pushsection .noinstr.text, "ax"
-
 /*
  * Force an event check by making a hypercall, but preserve regs
  * before making the call.
author maintainer
#90 lore raw

PATCH v2 22/24 x86/xen: Mark xen_force_evtchn_callback() noinstr

In reply to Peter Zijlstra

vmlinux.o: warning: objtool: check_events()+0xd: call to xen_force_evtchn_callback() leaves .noinstr.text section

---
 arch/x86/include/asm/xen/hypercall.h |    2 +-
 arch/x86/xen/irq.c                   |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/include/asm/xen/hypercall.h +1 -1
@@ -358,7 +358,7 @@ HYPERVISOR_event_channel_op(int cmd, voi
 	return _hypercall2(int, event_channel_op, cmd, arg);
 }
 
-static inline int
+static __always_inline int
 HYPERVISOR_xen_version(int cmd, void *arg)
 {
 	return _hypercall2(int, xen_version, cmd, arg);
arch/x86/xen/irq.c +1 -1
@@ -19,7 +19,7 @@
  * callback mask. We do this in a very simple manner, by making a call
  * down into Xen. The pending flag will be checked by Xen on return.
  */
-void xen_force_evtchn_callback(void)
+noinstr void xen_force_evtchn_callback(void)
 {
 	(void)HYPERVISOR_xen_version(0, NULL);
 }
merge bot Applied
#92 lore raw

[tip: objtool/core] x86/xen: Mark xen_force_evtchn_callback() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     41b8edc60d7232d1f3e49165fb6de20f424c4385
Gitweb:        https://git.kernel.org/tip/41b8edc60d7232d1f3e49165fb6de20f424c4385
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:21 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:51 +02:00

x86/xen: Mark xen_force_evtchn_callback() noinstr

vmlinux.o: warning: objtool: check_events()+0xd: call to xen_force_evtchn_callback() leaves .noinstr.text section

---
 arch/x86/include/asm/xen/hypercall.h | 2 +-
 arch/x86/xen/irq.c                   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/include/asm/xen/hypercall.h +1 -1
index 990b8aa..4a7ff8b 100644
@@ -358,7 +358,7 @@ HYPERVISOR_event_channel_op(int cmd, void *arg)
 	return _hypercall2(int, event_channel_op, cmd, arg);
 }
 
-static inline int
+static __always_inline int
 HYPERVISOR_xen_version(int cmd, void *arg)
 {
 	return _hypercall2(int, xen_version, cmd, arg);
arch/x86/xen/irq.c +1 -1
index f52b60d..2f695b5 100644
@@ -19,7 +19,7 @@
  * callback mask. We do this in a very simple manner, by making a call
  * down into Xen. The pending flag will be checked by Xen on return.
  */
-void xen_force_evtchn_callback(void)
+noinstr void xen_force_evtchn_callback(void)
 {
 	(void)HYPERVISOR_xen_version(0, NULL);
 }
merge bot Applied
#93 lore raw

[tip: objtool/core] x86/xen: Mark xen_force_evtchn_callback() noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     847d9317b2b9c7ecc14b953e6ecf9c12bcdb42e9
Gitweb:        https://git.kernel.org/tip/847d9317b2b9c7ecc14b953e6ecf9c12bcdb42e9
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:21 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:20:25 +02:00

x86/xen: Mark xen_force_evtchn_callback() noinstr

vmlinux.o: warning: objtool: check_events()+0xd: call to xen_force_evtchn_callback() leaves .noinstr.text section

---
 arch/x86/include/asm/xen/hypercall.h | 2 +-
 arch/x86/xen/irq.c                   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/include/asm/xen/hypercall.h +1 -1
index 990b8aa..4a7ff8b 100644
@@ -358,7 +358,7 @@ HYPERVISOR_event_channel_op(int cmd, void *arg)
 	return _hypercall2(int, event_channel_op, cmd, arg);
 }
 
-static inline int
+static __always_inline int
 HYPERVISOR_xen_version(int cmd, void *arg)
 {
 	return _hypercall2(int, xen_version, cmd, arg);
arch/x86/xen/irq.c +1 -1
index f52b60d..2f695b5 100644
@@ -19,7 +19,7 @@
  * callback mask. We do this in a very simple manner, by making a call
  * down into Xen. The pending flag will be checked by Xen on return.
  */
-void xen_force_evtchn_callback(void)
+noinstr void xen_force_evtchn_callback(void)
 {
 	(void)HYPERVISOR_xen_version(0, NULL);
 }
author maintainer
#94 lore raw

PATCH v2 23/24 x86/xen: Rework the xen_{cpu,irq,mmu}_ops[] arrays

In reply to Peter Zijlstra

In order to allow objtool to make sense of all the various paravirt functions, it needs to either parse whole pv_ops[] tables, or observe individual assignments in the form:

bf87: 48 c7 05 00 00 00 00 00 00 00 00 movq $0x0,0x0(%rip)

    bf92 <xen_init_spinlocks+0x5f>
    bf8a: R_X86_64_PC32     pv_ops+0x268

As is, xen_cpu_ops[] is at offset +0 in pv_ops[] and could thus be parsed as a 'normal' pv_ops[] table, however xen_irq_ops[] and xen_mmu_ops[] are not.

Worse, both the latter two are compiled into the individual assignment for by current GCC, but that's not something one can rely on.

Therefore, convert all three into full pv_ops[] tables. This has the benefit of not needing to teach objtool about the offsets and resulting in more conservative code-gen.

---
 arch/x86/xen/enlighten_pv.c |   66 ++++++++++++++++---------------
 arch/x86/xen/irq.c          |   17 ++++----
 arch/x86/xen/mmu_pv.c       |   92 ++++++++++++++++++++++----------------------
 3 files changed, 91 insertions(+), 84 deletions(-)
arch/x86/xen/enlighten_pv.c +34 -32
@@ -1051,52 +1051,54 @@ static const struct pv_info xen_info __i
 	.name = "Xen",
 };
 
-static const struct pv_cpu_ops xen_cpu_ops __initconst = {
-	.cpuid = xen_cpuid,
+static const typeof(pv_ops) xen_cpu_ops __initconst = {
+	.cpu = {
+		.cpuid = xen_cpuid,
 
-	.set_debugreg = xen_set_debugreg,
-	.get_debugreg = xen_get_debugreg,
+		.set_debugreg = xen_set_debugreg,
+		.get_debugreg = xen_get_debugreg,
 
-	.read_cr0 = xen_read_cr0,
-	.write_cr0 = xen_write_cr0,
+		.read_cr0 = xen_read_cr0,
+		.write_cr0 = xen_write_cr0,
 
-	.write_cr4 = xen_write_cr4,
+		.write_cr4 = xen_write_cr4,
 
-	.wbinvd = native_wbinvd,
+		.wbinvd = native_wbinvd,
 
-	.read_msr = xen_read_msr,
-	.write_msr = xen_write_msr,
+		.read_msr = xen_read_msr,
+		.write_msr = xen_write_msr,
 
-	.read_msr_safe = xen_read_msr_safe,
-	.write_msr_safe = xen_write_msr_safe,
+		.read_msr_safe = xen_read_msr_safe,
+		.write_msr_safe = xen_write_msr_safe,
 
-	.read_pmc = xen_read_pmc,
+		.read_pmc = xen_read_pmc,
 
-	.load_tr_desc = paravirt_nop,
-	.set_ldt = xen_set_ldt,
-	.load_gdt = xen_load_gdt,
-	.load_idt = xen_load_idt,
-	.load_tls = xen_load_tls,
-	.load_gs_index = xen_load_gs_index,
+		.load_tr_desc = paravirt_nop,
+		.set_ldt = xen_set_ldt,
+		.load_gdt = xen_load_gdt,
+		.load_idt = xen_load_idt,
+		.load_tls = xen_load_tls,
+		.load_gs_index = xen_load_gs_index,
 
-	.alloc_ldt = xen_alloc_ldt,
-	.free_ldt = xen_free_ldt,
+		.alloc_ldt = xen_alloc_ldt,
+		.free_ldt = xen_free_ldt,
 
-	.store_tr = xen_store_tr,
+		.store_tr = xen_store_tr,
 
-	.write_ldt_entry = xen_write_ldt_entry,
-	.write_gdt_entry = xen_write_gdt_entry,
-	.write_idt_entry = xen_write_idt_entry,
-	.load_sp0 = xen_load_sp0,
+		.write_ldt_entry = xen_write_ldt_entry,
+		.write_gdt_entry = xen_write_gdt_entry,
+		.write_idt_entry = xen_write_idt_entry,
+		.load_sp0 = xen_load_sp0,
 
 #ifdef CONFIG_X86_IOPL_IOPERM
-	.invalidate_io_bitmap = xen_invalidate_io_bitmap,
-	.update_io_bitmap = xen_update_io_bitmap,
+		.invalidate_io_bitmap = xen_invalidate_io_bitmap,
+		.update_io_bitmap = xen_update_io_bitmap,
 #endif
-	.io_delay = xen_io_delay,
+		.io_delay = xen_io_delay,
 
-	.start_context_switch = paravirt_start_context_switch,
-	.end_context_switch = xen_end_context_switch,
+		.start_context_switch = paravirt_start_context_switch,
+		.end_context_switch = xen_end_context_switch,
+	},
 };
 
 static void xen_restart(char *msg)
@@ -1232,7 +1234,7 @@ asmlinkage __visible void __init xen_sta
 
 	/* Install Xen paravirt ops */
 	pv_info = xen_info;
-	pv_ops.cpu = xen_cpu_ops;
+	pv_ops.cpu = xen_cpu_ops.cpu;
 	paravirt_iret = xen_iret;
 	xen_init_irq_ops();
 
arch/x86/xen/irq.c +10 -7
@@ -94,17 +94,20 @@ static void xen_halt(void)
 		xen_safe_halt();
 }
 
-static const struct pv_irq_ops xen_irq_ops __initconst = {
-	.save_fl = PV_CALLEE_SAVE(xen_save_fl),
-	.irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
-	.irq_enable = PV_CALLEE_SAVE(xen_irq_enable),
+static const typeof(pv_ops) xen_irq_ops __initconst = {
+	.irq = {
 
-	.safe_halt = xen_safe_halt,
-	.halt = xen_halt,
+		.save_fl = PV_CALLEE_SAVE(xen_save_fl),
+		.irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
+		.irq_enable = PV_CALLEE_SAVE(xen_irq_enable),
+
+		.safe_halt = xen_safe_halt,
+		.halt = xen_halt,
+	},
 };
 
 void __init xen_init_irq_ops(void)
 {
-	pv_ops.irq = xen_irq_ops;
+	pv_ops.irq = xen_irq_ops.irq;
 	x86_init.irqs.intr_init = xen_init_IRQ;
 }
arch/x86/xen/mmu_pv.c +47 -45

121 lines not on this page · raw message

maintainer Reviewed-by on v2 23/24
#95 lore raw

Re: [PATCH v2 23/24] x86/xen: Rework the xen_{cpu,irq,mmu}_ops[] arrays

Quoted 12 lines · Peter Zijlstra

In order to allow objtool to make sense of all the various paravirt functions, it needs to either parse whole pv_ops[] tables, or observe individual assignments in the form:

   bf87:       48 c7 05 00 00 00 00 00 00 00 00        movq   $0x0,0x0(%rip)
     bf92 <xen_init_spinlocks+0x5f>
     bf8a: R_X86_64_PC32     pv_ops+0x268

As is, xen_cpu_ops[] is at offset +0 in pv_ops[] and could thus be parsed as a 'normal' pv_ops[] table, however xen_irq_ops[] and xen_mmu_ops[] are not.

Quoted 8 lines

Worse, both the latter two are compiled into the individual assignment for by current GCC, but that's not something one can rely on.

Therefore, convert all three into full pv_ops[] tables. This has the benefit of not needing to teach objtool about the offsets and resulting in more conservative code-gen.

First I was worried by the additional memory consumption, but as the modified tables are all tagged to be __init I don't think this matters.

So:

Juergen

merge bot Applied
#96 lore raw

[tip: objtool/core] x86/xen: Rework the xen_{cpu,irq,mmu}_opsarrays

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     723a80b05f0b118c53a69ff20384d28b84219afa
Gitweb:        https://git.kernel.org/tip/723a80b05f0b118c53a69ff20384d28b84219afa
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:22 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:51 +02:00

x86/xen: Rework the xen_{cpu,irq,mmu}_opsarrays

In order to allow objtool to make sense of all the various paravirt functions, it needs to either parse whole pv_ops[] tables, or observe individual assignments in the form:

bf87: 48 c7 05 00 00 00 00 00 00 00 00 movq $0x0,0x0(%rip)

    bf92 <xen_init_spinlocks+0x5f>
    bf8a: R_X86_64_PC32     pv_ops+0x268

As is, xen_cpu_ops[] is at offset +0 in pv_ops[] and could thus be parsed as a 'normal' pv_ops[] table, however xen_irq_ops[] and xen_mmu_ops[] are not.

Worse, both the latter two are compiled into the individual assignment for by current GCC, but that's not something one can rely on.

Therefore, convert all three into full pv_ops[] tables. This has the benefit of not needing to teach objtool about the offsets and resulting in more conservative code-gen.

---
 arch/x86/xen/enlighten_pv.c | 66 +++++++++++++-------------
 arch/x86/xen/irq.c          | 17 ++++---
 arch/x86/xen/mmu_pv.c       | 90 ++++++++++++++++++------------------
 3 files changed, 90 insertions(+), 83 deletions(-)
arch/x86/xen/enlighten_pv.c +34 -32
index 2b1a8ba..6ed0af7 100644
@@ -1050,52 +1050,54 @@ static const struct pv_info xen_info __initconst = {
 	.name = "Xen",
 };
 
-static const struct pv_cpu_ops xen_cpu_ops __initconst = {
-	.cpuid = xen_cpuid,
+static const typeof(pv_ops) xen_cpu_ops __initconst = {
+	.cpu = {
+		.cpuid = xen_cpuid,
 
-	.set_debugreg = xen_set_debugreg,
-	.get_debugreg = xen_get_debugreg,
+		.set_debugreg = xen_set_debugreg,
+		.get_debugreg = xen_get_debugreg,
 
-	.read_cr0 = xen_read_cr0,
-	.write_cr0 = xen_write_cr0,
+		.read_cr0 = xen_read_cr0,
+		.write_cr0 = xen_write_cr0,
 
-	.write_cr4 = xen_write_cr4,
+		.write_cr4 = xen_write_cr4,
 
-	.wbinvd = native_wbinvd,
+		.wbinvd = native_wbinvd,
 
-	.read_msr = xen_read_msr,
-	.write_msr = xen_write_msr,
+		.read_msr = xen_read_msr,
+		.write_msr = xen_write_msr,
 
-	.read_msr_safe = xen_read_msr_safe,
-	.write_msr_safe = xen_write_msr_safe,
+		.read_msr_safe = xen_read_msr_safe,
+		.write_msr_safe = xen_write_msr_safe,
 
-	.read_pmc = xen_read_pmc,
+		.read_pmc = xen_read_pmc,
 
-	.load_tr_desc = paravirt_nop,
-	.set_ldt = xen_set_ldt,
-	.load_gdt = xen_load_gdt,
-	.load_idt = xen_load_idt,
-	.load_tls = xen_load_tls,
-	.load_gs_index = xen_load_gs_index,
+		.load_tr_desc = paravirt_nop,
+		.set_ldt = xen_set_ldt,
+		.load_gdt = xen_load_gdt,
+		.load_idt = xen_load_idt,
+		.load_tls = xen_load_tls,
+		.load_gs_index = xen_load_gs_index,
 
-	.alloc_ldt = xen_alloc_ldt,
-	.free_ldt = xen_free_ldt,
+		.alloc_ldt = xen_alloc_ldt,
+		.free_ldt = xen_free_ldt,
 
-	.store_tr = xen_store_tr,
+		.store_tr = xen_store_tr,
 
-	.write_ldt_entry = xen_write_ldt_entry,
-	.write_gdt_entry = xen_write_gdt_entry,
-	.write_idt_entry = xen_write_idt_entry,
-	.load_sp0 = xen_load_sp0,
+		.write_ldt_entry = xen_write_ldt_entry,
+		.write_gdt_entry = xen_write_gdt_entry,
+		.write_idt_entry = xen_write_idt_entry,
+		.load_sp0 = xen_load_sp0,
 
 #ifdef CONFIG_X86_IOPL_IOPERM
-	.invalidate_io_bitmap = xen_invalidate_io_bitmap,
-	.update_io_bitmap = xen_update_io_bitmap,
+		.invalidate_io_bitmap = xen_invalidate_io_bitmap,
+		.update_io_bitmap = xen_update_io_bitmap,
 #endif
-	.io_delay = xen_io_delay,
+		.io_delay = xen_io_delay,
 
-	.start_context_switch = paravirt_start_context_switch,
-	.end_context_switch = xen_end_context_switch,
+		.start_context_switch = paravirt_start_context_switch,
+		.end_context_switch = xen_end_context_switch,
+	},
 };
 
 static void xen_restart(char *msg)
@@ -1231,7 +1233,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
 
 	/* Install Xen paravirt ops */
 	pv_info = xen_info;
-	pv_ops.cpu = xen_cpu_ops;
+	pv_ops.cpu = xen_cpu_ops.cpu;
 	paravirt_iret = xen_iret;
 	xen_init_irq_ops();
 
arch/x86/xen/irq.c +10 -7
index 2f695b5..4fe387e 100644
@@ -94,17 +94,20 @@ static void xen_halt(void)
 		xen_safe_halt();
 }
 
-static const struct pv_irq_ops xen_irq_ops __initconst = {
-	.save_fl = PV_CALLEE_SAVE(xen_save_fl),
-	.irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
-	.irq_enable = PV_CALLEE_SAVE(xen_irq_enable),
+static const typeof(pv_ops) xen_irq_ops __initconst = {
+	.irq = {
 
-	.safe_halt = xen_safe_halt,
-	.halt = xen_halt,
+		.save_fl = PV_CALLEE_SAVE(xen_save_fl),
+		.irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
+		.irq_enable = PV_CALLEE_SAVE(xen_irq_enable),
+
+		.safe_halt = xen_safe_halt,
+		.halt = xen_halt,
+	},
 };
 
 void __init xen_init_irq_ops(void)
 {
-	pv_ops.irq = xen_irq_ops;
+	pv_ops.irq = xen_irq_ops.irq;
 	x86_init.irqs.intr_init = xen_init_IRQ;
 }
arch/x86/xen/mmu_pv.c +46 -44

120 lines not on this page · raw message

merge bot Applied
#97 lore raw

[tip: objtool/core] x86/xen: Rework the xen_{cpu,irq,mmu}_opsarrays

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     1462eb381b4c27576a3e818bc9f918765d327fdf
Gitweb:        https://git.kernel.org/tip/1462eb381b4c27576a3e818bc9f918765d327fdf
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:22 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:20:26 +02:00

x86/xen: Rework the xen_{cpu,irq,mmu}_opsarrays

In order to allow objtool to make sense of all the various paravirt functions, it needs to either parse whole pv_ops[] tables, or observe individual assignments in the form:

bf87: 48 c7 05 00 00 00 00 00 00 00 00 movq $0x0,0x0(%rip)

    bf92 <xen_init_spinlocks+0x5f>
    bf8a: R_X86_64_PC32     pv_ops+0x268

As is, xen_cpu_ops[] is at offset +0 in pv_ops[] and could thus be parsed as a 'normal' pv_ops[] table, however xen_irq_ops[] and xen_mmu_ops[] are not.

Worse, both the latter two are compiled into the individual assignment for by current GCC, but that's not something one can rely on.

Therefore, convert all three into full pv_ops[] tables. This has the benefit of not needing to teach objtool about the offsets and resulting in more conservative code-gen.

---
 arch/x86/xen/enlighten_pv.c | 66 +++++++++++++-------------
 arch/x86/xen/irq.c          | 17 ++++---
 arch/x86/xen/mmu_pv.c       | 90 ++++++++++++++++++------------------
 3 files changed, 90 insertions(+), 83 deletions(-)
arch/x86/xen/enlighten_pv.c +34 -32
index 2b1a8ba..6ed0af7 100644
@@ -1050,52 +1050,54 @@ static const struct pv_info xen_info __initconst = {
 	.name = "Xen",
 };
 
-static const struct pv_cpu_ops xen_cpu_ops __initconst = {
-	.cpuid = xen_cpuid,
+static const typeof(pv_ops) xen_cpu_ops __initconst = {
+	.cpu = {
+		.cpuid = xen_cpuid,
 
-	.set_debugreg = xen_set_debugreg,
-	.get_debugreg = xen_get_debugreg,
+		.set_debugreg = xen_set_debugreg,
+		.get_debugreg = xen_get_debugreg,
 
-	.read_cr0 = xen_read_cr0,
-	.write_cr0 = xen_write_cr0,
+		.read_cr0 = xen_read_cr0,
+		.write_cr0 = xen_write_cr0,
 
-	.write_cr4 = xen_write_cr4,
+		.write_cr4 = xen_write_cr4,
 
-	.wbinvd = native_wbinvd,
+		.wbinvd = native_wbinvd,
 
-	.read_msr = xen_read_msr,
-	.write_msr = xen_write_msr,
+		.read_msr = xen_read_msr,
+		.write_msr = xen_write_msr,
 
-	.read_msr_safe = xen_read_msr_safe,
-	.write_msr_safe = xen_write_msr_safe,
+		.read_msr_safe = xen_read_msr_safe,
+		.write_msr_safe = xen_write_msr_safe,
 
-	.read_pmc = xen_read_pmc,
+		.read_pmc = xen_read_pmc,
 
-	.load_tr_desc = paravirt_nop,
-	.set_ldt = xen_set_ldt,
-	.load_gdt = xen_load_gdt,
-	.load_idt = xen_load_idt,
-	.load_tls = xen_load_tls,
-	.load_gs_index = xen_load_gs_index,
+		.load_tr_desc = paravirt_nop,
+		.set_ldt = xen_set_ldt,
+		.load_gdt = xen_load_gdt,
+		.load_idt = xen_load_idt,
+		.load_tls = xen_load_tls,
+		.load_gs_index = xen_load_gs_index,
 
-	.alloc_ldt = xen_alloc_ldt,
-	.free_ldt = xen_free_ldt,
+		.alloc_ldt = xen_alloc_ldt,
+		.free_ldt = xen_free_ldt,
 
-	.store_tr = xen_store_tr,
+		.store_tr = xen_store_tr,
 
-	.write_ldt_entry = xen_write_ldt_entry,
-	.write_gdt_entry = xen_write_gdt_entry,
-	.write_idt_entry = xen_write_idt_entry,
-	.load_sp0 = xen_load_sp0,
+		.write_ldt_entry = xen_write_ldt_entry,
+		.write_gdt_entry = xen_write_gdt_entry,
+		.write_idt_entry = xen_write_idt_entry,
+		.load_sp0 = xen_load_sp0,
 
 #ifdef CONFIG_X86_IOPL_IOPERM
-	.invalidate_io_bitmap = xen_invalidate_io_bitmap,
-	.update_io_bitmap = xen_update_io_bitmap,
+		.invalidate_io_bitmap = xen_invalidate_io_bitmap,
+		.update_io_bitmap = xen_update_io_bitmap,
 #endif
-	.io_delay = xen_io_delay,
+		.io_delay = xen_io_delay,
 
-	.start_context_switch = paravirt_start_context_switch,
-	.end_context_switch = xen_end_context_switch,
+		.start_context_switch = paravirt_start_context_switch,
+		.end_context_switch = xen_end_context_switch,
+	},
 };
 
 static void xen_restart(char *msg)
@@ -1231,7 +1233,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
 
 	/* Install Xen paravirt ops */
 	pv_info = xen_info;
-	pv_ops.cpu = xen_cpu_ops;
+	pv_ops.cpu = xen_cpu_ops.cpu;
 	paravirt_iret = xen_iret;
 	xen_init_irq_ops();
 
arch/x86/xen/irq.c +10 -7
index 2f695b5..4fe387e 100644
@@ -94,17 +94,20 @@ static void xen_halt(void)
 		xen_safe_halt();
 }
 
-static const struct pv_irq_ops xen_irq_ops __initconst = {
-	.save_fl = PV_CALLEE_SAVE(xen_save_fl),
-	.irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
-	.irq_enable = PV_CALLEE_SAVE(xen_irq_enable),
+static const typeof(pv_ops) xen_irq_ops __initconst = {
+	.irq = {
 
-	.safe_halt = xen_safe_halt,
-	.halt = xen_halt,
+		.save_fl = PV_CALLEE_SAVE(xen_save_fl),
+		.irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
+		.irq_enable = PV_CALLEE_SAVE(xen_irq_enable),
+
+		.safe_halt = xen_safe_halt,
+		.halt = xen_halt,
+	},
 };
 
 void __init xen_init_irq_ops(void)
 {
-	pv_ops.irq = xen_irq_ops;
+	pv_ops.irq = xen_irq_ops.irq;
 	x86_init.irqs.intr_init = xen_init_IRQ;
 }
arch/x86/xen/mmu_pv.c +46 -44

120 lines not on this page · raw message

author maintainer
#98 lore raw

PATCH v2 24/24 objtool: Support pv_opsindirect calls for noinstr

In reply to Peter Zijlstra

Normally objtool will now follow indirect calls; there is no need.

However, this becomes a problem with noinstr validation; if there's an indirect call from noinstr code, we very much need to know it is to another noinstr function. Luckily there aren't many indirect calls in entry code with the obvious exception of paravirt. As such, noinstr validation didn't work with paravirt kernels.

In order to track pv_ops[] call targets, objtool reads the static pv_ops[] tables as well as direct assignments to the pv_ops[] array, provided the compiler makes them a single instruction like:

bf87: 48 c7 05 00 00 00 00 00 00 00 00 movq $0x0,0x0(%rip)

    bf92 <xen_init_spinlocks+0x5f>
    bf8a: R_X86_64_PC32     pv_ops+0x268

There are, as of yet, no warnings for when this goes wrong :/

Using the functions found with the above means, all pv_ops[] calls are now subject to noinstr validation.

---
 lib/Kconfig.debug                       |    2 
 tools/objtool/arch/x86/decode.c         |   34 ++++++-
 tools/objtool/check.c                   |  151 +++++++++++++++++++++++++++++---
 tools/objtool/include/objtool/arch.h    |    2 
 tools/objtool/include/objtool/elf.h     |    1 
 tools/objtool/include/objtool/objtool.h |    9 +
 tools/objtool/objtool.c                 |   22 ++++
 7 files changed, 208 insertions(+), 13 deletions(-)
lib/Kconfig.debug +1 -1
@@ -445,7 +445,7 @@ config STACK_VALIDATION
 
 config VMLINUX_VALIDATION
 	bool
-	depends on STACK_VALIDATION && DEBUG_ENTRY && !PARAVIRT
+	depends on STACK_VALIDATION && DEBUG_ENTRY
 	default y
 
 config VMLINUX_MAP
tools/objtool/arch/x86/decode.c +33 -1
@@ -20,6 +20,7 @@
 #include <objtool/arch.h>
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
+#include <objtool/builtin.h>
 #include <arch/elf.h>
 
 static int is_x86_64(const struct elf *elf)
@@ -102,12 +103,13 @@ unsigned long arch_jump_destination(stru
 #define rm_is_mem(reg)	(mod_is_mem() && !is_RIP() && rm_is(reg))
 #define rm_is_reg(reg)	(mod_is_reg() && modrm_rm == (reg))
 
-int arch_decode_instruction(const struct elf *elf, const struct section *sec,
+int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
 			    unsigned long offset, unsigned int maxlen,
 			    unsigned int *len, enum insn_type *type,
 			    unsigned long *immediate,
 			    struct list_head *ops_list)
 {
+	const struct elf *elf = file->elf;
 	struct insn insn;
 	int x86_64, ret;
 	unsigned char op1, op2,
@@ -544,6 +546,36 @@ int arch_decode_instruction(const struct
 		*type = INSN_RETURN;
 		break;
 
+	case 0xc7: /* mov imm, r/m */
+		if (!noinstr)
+			break;
+
+		if (insn.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) {
+			struct reloc *immr, *disp;
+			struct symbol *func;
+			int idx;
+
+			immr = find_reloc_by_dest(elf, (void *)sec, offset+3);
+			disp = find_reloc_by_dest(elf, (void *)sec, offset+7);
+
+			if (!immr || strcmp(immr->sym->name, "pv_ops"))
+				break;
+
+			idx = (immr->addend + 8) / sizeof(void *);
+
+			func = disp->sym;
+			if (disp->sym->type == STT_SECTION)
+				func = find_symbol_by_offset(disp->sym->sec, disp->addend);
+			if (!func) {
+				WARN("no func for pv_ops[]");
+				return -1;
+			}
+
+			objtool_pv_add(file, idx, func);
+		}
+
+		break;
+
 	case 0xcf: /* iret */
 		/*
 		 * Handle sync_core(), which has an IRET to self.
tools/objtool/check.c +141 -10

231 lines not on this page · raw message

tools/objtool/include/objtool/arch.h +1 -1
@@ -69,7 +69,7 @@ struct instruction;
 
 void arch_initial_func_cfi_state(struct cfi_init_state *state);
 
-int arch_decode_instruction(const struct elf *elf, const struct section *sec,
+int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
 			    unsigned long offset, unsigned int maxlen,
 			    unsigned int *len, enum insn_type *type,
 			    unsigned long *immediate,
tools/objtool/include/objtool/elf.h +1 -0
@@ -57,6 +57,7 @@ struct symbol {
 	struct symbol *pfunc, *cfunc, *alias;
 	bool uaccess_safe;
 	bool static_call_tramp;
+	struct list_head pv_target;
 };
 
 struct reloc {
tools/objtool/include/objtool/objtool.h +9 -0
@@ -14,6 +14,11 @@
 
 #define __weak __attribute__((weak))
 
+struct pv_state {
+	bool clean;
+	struct list_head targets;
+};
+
 struct objtool_file {
 	struct elf *elf;
 	struct list_head insn_list;
@@ -25,10 +30,14 @@ struct objtool_file {
 
 	unsigned long jl_short, jl_long;
 	unsigned long jl_nop_short, jl_nop_long;
+
+	struct pv_state *pv_ops;
 };
 
 struct objtool_file *objtool_open_read(const char *_objname);
 
+void objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func);
+
 int check(struct objtool_file *file);
 int orc_dump(const char *objname);
 int orc_create(struct objtool_file *file);
tools/objtool/objtool.c +22 -0
@@ -135,6 +135,28 @@ struct objtool_file *objtool_open_read(c
 	return &file;
 }
 
+void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
+{
+	if (!noinstr)
+		return;
+
+	if (!f->pv_ops) {
+		WARN("paravirt confusion");
+		return;
+	}
+
+	/*
+	 * These functions will be patched into native code,
+	 * see paravirt_patch().
+	 */
+	if (!strcmp(func->name, "_paravirt_nop") ||
+	    !strcmp(func->name, "_paravirt_ident_64"))
+		return;
+
+	list_add(&func->pv_target, &f->pv_ops[idx].targets);
+	f->pv_ops[idx].clean = false;
+}
+
 static void cmd_usage(void)
 {
 	unsigned int i, longest = 0;
merge bot Applied
#99 lore raw

[tip: objtool/core] objtool: Support pv_opsindirect calls for noinstr

The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     55a918e61cf45f28157a2f0bb2535fa79e4a137d
Gitweb:        https://git.kernel.org/tip/55a918e61cf45f28157a2f0bb2535fa79e4a137d
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:23 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 15 Sep 2021 15:51:51 +02:00

objtool: Support pv_opsindirect calls for noinstr

Normally objtool will now follow indirect calls; there is no need.

However, this becomes a problem with noinstr validation; if there's an indirect call from noinstr code, we very much need to know it is to another noinstr function. Luckily there aren't many indirect calls in entry code with the obvious exception of paravirt. As such, noinstr validation didn't work with paravirt kernels.

In order to track pv_ops[] call targets, objtool reads the static pv_ops[] tables as well as direct assignments to the pv_ops[] array, provided the compiler makes them a single instruction like:

bf87: 48 c7 05 00 00 00 00 00 00 00 00 movq $0x0,0x0(%rip)

    bf92 <xen_init_spinlocks+0x5f>
    bf8a: R_X86_64_PC32     pv_ops+0x268

There are, as of yet, no warnings for when this goes wrong :/

Using the functions found with the above means, all pv_ops[] calls are now subject to noinstr validation.

---
 lib/Kconfig.debug                       |   2 +-
 tools/objtool/arch/x86/decode.c         |  34 ++++-
 tools/objtool/check.c                   | 151 +++++++++++++++++++++--
 tools/objtool/include/objtool/arch.h    |   2 +-
 tools/objtool/include/objtool/elf.h     |   1 +-
 tools/objtool/include/objtool/objtool.h |   9 +-
 tools/objtool/objtool.c                 |  22 +++-
 7 files changed, 208 insertions(+), 13 deletions(-)
lib/Kconfig.debug +1 -1
index ed4a31e..63a4735 100644
@@ -458,7 +458,7 @@ config STACK_VALIDATION
 
 config VMLINUX_VALIDATION
 	bool
-	depends on STACK_VALIDATION && DEBUG_ENTRY && !PARAVIRT
+	depends on STACK_VALIDATION && DEBUG_ENTRY
 	default y
 
 config VMLINUX_MAP
tools/objtool/arch/x86/decode.c +33 -1
index 340a3dc..3172983 100644
@@ -20,6 +20,7 @@
 #include <objtool/arch.h>
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
+#include <objtool/builtin.h>
 #include <arch/elf.h>
 
 static int is_x86_64(const struct elf *elf)
@@ -102,12 +103,13 @@ unsigned long arch_jump_destination(struct instruction *insn)
 #define rm_is_mem(reg)	(mod_is_mem() && !is_RIP() && rm_is(reg))
 #define rm_is_reg(reg)	(mod_is_reg() && modrm_rm == (reg))
 
-int arch_decode_instruction(const struct elf *elf, const struct section *sec,
+int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
 			    unsigned long offset, unsigned int maxlen,
 			    unsigned int *len, enum insn_type *type,
 			    unsigned long *immediate,
 			    struct list_head *ops_list)
 {
+	const struct elf *elf = file->elf;
 	struct insn insn;
 	int x86_64, ret;
 	unsigned char op1, op2,
@@ -544,6 +546,36 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
 		*type = INSN_RETURN;
 		break;
 
+	case 0xc7: /* mov imm, r/m */
+		if (!noinstr)
+			break;
+
+		if (insn.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) {
+			struct reloc *immr, *disp;
+			struct symbol *func;
+			int idx;
+
+			immr = find_reloc_by_dest(elf, (void *)sec, offset+3);
+			disp = find_reloc_by_dest(elf, (void *)sec, offset+7);
+
+			if (!immr || strcmp(immr->sym->name, "pv_ops"))
+				break;
+
+			idx = (immr->addend + 8) / sizeof(void *);
+
+			func = disp->sym;
+			if (disp->sym->type == STT_SECTION)
+				func = find_symbol_by_offset(disp->sym->sec, disp->addend);
+			if (!func) {
+				WARN("no func for pv_ops[]");
+				return -1;
+			}
+
+			objtool_pv_add(file, idx, func);
+		}
+
+		break;
+
 	case 0xcf: /* iret */
 		/*
 		 * Handle sync_core(), which has an IRET to self.
tools/objtool/check.c +141 -10

231 lines not on this page · raw message

tools/objtool/include/objtool/arch.h +1 -1
index 6f482ae..589ff58 100644
@@ -69,7 +69,7 @@ struct instruction;
 
 void arch_initial_func_cfi_state(struct cfi_init_state *state);
 
-int arch_decode_instruction(const struct elf *elf, const struct section *sec,
+int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
 			    unsigned long offset, unsigned int maxlen,
 			    unsigned int *len, enum insn_type *type,
 			    unsigned long *immediate,
tools/objtool/include/objtool/elf.h +1 -0
index e343950..c3857fa 100644
@@ -57,6 +57,7 @@ struct symbol {
 	struct symbol *pfunc, *cfunc, *alias;
 	bool uaccess_safe;
 	bool static_call_tramp;
+	struct list_head pv_target;
 };
 
 struct reloc {
tools/objtool/include/objtool/objtool.h +9 -0
index 24fa836..f99fbc6 100644
@@ -14,6 +14,11 @@
 
 #define __weak __attribute__((weak))
 
+struct pv_state {
+	bool clean;
+	struct list_head targets;
+};
+
 struct objtool_file {
 	struct elf *elf;
 	struct list_head insn_list;
@@ -25,10 +30,14 @@ struct objtool_file {
 
 	unsigned long jl_short, jl_long;
 	unsigned long jl_nop_short, jl_nop_long;
+
+	struct pv_state *pv_ops;
 };
 
 struct objtool_file *objtool_open_read(const char *_objname);
 
+void objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func);
+
 int check(struct objtool_file *file);
 int orc_dump(const char *objname);
 int orc_create(struct objtool_file *file);
tools/objtool/objtool.c +22 -0
index e21db8b..c90c708 100644
@@ -135,6 +135,28 @@ struct objtool_file *objtool_open_read(const char *_objname)
 	return &file;
 }
 
+void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
+{
+	if (!noinstr)
+		return;
+
+	if (!f->pv_ops) {
+		WARN("paravirt confusion");
+		return;
+	}
+
+	/*
+	 * These functions will be patched into native code,
+	 * see paravirt_patch().
+	 */
+	if (!strcmp(func->name, "_paravirt_nop") ||
+	    !strcmp(func->name, "_paravirt_ident_64"))
+		return;
+
+	list_add(&func->pv_target, &f->pv_ops[idx].targets);
+	f->pv_ops[idx].clean = false;
+}
+
 static void cmd_usage(void)
 {
 	unsigned int i, longest = 0;
merge bot Applied
#100 lore raw

[tip: objtool/core] objtool: Support pv_opsindirect calls for noinstr

In reply to Peter Zijlstra
The following commit has been merged into the objtool/core branch of tip:

The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     db2b0c5d7b6f19b3c2cab08c531b65342eb5252b
Gitweb:        https://git.kernel.org/tip/db2b0c5d7b6f19b3c2cab08c531b65342eb5252b
Author:        Peter Zijlstra <[email protected]>
AuthorDate:    Thu, 24 Jun 2021 11:41:23 +02:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Fri, 17 Sep 2021 13:20:26 +02:00

objtool: Support pv_opsindirect calls for noinstr

Normally objtool will now follow indirect calls; there is no need.

However, this becomes a problem with noinstr validation; if there's an indirect call from noinstr code, we very much need to know it is to another noinstr function. Luckily there aren't many indirect calls in entry code with the obvious exception of paravirt. As such, noinstr validation didn't work with paravirt kernels.

In order to track pv_ops[] call targets, objtool reads the static pv_ops[] tables as well as direct assignments to the pv_ops[] array, provided the compiler makes them a single instruction like:

bf87: 48 c7 05 00 00 00 00 00 00 00 00 movq $0x0,0x0(%rip)

    bf92 <xen_init_spinlocks+0x5f>
    bf8a: R_X86_64_PC32     pv_ops+0x268

There are, as of yet, no warnings for when this goes wrong :/

Using the functions found with the above means, all pv_ops[] calls are now subject to noinstr validation.

---
 lib/Kconfig.debug                       |   2 +-
 tools/objtool/arch/x86/decode.c         |  34 ++++-
 tools/objtool/check.c                   | 151 +++++++++++++++++++++--
 tools/objtool/include/objtool/arch.h    |   2 +-
 tools/objtool/include/objtool/elf.h     |   1 +-
 tools/objtool/include/objtool/objtool.h |   9 +-
 tools/objtool/objtool.c                 |  22 +++-
 7 files changed, 208 insertions(+), 13 deletions(-)
lib/Kconfig.debug +1 -1
index ed4a31e..63a4735 100644
@@ -458,7 +458,7 @@ config STACK_VALIDATION
 
 config VMLINUX_VALIDATION
 	bool
-	depends on STACK_VALIDATION && DEBUG_ENTRY && !PARAVIRT
+	depends on STACK_VALIDATION && DEBUG_ENTRY
 	default y
 
 config VMLINUX_MAP
tools/objtool/arch/x86/decode.c +33 -1
index 340a3dc..3172983 100644
@@ -20,6 +20,7 @@
 #include <objtool/arch.h>
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
+#include <objtool/builtin.h>
 #include <arch/elf.h>
 
 static int is_x86_64(const struct elf *elf)
@@ -102,12 +103,13 @@ unsigned long arch_jump_destination(struct instruction *insn)
 #define rm_is_mem(reg)	(mod_is_mem() && !is_RIP() && rm_is(reg))
 #define rm_is_reg(reg)	(mod_is_reg() && modrm_rm == (reg))
 
-int arch_decode_instruction(const struct elf *elf, const struct section *sec,
+int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
 			    unsigned long offset, unsigned int maxlen,
 			    unsigned int *len, enum insn_type *type,
 			    unsigned long *immediate,
 			    struct list_head *ops_list)
 {
+	const struct elf *elf = file->elf;
 	struct insn insn;
 	int x86_64, ret;
 	unsigned char op1, op2,
@@ -544,6 +546,36 @@ int arch_decode_instruction(const struct elf *elf, const struct section *sec,
 		*type = INSN_RETURN;
 		break;
 
+	case 0xc7: /* mov imm, r/m */
+		if (!noinstr)
+			break;
+
+		if (insn.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) {
+			struct reloc *immr, *disp;
+			struct symbol *func;
+			int idx;
+
+			immr = find_reloc_by_dest(elf, (void *)sec, offset+3);
+			disp = find_reloc_by_dest(elf, (void *)sec, offset+7);
+
+			if (!immr || strcmp(immr->sym->name, "pv_ops"))
+				break;
+
+			idx = (immr->addend + 8) / sizeof(void *);
+
+			func = disp->sym;
+			if (disp->sym->type == STT_SECTION)
+				func = find_symbol_by_offset(disp->sym->sec, disp->addend);
+			if (!func) {
+				WARN("no func for pv_ops[]");
+				return -1;
+			}
+
+			objtool_pv_add(file, idx, func);
+		}
+
+		break;
+
 	case 0xcf: /* iret */
 		/*
 		 * Handle sync_core(), which has an IRET to self.
tools/objtool/check.c +141 -10

231 lines not on this page · raw message

tools/objtool/include/objtool/arch.h +1 -1
index 6f482ae..589ff58 100644
@@ -69,7 +69,7 @@ struct instruction;
 
 void arch_initial_func_cfi_state(struct cfi_init_state *state);
 
-int arch_decode_instruction(const struct elf *elf, const struct section *sec,
+int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
 			    unsigned long offset, unsigned int maxlen,
 			    unsigned int *len, enum insn_type *type,
 			    unsigned long *immediate,
tools/objtool/include/objtool/elf.h +1 -0
index e343950..c3857fa 100644
@@ -57,6 +57,7 @@ struct symbol {
 	struct symbol *pfunc, *cfunc, *alias;
 	bool uaccess_safe;
 	bool static_call_tramp;
+	struct list_head pv_target;
 };
 
 struct reloc {
tools/objtool/include/objtool/objtool.h +9 -0
index 24fa836..f99fbc6 100644
@@ -14,6 +14,11 @@
 
 #define __weak __attribute__((weak))
 
+struct pv_state {
+	bool clean;
+	struct list_head targets;
+};
+
 struct objtool_file {
 	struct elf *elf;
 	struct list_head insn_list;
@@ -25,10 +30,14 @@ struct objtool_file {
 
 	unsigned long jl_short, jl_long;
 	unsigned long jl_nop_short, jl_nop_long;
+
+	struct pv_state *pv_ops;
 };
 
 struct objtool_file *objtool_open_read(const char *_objname);
 
+void objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func);
+
 int check(struct objtool_file *file);
 int orc_dump(const char *objname);
 int orc_create(struct objtool_file *file);
tools/objtool/objtool.c +22 -0
index e21db8b..c90c708 100644
@@ -135,6 +135,28 @@ struct objtool_file *objtool_open_read(const char *_objname)
 	return &file;
 }
 
+void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
+{
+	if (!noinstr)
+		return;
+
+	if (!f->pv_ops) {
+		WARN("paravirt confusion");
+		return;
+	}
+
+	/*
+	 * These functions will be patched into native code,
+	 * see paravirt_patch().
+	 */
+	if (!strcmp(func->name, "_paravirt_nop") ||
+	    !strcmp(func->name, "_paravirt_ident_64"))
+		return;
+
+	list_add(&func->pv_target, &f->pv_ops[idx].targets);
+	f->pv_ops[idx].clean = false;
+}
+
 static void cmd_usage(void)
 {
 	unsigned int i, longest = 0;
#101 lore raw
In reply to Peter Zijlstra
Quoted 1 line · On Thu, 24 Jun 2021 11:40:59 +0200 Peter Zijlstra <[email protected]> wrote:

Steve, can I please delete TRACE_BRANCH_PROFILING and PROFILE_ALL_BRANCHES already?

The TRACE_BRANCH_PROFILING, I never used, so I'm happy to delete it, but I still use the PROFILE_ALL_BRANCHES.

But I'm curious, what's the issue with the PROFILE_ALL_BRANCHES?

You can make it ignore files, by simply adding a:

#define DISABLE_BRANCH_PROFILING

at the top of the file (before any of the includes).

So if your issue is that it makes it hard for some code, simply add that to the top of the file, and it should just work.

-- Steve