Skip to content

Commit 633260f

Browse files
committed
x86/irq: Convey vector as argument and not in ptregs
Device interrupts which go through do_IRQ() or the spurious interrupt handler have their separate entry code on 64 bit for no good reason. Both 32 and 64 bit transport the vector number through ORIG_[RE]AX in pt_regs. Further the vector number is forced to fit into an u8 and is complemented and offset by 0x80 so it's in the signed character range. Otherwise GAS would expand the pushq to a 5 byte instruction for any vector > 0x7F. Treat the vector number like an error code and hand it to the C function as argument. This allows to get rid of the extra entry code in a later step. Simplify the error code push magic by implementing the pushq imm8 via a '.byte 0x6a, vector' sequence so GAS is not able to screw it up. As the pushq imm8 is sign extending the resulting error code needs to be truncated to 8 bits in C code. Originally-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@kernel.org> Acked-by: Andy Lutomirski <luto@kernel.org> Link: https://lore.kernel.org/r/20200521202118.796915981@linutronix.de
1 parent 79b9c18 commit 633260f

File tree

11 files changed

+103
-78
lines changed

11 files changed

+103
-78
lines changed

arch/x86/entry/calling.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,10 @@ For 32-bit we have the following conventions - kernel is built with
341341
#endif
342342
.endm
343343

344-
#endif /* CONFIG_X86_64 */
344+
#else /* CONFIG_X86_64 */
345+
# undef UNWIND_HINT_IRET_REGS
346+
# define UNWIND_HINT_IRET_REGS
347+
#endif /* !CONFIG_X86_64 */
345348

346349
.macro STACKLEAK_ERASE
347350
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK

arch/x86/entry/entry_32.S

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,40 +1215,15 @@ SYM_FUNC_END(entry_INT80_32)
12151215
#endif
12161216
.endm
12171217

1218-
/*
1219-
* Build the entry stubs with some assembler magic.
1220-
* We pack 1 stub into every 8-byte block.
1221-
*/
1222-
.align 8
1223-
SYM_CODE_START(irq_entries_start)
1224-
vector=FIRST_EXTERNAL_VECTOR
1225-
.rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
1226-
pushl $(~vector+0x80) /* Note: always in signed byte range */
1227-
vector=vector+1
1228-
jmp common_interrupt
1229-
.align 8
1230-
.endr
1231-
SYM_CODE_END(irq_entries_start)
1232-
12331218
#ifdef CONFIG_X86_LOCAL_APIC
1234-
.align 8
1235-
SYM_CODE_START(spurious_entries_start)
1236-
vector=FIRST_SYSTEM_VECTOR
1237-
.rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
1238-
pushl $(~vector+0x80) /* Note: always in signed byte range */
1239-
vector=vector+1
1240-
jmp common_spurious
1241-
.align 8
1242-
.endr
1243-
SYM_CODE_END(spurious_entries_start)
1244-
12451219
SYM_CODE_START_LOCAL(common_spurious)
12461220
ASM_CLAC
1247-
addl $-0x80, (%esp) /* Adjust vector into the [-256, -1] range */
12481221
SAVE_ALL switch_stacks=1
12491222
ENCODE_FRAME_POINTER
12501223
TRACE_IRQS_OFF
12511224
movl %esp, %eax
1225+
movl PT_ORIG_EAX(%esp), %edx /* get the vector from stack */
1226+
movl $-1, PT_ORIG_EAX(%esp) /* no syscall to restart */
12521227
call smp_spurious_interrupt
12531228
jmp ret_from_intr
12541229
SYM_CODE_END(common_spurious)
@@ -1261,12 +1236,12 @@ SYM_CODE_END(common_spurious)
12611236
.p2align CONFIG_X86_L1_CACHE_SHIFT
12621237
SYM_CODE_START_LOCAL(common_interrupt)
12631238
ASM_CLAC
1264-
addl $-0x80, (%esp) /* Adjust vector into the [-256, -1] range */
1265-
12661239
SAVE_ALL switch_stacks=1
12671240
ENCODE_FRAME_POINTER
12681241
TRACE_IRQS_OFF
12691242
movl %esp, %eax
1243+
movl PT_ORIG_EAX(%esp), %edx /* get the vector from stack */
1244+
movl $-1, PT_ORIG_EAX(%esp) /* no syscall to restart */
12701245
call do_IRQ
12711246
jmp ret_from_intr
12721247
SYM_CODE_END(common_interrupt)

