void xen_set_segment_base(int reg, ulong_t value) { long err; if ((err = HYPERVISOR_set_segment_base(reg, value)) != 0) { /* * X_EFAULT: bad address * X_EINVAL: bad type */ panic("xen_set_segment_base(%d, %lx): error %d", reg, value, -(int)err); } }
static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) { int ret; ret = 0; switch (msr) { #ifdef CONFIG_X86_64 unsigned which; u64 base; case MSR_FS_BASE: which = SEGBASE_FS; goto set; case MSR_KERNEL_GS_BASE: which = SEGBASE_GS_USER; goto set; case MSR_GS_BASE: which = SEGBASE_GS_KERNEL; goto set; set: base = ((u64)high << 32) | low; if (HYPERVISOR_set_segment_base(which, base) != 0) ret = -EIO; break; #endif case MSR_STAR: case MSR_CSTAR: case MSR_LSTAR: case MSR_SYSCALL_MASK: case MSR_IA32_SYSENTER_CS: case MSR_IA32_SYSENTER_ESP: case MSR_IA32_SYSENTER_EIP: /* Fast syscall setup is all done in hypercalls, so these are all ignored. Stub them out here to stop Xen console noise. */ break; default: ret = native_write_msr_safe(msr, low, high); } return ret; }
static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) { int ret; ret = 0; switch (msr) { #ifdef CONFIG_X86_64 unsigned which; u64 base; case MSR_FS_BASE: which = SEGBASE_FS; goto set; case MSR_KERNEL_GS_BASE: which = SEGBASE_GS_USER; goto set; case MSR_GS_BASE: which = SEGBASE_GS_KERNEL; goto set; set: base = ((u64)high << 32) | low; if (HYPERVISOR_set_segment_base(which, base) != 0) ret = -EIO; break; #endif case MSR_STAR: case MSR_CSTAR: case MSR_LSTAR: case MSR_SYSCALL_MASK: case MSR_IA32_SYSENTER_CS: case MSR_IA32_SYSENTER_ESP: case MSR_IA32_SYSENTER_EIP: /* */ break; case MSR_IA32_CR_PAT: if (smp_processor_id() == 0) xen_set_pat(((u64)high << 32) | low); break; default: ret = native_write_msr_safe(msr, low, high); } return ret; }
static void xen_load_gs_index(unsigned int idx) { if (HYPERVISOR_set_segment_base(SEGBASE_GS_USER_SEL, idx)) BUG(); }
/* * Update the segment registers with new values from the pcb. * * We have to do this carefully, and in the following order, * in case any of the selectors points at a bogus descriptor. * If they do, we'll catch trap with on_trap and return 1. * returns 0 on success. * * This is particularly tricky for %gs. * This routine must be executed under a cli. */ int update_sregs(struct regs *rp, klwp_t *lwp) { pcb_t *pcb = &lwp->lwp_pcb; ulong_t kgsbase; on_trap_data_t otd; int rc = 0; if (!on_trap(&otd, OT_SEGMENT_ACCESS)) { #if defined(__xpv) /* * On the hyervisor this is easy. The hypercall below will * swapgs and load %gs with the user selector. If the user * selector is bad the hypervisor will catch the fault and * load %gs with the null selector instead. Either way the * kernel's gsbase is not damaged. */ kgsbase = (ulong_t)CPU; if (HYPERVISOR_set_segment_base(SEGBASE_GS_USER_SEL, pcb->pcb_gs) != 0) { no_trap(); return (1); } rp->r_gs = pcb->pcb_gs; ASSERT((cpu_t *)kgsbase == CPU); #else /* __xpv */ /* * A little more complicated running native. */ kgsbase = (ulong_t)CPU; __set_gs(pcb->pcb_gs); /* * If __set_gs fails it's because the new %gs is a bad %gs, * we'll be taking a trap but with the original %gs and %gsbase * undamaged (i.e. pointing at curcpu). * * We've just mucked up the kernel's gsbase. Oops. In * particular we can't take any traps at all. Make the newly * computed gsbase be the hidden gs via __swapgs, and fix * the kernel's gsbase back again. Later, when we return to * userland we'll swapgs again restoring gsbase just loaded * above. */ __swapgs(); rp->r_gs = pcb->pcb_gs; /* * restore kernel's gsbase */ wrmsr(MSR_AMD_GSBASE, kgsbase); #endif /* __xpv */ /* * Only override the descriptor base address if * r_gs == LWPGS_SEL or if r_gs == NULL. A note on * NULL descriptors -- 32-bit programs take faults * if they deference NULL descriptors; however, * when 64-bit programs load them into %fs or %gs, * they DONT fault -- only the base address remains * whatever it was from the last load. Urk. * * XXX - note that lwp_setprivate now sets %fs/%gs to the * null selector for 64 bit processes. Whereas before * %fs/%gs were set to LWP(FS|GS)_SEL regardless of * the process's data model. For now we check for both * values so that the kernel can also support the older * libc. This should be ripped out at some point in the * future. */ if (pcb->pcb_gs == LWPGS_SEL || pcb->pcb_gs == 0) { #if defined(__xpv) if (HYPERVISOR_set_segment_base(SEGBASE_GS_USER, pcb->pcb_gsbase)) { no_trap(); return (1); } #else wrmsr(MSR_AMD_KGSBASE, pcb->pcb_gsbase); #endif } __set_ds(pcb->pcb_ds); rp->r_ds = pcb->pcb_ds; __set_es(pcb->pcb_es); rp->r_es = pcb->pcb_es; __set_fs(pcb->pcb_fs); rp->r_fs = pcb->pcb_fs; /* * Same as for %gs */ if (pcb->pcb_fs == LWPFS_SEL || pcb->pcb_fs == 0) { #if defined(__xpv) if (HYPERVISOR_set_segment_base(SEGBASE_FS, pcb->pcb_fsbase)) { no_trap(); return (1); } #else wrmsr(MSR_AMD_FSBASE, pcb->pcb_fsbase); #endif } } else { cli(); rc = 1; } no_trap(); return (rc); }