On 11/10/2014 03:55 PM, Andi Kleen wrote: > From: Andi Kleen <[email protected]> > > Convert arch_prctl to use the new instructions to > change fs/gs if available, instead of using MSRs. > > This is merely a small performance optimization, > no new functionality. > > With the new instructions the syscall is really obsolete, > as everything can be set directly in ring 3. But the syscall > is widely used by existing software, so we still support it. > > The syscall still enforces that the addresses are not > in kernel space, even though that is not needed more. > This is mainly so that the programs written for new CPUs > do not suddenly fail on old CPUs. > > With the new instructions available it prefers to use > them in the context switch, instead of using the old > "use GDT segment rewrite" trick. > > Signed-off-by: Andi Kleen <[email protected]> > --- > arch/x86/kernel/process_64.c | 45 > ++++++++++++++++++++++++++++++++++++-------- > 1 file changed, 37 insertions(+), 8 deletions(-) > > diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c > index df554e2..010fe15 100644 > --- a/arch/x86/kernel/process_64.c > +++ b/arch/x86/kernel/process_64.c > @@ -483,15 +483,23 @@ long do_arch_prctl(struct task_struct *task, int code, > unsigned long addr) > int ret = 0; > int doit = task == current; > int cpu; > + int fast_seg = boot_cpu_has(X86_FEATURE_FSGSBASE); > > switch (code) { > case ARCH_SET_GS: > + /* > + * With fast_seg we don't need that check anymore, > + * but keep it so that programs do not suddenly > + * start failing when run on older CPUs. > + * If you really want to set a address in kernel space > + * use WRGSBASE directly. > + */ > if (addr >= TASK_SIZE_OF(task)) > return -EPERM; > cpu = get_cpu(); > /* handle small bases via the GDT because that's faster to > switch. */ > - if (addr <= 0xffffffff) { > + if (addr <= 0xffffffff && !fast_seg) { > set_32bit_tls(task, GS_TLS, addr); > if (doit) { > load_TLS(&task->thread, cpu); > @@ -503,8 +511,17 @@ long do_arch_prctl(struct task_struct *task, int code, > unsigned long addr) > task->thread.gsindex = 0; > task->thread.gs = addr; > if (doit) { > - load_gs_index(0); > - ret = wrmsrl_safe(MSR_KERNEL_GS_BASE, addr); > + if (fast_seg) { > + local_irq_disable(); > + swapgs(); > + loadsegment(gs, 0); > + wrgsbase(addr); > + swapgs(); > + local_irq_enable();
Does this (and the other copies of this) need kprobe protection? --Andy -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/