arch/x86/entry/entry_64.S

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -358,34 +358,6 @@ SYM_CODE_START(ret_from_fork)
358358
SYM_CODE_END(ret_from_fork)
359359
.popsection
360360

361-
/*
362-
* Build the entry stubs with some assembler magic.
363-
* We pack 1 stub into every 8-byte block.
364-
*/
365-
.align 8
366-
SYM_CODE_START(irq_entries_start)
367-
vector=FIRST_EXTERNAL_VECTOR
368-
.rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
369-
UNWIND_HINT_IRET_REGS
370-
pushq $(~vector+0x80) /* Note: always in signed byte range */
371-
jmp common_interrupt
372-
.align 8
373-
vector=vector+1
374-
.endr
375-
SYM_CODE_END(irq_entries_start)
376-
377-
.align 8
378-
SYM_CODE_START(spurious_entries_start)
379-
vector=FIRST_SYSTEM_VECTOR
380-
.rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
381-
UNWIND_HINT_IRET_REGS
382-
pushq $(~vector+0x80) /* Note: always in signed byte range */
383-
jmp common_spurious
384-
.align 8
385-
vector=vector+1
386-
.endr
387-
SYM_CODE_END(spurious_entries_start)
388-
389361
.macro DEBUG_ENTRY_ASSERT_IRQS_OFF
390362
#ifdef CONFIG_DEBUG_ENTRY
391363
pushq %rax
@@ -755,13 +727,14 @@ _ASM_NOKPROBE(interrupt_entry)
755727
/* Interrupt entry/exit. */
756728

757729
/*
758-
* The interrupt stubs push (~vector+0x80) onto the stack and
730+
* The interrupt stubs push vector onto the stack and
759731
* then jump to common_spurious/interrupt.
760732
*/
761733
SYM_CODE_START_LOCAL(common_spurious)
762-
addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
763734
call interrupt_entry
764735
UNWIND_HINT_REGS indirect=1
736+
movq ORIG_RAX(%rdi), %rsi /* get vector from stack */
737+
movq $-1, ORIG_RAX(%rdi) /* no syscall to restart */
765738
call smp_spurious_interrupt /* rdi points to pt_regs */
766739
jmp ret_from_intr
767740
SYM_CODE_END(common_spurious)
@@ -770,10 +743,11 @@ _ASM_NOKPROBE(common_spurious)
770743
/* common_interrupt is a hotpath. Align it */
771744
.p2align CONFIG_X86_L1_CACHE_SHIFT
772745
SYM_CODE_START_LOCAL(common_interrupt)
773-
addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
774746
call interrupt_entry
775747
UNWIND_HINT_REGS indirect=1
776-
call do_IRQ /* rdi points to pt_regs */
748+
movq ORIG_RAX(%rdi), %rsi /* get vector from stack */
749+
movq $-1, ORIG_RAX(%rdi) /* no syscall to restart */
750+
call do_IRQ /* rdi points to pt_regs */
777751
/* 0(%rsp): old RSP */
778752
ret_from_intr:
779753
DISABLE_INTERRUPTS(CLBR_ANY)
@@ -1022,7 +996,7 @@ apicinterrupt RESCHEDULE_VECTOR reschedule_interrupt smp_reschedule_interrupt
1022996
#endif
1023997

