ia64/xen-unstable
changeset 8926:f97dd89691e7
Add arch/i386/kernel/{asm-offsets.c,sysenter.c,vm86.c,vsyscall.S} to sparse tree.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author | cl349@firebug.cl.cam.ac.uk |
---|---|
date | Mon Feb 20 14:37:13 2006 +0000 (2006-02-20) |
parents | 3083585fb248 |
children | 16a91d8dd8ed |
files | linux-2.6-xen-sparse/arch/i386/kernel/asm-offsets.c linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c linux-2.6-xen-sparse/arch/i386/kernel/vm86.c linux-2.6-xen-sparse/arch/i386/kernel/vsyscall.S |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/linux-2.6-xen-sparse/arch/i386/kernel/asm-offsets.c Mon Feb 20 14:37:13 2006 +0000 1.3 @@ -0,0 +1,72 @@ 1.4 +/* 1.5 + * Generate definitions needed by assembly language modules. 1.6 + * This code generates raw asm output which is post-processed 1.7 + * to extract and format the required data. 1.8 + */ 1.9 + 1.10 +#include <linux/sched.h> 1.11 +#include <linux/signal.h> 1.12 +#include <linux/personality.h> 1.13 +#include <linux/suspend.h> 1.14 +#include <asm/ucontext.h> 1.15 +#include "sigframe.h" 1.16 +#include <asm/fixmap.h> 1.17 +#include <asm/processor.h> 1.18 +#include <asm/thread_info.h> 1.19 + 1.20 +#define DEFINE(sym, val) \ 1.21 + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) 1.22 + 1.23 +#define BLANK() asm volatile("\n->" : : ) 1.24 + 1.25 +#define OFFSET(sym, str, mem) \ 1.26 + DEFINE(sym, offsetof(struct str, mem)); 1.27 + 1.28 +void foo(void) 1.29 +{ 1.30 + OFFSET(SIGCONTEXT_eax, sigcontext, eax); 1.31 + OFFSET(SIGCONTEXT_ebx, sigcontext, ebx); 1.32 + OFFSET(SIGCONTEXT_ecx, sigcontext, ecx); 1.33 + OFFSET(SIGCONTEXT_edx, sigcontext, edx); 1.34 + OFFSET(SIGCONTEXT_esi, sigcontext, esi); 1.35 + OFFSET(SIGCONTEXT_edi, sigcontext, edi); 1.36 + OFFSET(SIGCONTEXT_ebp, sigcontext, ebp); 1.37 + OFFSET(SIGCONTEXT_esp, sigcontext, esp); 1.38 + OFFSET(SIGCONTEXT_eip, sigcontext, eip); 1.39 + BLANK(); 1.40 + 1.41 + OFFSET(CPUINFO_x86, cpuinfo_x86, x86); 1.42 + OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor); 1.43 + OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model); 1.44 + OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask); 1.45 + OFFSET(CPUINFO_hard_math, cpuinfo_x86, hard_math); 1.46 + OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level); 1.47 + OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability); 1.48 + OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id); 1.49 + BLANK(); 1.50 + 1.51 + OFFSET(TI_task, thread_info, task); 1.52 + OFFSET(TI_exec_domain, thread_info, exec_domain); 1.53 + OFFSET(TI_flags, thread_info, flags); 1.54 + OFFSET(TI_status, thread_info, status); 1.55 + OFFSET(TI_cpu, thread_info, cpu); 1.56 + OFFSET(TI_preempt_count, thread_info, preempt_count); 1.57 + OFFSET(TI_addr_limit, thread_info, addr_limit); 1.58 + OFFSET(TI_restart_block, thread_info, restart_block); 1.59 + BLANK(); 1.60 + 1.61 + OFFSET(EXEC_DOMAIN_handler, exec_domain, handler); 1.62 + OFFSET(RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext); 1.63 + BLANK(); 1.64 + 1.65 + OFFSET(pbe_address, pbe, address); 1.66 + OFFSET(pbe_orig_address, pbe, orig_address); 1.67 + OFFSET(pbe_next, pbe, next); 1.68 + 1.69 + /* Offset from the sysenter stack to tss.esp0 */ 1.70 + DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, esp0) - 1.71 + sizeof(struct tss_struct)); 1.72 + 1.73 + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); 1.74 + DEFINE(VSYSCALL_BASE, __fix_to_virt(FIX_VSYSCALL)); 1.75 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c Mon Feb 20 14:37:13 2006 +0000 2.3 @@ -0,0 +1,67 @@ 2.4 +/* 2.5 + * linux/arch/i386/kernel/sysenter.c 2.6 + * 2.7 + * (C) Copyright 2002 Linus Torvalds 2.8 + * 2.9 + * This file contains the needed initializations to support sysenter. 2.10 + */ 2.11 + 2.12 +#include <linux/init.h> 2.13 +#include <linux/smp.h> 2.14 +#include <linux/thread_info.h> 2.15 +#include <linux/sched.h> 2.16 +#include <linux/gfp.h> 2.17 +#include <linux/string.h> 2.18 +#include <linux/elf.h> 2.19 + 2.20 +#include <asm/cpufeature.h> 2.21 +#include <asm/msr.h> 2.22 +#include <asm/pgtable.h> 2.23 +#include <asm/unistd.h> 2.24 + 2.25 +extern asmlinkage void sysenter_entry(void); 2.26 + 2.27 +void enable_sep_cpu(void) 2.28 +{ 2.29 + int cpu = get_cpu(); 2.30 + struct tss_struct *tss = &per_cpu(init_tss, cpu); 2.31 + 2.32 + if (!boot_cpu_has(X86_FEATURE_SEP)) { 2.33 + put_cpu(); 2.34 + return; 2.35 + } 2.36 + 2.37 + tss->ss1 = __KERNEL_CS; 2.38 + tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; 2.39 + wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); 2.40 + wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0); 2.41 + wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0); 2.42 + put_cpu(); 2.43 +} 2.44 + 2.45 +/* 2.46 + * These symbols are defined by vsyscall.o to mark the bounds 2.47 + * of the ELF DSO images included therein. 2.48 + */ 2.49 +extern const char vsyscall_int80_start, vsyscall_int80_end; 2.50 +extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; 2.51 + 2.52 +int __init sysenter_setup(void) 2.53 +{ 2.54 + void *page = (void *)get_zeroed_page(GFP_ATOMIC); 2.55 + 2.56 + __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY_EXEC); 2.57 + 2.58 + if (!boot_cpu_has(X86_FEATURE_SEP)) { 2.59 + memcpy(page, 2.60 + &vsyscall_int80_start, 2.61 + &vsyscall_int80_end - &vsyscall_int80_start); 2.62 + return 0; 2.63 + } 2.64 + 2.65 + memcpy(page, 2.66 + &vsyscall_sysenter_start, 2.67 + &vsyscall_sysenter_end - &vsyscall_sysenter_start); 2.68 + 2.69 + return 0; 2.70 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/linux-2.6-xen-sparse/arch/i386/kernel/vm86.c Mon Feb 20 14:37:13 2006 +0000 3.3 @@ -0,0 +1,809 @@ 3.4 +/* 3.5 + * linux/kernel/vm86.c 3.6 + * 3.7 + * Copyright (C) 1994 Linus Torvalds 3.8 + * 3.9 + * 29 dec 2001 - Fixed oopses caused by unchecked access to the vm86 3.10 + * stack - Manfred Spraul <manfred@colorfullife.com> 3.11 + * 3.12 + * 22 mar 2002 - Manfred detected the stackfaults, but didn't handle 3.13 + * them correctly. Now the emulation will be in a 3.14 + * consistent state after stackfaults - Kasper Dupont 3.15 + * <kasperd@daimi.au.dk> 3.16 + * 3.17 + * 22 mar 2002 - Added missing clear_IF in set_vflags_* Kasper Dupont 3.18 + * <kasperd@daimi.au.dk> 3.19 + * 3.20 + * ?? ??? 2002 - Fixed premature returns from handle_vm86_fault 3.21 + * caused by Kasper Dupont's changes - Stas Sergeev 3.22 + * 3.23 + * 4 apr 2002 - Fixed CHECK_IF_IN_TRAP broken by Stas' changes. 3.24 + * Kasper Dupont <kasperd@daimi.au.dk> 3.25 + * 3.26 + * 9 apr 2002 - Changed syntax of macros in handle_vm86_fault. 3.27 + * Kasper Dupont <kasperd@daimi.au.dk> 3.28 + * 3.29 + * 9 apr 2002 - Changed stack access macros to jump to a label 3.30 + * instead of returning to userspace. This simplifies 3.31 + * do_int, and is needed by handle_vm6_fault. Kasper 3.32 + * Dupont <kasperd@daimi.au.dk> 3.33 + * 3.34 + */ 3.35 + 3.36 +#include <linux/capability.h> 3.37 +#include <linux/config.h> 3.38 +#include <linux/errno.h> 3.39 +#include <linux/interrupt.h> 3.40 +#include <linux/sched.h> 3.41 +#include <linux/kernel.h> 3.42 +#include <linux/signal.h> 3.43 +#include <linux/string.h> 3.44 +#include <linux/mm.h> 3.45 +#include <linux/smp.h> 3.46 +#include <linux/smp_lock.h> 3.47 +#include <linux/highmem.h> 3.48 +#include <linux/ptrace.h> 3.49 + 3.50 +#include <asm/uaccess.h> 3.51 +#include <asm/io.h> 3.52 +#include <asm/tlbflush.h> 3.53 +#include <asm/irq.h> 3.54 + 3.55 +/* 3.56 + * Known problems: 3.57 + * 3.58 + * Interrupt handling is not guaranteed: 3.59 + * - a real x86 will disable all interrupts for one instruction 3.60 + * after a "mov ss,xx" to make stack handling atomic even without 3.61 + * the 'lss' instruction. We can't guarantee this in v86 mode, 3.62 + * as the next instruction might result in a page fault or similar. 3.63 + * - a real x86 will have interrupts disabled for one instruction 3.64 + * past the 'sti' that enables them. We don't bother with all the 3.65 + * details yet. 3.66 + * 3.67 + * Let's hope these problems do not actually matter for anything. 3.68 + */ 3.69 + 3.70 + 3.71 +#define KVM86 ((struct kernel_vm86_struct *)regs) 3.72 +#define VMPI KVM86->vm86plus 3.73 + 3.74 + 3.75 +/* 3.76 + * 8- and 16-bit register defines.. 3.77 + */ 3.78 +#define AL(regs) (((unsigned char *)&((regs)->eax))[0]) 3.79 +#define AH(regs) (((unsigned char *)&((regs)->eax))[1]) 3.80 +#define IP(regs) (*(unsigned short *)&((regs)->eip)) 3.81 +#define SP(regs) (*(unsigned short *)&((regs)->esp)) 3.82 + 3.83 +/* 3.84 + * virtual flags (16 and 32-bit versions) 3.85 + */ 3.86 +#define VFLAGS (*(unsigned short *)&(current->thread.v86flags)) 3.87 +#define VEFLAGS (current->thread.v86flags) 3.88 + 3.89 +#define set_flags(X,new,mask) \ 3.90 +((X) = ((X) & ~(mask)) | ((new) & (mask))) 3.91 + 3.92 +#define SAFE_MASK (0xDD5) 3.93 +#define RETURN_MASK (0xDFF) 3.94 + 3.95 +#define VM86_REGS_PART2 orig_eax 3.96 +#define VM86_REGS_SIZE1 \ 3.97 + ( (unsigned)( & (((struct kernel_vm86_regs *)0)->VM86_REGS_PART2) ) ) 3.98 +#define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1) 3.99 + 3.100 +struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs)); 3.101 +struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs) 3.102 +{ 3.103 + struct tss_struct *tss; 3.104 + struct pt_regs *ret; 3.105 + unsigned long tmp; 3.106 + 3.107 + /* 3.108 + * This gets called from entry.S with interrupts disabled, but 3.109 + * from process context. Enable interrupts here, before trying 3.110 + * to access user space. 3.111 + */ 3.112 + local_irq_enable(); 3.113 + 3.114 + if (!current->thread.vm86_info) { 3.115 + printk("no vm86_info: BAD\n"); 3.116 + do_exit(SIGSEGV); 3.117 + } 3.118 + set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->thread.v86mask); 3.119 + tmp = copy_to_user(¤t->thread.vm86_info->regs,regs, VM86_REGS_SIZE1); 3.120 + tmp += copy_to_user(¤t->thread.vm86_info->regs.VM86_REGS_PART2, 3.121 + ®s->VM86_REGS_PART2, VM86_REGS_SIZE2); 3.122 + tmp += put_user(current->thread.screen_bitmap,¤t->thread.vm86_info->screen_bitmap); 3.123 + if (tmp) { 3.124 + printk("vm86: could not access userspace vm86_info\n"); 3.125 + do_exit(SIGSEGV); 3.126 + } 3.127 + 3.128 + tss = &per_cpu(init_tss, get_cpu()); 3.129 + current->thread.esp0 = current->thread.saved_esp0; 3.130 + current->thread.sysenter_cs = __KERNEL_CS; 3.131 + load_esp0(tss, ¤t->thread); 3.132 + current->thread.saved_esp0 = 0; 3.133 + put_cpu(); 3.134 + 3.135 + loadsegment(fs, current->thread.saved_fs); 3.136 + loadsegment(gs, current->thread.saved_gs); 3.137 + ret = KVM86->regs32; 3.138 + return ret; 3.139 +} 3.140 + 3.141 +static void mark_screen_rdonly(struct mm_struct *mm) 3.142 +{ 3.143 + pgd_t *pgd; 3.144 + pud_t *pud; 3.145 + pmd_t *pmd; 3.146 + pte_t *pte; 3.147 + spinlock_t *ptl; 3.148 + int i; 3.149 + 3.150 + pgd = pgd_offset(mm, 0xA0000); 3.151 + if (pgd_none_or_clear_bad(pgd)) 3.152 + goto out; 3.153 + pud = pud_offset(pgd, 0xA0000); 3.154 + if (pud_none_or_clear_bad(pud)) 3.155 + goto out; 3.156 + pmd = pmd_offset(pud, 0xA0000); 3.157 + if (pmd_none_or_clear_bad(pmd)) 3.158 + goto out; 3.159 + pte = pte_offset_map_lock(mm, pmd, 0xA0000, &ptl); 3.160 + for (i = 0; i < 32; i++) { 3.161 + if (pte_present(*pte)) 3.162 + set_pte(pte, pte_wrprotect(*pte)); 3.163 + pte++; 3.164 + } 3.165 + pte_unmap_unlock(pte, ptl); 3.166 +out: 3.167 + flush_tlb(); 3.168 +} 3.169 + 3.170 + 3.171 + 3.172 +static int do_vm86_irq_handling(int subfunction, int irqnumber); 3.173 +static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk); 3.174 + 3.175 +asmlinkage int sys_vm86old(struct pt_regs regs) 3.176 +{ 3.177 + struct vm86_struct __user *v86 = (struct vm86_struct __user *)regs.ebx; 3.178 + struct kernel_vm86_struct info; /* declare this _on top_, 3.179 + * this avoids wasting of stack space. 3.180 + * This remains on the stack until we 3.181 + * return to 32 bit user space. 3.182 + */ 3.183 + struct task_struct *tsk; 3.184 + int tmp, ret = -EPERM; 3.185 + 3.186 + tsk = current; 3.187 + if (tsk->thread.saved_esp0) 3.188 + goto out; 3.189 + tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1); 3.190 + tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2, 3.191 + (long)&info.vm86plus - (long)&info.regs.VM86_REGS_PART2); 3.192 + ret = -EFAULT; 3.193 + if (tmp) 3.194 + goto out; 3.195 + memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus); 3.196 + info.regs32 = ®s; 3.197 + tsk->thread.vm86_info = v86; 3.198 + do_sys_vm86(&info, tsk); 3.199 + ret = 0; /* we never return here */ 3.200 +out: 3.201 + return ret; 3.202 +} 3.203 + 3.204 + 3.205 +asmlinkage int sys_vm86(struct pt_regs regs) 3.206 +{ 3.207 + struct kernel_vm86_struct info; /* declare this _on top_, 3.208 + * this avoids wasting of stack space. 3.209 + * This remains on the stack until we 3.210 + * return to 32 bit user space. 3.211 + */ 3.212 + struct task_struct *tsk; 3.213 + int tmp, ret; 3.214 + struct vm86plus_struct __user *v86; 3.215 + 3.216 + tsk = current; 3.217 + switch (regs.ebx) { 3.218 + case VM86_REQUEST_IRQ: 3.219 + case VM86_FREE_IRQ: 3.220 + case VM86_GET_IRQ_BITS: 3.221 + case VM86_GET_AND_RESET_IRQ: 3.222 + ret = do_vm86_irq_handling(regs.ebx, (int)regs.ecx); 3.223 + goto out; 3.224 + case VM86_PLUS_INSTALL_CHECK: 3.225 + /* NOTE: on old vm86 stuff this will return the error 3.226 + from access_ok(), because the subfunction is 3.227 + interpreted as (invalid) address to vm86_struct. 3.228 + So the installation check works. 3.229 + */ 3.230 + ret = 0; 3.231 + goto out; 3.232 + } 3.233 + 3.234 + /* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */ 3.235 + ret = -EPERM; 3.236 + if (tsk->thread.saved_esp0) 3.237 + goto out; 3.238 + v86 = (struct vm86plus_struct __user *)regs.ecx; 3.239 + tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1); 3.240 + tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2, 3.241 + (long)&info.regs32 - (long)&info.regs.VM86_REGS_PART2); 3.242 + ret = -EFAULT; 3.243 + if (tmp) 3.244 + goto out; 3.245 + info.regs32 = ®s; 3.246 + info.vm86plus.is_vm86pus = 1; 3.247 + tsk->thread.vm86_info = (struct vm86_struct __user *)v86; 3.248 + do_sys_vm86(&info, tsk); 3.249 + ret = 0; /* we never return here */ 3.250 +out: 3.251 + return ret; 3.252 +} 3.253 + 3.254 + 3.255 +static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk) 3.256 +{ 3.257 + struct tss_struct *tss; 3.258 +/* 3.259 + * make sure the vm86() system call doesn't try to do anything silly 3.260 + */ 3.261 + info->regs.__null_ds = 0; 3.262 + info->regs.__null_es = 0; 3.263 + 3.264 +/* we are clearing fs,gs later just before "jmp resume_userspace", 3.265 + * because starting with Linux 2.1.x they aren't no longer saved/restored 3.266 + */ 3.267 + 3.268 +/* 3.269 + * The eflags register is also special: we cannot trust that the user 3.270 + * has set it up safely, so this makes sure interrupt etc flags are 3.271 + * inherited from protected mode. 3.272 + */ 3.273 + VEFLAGS = info->regs.eflags; 3.274 + info->regs.eflags &= SAFE_MASK; 3.275 + info->regs.eflags |= info->regs32->eflags & ~SAFE_MASK; 3.276 + info->regs.eflags |= VM_MASK; 3.277 + 3.278 + switch (info->cpu_type) { 3.279 + case CPU_286: 3.280 + tsk->thread.v86mask = 0; 3.281 + break; 3.282 + case CPU_386: 3.283 + tsk->thread.v86mask = NT_MASK | IOPL_MASK; 3.284 + break; 3.285 + case CPU_486: 3.286 + tsk->thread.v86mask = AC_MASK | NT_MASK | IOPL_MASK; 3.287 + break; 3.288 + default: 3.289 + tsk->thread.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK; 3.290 + break; 3.291 + } 3.292 + 3.293 +/* 3.294 + * Save old state, set default return value (%eax) to 0 3.295 + */ 3.296 + info->regs32->eax = 0; 3.297 + tsk->thread.saved_esp0 = tsk->thread.esp0; 3.298 + savesegment(fs, tsk->thread.saved_fs); 3.299 + savesegment(gs, tsk->thread.saved_gs); 3.300 + 3.301 + tss = &per_cpu(init_tss, get_cpu()); 3.302 + tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; 3.303 + if (cpu_has_sep) 3.304 + tsk->thread.sysenter_cs = 0; 3.305 + load_esp0(tss, &tsk->thread); 3.306 + put_cpu(); 3.307 + 3.308 + tsk->thread.screen_bitmap = info->screen_bitmap; 3.309 + if (info->flags & VM86_SCREEN_BITMAP) 3.310 + mark_screen_rdonly(tsk->mm); 3.311 + __asm__ __volatile__( 3.312 + "xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gs\n\t" 3.313 + "movl %0,%%esp\n\t" 3.314 + "movl %1,%%ebp\n\t" 3.315 + "jmp resume_userspace" 3.316 + : /* no outputs */ 3.317 + :"r" (&info->regs), "r" (task_thread_info(tsk)) : "ax"); 3.318 + /* we never return here */ 3.319 +} 3.320 + 3.321 +static inline void return_to_32bit(struct kernel_vm86_regs * regs16, int retval) 3.322 +{ 3.323 + struct pt_regs * regs32; 3.324 + 3.325 + regs32 = save_v86_state(regs16); 3.326 + regs32->eax = retval; 3.327 + __asm__ __volatile__("movl %0,%%esp\n\t" 3.328 + "movl %1,%%ebp\n\t" 3.329 + "jmp resume_userspace" 3.330 + : : "r" (regs32), "r" (current_thread_info())); 3.331 +} 3.332 + 3.333 +static inline void set_IF(struct kernel_vm86_regs * regs) 3.334 +{ 3.335 + VEFLAGS |= VIF_MASK; 3.336 + if (VEFLAGS & VIP_MASK) 3.337 + return_to_32bit(regs, VM86_STI); 3.338 +} 3.339 + 3.340 +static inline void clear_IF(struct kernel_vm86_regs * regs) 3.341 +{ 3.342 + VEFLAGS &= ~VIF_MASK; 3.343 +} 3.344 + 3.345 +static inline void clear_TF(struct kernel_vm86_regs * regs) 3.346 +{ 3.347 + regs->eflags &= ~TF_MASK; 3.348 +} 3.349 + 3.350 +static inline void clear_AC(struct kernel_vm86_regs * regs) 3.351 +{ 3.352 + regs->eflags &= ~AC_MASK; 3.353 +} 3.354 + 3.355 +/* It is correct to call set_IF(regs) from the set_vflags_* 3.356 + * functions. However someone forgot to call clear_IF(regs) 3.357 + * in the opposite case. 3.358 + * After the command sequence CLI PUSHF STI POPF you should 3.359 + * end up with interrups disabled, but you ended up with 3.360 + * interrupts enabled. 3.361 + * ( I was testing my own changes, but the only bug I 3.362 + * could find was in a function I had not changed. ) 3.363 + * [KD] 3.364 + */ 3.365 + 3.366 +static inline void set_vflags_long(unsigned long eflags, struct kernel_vm86_regs * regs) 3.367 +{ 3.368 + set_flags(VEFLAGS, eflags, current->thread.v86mask); 3.369 + set_flags(regs->eflags, eflags, SAFE_MASK); 3.370 + if (eflags & IF_MASK) 3.371 + set_IF(regs); 3.372 + else 3.373 + clear_IF(regs); 3.374 +} 3.375 + 3.376 +static inline void set_vflags_short(unsigned short flags, struct kernel_vm86_regs * regs) 3.377 +{ 3.378 + set_flags(VFLAGS, flags, current->thread.v86mask); 3.379 + set_flags(regs->eflags, flags, SAFE_MASK); 3.380 + if (flags & IF_MASK) 3.381 + set_IF(regs); 3.382 + else 3.383 + clear_IF(regs); 3.384 +} 3.385 + 3.386 +static inline unsigned long get_vflags(struct kernel_vm86_regs * regs) 3.387 +{ 3.388 + unsigned long flags = regs->eflags & RETURN_MASK; 3.389 + 3.390 + if (VEFLAGS & VIF_MASK) 3.391 + flags |= IF_MASK; 3.392 + flags |= IOPL_MASK; 3.393 + return flags | (VEFLAGS & current->thread.v86mask); 3.394 +} 3.395 + 3.396 +static inline int is_revectored(int nr, struct revectored_struct * bitmap) 3.397 +{ 3.398 + __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0" 3.399 + :"=r" (nr) 3.400 + :"m" (*bitmap),"r" (nr)); 3.401 + return nr; 3.402 +} 3.403 + 3.404 +#define val_byte(val, n) (((__u8 *)&val)[n]) 3.405 + 3.406 +#define pushb(base, ptr, val, err_label) \ 3.407 + do { \ 3.408 + __u8 __val = val; \ 3.409 + ptr--; \ 3.410 + if (put_user(__val, base + ptr) < 0) \ 3.411 + goto err_label; \ 3.412 + } while(0) 3.413 + 3.414 +#define pushw(base, ptr, val, err_label) \ 3.415 + do { \ 3.416 + __u16 __val = val; \ 3.417 + ptr--; \ 3.418 + if (put_user(val_byte(__val, 1), base + ptr) < 0) \ 3.419 + goto err_label; \ 3.420 + ptr--; \ 3.421 + if (put_user(val_byte(__val, 0), base + ptr) < 0) \ 3.422 + goto err_label; \ 3.423 + } while(0) 3.424 + 3.425 +#define pushl(base, ptr, val, err_label) \ 3.426 + do { \ 3.427 + __u32 __val = val; \ 3.428 + ptr--; \ 3.429 + if (put_user(val_byte(__val, 3), base + ptr) < 0) \ 3.430 + goto err_label; \ 3.431 + ptr--; \ 3.432 + if (put_user(val_byte(__val, 2), base + ptr) < 0) \ 3.433 + goto err_label; \ 3.434 + ptr--; \ 3.435 + if (put_user(val_byte(__val, 1), base + ptr) < 0) \ 3.436 + goto err_label; \ 3.437 + ptr--; \ 3.438 + if (put_user(val_byte(__val, 0), base + ptr) < 0) \ 3.439 + goto err_label; \ 3.440 + } while(0) 3.441 + 3.442 +#define popb(base, ptr, err_label) \ 3.443 + ({ \ 3.444 + __u8 __res; \ 3.445 + if (get_user(__res, base + ptr) < 0) \ 3.446 + goto err_label; \ 3.447 + ptr++; \ 3.448 + __res; \ 3.449 + }) 3.450 + 3.451 +#define popw(base, ptr, err_label) \ 3.452 + ({ \ 3.453 + __u16 __res; \ 3.454 + if (get_user(val_byte(__res, 0), base + ptr) < 0) \ 3.455 + goto err_label; \ 3.456 + ptr++; \ 3.457 + if (get_user(val_byte(__res, 1), base + ptr) < 0) \ 3.458 + goto err_label; \ 3.459 + ptr++; \ 3.460 + __res; \ 3.461 + }) 3.462 + 3.463 +#define popl(base, ptr, err_label) \ 3.464 + ({ \ 3.465 + __u32 __res; \ 3.466 + if (get_user(val_byte(__res, 0), base + ptr) < 0) \ 3.467 + goto err_label; \ 3.468 + ptr++; \ 3.469 + if (get_user(val_byte(__res, 1), base + ptr) < 0) \ 3.470 + goto err_label; \ 3.471 + ptr++; \ 3.472 + if (get_user(val_byte(__res, 2), base + ptr) < 0) \ 3.473 + goto err_label; \ 3.474 + ptr++; \ 3.475 + if (get_user(val_byte(__res, 3), base + ptr) < 0) \ 3.476 + goto err_label; \ 3.477 + ptr++; \ 3.478 + __res; \ 3.479 + }) 3.480 + 3.481 +/* There are so many possible reasons for this function to return 3.482 + * VM86_INTx, so adding another doesn't bother me. We can expect 3.483 + * userspace programs to be able to handle it. (Getting a problem 3.484 + * in userspace is always better than an Oops anyway.) [KD] 3.485 + */ 3.486 +static void do_int(struct kernel_vm86_regs *regs, int i, 3.487 + unsigned char __user * ssp, unsigned short sp) 3.488 +{ 3.489 + unsigned long __user *intr_ptr; 3.490 + unsigned long segoffs; 3.491 + 3.492 + if (regs->cs == BIOSSEG) 3.493 + goto cannot_handle; 3.494 + if (is_revectored(i, &KVM86->int_revectored)) 3.495 + goto cannot_handle; 3.496 + if (i==0x21 && is_revectored(AH(regs),&KVM86->int21_revectored)) 3.497 + goto cannot_handle; 3.498 + intr_ptr = (unsigned long __user *) (i << 2); 3.499 + if (get_user(segoffs, intr_ptr)) 3.500 + goto cannot_handle; 3.501 + if ((segoffs >> 16) == BIOSSEG) 3.502 + goto cannot_handle; 3.503 + pushw(ssp, sp, get_vflags(regs), cannot_handle); 3.504 + pushw(ssp, sp, regs->cs, cannot_handle); 3.505 + pushw(ssp, sp, IP(regs), cannot_handle); 3.506 + regs->cs = segoffs >> 16; 3.507 + SP(regs) -= 6; 3.508 + IP(regs) = segoffs & 0xffff; 3.509 + clear_TF(regs); 3.510 + clear_IF(regs); 3.511 + clear_AC(regs); 3.512 + return; 3.513 + 3.514 +cannot_handle: 3.515 + return_to_32bit(regs, VM86_INTx + (i << 8)); 3.516 +} 3.517 + 3.518 +int handle_vm86_trap(struct kernel_vm86_regs * regs, long error_code, int trapno) 3.519 +{ 3.520 + if (VMPI.is_vm86pus) { 3.521 + if ( (trapno==3) || (trapno==1) ) 3.522 + return_to_32bit(regs, VM86_TRAP + (trapno << 8)); 3.523 + do_int(regs, trapno, (unsigned char __user *) (regs->ss << 4), SP(regs)); 3.524 + return 0; 3.525 + } 3.526 + if (trapno !=1) 3.527 + return 1; /* we let this handle by the calling routine */ 3.528 + if (current->ptrace & PT_PTRACED) { 3.529 + unsigned long flags; 3.530 + spin_lock_irqsave(¤t->sighand->siglock, flags); 3.531 + sigdelset(¤t->blocked, SIGTRAP); 3.532 + recalc_sigpending(); 3.533 + spin_unlock_irqrestore(¤t->sighand->siglock, flags); 3.534 + } 3.535 + send_sig(SIGTRAP, current, 1); 3.536 + current->thread.trap_no = trapno; 3.537 + current->thread.error_code = error_code; 3.538 + return 0; 3.539 +} 3.540 + 3.541 +void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code) 3.542 +{ 3.543 + unsigned char opcode; 3.544 + unsigned char __user *csp; 3.545 + unsigned char __user *ssp; 3.546 + unsigned short ip, sp, orig_flags; 3.547 + int data32, pref_done; 3.548 + 3.549 +#define CHECK_IF_IN_TRAP \ 3.550 + if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \ 3.551 + newflags |= TF_MASK 3.552 +#define VM86_FAULT_RETURN do { \ 3.553 + if (VMPI.force_return_for_pic && (VEFLAGS & (IF_MASK | VIF_MASK))) \ 3.554 + return_to_32bit(regs, VM86_PICRETURN); \ 3.555 + if (orig_flags & TF_MASK) \ 3.556 + handle_vm86_trap(regs, 0, 1); \ 3.557 + return; } while (0) 3.558 + 3.559 + orig_flags = *(unsigned short *)®s->eflags; 3.560 + 3.561 + csp = (unsigned char __user *) (regs->cs << 4); 3.562 + ssp = (unsigned char __user *) (regs->ss << 4); 3.563 + sp = SP(regs); 3.564 + ip = IP(regs); 3.565 + 3.566 + data32 = 0; 3.567 + pref_done = 0; 3.568 + do { 3.569 + switch (opcode = popb(csp, ip, simulate_sigsegv)) { 3.570 + case 0x66: /* 32-bit data */ data32=1; break; 3.571 + case 0x67: /* 32-bit address */ break; 3.572 + case 0x2e: /* CS */ break; 3.573 + case 0x3e: /* DS */ break; 3.574 + case 0x26: /* ES */ break; 3.575 + case 0x36: /* SS */ break; 3.576 + case 0x65: /* GS */ break; 3.577 + case 0x64: /* FS */ break; 3.578 + case 0xf2: /* repnz */ break; 3.579 + case 0xf3: /* rep */ break; 3.580 + default: pref_done = 1; 3.581 + } 3.582 + } while (!pref_done); 3.583 + 3.584 + switch (opcode) { 3.585 + 3.586 + /* pushf */ 3.587 + case 0x9c: 3.588 + if (data32) { 3.589 + pushl(ssp, sp, get_vflags(regs), simulate_sigsegv); 3.590 + SP(regs) -= 4; 3.591 + } else { 3.592 + pushw(ssp, sp, get_vflags(regs), simulate_sigsegv); 3.593 + SP(regs) -= 2; 3.594 + } 3.595 + IP(regs) = ip; 3.596 + VM86_FAULT_RETURN; 3.597 + 3.598 + /* popf */ 3.599 + case 0x9d: 3.600 + { 3.601 + unsigned long newflags; 3.602 + if (data32) { 3.603 + newflags=popl(ssp, sp, simulate_sigsegv); 3.604 + SP(regs) += 4; 3.605 + } else { 3.606 + newflags = popw(ssp, sp, simulate_sigsegv); 3.607 + SP(regs) += 2; 3.608 + } 3.609 + IP(regs) = ip; 3.610 + CHECK_IF_IN_TRAP; 3.611 + if (data32) { 3.612 + set_vflags_long(newflags, regs); 3.613 + } else { 3.614 + set_vflags_short(newflags, regs); 3.615 + } 3.616 + VM86_FAULT_RETURN; 3.617 + } 3.618 + 3.619 + /* int xx */ 3.620 + case 0xcd: { 3.621 + int intno=popb(csp, ip, simulate_sigsegv); 3.622 + IP(regs) = ip; 3.623 + if (VMPI.vm86dbg_active) { 3.624 + if ( (1 << (intno &7)) & VMPI.vm86dbg_intxxtab[intno >> 3] ) 3.625 + return_to_32bit(regs, VM86_INTx + (intno << 8)); 3.626 + } 3.627 + do_int(regs, intno, ssp, sp); 3.628 + return; 3.629 + } 3.630 + 3.631 + /* iret */ 3.632 + case 0xcf: 3.633 + { 3.634 + unsigned long newip; 3.635 + unsigned long newcs; 3.636 + unsigned long newflags; 3.637 + if (data32) { 3.638 + newip=popl(ssp, sp, simulate_sigsegv); 3.639 + newcs=popl(ssp, sp, simulate_sigsegv); 3.640 + newflags=popl(ssp, sp, simulate_sigsegv); 3.641 + SP(regs) += 12; 3.642 + } else { 3.643 + newip = popw(ssp, sp, simulate_sigsegv); 3.644 + newcs = popw(ssp, sp, simulate_sigsegv); 3.645 + newflags = popw(ssp, sp, simulate_sigsegv); 3.646 + SP(regs) += 6; 3.647 + } 3.648 + IP(regs) = newip; 3.649 + regs->cs = newcs; 3.650 + CHECK_IF_IN_TRAP; 3.651 + if (data32) { 3.652 + set_vflags_long(newflags, regs); 3.653 + } else { 3.654 + set_vflags_short(newflags, regs); 3.655 + } 3.656 + VM86_FAULT_RETURN; 3.657 + } 3.658 + 3.659 + /* cli */ 3.660 + case 0xfa: 3.661 + IP(regs) = ip; 3.662 + clear_IF(regs); 3.663 + VM86_FAULT_RETURN; 3.664 + 3.665 + /* sti */ 3.666 + /* 3.667 + * Damn. This is incorrect: the 'sti' instruction should actually 3.668 + * enable interrupts after the /next/ instruction. Not good. 3.669 + * 3.670 + * Probably needs some horsing around with the TF flag. Aiee.. 3.671 + */ 3.672 + case 0xfb: 3.673 + IP(regs) = ip; 3.674 + set_IF(regs); 3.675 + VM86_FAULT_RETURN; 3.676 + 3.677 + default: 3.678 + return_to_32bit(regs, VM86_UNKNOWN); 3.679 + } 3.680 + 3.681 + return; 3.682 + 3.683 +simulate_sigsegv: 3.684 + /* FIXME: After a long discussion with Stas we finally 3.685 + * agreed, that this is wrong. Here we should 3.686 + * really send a SIGSEGV to the user program. 3.687 + * But how do we create the correct context? We 3.688 + * are inside a general protection fault handler 3.689 + * and has just returned from a page fault handler. 3.690 + * The correct context for the signal handler 3.691 + * should be a mixture of the two, but how do we 3.692 + * get the information? [KD] 3.693 + */ 3.694 + return_to_32bit(regs, VM86_UNKNOWN); 3.695 +} 3.696 + 3.697 +/* ---------------- vm86 special IRQ passing stuff ----------------- */ 3.698 + 3.699 +#define VM86_IRQNAME "vm86irq" 3.700 + 3.701 +static struct vm86_irqs { 3.702 + struct task_struct *tsk; 3.703 + int sig; 3.704 +} vm86_irqs[16]; 3.705 + 3.706 +static DEFINE_SPINLOCK(irqbits_lock); 3.707 +static int irqbits; 3.708 + 3.709 +#define ALLOWED_SIGS ( 1 /* 0 = don't send a signal */ \ 3.710 + | (1 << SIGUSR1) | (1 << SIGUSR2) | (1 << SIGIO) | (1 << SIGURG) \ 3.711 + | (1 << SIGUNUSED) ) 3.712 + 3.713 +static irqreturn_t irq_handler(int intno, void *dev_id, struct pt_regs * regs) 3.714 +{ 3.715 + int irq_bit; 3.716 + unsigned long flags; 3.717 + 3.718 + spin_lock_irqsave(&irqbits_lock, flags); 3.719 + irq_bit = 1 << intno; 3.720 + if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk) 3.721 + goto out; 3.722 + irqbits |= irq_bit; 3.723 + if (vm86_irqs[intno].sig) 3.724 + send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1); 3.725 + /* 3.726 + * IRQ will be re-enabled when user asks for the irq (whether 3.727 + * polling or as a result of the signal) 3.728 + */ 3.729 + disable_irq_nosync(intno); 3.730 + spin_unlock_irqrestore(&irqbits_lock, flags); 3.731 + return IRQ_HANDLED; 3.732 + 3.733 +out: 3.734 + spin_unlock_irqrestore(&irqbits_lock, flags); 3.735 + return IRQ_NONE; 3.736 +} 3.737 + 3.738 +static inline void free_vm86_irq(int irqnumber) 3.739 +{ 3.740 + unsigned long flags; 3.741 + 3.742 + free_irq(irqnumber, NULL); 3.743 + vm86_irqs[irqnumber].tsk = NULL; 3.744 + 3.745 + spin_lock_irqsave(&irqbits_lock, flags); 3.746 + irqbits &= ~(1 << irqnumber); 3.747 + spin_unlock_irqrestore(&irqbits_lock, flags); 3.748 +} 3.749 + 3.750 +void release_vm86_irqs(struct task_struct *task) 3.751 +{ 3.752 + int i; 3.753 + for (i = FIRST_VM86_IRQ ; i <= LAST_VM86_IRQ; i++) 3.754 + if (vm86_irqs[i].tsk == task) 3.755 + free_vm86_irq(i); 3.756 +} 3.757 + 3.758 +static inline int get_and_reset_irq(int irqnumber) 3.759 +{ 3.760 + int bit; 3.761 + unsigned long flags; 3.762 + int ret = 0; 3.763 + 3.764 + if (invalid_vm86_irq(irqnumber)) return 0; 3.765 + if (vm86_irqs[irqnumber].tsk != current) return 0; 3.766 + spin_lock_irqsave(&irqbits_lock, flags); 3.767 + bit = irqbits & (1 << irqnumber); 3.768 + irqbits &= ~bit; 3.769 + if (bit) { 3.770 + enable_irq(irqnumber); 3.771 + ret = 1; 3.772 + } 3.773 + 3.774 + spin_unlock_irqrestore(&irqbits_lock, flags); 3.775 + return ret; 3.776 +} 3.777 + 3.778 + 3.779 +static int do_vm86_irq_handling(int subfunction, int irqnumber) 3.780 +{ 3.781 + int ret; 3.782 + switch (subfunction) { 3.783 + case VM86_GET_AND_RESET_IRQ: { 3.784 + return get_and_reset_irq(irqnumber); 3.785 + } 3.786 + case VM86_GET_IRQ_BITS: { 3.787 + return irqbits; 3.788 + } 3.789 + case VM86_REQUEST_IRQ: { 3.790 + int sig = irqnumber >> 8; 3.791 + int irq = irqnumber & 255; 3.792 + if (!capable(CAP_SYS_ADMIN)) return -EPERM; 3.793 + if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM; 3.794 + if (invalid_vm86_irq(irq)) return -EPERM; 3.795 + if (vm86_irqs[irq].tsk) return -EPERM; 3.796 + ret = request_irq(irq, &irq_handler, 0, VM86_IRQNAME, NULL); 3.797 + if (ret) return ret; 3.798 + vm86_irqs[irq].sig = sig; 3.799 + vm86_irqs[irq].tsk = current; 3.800 + return irq; 3.801 + } 3.802 + case VM86_FREE_IRQ: { 3.803 + if (invalid_vm86_irq(irqnumber)) return -EPERM; 3.804 + if (!vm86_irqs[irqnumber].tsk) return 0; 3.805 + if (vm86_irqs[irqnumber].tsk != current) return -EPERM; 3.806 + free_vm86_irq(irqnumber); 3.807 + return 0; 3.808 + } 3.809 + } 3.810 + return -EINVAL; 3.811 +} 3.812 +
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/linux-2.6-xen-sparse/arch/i386/kernel/vsyscall.S Mon Feb 20 14:37:13 2006 +0000 4.3 @@ -0,0 +1,15 @@ 4.4 +#include <linux/init.h> 4.5 + 4.6 +__INITDATA 4.7 + 4.8 + .globl vsyscall_int80_start, vsyscall_int80_end 4.9 +vsyscall_int80_start: 4.10 + .incbin "arch/i386/kernel/vsyscall-int80.so" 4.11 +vsyscall_int80_end: 4.12 + 4.13 + .globl vsyscall_sysenter_start, vsyscall_sysenter_end 4.14 +vsyscall_sysenter_start: 4.15 + .incbin "arch/i386/kernel/vsyscall-sysenter.so" 4.16 +vsyscall_sysenter_end: 4.17 + 4.18 +__FINIT