Skip to content

Commit 198d208

Browse files
Steven RostedtH. Peter Anvin
authored andcommitted
x86: Keep thread_info on thread stack in x86_32
x86_64 uses a per_cpu variable kernel_stack to always point to the thread stack of current. This is where the thread_info is stored and is accessed from this location even when the irq or exception stack is in use. This removes the complexity of having to maintain the thread info on the stack when interrupts are running and having to copy the preempt_count and other fields to the interrupt stack. x86_32 uses the old method of copying the thread_info from the thread stack to the exception stack just before executing the exception. Having the two different requires #ifdefs and also the x86_32 way is a bit of a pain to maintain. By converting x86_32 to the same method of x86_64, we can remove #ifdefs, clean up the x86_32 code a little, and remove the overhead of the copy. Cc: Andrew Morton <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Brian Gerst <[email protected]> Signed-off-by: Steven Rostedt <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: H. Peter Anvin <[email protected]>
1 parent 0788aa6 commit 198d208

File tree

8 files changed

+89
-100
lines changed

8 files changed

+89
-100
lines changed

arch/x86/include/asm/processor.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,15 @@ struct stack_canary {
449449
};
450450
DECLARE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
451451
#endif
452+
/*
453+
* per-CPU IRQ handling stacks
454+
*/
455+
struct irq_stack {
456+
u32 stack[THREAD_SIZE/sizeof(u32)];
457+
} __aligned(THREAD_SIZE);
458+
459+
DECLARE_PER_CPU(struct irq_stack *, hardirq_stack);
460+
DECLARE_PER_CPU(struct irq_stack *, softirq_stack);
452461
#endif /* X86_64 */
453462

454463
extern unsigned int xstate_size;

arch/x86/include/asm/thread_info.h

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <linux/compiler.h>
1111
#include <asm/page.h>
12+
#include <asm/percpu.h>
1213
#include <asm/types.h>
1314

1415
/*
@@ -34,12 +35,6 @@ struct thread_info {
3435
void __user *sysenter_return;
3536
unsigned int sig_on_uaccess_error:1;
3637
unsigned int uaccess_err:1; /* uaccess failed */
37-
#ifdef CONFIG_X86_32
38-
unsigned long previous_esp; /* ESP of the previous stack in
39-
case of nested (IRQ) stacks
40-
(Moved to end, to be removed soon)
41-
*/
42-
#endif
4338
};
4439

4540
#define INIT_THREAD_INFO(tsk) \
@@ -153,48 +148,16 @@ struct thread_info {
153148
#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
154149
#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW)
155150

156-
#ifdef CONFIG_X86_32
151+
#define STACK_WARN (THREAD_SIZE/8)
152+
#define KERNEL_STACK_OFFSET (5*(BITS_PER_LONG/8))
157153

158-
#define STACK_WARN (THREAD_SIZE/8)
159154
/*
160155
* macros/functions for gaining access to the thread information structure
161156
*
162157
* preempt_count needs to be 1 initially, until the scheduler is functional.
163158
*/
164159
#ifndef __ASSEMBLY__
165160

166-
#define current_stack_pointer ({ \
167-
unsigned long sp; \
168-
asm("mov %%esp,%0" : "=g" (sp)); \
169-
sp; \
170-
})
171-
172-
/* how to get the thread information struct from C */
173-
static inline struct thread_info *current_thread_info(void)
174-
{
175-
return (struct thread_info *)
176-
(current_stack_pointer & ~(THREAD_SIZE - 1));
177-
}
178-
179-
#else /* !__ASSEMBLY__ */
180-
181-
/* how to get the thread information struct from ASM */
182-
#define GET_THREAD_INFO(reg) \
183-
movl $-THREAD_SIZE, reg; \
184-
andl %esp, reg
185-
186-
#endif
187-
188-
#else /* X86_32 */
189-
190-
#include <asm/percpu.h>
191-
#define KERNEL_STACK_OFFSET (5*8)
192-
193-
/*
194-
* macros/functions for gaining access to the thread information structure
195-
* preempt_count needs to be 1 initially, until the scheduler is functional.
196-
*/
197-
#ifndef __ASSEMBLY__
198161
DECLARE_PER_CPU(unsigned long, kernel_stack);
199162

200163
static inline struct thread_info *current_thread_info(void)
@@ -209,8 +172,8 @@ static inline struct thread_info *current_thread_info(void)
209172

210173
/* how to get the thread information struct from ASM */
211174
#define GET_THREAD_INFO(reg) \
212-
movq PER_CPU_VAR(kernel_stack),reg ; \
213-
subq $(THREAD_SIZE-KERNEL_STACK_OFFSET),reg
175+
_ASM_MOV PER_CPU_VAR(kernel_stack),reg ; \
176+
_ASM_SUB $(THREAD_SIZE-KERNEL_STACK_OFFSET),reg ;
214177

