Index: sys/arm/linux/linux_machdep.c =================================================================== --- sys/arm/linux/linux_machdep.c +++ sys/arm/linux/linux_machdep.c @@ -256,6 +256,59 @@ return (linux_select(td, &newsel)); } +struct timeval32 { + uint32_t tv_sec; + uint32_t tv_usec; +}; + +int +linux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap) +{ + struct timeval atv; + struct timeval32 atv32; + struct timezone rtz; + int error = 0; + + if (uap->tp) { + microtime(&atv); + atv32.tv_sec = atv.tv_sec; + atv32.tv_usec = atv.tv_usec; + error = copyout(&atv32, uap->tp, sizeof(atv32)); + } + if (error == 0 && uap->tzp != NULL) { + rtz.tz_minuteswest = tz_minuteswest; + rtz.tz_dsttime = tz_dsttime; + error = copyout(&rtz, uap->tzp, sizeof(rtz)); + } + return (error); +} + +int +linux_settimeofday(struct thread *td, struct linux_settimeofday_args *uap) +{ + struct timeval32 atv32; + struct timeval atv, *tvp; + struct timezone atz, *tzp; + int error; + + if (uap->tp) { + error = copyin(uap->tp, &atv32, sizeof(atv32)); + if (error) + return (error); + atv.tv_sec = atv32.tv_sec; + atv.tv_usec = atv32.tv_usec; + tvp = &atv; + } else + tvp = NULL; + if (uap->tzp) { + error = copyin(uap->tzp, &atz, sizeof(atz)); + if (error) + return (error); + tzp = &atz; + } else + tzp = NULL; + return (kern_settimeofday(td, tvp, tzp)); +} int linux_set_cloned_tls(struct thread *td, void *desc) { @@ -535,98 +588,6 @@ } int -linux_ioperm(struct thread *td, struct linux_ioperm_args *args) -{ - int error; - struct i386_ioperm_args iia; - - iia.start = args->start; - iia.length = args->length; - iia.enable = args->enable; - error = i386_set_ioperm(td, &iia); - return (error); -} - -int -linux_iopl(struct thread *td, struct linux_iopl_args *args) -{ - int error; - - if (args->level < 0 || args->level > 3) - return (EINVAL); - if ((error = priv_check(td, PRIV_IO)) != 0) - return (error); - if ((error = securelevel_gt(td->td_ucred, 0)) != 0) - return (error); - td->td_frame->tf_eflags = (td->td_frame->tf_eflags & ~PSL_IOPL) | - (args->level * (PSL_IOPL / 3)); - return (0); -} - -int -linux_modify_ldt(struct thread *td, struct linux_modify_ldt_args *uap) -{ - int error; - struct i386_ldt_args ldt; - struct l_descriptor ld; - union descriptor desc; - int size, written; - - switch (uap->func) { - case 0x00: /* read_ldt */ - ldt.start = 0; - ldt.descs = uap->ptr; - ldt.num = uap->bytecount / sizeof(union descriptor); - error = i386_get_ldt(td, &ldt); - td->td_retval[0] *= sizeof(union descriptor); - break; - case 0x02: /* read_default_ldt = 0 */ - size = 5*sizeof(struct l_desc_struct); - if (size > uap->bytecount) - size = uap->bytecount; - for (written = error = 0; written < size && error == 0; written++) - error = subyte((char *)uap->ptr + written, 0); - td->td_retval[0] = written; - break; - case 0x01: /* write_ldt */ - case 0x11: /* write_ldt */ - if (uap->bytecount != sizeof(ld)) - return (EINVAL); - - error = copyin(uap->ptr, &ld, sizeof(ld)); - if (error) - return (error); - - ldt.start = ld.entry_number; - ldt.descs = &desc; - ldt.num = 1; - desc.sd.sd_lolimit = (ld.limit & 0x0000ffff); - desc.sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16; - desc.sd.sd_lobase = (ld.base_addr & 0x00ffffff); - desc.sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24; - desc.sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) | - (ld.contents << 2); - desc.sd.sd_dpl = 3; - desc.sd.sd_p = (ld.seg_not_present ^ 1); - desc.sd.sd_xx = 0; - desc.sd.sd_def32 = ld.seg_32bit; - desc.sd.sd_gran = ld.limit_in_pages; - error = i386_set_ldt(td, &ldt, &desc); - break; - default: - error = ENOSYS; - break; - } - - if (error == EOPNOTSUPP) { - printf("linux: modify_ldt needs kernel option USER_LDT\n"); - error = ENOSYS; - } - - return (error); -} - -int linux_sigaction(struct thread *td, struct linux_sigaction_args *args) { l_osigaction_t osa; @@ -775,155 +736,6 @@ return sys_ftruncate(td, &sa); } -int -linux_set_thread_area(struct thread *td, struct linux_set_thread_area_args *args) -{ - struct l_user_desc info; - int error; - int idx; - int a[2]; - struct segment_descriptor sd; - - error = copyin(args->desc, &info, sizeof(struct l_user_desc)); - if (error) - return (error); - -#ifdef DEBUG - if (ldebug(set_thread_area)) - printf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, %i, %i, %i\n"), - info.entry_number, - info.base_addr, - info.limit, - info.seg_32bit, - info.contents, - info.read_exec_only, - info.limit_in_pages, - info.seg_not_present, - info.useable); -#endif - - idx = info.entry_number; - /* - * Semantics of linux version: every thread in the system has array of - * 3 tls descriptors. 1st is GLIBC TLS, 2nd is WINE, 3rd unknown. This - * syscall loads one of the selected tls decriptors with a value and - * also loads GDT descriptors 6, 7 and 8 with the content of the - * per-thread descriptors. - * - * Semantics of fbsd version: I think we can ignore that linux has 3 - * per-thread descriptors and use just the 1st one. The tls_array[] - * is used only in set/get-thread_area() syscalls and for loading the - * GDT descriptors. In fbsd we use just one GDT descriptor for TLS so - * we will load just one. - * - * XXX: this doesn't work when a user space process tries to use more - * than 1 TLS segment. Comment in the linux sources says wine might do - * this. - */ - - /* - * we support just GLIBC TLS now - * we should let 3 proceed as well because we use this segment so - * if code does two subsequent calls it should succeed - */ - if (idx != 6 && idx != -1 && idx != 3) - return (EINVAL); - - /* - * we have to copy out the GDT entry we use - * FreeBSD uses GDT entry #3 for storing %gs so load that - * - * XXX: what if a user space program doesn't check this value and tries - * to use 6, 7 or 8? - */ - idx = info.entry_number = 3; - error = copyout(&info, args->desc, sizeof(struct l_user_desc)); - if (error) - return (error); - - if (LINUX_LDT_empty(&info)) { - a[0] = 0; - a[1] = 0; - } else { - a[0] = LINUX_LDT_entry_a(&info); - a[1] = LINUX_LDT_entry_b(&info); - } - - memcpy(&sd, &a, sizeof(a)); -#ifdef DEBUG - if (ldebug(set_thread_area)) - printf("Segment created in set_thread_area: lobase: %x, hibase: %x, lolimit: %x, hilimit: %x, type: %i, dpl: %i, p: %i, xx: %i, def32: %i, gran: %i\n", sd.sd_lobase, - sd.sd_hibase, - sd.sd_lolimit, - sd.sd_hilimit, - sd.sd_type, - sd.sd_dpl, - sd.sd_p, - sd.sd_xx, - sd.sd_def32, - sd.sd_gran); -#endif - - /* this is taken from i386 version of cpu_set_user_tls() */ - critical_enter(); - /* set %gs */ - td->td_pcb->pcb_gsd = sd; - PCPU_GET(fsgs_gdt)[1] = sd; - load_gs(GSEL(GUGS_SEL, SEL_UPL)); - critical_exit(); - - return (0); -} - -int -linux_get_thread_area(struct thread *td, struct linux_get_thread_area_args *args) -{ - - struct l_user_desc info; - int error; - int idx; - struct l_desc_struct desc; - struct segment_descriptor sd; - -#ifdef DEBUG - if (ldebug(get_thread_area)) - printf(ARGS(get_thread_area, "%p"), args->desc); -#endif - - error = copyin(args->desc, &info, sizeof(struct l_user_desc)); - if (error) - return (error); - - idx = info.entry_number; - /* XXX: I am not sure if we want 3 to be allowed too. */ - if (idx != 6 && idx != 3) - return (EINVAL); - - idx = 3; - - memset(&info, 0, sizeof(info)); - - sd = PCPU_GET(fsgs_gdt)[1]; - - memcpy(&desc, &sd, sizeof(desc)); - - info.entry_number = idx; - info.base_addr = LINUX_GET_BASE(&desc); - info.limit = LINUX_GET_LIMIT(&desc); - info.seg_32bit = LINUX_GET_32BIT(&desc); - info.contents = LINUX_GET_CONTENTS(&desc); - info.read_exec_only = !LINUX_GET_WRITABLE(&desc); - info.limit_in_pages = LINUX_GET_LIMIT_PAGES(&desc); - info.seg_not_present = !LINUX_GET_PRESENT(&desc); - info.useable = LINUX_GET_USEABLE(&desc); - - error = copyout(&info, args->desc, sizeof(struct l_user_desc)); - if (error) - return (EFAULT); - - return (0); -} - /* XXX: this wont work with module - convert it */ int linux_mq_open(struct thread *td, struct linux_mq_open_args *args) @@ -984,3 +796,14 @@ return (ENOSYS); #endif } + +int +linux_set_tls(struct thread *td, struct linux_set_tls_args *args) +{ + + td->td_md.md_tp = (register_t)args->tls; + // Do it ?? + set_tls(args->tls); + + return (0); +} \ No newline at end of file