#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/processor.h>
+#include <asm/prctl.h>
#include <asm/i387.h>
#include <asm/debugreg.h>
#include <asm/ldt.h>
case offsetof(struct user_regs_struct,fs_base):
if (value >= TASK_SIZE_OF(child))
return -EIO;
- child->thread.fs = value;
+ /*
+ * When changing the segment base, use do_arch_prctl
+ * to set either thread.fs or thread.fsindex and the
+ * corresponding GDT slot.
+ */
+ if (child->thread.fs != value)
+ return do_arch_prctl(child, ARCH_SET_FS, value);
return 0;
case offsetof(struct user_regs_struct,gs_base):
+ /*
+ * Exactly the same here as the %fs handling above.
+ */
if (value >= TASK_SIZE_OF(child))
return -EIO;
- child->thread.gs = value;
+ if (child->thread.gs != value)
+ return do_arch_prctl(child, ARCH_SET_GS, value);
return 0;
case offsetof(struct user_regs_struct, eflags):
value &= FLAG_MASK;
case offsetof(struct user_regs_struct, es):
return child->thread.es;
case offsetof(struct user_regs_struct, fs_base):
- return child->thread.fs;
+ /*
+ * do_arch_prctl may have used a GDT slot instead of
+ * the MSR. To userland, it appears the same either
+ * way, except the %fs segment selector might not be 0.
+ */
+ if (child->thread.fs != 0)
+ return child->thread.fs;
+ if (child->thread.fsindex != FS_TLS_SEL)
+ return 0;
+ return get_desc_base(&child->thread.tls_array[FS_TLS]);
case offsetof(struct user_regs_struct, gs_base):
- return child->thread.gs;
+ /*
+ * Exactly the same here as the %fs handling above.
+ */
+ if (child->thread.gs != 0)
+ return child->thread.gs;
+ if (child->thread.gsindex != GS_TLS_SEL)
+ return 0;
+ return get_desc_base(&child->thread.tls_array[GS_TLS]);
default:
regno = regno - sizeof(struct pt_regs);
val = get_stack_long(child, regno);