215178
/*
216179
* Same if PER_CPU_VAR(kernel_stack) is, perhaps with some offset, already in
@@ -220,8 +183,6 @@ static inline struct thread_info *current_thread_info(void)
220183

221184
#endif
222185

223-
#endif /* !X86_32 */
224-
225186
/*
226187
* Thread-synchronous status.
227188
*

arch/x86/kernel/cpu/common.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,10 @@ static __init int setup_disablecpuid(char *arg)
10781078
}
10791079
__setup("clearcpuid=", setup_disablecpuid);
10801080

1081+
DEFINE_PER_CPU(unsigned long, kernel_stack) =
1082+
(unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;
1083+
EXPORT_PER_CPU_SYMBOL(kernel_stack);
1084+
10811085
#ifdef CONFIG_X86_64
10821086
struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
10831087
struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1,
@@ -1094,10 +1098,6 @@ DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned =
10941098
&init_task;
10951099
EXPORT_PER_CPU_SYMBOL(current_task);
10961100

1097-
DEFINE_PER_CPU(unsigned long, kernel_stack) =
1098-
(unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;
1099-
EXPORT_PER_CPU_SYMBOL(kernel_stack);
1100-
11011101
DEFINE_PER_CPU(char *, irq_stack_ptr) =
11021102
init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64;
11031103

arch/x86/kernel/dumpstack_32.c

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,33 @@
1616

1717
#include <asm/stacktrace.h>
1818

19+
static void *is_irq_stack(void *p, void *irq)
20+
{
21+
if (p < irq || p >= (irq + THREAD_SIZE))
22+
return NULL;
23+
return irq + THREAD_SIZE;
24+
}
25+
26+
27+
static void *is_hardirq_stack(unsigned long *stack, int cpu)
28+
{
29+
void *irq = per_cpu(hardirq_stack, cpu);
30+
31+
return is_irq_stack(stack, irq);
32+
}
33+
34+
static void *is_softirq_stack(unsigned long *stack, int cpu)
35+
{
36+
void *irq = per_cpu(softirq_stack, cpu);
37+
38+
return is_irq_stack(stack, irq);
39+
}
1940

2041
void dump_trace(struct task_struct *task, struct pt_regs *regs,
2142
unsigned long *stack, unsigned long bp,
2243
const struct stacktrace_ops *ops, void *data)
2344
{
45+
const unsigned cpu = get_cpu();
2446
int graph = 0;
2547
u32 *prev_esp;
2648

@@ -40,18 +62,22 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
4062

4163
for (;;) {
4264
struct thread_info *context;
65+
void *end_stack;
66+
67+
end_stack = is_hardirq_stack(stack, cpu);
68+
if (!end_stack)
69+
end_stack = is_softirq_stack(stack, cpu);
4370

44-
context = (struct thread_info *)
45-
((unsigned long)stack & (~(THREAD_SIZE - 1)));
46-
bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);
71+
context = task_thread_info(task);
72+
bp = ops->walk_stack(context, stack, bp, ops, data,
73+
end_stack, &graph);
4774

4875
/* Stop if not on irq stack */
49-
if (task_stack_page(task) == context)
76+
if (!end_stack)
5077
break;
5178

52-
/* The previous esp is just above the context */
53-
prev_esp = (u32 *) ((char *)context + sizeof(struct thread_info) -
54-
sizeof(long));
79+
/* The previous esp is saved on the bottom of the stack */
80+
prev_esp = (u32 *)(end_stack - THREAD_SIZE);
5581
stack = (unsigned long *)*prev_esp;
5682
if (!stack)
5783
break;
@@ -60,6 +86,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
6086
break;
6187
touch_nmi_watchdog();
6288
}
89+
put_cpu();
6390
}
6491
EXPORT_SYMBOL(dump_trace);
6592

arch/x86/kernel/irq_32.c

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,8 @@ static inline int check_stack_overflow(void) { return 0; }
5555
static inline void print_stack_overflow(void) { }
5656
#endif
5757

58-
/*
59-
* per-CPU IRQ handling contexts (thread information and stack)
60-
*/
61-
union irq_ctx {
62-
struct thread_info tinfo;
63-
u32 stack[THREAD_SIZE/sizeof(u32)];
64-
} __attribute__((aligned(THREAD_SIZE)));
65-
66-
static DEFINE_PER_CPU(union irq_ctx *, hardirq_ctx);
67-
static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx);
58+
DEFINE_PER_CPU(struct irq_stack *, hardirq_stack);
59+
DEFINE_PER_CPU(struct irq_stack *, softirq_stack);
6860

6961
static void call_on_stack(void *func, void *stack)
7062
{
@@ -77,30 +69,36 @@ static void call_on_stack(void *func, void *stack)
7769
: "memory", "cc", "edx", "ecx", "eax");
7870
}
7971

72+
/* how to get the current stack pointer from C */
73+
register unsigned long current_stack_pointer asm("esp") __used;
74+
75+
static inline void *current_stack(void)
76+
{
77+
return (void *)(current_stack_pointer & ~(THREAD_SIZE - 1));
78+
}
79+
8080
static inline int
8181
execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
8282
{
83-
union irq_ctx *curctx, *irqctx;
83+
struct irq_stack *curstk, *irqstk;
8484
u32 *isp, *prev_esp, arg1, arg2;
8585

86-
curctx = (union irq_ctx *) current_thread_info();
87-
irqctx = __this_cpu_read(hardirq_ctx);
86+
curstk = (struct irq_stack *) current_stack();
87+
irqstk = __this_cpu_read(hardirq_stack);
8888

8989
/*
9090
* this is where we switch to the IRQ stack. However, if we are
9191
* already using the IRQ stack (because we interrupted a hardirq
9292
* handler) we can't do that and just have to keep using the
9393
* current stack (which is the irq stack already after all)
9494
*/
95-
if (unlikely(curctx == irqctx))
95+
if (unlikely(curstk == irqstk))
9696
return 0;
9797

98-
/* build the stack frame on the IRQ stack */
99-
isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
100-
irqctx->tinfo.task = curctx->tinfo.task;
101-
/* Save the next esp after thread_info */
102-
prev_esp = (u32 *) ((char *)irqctx + sizeof(struct thread_info) -
103-
sizeof(long));
98+
isp = (u32 *) ((char *)irqstk + sizeof(*irqstk));
99+
100+
/* Save the next esp at the bottom of the stack */
101+
prev_esp = (u32 *)irqstk;
104102
*prev_esp = current_stack_pointer;
105103

106104
if (unlikely(overflow))
@@ -121,49 +119,39 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
121119
*/
122120
void irq_ctx_init(int cpu)
123121
{
124-
union irq_ctx *irqctx;
122+
struct irq_stack *irqstk;
125123

126-
if (per_cpu(hardirq_ctx, cpu))
124+
if (per_cpu(hardirq_stack, cpu))
127125
return;
128126

129-
irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
127+
irqstk = page_address(alloc_pages_node(cpu_to_node(cpu),
130128
THREADINFO_GFP,
131129
THREAD_SIZE_ORDER));
132-
memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
133-
irqctx->tinfo.cpu = cpu;
134-
irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
130+
per_cpu(hardirq_stack, cpu) = irqstk;
135131

136-
per_cpu(hardirq_ctx, cpu) = irqctx;
137-
138-
irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
132+
irqstk = page_address(alloc_pages_node(cpu_to_node(cpu),
139133
THREADINFO_GFP,
140134
THREAD_SIZE_ORDER));
141-
memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
142-
irqctx->tinfo.cpu = cpu;
143-
irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
144-
145-
per_cpu(softirq_ctx, cpu) = irqctx;
135+
per_cpu(softirq_stack, cpu) = irqstk;
146136

147137
printk(KERN_DEBUG "CPU %u irqstacks, hard=%p soft=%p\n",
148-
cpu, per_cpu(hardirq_ctx, cpu), per_cpu(softirq_ctx, cpu));
138+
cpu, per_cpu(hardirq_stack, cpu), per_cpu(softirq_stack, cpu));
149139
}
150140

151141
void do_softirq_own_stack(void)
152142
{
153-
struct thread_info *curctx;
154-
union irq_ctx *irqctx;
143+
struct thread_info *curstk;
144+
struct irq_stack *irqstk;
155145
u32 *isp, *prev_esp;
156146

157-
curctx = current_thread_info();
158-
irqctx = __this_cpu_read(softirq_ctx);
159-
irqctx->tinfo.task = curctx->task;
147+
curstk = current_stack();
148+
irqstk = __this_cpu_read(softirq_stack);
160149

161150
/* build the stack frame on the softirq stack */
162-
isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
151+
isp = (u32 *) ((char *)irqstk + sizeof(*irqstk));
163152

164153
/* Push the previous esp onto the stack */
165-
prev_esp = (u32 *) ((char *)irqctx + sizeof(struct thread_info) -
166-
sizeof(long));
154+
prev_esp = (u32 *)irqstk;
167155
*prev_esp = current_stack_pointer;
168156

169157
call_on_stack(__do_softirq, isp);

arch/x86/kernel/process_32.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
314314
*/
315315
arch_end_context_switch(next_p);
316316

317+
this_cpu_write(kernel_stack,
318+
(unsigned long)task_stack_page(next_p) +
319+
THREAD_SIZE - KERNEL_STACK_OFFSET);
320+
317321
/*
318322
* Restore %gs if needed (which is common)
319323
*/

arch/x86/kernel/ptrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs)
189189
if (context == (sp & ~(THREAD_SIZE - 1)))
190190
return sp;
191191

192-
prev_esp = (u32 *)(context + sizeof(struct thread_info) - sizeof(long));
192+
prev_esp = (u32 *)(context);
193193
if (prev_esp)
194194
return (unsigned long)prev_esp;
195195

arch/x86/kernel/smpboot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,10 +758,10 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
758758
#else
759759
clear_tsk_thread_flag(idle, TIF_FORK);
760760
initial_gs = per_cpu_offset(cpu);
761+
#endif
761762
per_cpu(kernel_stack, cpu) =
762763
(unsigned long)task_stack_page(idle) -
763764
KERNEL_STACK_OFFSET + THREAD_SIZE;
764-
#endif
765765
early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
766766
initial_code = (unsigned long)start_secondary;
767767
stack_start = idle->thread.sp;

0 commit comments

Comments
 (0)