Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ccbeed3a authored by Tejun Heo's avatar Tejun Heo Committed by Ingo Molnar
Browse files

x86: make lazy %gs optional on x86_32



Impact: pt_regs changed, lazy gs handling made optional, add slight
        overhead to SAVE_ALL, simplifies error_code path a bit

On x86_32, %gs hasn't been used by kernel and handled lazily.  pt_regs
doesn't have place for it and gs is saved/loaded only when necessary.
In preparation for stack protector support, this patch makes lazy %gs
handling optional by doing the followings.

* Add CONFIG_X86_32_LAZY_GS and place for gs in pt_regs.

* Save and restore %gs along with other registers in entry_32.S unless
  LAZY_GS.  Note that this unfortunately adds "pushl $0" on SAVE_ALL
  even when LAZY_GS.  However, it adds no overhead to common exit path
  and simplifies entry path with error code.

* Define different user_gs accessors depending on LAZY_GS and add
  lazy_save_gs() and lazy_load_gs() which are noop if !LAZY_GS.  The
  lazy_*_gs() ops are used to save, load and clear %gs lazily.

* Define ELF_CORE_COPY_KERNEL_REGS() which always read %gs directly.

xen and lguest changes need to be verified.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Cc: Jeremy Fitzhardinge <jeremy@xensource.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>

Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent d9a89a26
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -207,6 +207,10 @@ config X86_TRAMPOLINE
	depends on X86_SMP || (X86_VOYAGER && SMP) || (64BIT && ACPI_SLEEP)
	default y

config X86_32_LAZY_GS
	def_bool y
	depends on X86_32

config KTIME_SCALAR
	def_bool X86_32
source "init/Kconfig"
+13 −2
Original line number Diff line number Diff line
@@ -112,7 +112,7 @@ extern unsigned int vdso_enabled;
 * now struct_user_regs, they are different)
 */

#define ELF_CORE_COPY_REGS(pr_reg, regs)	\
#define ELF_CORE_COPY_REGS_COMMON(pr_reg, regs)	\
do {						\
	pr_reg[0] = regs->bx;			\
	pr_reg[1] = regs->cx;			\
@@ -124,7 +124,6 @@ do { \
	pr_reg[7] = regs->ds & 0xffff;		\
	pr_reg[8] = regs->es & 0xffff;		\
	pr_reg[9] = regs->fs & 0xffff;		\
	pr_reg[10] = get_user_gs(regs);		\
	pr_reg[11] = regs->orig_ax;		\
	pr_reg[12] = regs->ip;			\
	pr_reg[13] = regs->cs & 0xffff;		\
@@ -133,6 +132,18 @@ do { \
	pr_reg[16] = regs->ss & 0xffff;		\
} while (0);

#define ELF_CORE_COPY_REGS(pr_reg, regs)	\
do {						\
	ELF_CORE_COPY_REGS_COMMON(pr_reg, regs);\
	pr_reg[10] = get_user_gs(regs);		\
} while (0);

#define ELF_CORE_COPY_KERNEL_REGS(pr_reg, regs)	\
do {						\
	ELF_CORE_COPY_REGS_COMMON(pr_reg, regs);\
	savesegment(gs, pr_reg[10]);		\
} while (0);

#define ELF_PLATFORM	(utsname()->machine)
#define set_personality_64bit()	do { } while (0)

+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ do { \
#ifdef CONFIG_X86_32
#define deactivate_mm(tsk, mm)			\
do {						\
	set_user_gs(task_pt_regs(tsk), 0);	\
	lazy_load_gs(0);			\
} while (0)
#else
#define deactivate_mm(tsk, mm)			\
+2 −2
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ struct pt_regs {
	int  xds;
	int  xes;
	int  xfs;
	/* int  gs; */
	int  xgs;
	long orig_eax;
	long eip;
	int  xcs;
@@ -50,7 +50,7 @@ struct pt_regs {
	unsigned long ds;
	unsigned long es;
	unsigned long fs;
	/* int  gs; */
	unsigned long gs;
	unsigned long orig_ax;
	unsigned long ip;
	unsigned long cs;
+11 −1
Original line number Diff line number Diff line
@@ -186,10 +186,20 @@ extern void native_load_gs_index(unsigned);
 * x86_32 user gs accessors.
 */
#ifdef CONFIG_X86_32
#ifdef CONFIG_X86_32_LAZY_GS
#define get_user_gs(regs)	(u16)({unsigned long v; savesegment(gs, v); v;})
#define set_user_gs(regs, v)	loadsegment(gs, (unsigned long)(v))
#define task_user_gs(tsk)	((tsk)->thread.gs)
#endif
#define lazy_save_gs(v)		savesegment(gs, (v))
#define lazy_load_gs(v)		loadsegment(gs, (v))
#else	/* X86_32_LAZY_GS */
#define get_user_gs(regs)	(u16)((regs)->gs)
#define set_user_gs(regs, v)	do { (regs)->gs = (v); } while (0)
#define task_user_gs(tsk)	(task_pt_regs(tsk)->gs)
#define lazy_save_gs(v)		do { } while (0)
#define lazy_load_gs(v)		do { } while (0)
#endif	/* X86_32_LAZY_GS */
#endif	/* X86_32 */

static inline unsigned long get_limit(unsigned long segment)
{
Loading