X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=kitten%2Farch%2Fx86_64%2Fkernel%2Fsys_arch_prctl.c;fp=kitten%2Farch%2Fx86_64%2Fkernel%2Fsys_arch_prctl.c;h=5243162ee2e4ba93a6f7bfd716dc961c7fbe79ff;hb=66a1a4c7a9edcd7d8bc207aca093d694a6e6b5b2;hp=0000000000000000000000000000000000000000;hpb=f7cf9c19ecb0a589dd45ae0d2c91814bd3c2acc2;p=palacios-OLD.git diff --git a/kitten/arch/x86_64/kernel/sys_arch_prctl.c b/kitten/arch/x86_64/kernel/sys_arch_prctl.c new file mode 100644 index 0000000..5243162 --- /dev/null +++ b/kitten/arch/x86_64/kernel/sys_arch_prctl.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + + +long +do_arch_prctl(struct task_struct *task, int code, unsigned long addr) +{ + int ret = 0; + int doit = task == current; + + switch (code) { + case ARCH_SET_GS: + if (addr >= task->arch.addr_limit) + return -EPERM; + + task->arch.thread.gsindex = 0; + task->arch.thread.gs = addr; + if (doit) { + /* The kernel's %gs is currently loaded, so this + call is needed to set the user version. */ + load_gs_index(0); + ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr); + } + + break; + case ARCH_SET_FS: + /* Not strictly needed for fs, but do it for symmetry + with gs */ + if (addr >= task->arch.addr_limit) + return -EPERM; + + task->arch.thread.fsindex = 0; + task->arch.thread.fs = addr; + if (doit) { + /* The kernel doesn't use %fs so we can set it + directly. set the selector to 0 to not confuse + __switch_to */ + asm volatile("movl %0,%%fs" :: "r" (0)); + ret = checking_wrmsrl(MSR_FS_BASE, addr); + } + + break; + case ARCH_GET_FS: { + unsigned long base; + if (doit) + rdmsrl(MSR_FS_BASE, base); + else + base = task->arch.thread.fs; + ret = put_user(base, (unsigned long __user *)addr); + break; + } + case ARCH_GET_GS: { + unsigned long base; + unsigned gsindex; + if (doit) { + asm("movl %%gs,%0" : "=r" (gsindex)); + if (gsindex) + rdmsrl(MSR_KERNEL_GS_BASE, base); + else + base = task->arch.thread.gs; + } + else + base = task->arch.thread.gs; + ret = put_user(base, (unsigned long __user *)addr); + break; + } + + default: + ret = -EINVAL; + break; + } + + return ret; +} + + +long +sys_arch_prctl(int code, unsigned long addr) +{ + return do_arch_prctl(current, code, addr); +} +