Mercurial > illumos > illumos-gate
diff usr/src/uts/intel/ia32/os/archdep.c @ 5084:7d838c5c0eed
PSARC 2006/260 Solaris on Xen
PSARC 2007/155 IPv4 Network Configuration Enhancements for Xen Guest Domains
6424124 panic in intr_thread->av_dispatch_autovect->atomic_add_ptr
6496858 mdb could use a memory-based IO backend
6515319 workaround for 6491065 needs to be removed from elfextract.c
6518807 snv_nightly: SUNWcakr pkgck error
6551858 PSARC 2006/260 Solaris on Xen
6584697 Can't boot Xen / Solaris dom0 if root is using ZFS
6593429 usr/src/cmd/devfsadm isn't linting properly
6600359 mdb_kvm_intrframe() is unused
6600750 can remove 'u' workaround from zlib
6601465 /dev/lofictl needs to accept kernel ioctl
6604043 Erronous ASSERT in sdev_vnops.c ASSERT(VTOSDEV(vp)->sdev_attrvp);
author | johnlev |
---|---|
date | Tue, 18 Sep 2007 15:46:43 -0700 |
parents | af6e7cd796cc |
children | 8e4cf0dbd8ca |
line wrap: on
line diff
--- a/usr/src/uts/intel/ia32/os/archdep.c Mon Sep 17 23:00:44 2007 -0700 +++ b/usr/src/uts/intel/ia32/os/archdep.c Tue Sep 18 15:46:43 2007 -0700 @@ -588,15 +588,35 @@ * Since struct regs stores each 16-bit segment register as a 32-bit greg_t, we * also explicitly zero the top 16 bits since they may be coming from the * user's address space via setcontext(2) or /proc. + * + * Note about null selector. When running on the hypervisor if we allow a + * process to set its %cs to null selector with RPL of 0 the hypervisor will + * crash the domain. If running on bare metal we would get a #gp fault and + * be able to kill the process and continue on. Therefore we make sure to + * force RPL to SEL_UPL even for null selector when setting %cs. */ +#if defined(IS_CS) || defined(IS_NOT_CS) +#error "IS_CS and IS_NOT_CS already defined" +#endif + +#define IS_CS 1 +#define IS_NOT_CS 0 + /*ARGSUSED*/ static greg_t -fix_segreg(greg_t sr, model_t datamodel) +fix_segreg(greg_t sr, int iscs, model_t datamodel) { kthread_t *t = curthread; switch (sr &= 0xffff) { + + case 0: + if (iscs == IS_CS) + return (0 | SEL_UPL); + else + return (0); + #if defined(__amd64) /* * If lwp attempts to switch data model then force their @@ -604,13 +624,13 @@ */ case U32CS_SEL: if (datamodel == DATAMODEL_NATIVE) - return (0); + return (0 | SEL_UPL); else return (sr); case UCS_SEL: if (datamodel == DATAMODEL_ILP32) - return (0); + return (0 | SEL_UPL); #elif defined(__i386) case UCS_SEL: #endif @@ -618,7 +638,7 @@ case UDS_SEL: case LWPFS_SEL: case LWPGS_SEL: - case 0: + case SEL_UPL: return (sr); default: break; @@ -628,20 +648,34 @@ * Allow this process's brand to do any necessary segment register * manipulation. */ - if (PROC_IS_BRANDED(t->t_procp) && BRMOP(t->t_procp)->b_fixsegreg) - return (BRMOP(t->t_procp)->b_fixsegreg(sr, datamodel)); + if (PROC_IS_BRANDED(t->t_procp) && BRMOP(t->t_procp)->b_fixsegreg) { + greg_t bsr = BRMOP(t->t_procp)->b_fixsegreg(sr, datamodel); + + if (bsr == 0 && iscs == IS_CS) + return (0 | SEL_UPL); + else + return (bsr); + } /* * Force it into the LDT in ring 3 for 32-bit processes, which by * default do not have an LDT, so that any attempt to use an invalid - * selector will reference the (non-existant) LDT, and cause a #gp fault - * for the process. + * selector will reference the (non-existant) LDT, and cause a #gp + * fault for the process. * * 64-bit processes get the null gdt selector since they * are not allowed to have a private LDT. */ #if defined(__amd64) - return (datamodel == DATAMODEL_ILP32 ? (sr | SEL_TI_LDT | SEL_UPL) : 0); + if (datamodel == DATAMODEL_ILP32) { + return (sr | SEL_TI_LDT | SEL_UPL); + } else { + if (iscs == IS_CS) + return (0 | SEL_UPL); + else + return (0); + } + #elif defined(__i386) return (sr | SEL_TI_LDT | SEL_UPL); #endif @@ -706,8 +740,8 @@ */ pcb->pcb_fsbase = grp[REG_FSBASE]; pcb->pcb_gsbase = grp[REG_GSBASE]; - pcb->pcb_fs = fix_segreg(grp[REG_FS], datamodel); - pcb->pcb_gs = fix_segreg(grp[REG_GS], datamodel); + pcb->pcb_fs = fix_segreg(grp[REG_FS], IS_NOT_CS, datamodel); + pcb->pcb_gs = fix_segreg(grp[REG_GS], IS_NOT_CS, datamodel); /* * Ensure that we go out via update_sregs @@ -729,30 +763,22 @@ rp->r_err = (uint32_t)grp[REG_ERR]; rp->r_rip = (uint32_t)grp[REG_RIP]; - /* - * The kernel uses %cs to determine if it is dealing with - * another part of the kernel or with a userland application. - * Specifically, it tests the privilege bits. For this reason, - * we must prevent user apps from ending up with a NULL selector - * in %cs. Instead, we'll use index 0 into the GDT but with the - * privilege bits set to usermode. - */ - rp->r_cs = fix_segreg(grp[REG_CS], datamodel) | SEL_UPL; - rp->r_ss = fix_segreg(grp[REG_DS], datamodel); + rp->r_cs = fix_segreg(grp[REG_CS], IS_CS, datamodel); + rp->r_ss = fix_segreg(grp[REG_DS], IS_NOT_CS, datamodel); rp->r_rsp = (uint32_t)grp[REG_RSP]; if (thisthread) kpreempt_disable(); - pcb->pcb_ds = fix_segreg(grp[REG_DS], datamodel); - pcb->pcb_es = fix_segreg(grp[REG_ES], datamodel); + pcb->pcb_ds = fix_segreg(grp[REG_DS], IS_NOT_CS, datamodel); + pcb->pcb_es = fix_segreg(grp[REG_ES], IS_NOT_CS, datamodel); /* * (See fsbase/gsbase commentary above) */ - pcb->pcb_fs = fix_segreg(grp[REG_FS], datamodel); - pcb->pcb_gs = fix_segreg(grp[REG_GS], datamodel); + pcb->pcb_fs = fix_segreg(grp[REG_FS], IS_NOT_CS, datamodel); + pcb->pcb_gs = fix_segreg(grp[REG_GS], IS_NOT_CS, datamodel); /* * Ensure that we go out via update_sregs @@ -782,12 +808,12 @@ */ bcopy(grp, &rp->r_gs, sizeof (gregset_t)); - rp->r_cs = fix_segreg(rp->r_cs, datamodel); - rp->r_ss = fix_segreg(rp->r_ss, datamodel); - rp->r_ds = fix_segreg(rp->r_ds, datamodel); - rp->r_es = fix_segreg(rp->r_es, datamodel); - rp->r_fs = fix_segreg(rp->r_fs, datamodel); - rp->r_gs = fix_segreg(rp->r_gs, datamodel); + rp->r_cs = fix_segreg(rp->r_cs, IS_CS, datamodel); + rp->r_ss = fix_segreg(rp->r_ss, IS_NOT_CS, datamodel); + rp->r_ds = fix_segreg(rp->r_ds, IS_NOT_CS, datamodel); + rp->r_es = fix_segreg(rp->r_es, IS_NOT_CS, datamodel); + rp->r_fs = fix_segreg(rp->r_fs, IS_NOT_CS, datamodel); + rp->r_gs = fix_segreg(rp->r_gs, IS_NOT_CS, datamodel); #endif /* __i386 */ } @@ -1140,6 +1166,7 @@ if (!panicstr) printf("traceback: %%fp = %p\n", (void *)fp); + fp = (struct frame *)plat_traceback(fpreg); if ((uintptr_t)fp < KERNELBASE) goto out; @@ -1222,6 +1249,7 @@ kpreempt_enable(); + fp = (struct frame *)plat_traceback(fpreg); if ((uintptr_t)fp < KERNELBASE) goto out;