int sysarch_ldt(struct thread *td, struct sysarch_args *uap, int uap_space) { struct i386_ldt_args *largs, la; struct user_segment_descriptor *lp; int error = 0; /* * XXXKIB check that the BSM generation code knows to encode * the op argument. */ AUDIT_ARG_CMD(uap->op); if (uap_space == UIO_USERSPACE) { error = copyin(uap->parms, &la, sizeof(struct i386_ldt_args)); if (error != 0) return (error); largs = &la; } else largs = (struct i386_ldt_args *)uap->parms; if (largs->num > max_ldt_segment || largs->num <= 0) return (EINVAL); switch (uap->op) { case I386_GET_LDT: error = amd64_get_ldt(td, largs); break; case I386_SET_LDT: td->td_pcb->pcb_full_iret = 1; if (largs->descs != NULL) { lp = (struct user_segment_descriptor *) kmem_alloc(kernel_map, largs->num * sizeof(struct user_segment_descriptor)); if (lp == NULL) { error = ENOMEM; break; } error = copyin(largs->descs, lp, largs->num * sizeof(struct user_segment_descriptor)); if (error == 0) error = amd64_set_ldt(td, largs, lp); kmem_free(kernel_map, (vm_offset_t)lp, largs->num * sizeof(struct user_segment_descriptor)); } else { error = amd64_set_ldt(td, largs, NULL); } break; } return (error); }
int sys_sysarch(struct proc *p, void *v, register_t *retval) { struct sys_sysarch_args /* { syscallarg(int) op; syscallarg(void *) parms; } */ *uap = v; int error = 0; switch(SCARG(uap, op)) { #if defined(USER_LDT) && 0 case AMD64_GET_LDT: error = amd64_get_ldt(p, SCARG(uap, parms), retval); break; case AMD64_SET_LDT: error = amd64_set_ldt(p, SCARG(uap, parms), retval); break; #endif case AMD64_IOPL: error = amd64_iopl(p, SCARG(uap, parms), retval); break; #if 0 case AMD64_GET_IOPERM: error = amd64_get_ioperm(p, SCARG(uap, parms), retval); break; case AMD64_SET_IOPERM: error = amd64_set_ioperm(p, SCARG(uap, parms), retval); break; #endif #ifdef MTRR case AMD64_GET_MTRR: error = amd64_get_mtrr(p, SCARG(uap, parms), retval); break; case AMD64_SET_MTRR: error = amd64_set_mtrr(p, SCARG(uap, parms), retval); break; #endif #if defined(PERFCTRS) && 0 case AMD64_PMC_INFO: error = pmc_info(p, SCARG(uap, parms), retval); break; case AMD64_PMC_STARTSTOP: error = pmc_startstop(p, SCARG(uap, parms), retval); break; case AMD64_PMC_READ: error = pmc_read(p, SCARG(uap, parms), retval); break; #endif default: error = EINVAL; break; } return (error); }
int setup_lcall_gate(void) { struct i386_ldt_args uap; struct user_segment_descriptor desc; uint32_t lcall_addr; int error; bzero(&uap, sizeof(uap)); uap.start = 0; uap.num = 1; lcall_addr = curproc->p_sysent->sv_psstrings - sz_lcall_tramp; bzero(&desc, sizeof(desc)); desc.sd_type = SDT_MEMERA; desc.sd_dpl = SEL_UPL; desc.sd_p = 1; desc.sd_def32 = 1; desc.sd_gran = 1; desc.sd_lolimit = 0xffff; desc.sd_hilimit = 0xf; desc.sd_lobase = lcall_addr; desc.sd_hibase = lcall_addr >> 24; error = amd64_set_ldt(curthread, &uap, &desc); if (error != 0) return (error); return (0); }
int setup_lcall_gate(void) { struct i386_ldt_args uap; struct user_segment_descriptor descs[2]; struct gate_descriptor *ssd; uint32_t lcall_addr; int error; bzero(&uap, sizeof(uap)); uap.start = 0; uap.num = 2; /* * This is the easiest way to cut the space for system * descriptor in ldt. Manually adjust the descriptor type to * the call gate later. */ bzero(&descs[0], sizeof(descs)); descs[0].sd_type = SDT_SYSNULL; descs[1].sd_type = SDT_SYSNULL; error = amd64_set_ldt(curthread, &uap, descs); if (error != 0) return (error); lcall_addr = curproc->p_sysent->sv_psstrings - sz_lcall_tramp; mtx_lock(&dt_lock); ssd = (struct gate_descriptor *)(curproc->p_md.md_ldt->ldt_base); bzero(ssd, sizeof(*ssd)); ssd->gd_looffset = lcall_addr; ssd->gd_hioffset = lcall_addr >> 16; ssd->gd_selector = _ucodesel; ssd->gd_type = SDT_SYSCGT; ssd->gd_dpl = SEL_UPL; ssd->gd_p = 1; mtx_unlock(&dt_lock); return (0); }