int sys_penguin_arch_prctl(struct penguin_arch_prctl_args *args) { kprintf("sys_arch_prctl, %x\n", args->code); int error = 0; struct tls_info info; switch(args->code) { case ARCH_SET_GS: info.base = (void*)args->addr; info.size = -1; curthread->td_tls.info[1] = info; set_user_TLS(); break; case ARCH_GET_GS: panic("TODO"); break; case ARCH_SET_FS: info.base = (void*)args->addr; info.size = -1; curthread->td_tls.info[0] = info; set_user_TLS(); break; case ARCH_GET_FS: panic("TODO"); break; default: error = -1; } kprintf("sys_arch_prctl returns error %d\n", error); args->sysmsg_result64 = error; return 0; }
/* * set a TLS descriptor. For x86_64 descriptor 0 identifies %fs and * descriptor 1 identifies %gs, and 0 is returned in sysmsg_result. * * Returns the value userland needs to load into %gs representing the * TLS descriptor or -1 on error. * * (int which, struct tls_info *info, size_t infosize) * * MPSAFE */ int sys_set_tls_area(struct set_tls_area_args *uap) { struct tls_info info; int error; int i; /* * Sanity checks * * which 0 == %fs, which 1 == %gs */ i = uap->which; if (i < 0 || i > 1) return (ERANGE); if (uap->infosize < 0) return (EINVAL); /* * Maintain forwards compatibility with future extensions. */ if (uap->infosize != sizeof(info)) { bzero(&info, sizeof(info)); error = copyin(uap->info, &info, min(sizeof(info), uap->infosize)); } else { error = copyin(uap->info, &info, sizeof(info)); } if (error) return (error); if (info.size < -1) return (EINVAL); /* * For x86_64 we can only adjust FSBASE and GSBASE */ curthread->td_tls.info[i] = info; set_user_TLS(); uap->sysmsg_result = 0; /* segment descriptor $0 */ return(0); }