|
|
|
@ -2285,7 +2285,7 @@ static abi_long write_ldt(CPUX86State *env, |
|
|
|
struct target_modify_ldt_ldt_s ldt_info; |
|
|
|
struct target_modify_ldt_ldt_s *target_ldt_info; |
|
|
|
int seg_32bit, contents, read_exec_only, limit_in_pages; |
|
|
|
int seg_not_present, useable; |
|
|
|
int seg_not_present, useable, lm; |
|
|
|
uint32_t *lp, entry_1, entry_2; |
|
|
|
|
|
|
|
if (bytecount != sizeof(ldt_info)) |
|
|
|
@ -2306,7 +2306,11 @@ static abi_long write_ldt(CPUX86State *env, |
|
|
|
limit_in_pages = (ldt_info.flags >> 4) & 1; |
|
|
|
seg_not_present = (ldt_info.flags >> 5) & 1; |
|
|
|
useable = (ldt_info.flags >> 6) & 1; |
|
|
|
|
|
|
|
#ifdef TARGET_ABI32 |
|
|
|
lm = 0; |
|
|
|
#else |
|
|
|
lm = (ldt_info.flags >> 7) & 1; |
|
|
|
#endif |
|
|
|
if (contents == 3) { |
|
|
|
if (oldmode) |
|
|
|
return -TARGET_EINVAL; |
|
|
|
@ -2349,6 +2353,7 @@ static abi_long write_ldt(CPUX86State *env, |
|
|
|
((seg_not_present ^ 1) << 15) | |
|
|
|
(seg_32bit << 22) | |
|
|
|
(limit_in_pages << 23) | |
|
|
|
(lm << 21) | |
|
|
|
0x7000; |
|
|
|
if (!oldmode) |
|
|
|
entry_2 |= (useable << 20); |
|
|
|
@ -2384,6 +2389,138 @@ abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) |
|
|
|
{ |
|
|
|
uint64_t *gdt_table = g2h(env->gdt.base); |
|
|
|
struct target_modify_ldt_ldt_s ldt_info; |
|
|
|
struct target_modify_ldt_ldt_s *target_ldt_info; |
|
|
|
int seg_32bit, contents, read_exec_only, limit_in_pages; |
|
|
|
int seg_not_present, useable, lm; |
|
|
|
uint32_t *lp, entry_1, entry_2; |
|
|
|
int i; |
|
|
|
|
|
|
|
lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1); |
|
|
|
if (!target_ldt_info) |
|
|
|
return -TARGET_EFAULT; |
|
|
|
ldt_info.entry_number = tswap32(target_ldt_info->entry_number); |
|
|
|
ldt_info.base_addr = tswapl(target_ldt_info->base_addr); |
|
|
|
ldt_info.limit = tswap32(target_ldt_info->limit); |
|
|
|
ldt_info.flags = tswap32(target_ldt_info->flags); |
|
|
|
if (ldt_info.entry_number == -1) { |
|
|
|
for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) { |
|
|
|
if (gdt_table[i] == 0) { |
|
|
|
ldt_info.entry_number = i; |
|
|
|
target_ldt_info->entry_number = tswap32(i); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
unlock_user_struct(target_ldt_info, ptr, 1); |
|
|
|
|
|
|
|
if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || |
|
|
|
ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX) |
|
|
|
return -TARGET_EINVAL; |
|
|
|
seg_32bit = ldt_info.flags & 1; |
|
|
|
contents = (ldt_info.flags >> 1) & 3; |
|
|
|
read_exec_only = (ldt_info.flags >> 3) & 1; |
|
|
|
limit_in_pages = (ldt_info.flags >> 4) & 1; |
|
|
|
seg_not_present = (ldt_info.flags >> 5) & 1; |
|
|
|
useable = (ldt_info.flags >> 6) & 1; |
|
|
|
#ifdef TARGET_ABI32 |
|
|
|
lm = 0; |
|
|
|
#else |
|
|
|
lm = (ldt_info.flags >> 7) & 1; |
|
|
|
#endif |
|
|
|
|
|
|
|
if (contents == 3) { |
|
|
|
if (seg_not_present == 0) |
|
|
|
return -TARGET_EINVAL; |
|
|
|
} |
|
|
|
|
|
|
|
/* NOTE: same code as Linux kernel */ |
|
|
|
/* Allow LDTs to be cleared by the user. */ |
|
|
|
if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { |
|
|
|
if ((contents == 0 && |
|
|
|
read_exec_only == 1 && |
|
|
|
seg_32bit == 0 && |
|
|
|
limit_in_pages == 0 && |
|
|
|
seg_not_present == 1 && |
|
|
|
useable == 0 )) { |
|
|
|
entry_1 = 0; |
|
|
|
entry_2 = 0; |
|
|
|
goto install; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | |
|
|
|
(ldt_info.limit & 0x0ffff); |
|
|
|
entry_2 = (ldt_info.base_addr & 0xff000000) | |
|
|
|
((ldt_info.base_addr & 0x00ff0000) >> 16) | |
|
|
|
(ldt_info.limit & 0xf0000) | |
|
|
|
((read_exec_only ^ 1) << 9) | |
|
|
|
(contents << 10) | |
|
|
|
((seg_not_present ^ 1) << 15) | |
|
|
|
(seg_32bit << 22) | |
|
|
|
(limit_in_pages << 23) | |
|
|
|
(useable << 20) | |
|
|
|
(lm << 21) | |
|
|
|
0x7000; |
|
|
|
|
|
|
|
/* Install the new entry ... */ |
|
|
|
install: |
|
|
|
lp = (uint32_t *)(gdt_table + ldt_info.entry_number); |
|
|
|
lp[0] = tswap32(entry_1); |
|
|
|
lp[1] = tswap32(entry_2); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) |
|
|
|
{ |
|
|
|
struct target_modify_ldt_ldt_s *target_ldt_info; |
|
|
|
uint64_t *gdt_table = g2h(env->gdt.base); |
|
|
|
uint32_t base_addr, limit, flags; |
|
|
|
int seg_32bit, contents, read_exec_only, limit_in_pages, idx; |
|
|
|
int seg_not_present, useable, lm; |
|
|
|
uint32_t *lp, entry_1, entry_2; |
|
|
|
|
|
|
|
lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1); |
|
|
|
if (!target_ldt_info) |
|
|
|
return -TARGET_EFAULT; |
|
|
|
idx = tswap32(target_ldt_info->entry_number); |
|
|
|
if (idx < TARGET_GDT_ENTRY_TLS_MIN || |
|
|
|
idx > TARGET_GDT_ENTRY_TLS_MAX) { |
|
|
|
unlock_user_struct(target_ldt_info, ptr, 1); |
|
|
|
return -TARGET_EINVAL; |
|
|
|
} |
|
|
|
lp = (uint32_t *)(gdt_table + idx); |
|
|
|
entry_1 = tswap32(lp[0]); |
|
|
|
entry_2 = tswap32(lp[1]); |
|
|
|
|
|
|
|
read_exec_only = ((entry_2 >> 9) & 1) ^ 1; |
|
|
|
contents = (entry_2 >> 10) & 3; |
|
|
|
seg_not_present = ((entry_2 >> 15) & 1) ^ 1; |
|
|
|
seg_32bit = (entry_2 >> 22) & 1; |
|
|
|
limit_in_pages = (entry_2 >> 23) & 1; |
|
|
|
useable = (entry_2 >> 20) & 1; |
|
|
|
#ifdef TARGET_ABI32 |
|
|
|
lm = 0; |
|
|
|
#else |
|
|
|
lm = (entry_2 >> 21) & 1; |
|
|
|
#endif |
|
|
|
flags = (seg_32bit << 0) | (contents << 1) | |
|
|
|
(read_exec_only << 3) | (limit_in_pages << 4) | |
|
|
|
(seg_not_present << 5) | (useable << 6) | (lm << 7); |
|
|
|
limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000); |
|
|
|
base_addr = (entry_1 >> 16) | |
|
|
|
(entry_2 & 0xff000000) | |
|
|
|
((entry_2 & 0xff) << 16); |
|
|
|
target_ldt_info->base_addr = tswapl(base_addr); |
|
|
|
target_ldt_info->limit = tswap32(limit); |
|
|
|
target_ldt_info->flags = tswap32(flags); |
|
|
|
unlock_user_struct(target_ldt_info, ptr, 1); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
#endif /* defined(TARGET_I386) */ |
|
|
|
|
|
|
|
/* this stack is the equivalent of the kernel stack associated with a
|
|
|
|
@ -5136,18 +5273,25 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, |
|
|
|
#endif |
|
|
|
#ifdef TARGET_NR_set_thread_area |
|
|
|
case TARGET_NR_set_thread_area: |
|
|
|
#ifdef TARGET_MIPS |
|
|
|
#if defined(TARGET_MIPS) |
|
|
|
((CPUMIPSState *) cpu_env)->tls_value = arg1; |
|
|
|
ret = 0; |
|
|
|
break; |
|
|
|
#elif defined(TARGET_I386) && defined(TARGET_ABI32) |
|
|
|
ret = do_set_thread_area(cpu_env, arg1); |
|
|
|
break; |
|
|
|
#else |
|
|
|
goto unimplemented_nowarn; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
#ifdef TARGET_NR_get_thread_area |
|
|
|
case TARGET_NR_get_thread_area: |
|
|
|
#if defined(TARGET_I386) && defined(TARGET_ABI32) |
|
|
|
ret = do_get_thread_area(cpu_env, arg1); |
|
|
|
#else |
|
|
|
goto unimplemented_nowarn; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
#ifdef TARGET_NR_getdomainname |
|
|
|
case TARGET_NR_getdomainname: |
|
|
|
goto unimplemented_nowarn; |
|
|
|
|