Commit d8ce4c5f authored by Linus Torvalds's avatar Linus Torvalds

Sysenter cleanups (originals by Brian Gerst, updated and expanded by me):

 - set up kernel stack pointer for sysenter at each context switch.
 - disable sysenter while in vm86 mode.
 - clean up mtrr number defines and SEP feature testing
parent 5909af06
......@@ -516,7 +516,7 @@ void __init cpu_init (void)
BUG();
enter_lazy_tlb(&init_mm, current, cpu);
t->esp0 = thread->esp0;
load_esp0(t, thread->esp0);
set_tss_desc(cpu,t);
cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
load_TR_desc();
......
......@@ -443,7 +443,7 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
/*
* Reload esp0, LDT and the page table pointer:
*/
tss->esp0 = next->esp0;
load_esp0(tss, next->esp0);
/*
* Load the per-thread Thread-Local Storage descriptor.
......
......@@ -34,40 +34,14 @@ struct fake_sep_struct {
unsigned char stack[0];
} __attribute__((aligned(8192)));
static struct fake_sep_struct *alloc_sep_thread(int cpu)
{
struct fake_sep_struct *entry;
entry = (struct fake_sep_struct *) __get_free_pages(GFP_ATOMIC, 1);
if (!entry)
return NULL;
memset(entry, 0, PAGE_SIZE<<1);
entry->thread.task = &entry->task;
entry->task.thread_info = &entry->thread;
entry->thread.preempt_count = 1;
entry->thread.cpu = cpu;
return entry;
}
static void __init enable_sep_cpu(void *info)
{
int cpu = get_cpu();
struct fake_sep_struct *sep = alloc_sep_thread(cpu);
unsigned long *esp0_ptr = &(init_tss + cpu)->esp0;
unsigned long rel32;
rel32 = (unsigned long) sysenter_entry - (unsigned long) (sep->trampoline+11);
*(short *) (sep->trampoline+0) = 0x258b; /* movl xxxxx,%esp */
*(long **) (sep->trampoline+2) = esp0_ptr;
*(char *) (sep->trampoline+6) = 0xe9; /* jmp rl32 */
*(long *) (sep->trampoline+7) = rel32;
struct tss_struct *tss = init_tss + cpu;
wrmsr(0x174, __KERNEL_CS, 0); /* SYSENTER_CS_MSR */
wrmsr(0x175, PAGE_SIZE*2 + (unsigned long) sep, 0); /* SYSENTER_ESP_MSR */
wrmsr(0x176, (unsigned long) &sep->trampoline, 0); /* SYSENTER_EIP_MSR */
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp0, 0);
wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);
printk("Enabling SEP on CPU %d\n", cpu);
put_cpu();
......
......@@ -113,7 +113,8 @@ struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
do_exit(SIGSEGV);
}
tss = init_tss + smp_processor_id();
tss->esp0 = current->thread.esp0 = current->thread.saved_esp0;
current->thread.esp0 = current->thread.saved_esp0;
load_esp0(tss, current->thread.esp0);
current->thread.saved_esp0 = 0;
ret = KVM86->regs32;
return ret;
......@@ -284,6 +285,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
tsk->thread.saved_esp0 = tsk->thread.esp0;
tss = init_tss + smp_processor_id();
tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
disable_sysenter();
tsk->thread.screen_bitmap = info->screen_bitmap;
if (info->flags & VM86_SCREEN_BITMAP)
......
......@@ -7,6 +7,8 @@
#ifndef __ASM_I386_CPUFEATURE_H
#define __ASM_I386_CPUFEATURE_H
#include <linux/bitops.h>
#define NCAPINTS 4 /* Currently we have 4 32-bit words worth of info */
/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
......@@ -74,6 +76,7 @@
#define cpu_has_pae boot_cpu_has(X86_FEATURE_PAE)
#define cpu_has_pge boot_cpu_has(X86_FEATURE_PGE)
#define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC)
#define cpu_has_sep boot_cpu_has(X86_FEATURE_SEP)
#define cpu_has_mtrr boot_cpu_has(X86_FEATURE_MTRR)
#define cpu_has_mmx boot_cpu_has(X86_FEATURE_MMX)
#define cpu_has_fxsr boot_cpu_has(X86_FEATURE_FXSR)
......
......@@ -53,6 +53,10 @@
#define MSR_IA32_BBL_CR_CTL 0x119
#define MSR_IA32_SYSENTER_CS 0x174
#define MSR_IA32_SYSENTER_ESP 0x175
#define MSR_IA32_SYSENTER_EIP 0x176
#define MSR_IA32_MCG_CAP 0x179
#define MSR_IA32_MCG_STATUS 0x17a
#define MSR_IA32_MCG_CTL 0x17b
......
......@@ -14,6 +14,7 @@
#include <asm/types.h>
#include <asm/sigcontext.h>
#include <asm/cpufeature.h>
#include <asm/msr.h>
#include <linux/cache.h>
#include <linux/config.h>
#include <linux/threads.h>
......@@ -416,6 +417,21 @@ struct thread_struct {
{~0, } /* ioperm */ \
}
static inline void load_esp0(struct tss_struct *tss, unsigned long esp0)
{
tss->esp0 = esp0;
if (cpu_has_sep) {
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
wrmsr(MSR_IA32_SYSENTER_ESP, esp0, 0);
}
}
static inline void disable_sysenter(void)
{
if (cpu_has_sep)
wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
}
#define start_thread(regs, new_eip, new_esp) do { \
__asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \
set_fs(USER_DS); \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment