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) ...@@ -516,7 +516,7 @@ void __init cpu_init (void)
BUG(); BUG();
enter_lazy_tlb(&init_mm, current, cpu); enter_lazy_tlb(&init_mm, current, cpu);
t->esp0 = thread->esp0; load_esp0(t, thread->esp0);
set_tss_desc(cpu,t); set_tss_desc(cpu,t);
cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
load_TR_desc(); load_TR_desc();
......
...@@ -443,7 +443,7 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p) ...@@ -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: * 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. * Load the per-thread Thread-Local Storage descriptor.
......
...@@ -34,40 +34,14 @@ struct fake_sep_struct { ...@@ -34,40 +34,14 @@ struct fake_sep_struct {
unsigned char stack[0]; unsigned char stack[0];
} __attribute__((aligned(8192))); } __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) static void __init enable_sep_cpu(void *info)
{ {
int cpu = get_cpu(); int cpu = get_cpu();
struct fake_sep_struct *sep = alloc_sep_thread(cpu); struct tss_struct *tss = init_tss + 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;
wrmsr(0x174, __KERNEL_CS, 0); /* SYSENTER_CS_MSR */ wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
wrmsr(0x175, PAGE_SIZE*2 + (unsigned long) sep, 0); /* SYSENTER_ESP_MSR */ wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp0, 0);
wrmsr(0x176, (unsigned long) &sep->trampoline, 0); /* SYSENTER_EIP_MSR */ wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);
printk("Enabling SEP on CPU %d\n", cpu); printk("Enabling SEP on CPU %d\n", cpu);
put_cpu(); put_cpu();
......
...@@ -113,7 +113,8 @@ struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) ...@@ -113,7 +113,8 @@ struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
tss = init_tss + smp_processor_id(); 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; current->thread.saved_esp0 = 0;
ret = KVM86->regs32; ret = KVM86->regs32;
return ret; return ret;
...@@ -284,6 +285,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk ...@@ -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; tsk->thread.saved_esp0 = tsk->thread.esp0;
tss = init_tss + smp_processor_id(); tss = init_tss + smp_processor_id();
tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
disable_sysenter();
tsk->thread.screen_bitmap = info->screen_bitmap; tsk->thread.screen_bitmap = info->screen_bitmap;
if (info->flags & VM86_SCREEN_BITMAP) if (info->flags & VM86_SCREEN_BITMAP)
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#ifndef __ASM_I386_CPUFEATURE_H #ifndef __ASM_I386_CPUFEATURE_H
#define __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 */ #define NCAPINTS 4 /* Currently we have 4 32-bit words worth of info */
/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */ /* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
...@@ -74,6 +76,7 @@ ...@@ -74,6 +76,7 @@
#define cpu_has_pae boot_cpu_has(X86_FEATURE_PAE) #define cpu_has_pae boot_cpu_has(X86_FEATURE_PAE)
#define cpu_has_pge boot_cpu_has(X86_FEATURE_PGE) #define cpu_has_pge boot_cpu_has(X86_FEATURE_PGE)
#define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC) #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_mtrr boot_cpu_has(X86_FEATURE_MTRR)
#define cpu_has_mmx boot_cpu_has(X86_FEATURE_MMX) #define cpu_has_mmx boot_cpu_has(X86_FEATURE_MMX)
#define cpu_has_fxsr boot_cpu_has(X86_FEATURE_FXSR) #define cpu_has_fxsr boot_cpu_has(X86_FEATURE_FXSR)
......
...@@ -53,6 +53,10 @@ ...@@ -53,6 +53,10 @@
#define MSR_IA32_BBL_CR_CTL 0x119 #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_CAP 0x179
#define MSR_IA32_MCG_STATUS 0x17a #define MSR_IA32_MCG_STATUS 0x17a
#define MSR_IA32_MCG_CTL 0x17b #define MSR_IA32_MCG_CTL 0x17b
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <asm/types.h> #include <asm/types.h>
#include <asm/sigcontext.h> #include <asm/sigcontext.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/msr.h>
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/threads.h> #include <linux/threads.h>
...@@ -416,6 +417,21 @@ struct thread_struct { ...@@ -416,6 +417,21 @@ struct thread_struct {
{~0, } /* ioperm */ \ {~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 { \ #define start_thread(regs, new_eip, new_esp) do { \
__asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \ __asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \
set_fs(USER_DS); \ 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