1024998
apicinterrupt ERROR_APIC_VECTOR error_interrupt smp_error_interrupt
1025-
apicinterrupt SPURIOUS_APIC_VECTOR spurious_interrupt smp_spurious_interrupt
999+
apicinterrupt SPURIOUS_APIC_VECTOR spurious_apic_interrupt smp_spurious_apic_interrupt
10261000

10271001
#ifdef CONFIG_IRQ_WORK
10281002
apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt

arch/x86/include/asm/entry_arch.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ BUILD_INTERRUPT(kvm_posted_intr_nested_ipi, POSTED_INTR_NESTED_VECTOR)
3535

3636
BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
3737
BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
38-
BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
38+
BUILD_INTERRUPT(spurious_apic_interrupt,SPURIOUS_APIC_VECTOR)
3939
BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR)
4040

4141
#ifdef CONFIG_IRQ_WORK

arch/x86/include/asm/hw_irq.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ extern asmlinkage void irq_work_interrupt(void);
3939
extern asmlinkage void uv_bau_message_intr1(void);
4040

4141
extern asmlinkage void spurious_interrupt(void);
42+
extern asmlinkage void spurious_apic_interrupt(void);
4243
extern asmlinkage void thermal_interrupt(void);
4344
extern asmlinkage void reschedule_interrupt(void);
4445

arch/x86/include/asm/idtentry.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,54 @@ __visible noinstr void func(struct pt_regs *regs, \
347347
#define DECLARE_IDTENTRY_XEN(vector, func) \
348348
idtentry vector asm_exc_xen##func exc_##func has_error_code=0
349349

350+
/*
351+
* ASM code to emit the common vector entry stubs where each stub is
352+
* packed into 8 bytes.
353+
*
354+
* Note, that the 'pushq imm8' is emitted via '.byte 0x6a, vector' because
355+
* GCC treats the local vector variable as unsigned int and would expand
356+
* all vectors above 0x7F to a 5 byte push. The original code did an
357+
* adjustment of the vector number to be in the signed byte range to avoid
358+
* this. While clever it's mindboggling counterintuitive and requires the
359+
* odd conversion back to a real vector number in the C entry points. Using
360+
* .byte achieves the same thing and the only fixup needed in the C entry
361+
* point is to mask off the bits above bit 7 because the push is sign
362+
* extending.
363+
*/
364+
.align 8
365+
SYM_CODE_START(irq_entries_start)
366+
vector=FIRST_EXTERNAL_VECTOR
367+
pos = .
368+
.rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
369+
UNWIND_HINT_IRET_REGS
370+
.byte 0x6a, vector
371+
jmp common_interrupt
372+
nop
373+
/* Ensure that the above is 8 bytes max */
374+
. = pos + 8
375+
pos=pos+8
376+
vector=vector+1
377+
.endr
378+
SYM_CODE_END(irq_entries_start)
379+
380+
#ifdef CONFIG_X86_LOCAL_APIC
381+
.align 8
382+
SYM_CODE_START(spurious_entries_start)
383+
vector=FIRST_SYSTEM_VECTOR
384+
pos = .
385+
.rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
386+
UNWIND_HINT_IRET_REGS
387+
.byte 0x6a, vector
388+
jmp common_spurious
389+
nop
390+
/* Ensure that the above is 8 bytes max */
391+
. = pos + 8
392+
pos=pos+8
393+
vector=vector+1
394+
.endr
395+
SYM_CODE_END(spurious_entries_start)
396+
#endif
397+
350398
#endif /* __ASSEMBLY__ */
351399

352400
/*

arch/x86/include/asm/irq.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ extern void native_init_IRQ(void);
3636

3737
extern void handle_irq(struct irq_desc *desc, struct pt_regs *regs);
3838

39-
extern __visible void do_IRQ(struct pt_regs *regs);
39+
extern __visible void do_IRQ(struct pt_regs *regs, unsigned long vector);
4040

4141
extern void init_ISA_irqs(void);
4242

arch/x86/include/asm/traps.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ asmlinkage void smp_deferred_error_interrupt(struct pt_regs *regs);
4141
#endif
4242

4343
void smp_apic_timer_interrupt(struct pt_regs *regs);
44-
void smp_spurious_interrupt(struct pt_regs *regs);
4544
void smp_error_interrupt(struct pt_regs *regs);
45+
void smp_spurious_apic_interrupt(struct pt_regs *regs);
46+
void smp_spurious_interrupt(struct pt_regs *regs, unsigned long vector);
4647
asmlinkage void smp_irq_move_cleanup_interrupt(void);
4748

4849
#ifdef CONFIG_VMAP_STACK

arch/x86/kernel/apic/apic.c

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,15 +2120,29 @@ void __init register_lapic_address(unsigned long address)
21202120
* Local APIC interrupts
21212121
*/
21222122

2123-
/*
2124-
* This interrupt should _never_ happen with our APIC/SMP architecture
2123+
/**
2124+
* smp_spurious_interrupt - Catch all for interrupts raised on unused vectors
2125+
* @regs: Pointer to pt_regs on stack
2126+
* @error_code: The vector number is in the lower 8 bits
2127+
*
2128+
* This is invoked from ASM entry code to catch all interrupts which
2129+
* trigger on an entry which is routed to the common_spurious idtentry
2130+
* point.
2131+
*
2132+
* Also called from smp_spurious_apic_interrupt().
21252133
*/
2126-
__visible void __irq_entry smp_spurious_interrupt(struct pt_regs *regs)
2134+
__visible void __irq_entry smp_spurious_interrupt(struct pt_regs *regs,
2135+
unsigned long vector)
21272136
{
2128-
u8 vector = ~regs->orig_ax;
21292137
u32 v;
21302138

21312139
entering_irq();
2140+
/*
2141+
* The push in the entry ASM code which stores the vector number on
2142+
* the stack in the error code slot is sign expanding. Just use the
2143+
* lower 8 bits.
2144+
*/
2145+
vector &= 0xFF;
21322146
trace_spurious_apic_entry(vector);
21332147

21342148
inc_irq_stat(irq_spurious_count);
@@ -2149,18 +2163,23 @@ __visible void __irq_entry smp_spurious_interrupt(struct pt_regs *regs)
21492163
*/
21502164
v = apic_read(APIC_ISR + ((vector & ~0x1f) >> 1));
21512165
if (v & (1 << (vector & 0x1f))) {
2152-
pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Acked\n",
2166+
pr_info("Spurious interrupt (vector 0x%02lx) on CPU#%d. Acked\n",
21532167
vector, smp_processor_id());
21542168
ack_APIC_irq();
21552169
} else {
2156-
pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Not pending!\n",
2170+
pr_info("Spurious interrupt (vector 0x%02lx) on CPU#%d. Not pending!\n",
21572171
vector, smp_processor_id());
21582172
}
21592173
out:
21602174
trace_spurious_apic_exit(vector);
21612175
exiting_irq();
21622176
}
21632177

2178+
__visible void smp_spurious_apic_interrupt(struct pt_regs *regs)
2179+
{
2180+
smp_spurious_interrupt(regs, SPURIOUS_APIC_VECTOR);
2181+
}
2182+
21642183
/*
21652184
* This interrupt should never happen with our APIC/SMP architecture
21662185
*/

arch/x86/kernel/idt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ static const __initconst struct idt_data apic_idts[] = {
145145
#ifdef CONFIG_X86_UV
146146
INTG(UV_BAU_MESSAGE, uv_bau_message_intr1),
147147
#endif
148-
INTG(SPURIOUS_APIC_VECTOR, spurious_interrupt),
148+
INTG(SPURIOUS_APIC_VECTOR, spurious_apic_interrupt),
149149
INTG(ERROR_APIC_VECTOR, error_interrupt),
150150
#endif
151151
};

0 commit comments

Comments
 (0)