1 /* Copyright 2002,2003 Andi Kleen, SuSE Labs */
3 /* vsyscall handling for 32bit processes. Map a stub page into it
4 on demand because 32bit cannot reach the kernel's fixmaps */
7 #include <linux/string.h>
8 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/stringify.h>
12 #include <linux/security.h>
13 #include <asm/proto.h>
14 #include <asm/tlbflush.h>
15 #include <asm/ia32_unistd.h>
17 extern unsigned char syscall32_syscall
[], syscall32_syscall_end
[];
18 extern unsigned char syscall32_sysenter
[], syscall32_sysenter_end
[];
19 extern int sysctl_vsyscall32
;
22 static int use_sysenter
= -1;
25 syscall32_nopage(struct vm_area_struct
*vma
, unsigned long adr
, int *type
)
27 struct page
*p
= virt_to_page(adr
- vma
->vm_start
+ syscall32_page
);
32 /* Prevent VMA merging */
33 static void syscall32_vma_close(struct vm_area_struct
*vma
)
37 static struct vm_operations_struct syscall32_vm_ops
= {
38 .close
= syscall32_vma_close
,
39 .nopage
= syscall32_nopage
,
44 /* Setup a VMA at program startup for the vsyscall page */
45 int syscall32_setup_pages(struct linux_binprm
*bprm
, int exstack
)
47 int npages
= (VSYSCALL32_END
- VSYSCALL32_BASE
) >> PAGE_SHIFT
;
48 struct vm_area_struct
*vma
;
49 struct mm_struct
*mm
= current
->mm
;
52 vma
= kmem_cache_alloc(vm_area_cachep
, SLAB_KERNEL
);
56 memset(vma
, 0, sizeof(struct vm_area_struct
));
57 /* Could randomize here */
58 vma
->vm_start
= VSYSCALL32_BASE
;
59 vma
->vm_end
= VSYSCALL32_END
;
60 /* MAYWRITE to allow gdb to COW and set breakpoints */
61 vma
->vm_flags
= VM_READ
|VM_EXEC
|VM_MAYREAD
|VM_MAYEXEC
|VM_MAYWRITE
;
62 vma
->vm_flags
|= mm
->def_flags
;
63 vma
->vm_page_prot
= protection_map
[vma
->vm_flags
& 7];
64 vma
->vm_ops
= &syscall32_vm_ops
;
67 down_write(&mm
->mmap_sem
);
68 if ((ret
= insert_vm_struct(mm
, vma
))) {
69 up_write(&mm
->mmap_sem
);
70 kmem_cache_free(vm_area_cachep
, vma
);
73 mm
->total_vm
+= npages
;
74 up_write(&mm
->mmap_sem
);
78 static int __init
init_syscall32(void)
80 syscall32_page
= (void *)get_zeroed_page(GFP_KERNEL
);
82 panic("Cannot allocate syscall32 page");
83 if (use_sysenter
> 0) {
84 memcpy(syscall32_page
, syscall32_sysenter
,
85 syscall32_sysenter_end
- syscall32_sysenter
);
87 memcpy(syscall32_page
, syscall32_syscall
,
88 syscall32_syscall_end
- syscall32_syscall
);
93 __initcall(init_syscall32
);
95 /* May not be __init: called during resume */
96 void syscall32_cpu_init(void)
99 use_sysenter
= (boot_cpu_data
.x86_vendor
== X86_VENDOR_INTEL
);
101 /* Load these always in case some future AMD CPU supports
102 SYSENTER from compat mode too. */
103 checking_wrmsrl(MSR_IA32_SYSENTER_CS
, (u64
)__KERNEL_CS
);
104 checking_wrmsrl(MSR_IA32_SYSENTER_ESP
, 0ULL);
105 checking_wrmsrl(MSR_IA32_SYSENTER_EIP
, (u64
)ia32_sysenter_target
);
107 wrmsrl(MSR_CSTAR
, ia32_cstar_target
);