[PATCH 1/3] Standardize x86_64's desc_defs.h in preparation forexposure to i386.

From: Rusty Russell
Date: Wed Jul 18 2007 - 03:30:48 EST


KVM has independent definitions of these structures, which is bad.
However, the currently (i386-derived) x86-64 ones are suboptimal. The
first step is to clean them up, especially by making desc_struct a
union.

Additional changes:
1) s/ldttss_desc/ldttss_desc_64/ to clearly indicate it's x86-64 only.
2) Changed the type of the tls_array in struct thread_struct:
there seems little point to all these casts.
3) s/gate_struct/gate_struct_64/ to differentiate from new gate_struct_32.
4) New base/limit extraction convenience functions in desc_defs.h.

Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx>

diff -r ef94811a10d5 arch/x86_64/ia32/tls32.c
--- a/arch/x86_64/ia32/tls32.c Wed Jul 18 14:46:15 2007 +1000
+++ b/arch/x86_64/ia32/tls32.c Wed Jul 18 15:59:01 2007 +1000
@@ -19,7 +19,7 @@ static int get_free_idx(void)
int idx;

for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
- if (desc_empty((struct n_desc_struct *)(t->tls_array) + idx))
+ if (desc_empty(t->tls_array + idx))
return idx + GDT_ENTRY_TLS_MIN;
return -ESRCH;
}
@@ -31,7 +31,7 @@ int do_set_thread_area(struct thread_str
int do_set_thread_area(struct thread_struct *t, struct user_desc __user *u_info)
{
struct user_desc info;
- struct n_desc_struct *desc;
+ struct desc_struct *desc;
int cpu, idx;

if (copy_from_user(&info, u_info, sizeof(info)))
@@ -54,7 +54,7 @@ int do_set_thread_area(struct thread_str
if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
return -EINVAL;

- desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN;
+ desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN;

/*
* We must not get preempted while modifying the TLS.
@@ -62,11 +62,10 @@ int do_set_thread_area(struct thread_str
cpu = get_cpu();

if (LDT_empty(&info)) {
- desc->a = 0;
- desc->b = 0;
+ desc->raw = 0;
} else {
- desc->a = LDT_entry_a(&info);
- desc->b = LDT_entry_b(&info);
+ desc->raw32.a = LDT_entry_a(&info);
+ desc->raw32.b = LDT_entry_b(&info);
}
if (t == &current->thread)
load_TLS(t, cpu);
@@ -85,27 +85,13 @@ asmlinkage long sys32_set_thread_area(st
* Get the current Thread-Local Storage area:
*/

-#define GET_BASE(desc) ( \
- (((desc)->a >> 16) & 0x0000ffff) | \
- (((desc)->b << 16) & 0x00ff0000) | \
- ( (desc)->b & 0xff000000) )
-
-#define GET_LIMIT(desc) ( \
- ((desc)->a & 0x0ffff) | \
- ((desc)->b & 0xf0000) )
-
-#define GET_32BIT(desc) (((desc)->b >> 22) & 1)
-#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3)
-#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1)
-#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1)
-#define GET_PRESENT(desc) (((desc)->b >> 15) & 1)
-#define GET_USEABLE(desc) (((desc)->b >> 20) & 1)
-#define GET_LONGMODE(desc) (((desc)->b >> 21) & 1)
+#define GET_CONTENTS(desc) (((desc)->raw32.b >> 10) & 3)
+#define GET_WRITABLE(desc) (((desc)->raw32.b >> 9) & 1)

int do_get_thread_area(struct thread_struct *t, struct user_desc __user *u_info)
{
struct user_desc info;
- struct n_desc_struct *desc;
+ struct desc_struct *desc;
int idx;

if (get_user(idx, &u_info->entry_number))
@@ -113,19 +99,19 @@ int do_get_thread_area(struct thread_str
if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
return -EINVAL;

- desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN;
+ desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN;

memset(&info, 0, sizeof(struct user_desc));
info.entry_number = idx;
- info.base_addr = GET_BASE(desc);
- info.limit = GET_LIMIT(desc);
- info.seg_32bit = GET_32BIT(desc);
+ info.base_addr = get_seg_desc_base(&desc->seg);
+ info.limit = get_seg_desc_limit(&desc->seg);
+ info.seg_32bit = desc->seg.d;
info.contents = GET_CONTENTS(desc);
info.read_exec_only = !GET_WRITABLE(desc);
- info.limit_in_pages = GET_LIMIT_PAGES(desc);
- info.seg_not_present = !GET_PRESENT(desc);
- info.useable = GET_USEABLE(desc);
- info.lm = GET_LONGMODE(desc);
+ info.limit_in_pages = desc->seg.g;
+ info.seg_not_present = !desc->seg.p;
+ info.useable = desc->seg.avl;
+ info.lm = desc->seg.l;

if (copy_to_user(u_info, &info, sizeof(info)))
return -EFAULT;
@@ -140,7 +126,7 @@ asmlinkage long sys32_get_thread_area(st

int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs)
{
- struct n_desc_struct *desc;
+ struct desc_struct *desc;
struct user_desc info;
struct user_desc __user *cp;
int idx;
@@ -155,9 +141,9 @@ int ia32_child_tls(struct task_struct *p
if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
return -EINVAL;

- desc = (struct n_desc_struct *)(p->thread.tls_array) + idx - GDT_ENTRY_TLS_MIN;
- desc->a = LDT_entry_a(&info);
- desc->b = LDT_entry_b(&info);
+ desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
+ desc->raw32.a = LDT_entry_a(&info);
+ desc->raw32.b = LDT_entry_b(&info);

return 0;
}
diff -r ef94811a10d5 arch/x86_64/kernel/process.c
--- a/arch/x86_64/kernel/process.c Wed Jul 18 14:46:15 2007 +1000
+++ b/arch/x86_64/kernel/process.c Wed Jul 18 15:59:01 2007 +1000
@@ -432,19 +432,13 @@ static inline void set_32bit_tls(struct
.limit_in_pages = 1,
.useable = 1,
};
- struct n_desc_struct *desc = (void *)t->thread.tls_array;
- desc += tls;
- desc->a = LDT_entry_a(&ud);
- desc->b = LDT_entry_b(&ud);
+ t->thread.tls_array[tls].raw32.a = LDT_entry_a(&ud);
+ t->thread.tls_array[tls].raw32.b = LDT_entry_b(&ud);
}

static inline u32 read_32bit_tls(struct task_struct *t, int tls)
{
- struct desc_struct *desc = (void *)t->thread.tls_array;
- desc += tls;
- return desc->base0 |
- (((u32)desc->base1) << 16) |
- (((u32)desc->base2) << 24);
+ return get_seg_desc_base(&t->thread.tls_array[tls].seg);
}

/*
diff -r ef94811a10d5 arch/x86_64/kernel/suspend.c
--- a/arch/x86_64/kernel/suspend.c Wed Jul 18 14:46:15 2007 +1000
+++ b/arch/x86_64/kernel/suspend.c Wed Jul 18 15:59:01 2007 +1000
@@ -125,7 +125,7 @@ void fix_processor_context(void)

set_tss_desc(cpu,t); /* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy TSS or some similar stupidity. */

- cpu_gdt(cpu)[GDT_ENTRY_TSS].type = 9;
+ cpu_gdt(cpu)[GDT_ENTRY_TSS].seg.type = DESC_TSS;

syscall_init(); /* This sets MSR_*STAR and related */
load_TR_desc(); /* This does ltr */
diff -r ef94811a10d5 include/asm-x86_64/desc.h
--- a/include/asm-x86_64/desc.h Wed Jul 18 14:46:15 2007 +1000
+++ b/include/asm-x86_64/desc.h Wed Jul 18 15:59:01 2007 +1000
@@ -25,7 +25,7 @@ extern struct desc_struct cpu_gdt_table[
* something other than this.
*/
extern struct desc_struct default_ldt[];
-extern struct gate_struct idt_table[];
+extern struct gate_struct_64 idt_table[];
extern struct desc_ptr cpu_gdt_descr[];

/* the cpu gdt accessor */
@@ -33,7 +33,7 @@ extern struct desc_ptr cpu_gdt_descr[];

static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist)
{
- struct gate_struct s;
+ struct gate_struct_64 s;
s.offset_low = PTR_LOW(func);
s.segment = __KERNEL_CS;
s.ist = ist;
@@ -74,7 +74,7 @@ static inline void set_tssldt_descriptor
static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type,
unsigned size)
{
- struct ldttss_desc d;
+ struct ldttss_desc_64 d;
memset(&d,0,sizeof(d));
d.limit0 = size & 0xFFFF;
d.base0 = PTR_LOW(tss);
@@ -138,7 +138,7 @@ static inline void load_TLS(struct threa
static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
{
unsigned int i;
- u64 *gdt = (u64 *)(cpu_gdt(cpu) + GDT_ENTRY_TLS_MIN);
+ struct desc_struct *gdt = cpu_gdt(cpu) + GDT_ENTRY_TLS_MIN;

for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++)
gdt[i] = t->tls_array[i];
diff -r ef94811a10d5 include/asm-x86_64/desc_defs.h
--- a/include/asm-x86_64/desc_defs.h Wed Jul 18 14:46:15 2007 +1000
+++ b/include/asm-x86_64/desc_defs.h Wed Jul 18 16:20:57 2007 +1000
@@ -11,16 +11,43 @@

#include <linux/types.h>

-// 8 byte segment descriptor
-struct desc_struct {
+// 8 byte segment descriptor (GDT/LDT)
+struct segment_desc {
u16 limit0;
u16 base0;
unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1;
unsigned limit : 4, avl : 1, l : 1, d : 1, g : 1, base2 : 8;
} __attribute__((packed));

-struct n_desc_struct {
+static inline u32 get_seg_desc_base(const struct segment_desc *seg)
+{
+ return seg->base0 | ((u32)seg->base1 << 16) | ((u32)seg->base2 << 24);
+}
+
+static inline u32 get_seg_desc_limit(const struct segment_desc *seg)
+{
+ return seg->limit0 | ((u32)seg->limit << 16);
+}
+
+// 8 byte interrupt/trap descriptor (i386 IDT)
+struct gate_struct_32 {
+ u16 offset_low;
+ u16 segment;
+ unsigned zero0 : 8, type : 5, dpl : 2, p : 1;
+ u16 offset_middle;
+};
+
+struct raw_desc {
unsigned int a,b;
+};
+
+struct desc_struct {
+ union {
+ u64 raw;
+ struct segment_desc seg;
+ struct gate_struct_32 gate;
+ struct raw_desc raw32;
+ };
};

enum {
@@ -29,8 +56,8 @@ enum {
GATE_CALL = 0xC,
};

-// 16byte gate
-struct gate_struct {
+// 16byte gate (x86_64 only)
+struct gate_struct_64 {
u16 offset_low;
u16 segment;
unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
@@ -48,8 +75,8 @@ enum {
DESC_LDT = 0x2,
};

-// LDT or TSS descriptor in the GDT. 16 bytes.
-struct ldttss_desc {
+// LDT or TSS descriptor in the GDT (x86_64 only). 16 bytes.
+struct ldttss_desc_64 {
u16 limit0;
u16 base0;
unsigned base1 : 8, type : 5, dpl : 2, p : 1;
diff -r ef94811a10d5 include/asm-x86_64/processor.h
--- a/include/asm-x86_64/processor.h Wed Jul 18 14:46:15 2007 +1000
+++ b/include/asm-x86_64/processor.h Wed Jul 18 15:59:01 2007 +1000
@@ -21,6 +21,7 @@
#include <linux/personality.h>
#include <linux/cpumask.h>
#include <asm/processor-flags.h>
+#include <asm/desc_defs.h>

#define TF_MASK 0x00000100
#define IF_MASK 0x00000200
@@ -32,11 +33,16 @@
#define VIP_MASK 0x00100000 /* virtual interrupt pending */
#define ID_MASK 0x00200000

-#define desc_empty(desc) \
- (!((desc)->a | (desc)->b))
-
-#define desc_equal(desc1, desc2) \
- (((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b))
+static inline bool desc_empty(const struct desc_struct *desc)
+{
+ return !desc->raw;
+}
+
+static inline bool desc_equal(const struct desc_struct *d1,
+ const struct desc_struct *d2)
+{
+ return d1->raw == d2->raw;
+}

/*
* Default implementation of macro that returns current
@@ -238,7 +244,7 @@ struct thread_struct {
unsigned long *io_bitmap_ptr;
unsigned io_bitmap_max;
/* cached TLS descriptors. */
- u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
+ struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
} __attribute__((aligned(16)));

#define INIT_THREAD { \


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/