Hi, this is a series of patches that unify the struct desc_struct and friends across x86_64 and i386. As usual, it provides paravirt capabilities as a side-effect for x86_64. I consider the main goal, namely, of unifying the desc_struct, an ongoing effort, being this the beginning. A lot of old code has to be touched to accomplish that. I don't consider this patch ready for inclusion. Basically, the main reason is that I change the signatures of write_idt_entry(), write_gdt_entry(), and write_ldt_entry(). This is needed to account for the differences between the two architectures. (For example, gate descriptors in x86_64 are 16-byte long and can't be represented by low and high entries). As my patch series were 64-bit only, I hadn't come across the problem before. I think this interface is sane, but I'd like to hear opinions. Specially from Jeremy and Zach, since it would touch xen and vmi code. The later, by the way, is _not_ included in this series. Being the interface acked, we still have to write it. Thanks in advance for the review in opinions to come.
This patch aims to make the access of struct desc_struct variables equal across architectures. In this patch, I unify the i386 and x86_64 versions under an anonymous union, keeping the way they are accessed untouched (a and b for 32-bit code, individual bit-fields for 64-bit). This solution is not beautiful, but will allow us to integrate common code that differed by the way descriptors were used. This is to be viewed incrementally. There's simply too much code to be fixed at once. In the future, goal is to set up in a single way of acessing the desc_struct fields. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/apm_32.c | 2 +- arch/x86/kernel/cpu/common.c | 28 ++++++++++++++-------------- arch/x86/kernel/process_64.c | 2 +- arch/x86/kernel/traps_32.c | 2 +- include/asm-x86/desc_defs.h | 28 ++++++++++++++++++++-------- include/asm-x86/processor_32.h | 5 +---- 6 files changed, 38 insertions(+), 29 deletions(-) diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 8cd9778..b8b9339 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -405,7 +405,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user * user_list; static DEFINE_SPINLOCK(user_list_lock); -static const struct desc_struct bad_bios_desc = { 0, 0x00409200 }; +static const struct desc_struct bad_bios_desc = {{{ 0, 0x00409200 }}}; static const char driver_version[] = "1.16ac"; /* no spaces */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 235cd61..0fe1c1d 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -22,31 +22,31 @@ #include "cpu.h" DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { - [GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 }, - [GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 }, - [GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 }, - [GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 }, + [GDT_ENTRY_KERNEL_CS] = {{{ 0x0000ffff, 0x00cf9a00 }}}, + [GDT_ENTRY_KERNEL_DS] = {{{ 0x0000ffff, 0x00cf9200 }}}, + [GDT_ENTRY_DEFAULT_USER_CS] = {{{ 0x0000ffff, 0x00cffa00 }}}, + [GDT_ENTRY_DEFAULT_USER_DS] = {{{ 0x0000ffff, 0x00cff200 }}}, /* * Segments used for calling PnP BIOS have byte granularity. * They code segments and data segments have fixed 64k limits, * the transfer segment sizes are set at run time. */ - [GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ - [GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */ - [GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */ + [GDT_ENTRY_PNPBIOS_CS32] = {{{ 0x0000ffff, 0x00409a00 }}},/* 32-bit code */ + [GDT_ENTRY_PNPBIOS_CS16] = {{{ 0x0000ffff, 0x00009a00 }}},/* 16-bit code */ + [GDT_ENTRY_PNPBIOS_DS] = {{{ 0x0000ffff, 0x00009200 }}}, /* 16-bit data */ + [GDT_ENTRY_PNPBIOS_TS1] = {{{ 0x00000000, 0x00009200 }}},/* 16-bit data */ + [GDT_ENTRY_PNPBIOS_TS2] = {{{ 0x00000000, 0x00009200 }}},/* 16-bit data */ /* * The APM segments have byte granularity and their bases * are set at run time. All have 64k limits. */ - [GDT_ENTRY_APMBIOS_BASE] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ + [GDT_ENTRY_APMBIOS_BASE] = {{{ 0x0000ffff, 0x00409a00 }}},/* 32-bit code */ /* 16-bit code */ - [GDT_ENTRY_APMBIOS_BASE+1] = { 0x0000ffff, 0x00009a00 }, - [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */ + [GDT_ENTRY_APMBIOS_BASE+1] = {{{ 0x0000ffff, 0x00009a00 }}}, + [GDT_ENTRY_APMBIOS_BASE+2] = {{{ 0x0000ffff, 0x00409200 }}}, /* data */ - [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 }, - [GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 }, + [GDT_ENTRY_ESPFIX_SS] = {{{ 0x00000000, 0x00c09200 }}}, + [GDT_ENTRY_PERCPU] = {{{ 0x00000000, 0x00000000 }}}, } }; EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 6724840..9e99cb7 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -437,7 +437,7 @@ static inline void set_32bit_tls(struct task_struct *t, int tls, u32 addr) .limit_in_pages = 1, .useable = 1, }; - struct n_desc_struct *desc = (void *)t->thread.tls_array; + struct desc_struct *desc = (void *)t->thread.tls_array; desc += tls; desc->a = LDT_entry_a(&ud); desc->b = LDT_entry_b(&ud); diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index e15014e..94c5aea 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -76,7 +76,7 @@ char ignore_fpu_irq = 0; * F0 0F bug workaround.. We have a special link segment * for this. */ -struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; +struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {{{ 0, 0 }}}, }; asmlinkage void divide_error(void); asmlinkage void debug(void); diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index 0890040..b3db064 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -11,18 +11,30 @@ #include <linux/types.h> +/* + * FIXME: Acessing the desc_struct through its fields is more elegant, + * and should be the one valid thing to do. However, a lot of open code + * still touches the a and b acessors, and doing this allow us to do it + * incrementally. We keep the signature as a struct, rather than an union, + * so we can get rid of it transparently in the future -- glommer + */ +#define raw_desc_struct struct { unsigned int a, b; } +#define detailed_desc_struct \ + struct { \ + 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;\ + } + // 8 byte segment descriptor struct desc_struct { - 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; + union { + raw_desc_struct; + detailed_desc_struct; + }; } __attribute__((packed)); -struct n_desc_struct { - unsigned int a,b; -}; - enum { GATE_INTERRUPT = 0xE, GATE_TRAP = 0xF, diff --git a/include/asm-x86/processor_32.h b/include/asm-x86/processor_32.h index 0d83da1..f1fc049 100644 --- a/include/asm-x86/processor_32.h +++ b/include/asm-x86/processor_32.h @@ -20,14 +20,11 @@ #include <linux/cpumask.h> #include <linux/init.h> #include <asm/processor-flags.h> +#include <asm/desc_defs.h> /* flag for disabling the tsc */ extern int tsc_disable; -struct desc_struct { - unsigned long a,b; -}; - static inline int desc_empty(const void *ptr) { const u32 *desc = ptr; -- 1.4.4.2
This variable is not used anywere, and is then removed Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 1c26dbb..660cc84 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -30,11 +30,6 @@ static inline unsigned long __store_tr(void) #define store_tr(tr) (tr) = __store_tr() -/* - * This is the ldt that every process will get unless we need - * something other than this. - */ -extern struct desc_struct default_ldt[]; extern struct gate_struct idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; -- 1.4.4.2
Glauber de Oliveira Costa
2007-Dec-06 11:01 UTC
[PATCH 6/19] change write_idt_entry signature
this patch changes write_idt_entry signature. It now takes a gate_desc instead of the a and b parameters. It will allow it to be later unified between i386 and x86_64. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/paravirt_32.c | 2 +- arch/x86/xen/enlighten.c | 5 ++--- include/asm-x86/desc_32.h | 9 +++++++-- include/asm-x86/paravirt.h | 9 +++++---- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/paravirt_32.c b/arch/x86/kernel/paravirt_32.c index f4e3a8e..9ed46da 100644 --- a/arch/x86/kernel/paravirt_32.c +++ b/arch/x86/kernel/paravirt_32.c @@ -381,7 +381,7 @@ struct pv_cpu_ops pv_cpu_ops = { .load_tls = native_load_tls, .write_ldt_entry = write_dt_entry, .write_gdt_entry = write_dt_entry, - .write_idt_entry = write_dt_entry, + .write_idt_entry = write_idt_entry, .load_sp0 = native_load_sp0, .irq_enable_syscall_ret = native_irq_enable_syscall_ret, diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 53b097a..829a450 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -399,8 +399,7 @@ static DEFINE_PER_CPU(struct desc_ptr, idt_desc); /* Set an IDT entry. If the entry is part of the current IDT, then also update Xen. */ -static void xen_write_idt_entry(struct desc_struct *dt, int entrynum, - u32 low, u32 high) +static void xen_write_idt_entry(gate_desc *dt, int entrynum, gate_desc *g) { unsigned long p = (unsigned long)&dt[entrynum]; unsigned long start, end; @@ -412,7 +411,7 @@ static void xen_write_idt_entry(struct desc_struct *dt, int entrynum, xen_mc_flush(); - write_dt_entry(dt, entrynum, low, high); + native_write_idt_entry(dt, entrynum, g); if (p >= start && (p + 8) <= end) { struct trap_info info[2]; diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 77f1e5a..e77ed8c 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -70,9 +70,14 @@ static inline void pack_gate(gate_desc *gate, #define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) #define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) -#define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) +#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) #endif +static inline void native_write_idt_entry(gate_desc *idt, int entry, gate_desc *gate) +{ + memcpy(&idt[entry], gate, sizeof(*gate)); +} + static inline void write_dt_entry(struct desc_struct *dt, int entry, u32 entry_low, u32 entry_high) { @@ -142,7 +147,7 @@ static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned s { gate_desc g; pack_gate(&g, (unsigned long)addr, seg, type, 0); - write_idt_entry(idt_table, gate, g.a, g.b); + write_idt_entry(idt_table, gate, &g); } static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h index 0333fb6..d369b85 100644 --- a/include/asm-x86/paravirt.h +++ b/include/asm-x86/paravirt.h @@ -24,6 +24,7 @@ struct desc_ptr; struct tss_struct; struct mm_struct; struct desc_struct; +gate_desc; /* general info */ struct pv_info { @@ -99,8 +100,8 @@ struct pv_cpu_ops { int entrynum, u32 low, u32 high); void (*write_gdt_entry)(struct desc_struct *, int entrynum, u32 low, u32 high); - void (*write_idt_entry)(struct desc_struct *, - int entrynum, u32 low, u32 high); + void (*write_idt_entry)(gate_desc *, + int entrynum, gate_desc *gate); void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); void (*set_iopl_mask)(unsigned mask); @@ -667,9 +668,9 @@ static inline void write_gdt_entry(void *dt, int entry, u32 low, u32 high) { PVOP_VCALL4(pv_cpu_ops.write_gdt_entry, dt, entry, low, high); } -static inline void write_idt_entry(void *dt, int entry, u32 low, u32 high) +static inline void write_idt_entry(gate_desc *dt, int entry, gate_desc *g) { - PVOP_VCALL4(pv_cpu_ops.write_idt_entry, dt, entry, low, high); + PVOP_VCALL4(pv_cpu_ops.write_idt_entry, dt, entry, g); } static inline void set_iopl_mask(unsigned mask) { -- 1.4.4.2
To account for the differences in gate descriptor in i386 and x86_64 a gate_desc type is introduced. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/traps_32.c | 3 ++- include/asm-x86/desc_32.h | 15 ++++++++------- include/asm-x86/desc_64.h | 4 ++-- include/asm-x86/desc_defs.h | 8 +++++++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 94c5aea..6b03d88 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -76,7 +76,8 @@ char ignore_fpu_irq = 0; * F0 0F bug workaround.. We have a special link segment * for this. */ -struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {{{ 0, 0 }}}, }; +gate_desc idt_table[256] + __attribute__((__section__(".data.idt"))) = { {{{ 0, 0 }}}, }; asmlinkage void divide_error(void); asmlinkage void debug(void); diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index bc5ca34..77f1e5a 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -3,6 +3,7 @@ #include <asm/ldt.h> #include <asm/segment.h> +#include <asm/desc_defs.h> #ifndef __ASSEMBLY__ @@ -24,7 +25,7 @@ static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) } extern struct desc_ptr idt_descr; -extern struct desc_struct idt_table[]; +extern gate_desc idt_table[]; extern void set_intr_gate(unsigned int irq, void * addr); static inline void pack_descriptor(__u32 *a, __u32 *b, @@ -35,11 +36,11 @@ static inline void pack_descriptor(__u32 *a, __u32 *b, (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20); } -static inline void pack_gate(__u32 *a, __u32 *b, +static inline void pack_gate(gate_desc *gate, unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) { - *a = (seg << 16) | (base & 0xffff); - *b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); + gate->a = (seg << 16) | (base & 0xffff); + gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } #define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ @@ -139,9 +140,9 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) { - __u32 a, b; - pack_gate(&a, &b, (unsigned long)addr, seg, type, 0); - write_idt_entry(idt_table, gate, a, b); + gate_desc g; + pack_gate(&g, (unsigned long)addr, seg, type, 0); + write_idt_entry(idt_table, gate, g.a, g.b); } static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 660cc84..ffc6c06 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -30,7 +30,7 @@ static inline unsigned long __store_tr(void) #define store_tr(tr) (tr) = __store_tr() -extern struct gate_struct idt_table[]; +extern gate_desc idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; static inline void write_ldt_entry(struct desc_struct *ldt, @@ -58,7 +58,7 @@ static inline void store_gdt(struct desc_ptr *ptr) static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist) { - struct gate_struct s; + gate_desc s; s.offset_low = PTR_LOW(func); s.segment = __KERNEL_CS; diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index b3db064..e502549 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -42,7 +42,7 @@ enum { }; // 16byte gate -struct gate_struct { +struct gate_struct64 { u16 offset_low; u16 segment; unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; @@ -70,6 +70,12 @@ struct ldttss_desc { u32 zero1; } __attribute__((packed)); +#ifdef CONFIG_X86_64 +typedef struct gate_struct64 gate_desc; +#else +typedef struct desc_struct gate_desc; +#endif + struct desc_ptr { unsigned short size; unsigned long address; -- 1.4.4.2
this patch introduces ldt_desc type to account for the differences in the ldt descriptor in x86_64 and i386 Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 2 +- include/asm-x86/desc_defs.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index ffc6c06..8fe1b4c 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -113,7 +113,7 @@ static inline void store_idt(struct desc_ptr *dtr) static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type, unsigned size) { - struct ldttss_desc d; + struct ldttss_desc64 d; memset(&d, 0, sizeof(d)); d.limit0 = size & 0xFFFF; diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index e502549..3a562d1 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -61,7 +61,7 @@ enum { }; // LDT or TSS descriptor in the GDT. 16 bytes. -struct ldttss_desc { +struct ldttss_desc64 { u16 limit0; u16 base0; unsigned base1 : 8, type : 5, dpl : 2, p : 1; @@ -72,8 +72,10 @@ struct ldttss_desc { #ifdef CONFIG_X86_64 typedef struct gate_struct64 gate_desc; +typedef struct ldttss_desc64 ldt_desc; #else typedef struct desc_struct gate_desc; +typedef struct desc_struct ldt_desc; #endif struct desc_ptr { -- 1.4.4.2
This patch modifies the write_ldt() function to make use of the new struct desc_struct instead of entry_1 and entry_2 entries Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/ldt.c | 15 +++++++-------- 1 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index a8cdca3..7eb0c8a 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -186,7 +186,7 @@ static int read_default_ldt(void __user *ptr, unsigned long bytecount) static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) { struct mm_struct *mm = current->mm; - __u32 entry_1, entry_2; + struct desc_struct ldt; int error; struct user_desc ldt_info; @@ -218,21 +218,20 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { if (oldmode || LDT_empty(&ldt_info)) { - entry_1 = 0; - entry_2 = 0; + memset(&ldt, 0, sizeof(ldt)); goto install; } } - entry_1 = LDT_entry_a(&ldt_info); - entry_2 = LDT_entry_b(&ldt_info); + ldt.a = LDT_entry_a(&ldt_info); + ldt.b = LDT_entry_b(&ldt_info); if (oldmode) - entry_2 &= ~(1 << 20); + ldt.avl = 0; /* Install the new entry ... */ install: - write_ldt_entry(mm->context.ldt, ldt_info.entry_number, entry_1, - entry_2); + write_ldt_entry(mm->context.ldt, ldt_info.entry_number, + ldt.a, ldt.b); error = 0; out_unlock: -- 1.4.4.2
Glauber de Oliveira Costa
2007-Dec-06 11:01 UTC
[PATCH 12/19] move constants to desc_defs.h
this patch moves constant definitions regarding descriptor types from desc_32.h to desc_defs.h. The change from defines to enum to comply with previous versions in desc_defs.h Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_32.h | 8 -------- include/asm-x86/desc_defs.h | 7 +++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 46fe80a..5d1e848 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -43,14 +43,6 @@ static inline void pack_gate(gate_desc *gate, gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } -#define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ -#define DESCTYPE_TSS 0x89 /* present, system, DPL-0, 32-bit TSS */ -#define DESCTYPE_TASK 0x85 /* present, system, DPL-0, task gate */ -#define DESCTYPE_INT 0x8e /* present, system, DPL-0, interrupt gate */ -#define DESCTYPE_TRAP 0x8f /* present, system, DPL-0, trap gate */ -#define DESCTYPE_DPL3 0x60 /* DPL-3 */ -#define DESCTYPE_S 0x10 /* !system */ - #ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> #else diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index 3a562d1..3bfb7d9 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -58,6 +58,13 @@ struct gate_struct64 { enum { DESC_TSS = 0x9, DESC_LDT = 0x2, + DESCTYPE_LDT = 0x82, /* present, system, DPL-0, LDT */ + DESCTYPE_TSS = 0x89, /* present, system, DPL-0, 32-bit TSS */ + DESCTYPE_TASK = 0x85, /* present, system, DPL-0, task gate */ + DESCTYPE_INT = 0x8e, /* present, system, DPL-0, interrupt gate */ + DESCTYPE_TRAP = 0x8f, /* present, system, DPL-0, trap gate */ + DESCTYPE_DPL3 = 0x60, /* DPL-3 */ + DESCTYPE_S = 0x10, /* !system */ }; // LDT or TSS descriptor in the GDT. 16 bytes. -- 1.4.4.2
Glauber de Oliveira Costa
2007-Dec-06 11:01 UTC
[PATCH 14/19] use the same data type for tls_array.
This patch changes the type of tls_array in x86_64 to a desc_struct. Now, both i386 and x86_64 tls_array have the same type, and code accessing it can be shared. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 2 +- include/asm-x86/processor_64.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 2dc19e2..7fd9876 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -150,7 +150,7 @@ static inline void set_ldt(void *addr, int entries) static inline void load_TLS(struct thread_struct *t, unsigned int cpu) { unsigned int i; - u64 *gdt = (u64 *)(get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); + struct desc_struct *gdt = (get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) gdt[i] = t->tls_array[i]; diff --git a/include/asm-x86/processor_64.h b/include/asm-x86/processor_64.h index 5689a8a..742090f 100644 --- a/include/asm-x86/processor_64.h +++ b/include/asm-x86/processor_64.h @@ -19,6 +19,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 @@ -241,7 +242,7 @@ struct thread_struct { /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */ unsigned long debugctlmsr; /* 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 { \ -- 1.4.4.2
Glauber de Oliveira Costa
2007-Dec-06 11:01 UTC
[PATCH 13/19] unify non-paravirt parts of desc.h
This patch unifies the non-paravirt part of desc_{32,64}.h into desc.h. Most of it, is simply common code, that is moved to the shared header. The only exception is the set_ldt_desc in desc_64.h, which is changed - included its name - to accomodate for the way the ldt is set up in i386. Also, constant definitions used in desc_32.h are moved to desc_defs.h Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 87 ++++++++++++++++++++++++++++++++++++++ include/asm-x86/desc_32.h | 66 ---------------------------- include/asm-x86/desc_64.h | 64 ++++----------------------- include/asm-x86/mmu_context_64.h | 4 +- 4 files changed, 99 insertions(+), 122 deletions(-) diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index 6065c50..926d6f8 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h @@ -1,5 +1,92 @@ +#ifndef _ASM_DESC_H_ +#define _ASM_DESC_H_ + +#include <asm/desc_defs.h> + +#ifndef __ASSEMBLY__ +#include <asm/mmu.h> + +extern struct desc_ptr idt_descr; +extern gate_desc idt_table[]; + +#endif + #ifdef CONFIG_X86_32 # include "desc_32.h" #else # include "desc_64.h" #endif + +#ifndef __ASSEMBLY__ + +#define _LDT_empty(info) (\ + (info)->base_addr == 0 && \ + (info)->limit == 0 && \ + (info)->contents == 0 && \ + (info)->read_exec_only == 1 && \ + (info)->seg_32bit == 0 && \ + (info)->limit_in_pages == 0 && \ + (info)->seg_not_present == 1 && \ + (info)->useable == 0 ) + +#ifdef CONFIG_X86_64 +#define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0)) +#else +#define LDT_empty(info) (_LDT_empty(info)) +#endif + +static inline void clear_LDT(void) +{ + set_ldt(NULL, 0); +} + +/* + * load one particular LDT into the current CPU + */ +static inline void load_LDT_nolock(mm_context_t *pc) +{ + set_ldt(pc->ldt, pc->size); +} + +static inline void load_LDT(mm_context_t *pc) +{ + preempt_disable(); + load_LDT_nolock(pc); + preempt_enable(); +} + +static inline unsigned long get_desc_base(unsigned long *desc) +{ + unsigned long base; + base = ((desc[0] >> 16) & 0x0000ffff) | + ((desc[1] << 16) & 0x00ff0000) | + (desc[1] & 0xff000000); + return base; +} + +#else +/* + * GET_DESC_BASE reads the descriptor base of the specified segment. + * + * Args: + * idx - descriptor index + * gdt - GDT pointer + * base - 32bit register to which the base will be written + * lo_w - lo word of the "base" register + * lo_b - lo byte of the "base" register + * hi_b - hi byte of the low word of the "base" register + * + * Example: + * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) + * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. + */ +#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ + movb idx*8+4(gdt), lo_b; \ + movb idx*8+7(gdt), hi_b; \ + shll $16, base; \ + movw idx*8+2(gdt), lo_w; + + +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 5d1e848..960ec77 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -11,8 +11,6 @@ #include <linux/smp.h> #include <linux/percpu.h> -#include <asm/mmu.h> - struct gdt_page { struct desc_struct gdt[GDT_ENTRIES]; @@ -24,8 +22,6 @@ static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) return per_cpu(gdt_page, cpu).gdt; } -extern struct desc_ptr idt_descr; -extern gate_desc idt_table[]; extern void set_intr_gate(unsigned int irq, void * addr); static inline void pack_descriptor(struct desc_struct *desc, @@ -162,68 +158,6 @@ static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const vo #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) -#define LDT_empty(info) (\ - (info)->base_addr == 0 && \ - (info)->limit == 0 && \ - (info)->contents == 0 && \ - (info)->read_exec_only == 1 && \ - (info)->seg_32bit == 0 && \ - (info)->limit_in_pages == 0 && \ - (info)->seg_not_present == 1 && \ - (info)->useable == 0 ) - -static inline void clear_LDT(void) -{ - set_ldt(NULL, 0); -} - -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc) -{ - set_ldt(pc->ldt, pc->size); -} - -static inline void load_LDT(mm_context_t *pc) -{ - preempt_disable(); - load_LDT_nolock(pc); - preempt_enable(); -} - -static inline unsigned long get_desc_base(unsigned long *desc) -{ - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} - -#else /* __ASSEMBLY__ */ - -/* - * GET_DESC_BASE reads the descriptor base of the specified segment. - * - * Args: - * idx - descriptor index - * gdt - GDT pointer - * base - 32bit register to which the base will be written - * lo_w - lo word of the "base" register - * lo_b - lo byte of the "base" register - * hi_b - hi byte of the low word of the "base" register - * - * Example: - * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) - * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. - */ -#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ - movb idx*8+4(gdt), lo_b; \ - movb idx*8+7(gdt), hi_b; \ - shll $16, base; \ - movw idx*8+2(gdt), lo_w; - #endif /* !__ASSEMBLY__ */ #endif diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 3cd5f10..2dc19e2 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -9,16 +9,13 @@ #include <linux/string.h> #include <linux/smp.h> -#include <asm/desc_defs.h> #include <asm/segment.h> -#include <asm/mmu.h> extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; #define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8)) #define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8)) -#define clear_LDT() asm volatile("lldt %w0"::"r" (0)) static inline unsigned long __store_tr(void) { @@ -30,7 +27,6 @@ static inline unsigned long __store_tr(void) #define store_tr(tr) (tr) = __store_tr() -extern gate_desc idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; static inline void write_ldt_entry(struct desc_struct *ldt, @@ -138,22 +134,18 @@ static inline void set_tss_desc(unsigned cpu, void *addr) IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); } -static inline void set_ldt_desc(unsigned cpu, void *addr, int size) +static inline void set_ldt(void *addr, int entries) { - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], - (unsigned long)addr, DESC_LDT, size * 8 - 1); -} + if (likely(entries == 0)) + __asm__ __volatile__("lldt %w0"::"q" (0)); + else { + unsigned cpu = smp_processor_id(); -#define LDT_empty(info) (\ - (info)->base_addr == 0 && \ - (info)->limit == 0 && \ - (info)->contents == 0 && \ - (info)->read_exec_only == 1 && \ - (info)->seg_32bit == 0 && \ - (info)->limit_in_pages == 0 && \ - (info)->seg_not_present == 1 && \ - (info)->useable == 0 && \ - (info)->lm == 0) + set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], + (unsigned long)addr, DESC_LDT, entries * 8 - 1); + __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); + } +} static inline void load_TLS(struct thread_struct *t, unsigned int cpu) { @@ -164,42 +156,6 @@ static inline void load_TLS(struct thread_struct *t, unsigned int cpu) gdt[i] = t->tls_array[i]; } -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc, int cpu) -{ - int count = pc->size; - - if (likely(!count)) { - clear_LDT(); - return; - } - - set_ldt_desc(cpu, pc->ldt, count); - load_LDT_desc(); -} - -static inline void load_LDT(mm_context_t *pc) -{ - int cpu = get_cpu(); - - load_LDT_nolock(pc, cpu); - put_cpu(); -} - -extern struct desc_ptr idt_descr; - -static inline unsigned long get_desc_base(const void *ptr) -{ - const u32 *desc = ptr; - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} - #endif /* !__ASSEMBLY__ */ #endif diff --git a/include/asm-x86/mmu_context_64.h b/include/asm-x86/mmu_context_64.h index 29f95c3..98bfe43 100644 --- a/include/asm-x86/mmu_context_64.h +++ b/include/asm-x86/mmu_context_64.h @@ -43,7 +43,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, load_cr3(next->pgd); if (unlikely(next->context.ldt != prev->context.ldt)) - load_LDT_nolock(&next->context, cpu); + load_LDT_nolock(&next->context); } #ifdef CONFIG_SMP else { @@ -56,7 +56,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, * to make sure to use no freed page tables. */ load_cr3(next->pgd); - load_LDT_nolock(&next->context, cpu); + load_LDT_nolock(&next->context); } } #endif -- 1.4.4.2
This patch makes get_desc_base() receive a struct desc_struct, and then uses its internal fields to compute the base address. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/tls.c | 2 +- arch/x86/mm/fault_32.c | 2 +- include/asm-x86/desc.h | 8 ++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 74d2b65..98f428b 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -112,7 +112,7 @@ int do_get_thread_area(struct task_struct *p, int idx, memset(&info, 0, sizeof(struct user_desc)); info.entry_number = idx; - info.base_addr = get_desc_base((void *)desc); + info.base_addr = get_desc_base((struct desc_struct *)desc); info.limit = GET_LIMIT(desc); info.seg_32bit = GET_32BIT(desc); info.contents = GET_CONTENTS(desc); diff --git a/arch/x86/mm/fault_32.c b/arch/x86/mm/fault_32.c index 6056c6d..ef5ab2b 100644 --- a/arch/x86/mm/fault_32.c +++ b/arch/x86/mm/fault_32.c @@ -115,7 +115,7 @@ static inline unsigned long get_segment_eip(struct pt_regs *regs, } /* Decode the code segment base from the descriptor */ - base = get_desc_base((unsigned long *)desc); + base = get_desc_base((struct desc_struct *)desc); if (seg & (1<<2)) { mutex_unlock(¤t->mm->context.lock); diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index 926d6f8..3480cb1 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h @@ -55,13 +55,9 @@ static inline void load_LDT(mm_context_t *pc) preempt_enable(); } -static inline unsigned long get_desc_base(unsigned long *desc) +static inline unsigned long get_desc_base(struct desc_struct *desc) { - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; + return desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24); } #else -- 1.4.4.2
Provide a new type, tss_desc, to represent the tss descriptor in a unified way accross x86_64 and i386 Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_defs.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index 3bfb7d9..d4ae70d 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -80,9 +80,11 @@ struct ldttss_desc64 { #ifdef CONFIG_X86_64 typedef struct gate_struct64 gate_desc; typedef struct ldttss_desc64 ldt_desc; +typedef struct ldttss_desc64 tss_desc; #else typedef struct desc_struct gate_desc; typedef struct desc_struct ldt_desc; +typedef struct desc_struct tss_desc; #endif struct desc_ptr { -- 1.4.4.2
Glauber de Oliveira Costa
2007-Dec-06 11:02 UTC
[PATCH 17/19] unify paravirt pieces of descriptor handling
With the types used to access descriptors in x86_64 and i386 now being the same, the code that effectively handles them can now be easily shared. This patch moves the paravirt part of desc_32.h into desc.h, and then, we get paravirt support in x86_64 for free. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 155 +++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/desc_32.h | 120 --------------------------------- include/asm-x86/desc_64.h | 104 +++-------------------------- include/asm-x86/desc_defs.h | 6 +- 4 files changed, 169 insertions(+), 216 deletions(-) diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index 3480cb1..1773dd2 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h @@ -5,11 +5,166 @@ #ifndef __ASSEMBLY__ #include <asm/mmu.h> +#include <linux/smp.h> extern struct desc_ptr idt_descr; extern gate_desc idt_table[]; +#ifdef CONFIG_X86_64 +extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; +extern struct desc_ptr cpu_gdt_descr[]; +/* the cpu gdt accessor */ +#define get_cpu_gdt_table(_cpu) ((struct desc_struct *)cpu_gdt_descr[_cpu].address) +#else +struct gdt_page +{ + struct desc_struct gdt[GDT_ENTRIES]; +} __attribute__((aligned(PAGE_SIZE))); +DECLARE_PER_CPU(struct gdt_page, gdt_page); + +static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) +{ + return per_cpu(gdt_page, cpu).gdt; +} +#endif + +#ifdef CONFIG_PARAVIRT +#include <asm/paravirt.h> +#else +#define load_TR_desc() native_load_tr_desc() +#define load_gdt(dtr) native_load_gdt(dtr) +#define load_idt(dtr) native_load_idt(dtr) +#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) +#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) + +#define store_gdt(dtr) native_store_gdt(dtr) +#define store_idt(dtr) native_store_idt(dtr) +#define store_tr(tr) (tr = native_store_tr()) +#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) + +#define load_TLS(t, cpu) native_load_tls(t, cpu) +#define set_ldt native_set_ldt + +#define write_ldt_entry(dt, entry, desc) \ + native_write_ldt_entry(dt, entry, desc) +#define write_gdt_entry(dt, entry, desc, size) \ + native_write_gdt_entry(dt, entry, desc, size) +#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) +#endif + +static inline void native_write_idt_entry(gate_desc *idt, int entry, gate_desc *gate) +{ + memcpy(&idt[entry], gate, sizeof(*gate)); +} + +static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, + void *desc) +{ + memcpy(&ldt[entry], desc, 8); +} + +static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, + void *desc, int size) +{ + memcpy(&gdt[entry], desc, size); +} + +static inline void set_tssldt_descriptor(struct ldttss_desc64 *d, unsigned long tss, + unsigned type, unsigned size) +{ + memset(d, 0, sizeof(*d)); + d->limit0 = size & 0xFFFF; + d->base0 = PTR_LOW(tss); + d->base1 = PTR_MIDDLE(tss) & 0xFF; + d->type = type; + d->p = 1; + d->limit1 = (size >> 16) & 0xF; + d->base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF; + d->base3 = PTR_HIGH(tss); +} + +static inline void pack_descriptor(struct desc_struct *desc, unsigned long base, + unsigned long limit, unsigned char type, + unsigned char flags) +{ + desc->a = ((base & 0xffff) << 16) | (limit & 0xffff); + desc->b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | + (limit & 0x000f0000) | ((type & 0xff) << 8) | + ((flags & 0xf) << 20); +} + +static inline void pack_ldt(ldt_desc *ldt, unsigned long addr, + unsigned size) +{ + +#ifdef CONFIG_X86_64 + set_tssldt_descriptor(ldt, + addr, DESC_LDT, size); +#else + pack_descriptor(ldt, (unsigned long)addr, + size, + 0x80 | DESC_LDT, 0); #endif +} + +static inline void native_set_ldt(const void *addr, unsigned int entries) +{ + if (likely(entries == 0)) + __asm__ __volatile__("lldt %w0"::"q" (0)); + else { + unsigned cpu = smp_processor_id(); + ldt_desc ldt; + + pack_ldt(&ldt, (unsigned long)addr, + entries * sizeof(ldt) - 1); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, + &ldt, sizeof(ldt)); + __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); + } +} + +static inline void native_load_tr_desc(void) +{ + asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); +} + +static inline void native_load_gdt(const struct desc_ptr *dtr) +{ + asm volatile("lgdt %0"::"m" (*dtr)); +} + +static inline void native_load_idt(const struct desc_ptr *dtr) +{ + asm volatile("lidt %0"::"m" (*dtr)); +} + +static inline void native_store_gdt(struct desc_ptr *dtr) +{ + asm ("sgdt %0":"=m" (*dtr)); +} + +static inline void native_store_idt(struct desc_ptr *dtr) +{ + asm ("sidt %0":"=m" (*dtr)); +} + +static inline unsigned long native_store_tr(void) +{ + unsigned long tr; + asm ("str %0":"=r" (tr)); + return tr; +} + +static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) +{ + unsigned int i; + struct desc_struct *gdt = get_cpu_gdt_table(cpu); + + for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) + gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; +} +#endif /* __ASSEMBLY__ */ + #ifdef CONFIG_X86_32 # include "desc_32.h" diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 960ec77..e8f2bc2 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -8,30 +8,10 @@ #ifndef __ASSEMBLY__ #include <linux/preempt.h> -#include <linux/smp.h> #include <linux/percpu.h> -struct gdt_page -{ - struct desc_struct gdt[GDT_ENTRIES]; -} __attribute__((aligned(PAGE_SIZE))); -DECLARE_PER_CPU(struct gdt_page, gdt_page); - -static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) -{ - return per_cpu(gdt_page, cpu).gdt; -} - extern void set_intr_gate(unsigned int irq, void * addr); -static inline void pack_descriptor(struct desc_struct *desc, - unsigned long base, unsigned long limit, unsigned char type, unsigned char flags) -{ - desc->a = ((base & 0xffff) << 16) | (limit & 0xffff); - desc->b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | - (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20); -} - static inline void pack_gate(gate_desc *gate, unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) { @@ -39,106 +19,6 @@ static inline void pack_gate(gate_desc *gate, gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } -#ifdef CONFIG_PARAVIRT -#include <asm/paravirt.h> -#else -#define load_TR_desc() native_load_tr_desc() -#define load_gdt(dtr) native_load_gdt(dtr) -#define load_idt(dtr) native_load_idt(dtr) -#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) -#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) - -#define store_gdt(dtr) native_store_gdt(dtr) -#define store_idt(dtr) native_store_idt(dtr) -#define store_tr(tr) (tr = native_store_tr()) -#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) - -#define load_TLS(t, cpu) native_load_tls(t, cpu) -#define set_ldt native_set_ldt - -#define write_ldt_entry(dt, entry, desc) \ - native_write_ldt_entry(dt, entry, desc) -#define write_gdt_entry(dt, entry, desc, size) \ - native_write_gdt_entry(dt, entry, desc, size) -#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) -#endif - -static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, - void *desc) -{ - memcpy(&ldt[entry], desc, size); -} - -static inline void native_write_idt_entry(gate_desc *idt, int entry, gate_desc *gate) -{ - memcpy(&idt[entry], gate, sizeof(*gate)); -} - -static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, - void *desc, int size) -{ - memcpy(&gdt[entry], desc, size); -} - -static inline void native_set_ldt(const void *addr, unsigned int entries) -{ - if (likely(entries == 0)) - __asm__ __volatile__("lldt %w0"::"q" (0)); - else { - unsigned cpu = smp_processor_id(); - ldt_desc ldt; - - pack_descriptor(&ldt, (unsigned long)addr, - entries * sizeof(struct desc_struct) - 1, - DESCTYPE_LDT, 0); - write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, - &ldt, sizeof(ldt)); - __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); - } -} - - -static inline void native_load_tr_desc(void) -{ - asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); -} - -static inline void native_load_gdt(const struct desc_ptr *dtr) -{ - asm volatile("lgdt %0"::"m" (*dtr)); -} - -static inline void native_load_idt(const struct desc_ptr *dtr) -{ - asm volatile("lidt %0"::"m" (*dtr)); -} - -static inline void native_store_gdt(struct desc_ptr *dtr) -{ - asm ("sgdt %0":"=m" (*dtr)); -} - -static inline void native_store_idt(struct desc_ptr *dtr) -{ - asm ("sidt %0":"=m" (*dtr)); -} - -static inline unsigned long native_store_tr(void) -{ - unsigned long tr; - asm ("str %0":"=r" (tr)); - return tr; -} - -static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) -{ - unsigned int i; - struct desc_struct *gdt = get_cpu_gdt_table(cpu); - - for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) - gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; -} - static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) { gate_desc g; diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 7fd9876..fd907da 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -8,47 +8,10 @@ #ifndef __ASSEMBLY__ #include <linux/string.h> -#include <linux/smp.h> #include <asm/segment.h> -extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; - -#define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8)) -#define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8)) - -static inline unsigned long __store_tr(void) -{ - unsigned long tr; - - asm volatile ("str %w0":"=r" (tr)); - return tr; -} - -#define store_tr(tr) (tr) = __store_tr() - -extern struct desc_ptr cpu_gdt_descr[]; - -static inline void write_ldt_entry(struct desc_struct *ldt, - int entry, void *ptr) -{ - memcpy(&ldt[entry], ptr, 8); -} - -/* the cpu gdt accessor */ -#define get_cpu_gdt_table(_cpu) ((struct desc_struct *)cpu_gdt_descr[_cpu].address) - -static inline void load_gdt(const struct desc_ptr *ptr) -{ - asm volatile("lgdt %w0"::"m" (*ptr)); -} - -static inline void store_gdt(struct desc_ptr *ptr) -{ - asm("sgdt %w0":"=m" (*ptr)); -} - -static inline void _set_gate(void *adr, unsigned type, unsigned long func, +static inline void _set_gate(int gate, unsigned type, unsigned long func, unsigned dpl, unsigned ist) { gate_desc s; @@ -67,61 +30,37 @@ static inline void _set_gate(void *adr, unsigned type, unsigned long func, * does not need to be atomic because it is only done once at * setup time */ - memcpy(adr, &s, 16); + write_idt_entry(idt_table, gate, &s); } static inline void set_intr_gate(int nr, void *func) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 0, 0); } static inline void set_intr_gate_ist(int nr, void *func, unsigned ist) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 0, ist); } static inline void set_system_gate(int nr, void *func) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 3, 0); } static inline void set_system_gate_ist(int nr, void *func, unsigned ist) { - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist); -} - -static inline void load_idt(const struct desc_ptr *ptr) -{ - asm volatile("lidt %w0"::"m" (*ptr)); -} - -static inline void store_idt(struct desc_ptr *dtr) -{ - asm("sidt %w0":"=m" (*dtr)); -} - -static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, - unsigned type, unsigned size) -{ - struct ldttss_desc64 d; - - memset(&d, 0, sizeof(d)); - d.limit0 = size & 0xFFFF; - d.base0 = PTR_LOW(tss); - d.base1 = PTR_MIDDLE(tss) & 0xFF; - d.type = type; - d.p = 1; - d.limit1 = (size >> 16) & 0xF; - d.base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF; - d.base3 = PTR_HIGH(tss); - memcpy(ptr, &d, 16); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 3, ist); } static inline void set_tss_desc(unsigned cpu, void *addr) { + struct desc_struct *d = get_cpu_gdt_table(cpu); + tss_desc tss; + /* * sizeof(unsigned long) coming from an extra "long" at the end * of the iobitmap. See tss_struct definition in processor.h @@ -129,31 +68,10 @@ static inline void set_tss_desc(unsigned cpu, void *addr) * -1? seg base+limit should be pointing to the address of the * last valid byte */ - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS], + set_tssldt_descriptor(&tss, (unsigned long)addr, DESC_TSS, IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); -} - -static inline void set_ldt(void *addr, int entries) -{ - if (likely(entries == 0)) - __asm__ __volatile__("lldt %w0"::"q" (0)); - else { - unsigned cpu = smp_processor_id(); - - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], - (unsigned long)addr, DESC_LDT, entries * 8 - 1); - __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); - } -} - -static inline void load_TLS(struct thread_struct *t, unsigned int cpu) -{ - unsigned int i; - struct desc_struct *gdt = (get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); - - for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) - gdt[i] = t->tls_array[i]; + write_gdt_entry(d, GDT_ENTRY_TSS, &tss, sizeof(tss_desc)); } #endif /* !__ASSEMBLY__ */ diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index d4ae70d..69597f3 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -51,9 +51,9 @@ struct gate_struct64 { u32 zero1; } __attribute__((packed)); -#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF) -#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF) -#define PTR_HIGH(x) ((unsigned long)(x) >> 32) +#define PTR_LOW(x) ((unsigned long long)(x) & 0xFFFF) +#define PTR_MIDDLE(x) (((unsigned long long)(x) >> 16) & 0xFFFF) +#define PTR_HIGH(x) ((unsigned long long)(x) >> 32) enum { DESC_TSS = 0x9, -- 1.4.4.2
> +/* > + * FIXME: Acessing the desc_struct through its fields is more elegant, > + * and should be the one valid thing to do. However, a lot of open code > + * still touches the a and b acessors, and doing this allow us to do it > + * incrementally. We keep the signature as a struct, rather than an union, > + * so we can get rid of it transparently in the future -- glommer > + */ > +#define raw_desc_struct struct { unsigned int a, b; } > +#define detailed_desc_struct \ > + struct { \ > + 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;\ > + }The standard clean way to do this is with a anonymous union. -Andi
Since the last version of it received no comments on the interfaces, here it goes a version, that I feel ready for inclusion. The comments regarding style, specially the elimination of the #defines in the desc_struct definition were merged. I also implemented the vmi functions, missing last time. Ingo, in the absense of further complaints, could you please push to the x86 tree?
this patch introduces ldt_desc type to account for the differences in the ldt descriptor in x86_64 and i386 Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 2 +- include/asm-x86/desc_defs.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index ffc6c06..8fe1b4c 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -113,7 +113,7 @@ static inline void store_idt(struct desc_ptr *dtr) static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type, unsigned size) { - struct ldttss_desc d; + struct ldttss_desc64 d; memset(&d, 0, sizeof(d)); d.limit0 = size & 0xFFFF; diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index 05eff93..5a58fc1 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -58,7 +58,7 @@ enum { }; // LDT or TSS descriptor in the GDT. 16 bytes. -struct ldttss_desc { +struct ldttss_desc64 { u16 limit0; u16 base0; unsigned base1 : 8, type : 5, dpl : 2, p : 1; @@ -69,8 +69,10 @@ struct ldttss_desc { #ifdef CONFIG_X86_64 typedef struct gate_struct64 gate_desc; +typedef struct ldttss_desc64 ldt_desc; #else typedef struct desc_struct gate_desc; +typedef struct desc_struct ldt_desc; #endif struct desc_ptr { -- 1.5.0.6
This variable is not used anywere, and is then removed Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 1c26dbb..660cc84 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -30,11 +30,6 @@ static inline unsigned long __store_tr(void) #define store_tr(tr) (tr) = __store_tr() -/* - * This is the ldt that every process will get unless we need - * something other than this. - */ -extern struct desc_struct default_ldt[]; extern struct gate_struct idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; -- 1.5.0.6
To account for the differences in gate descriptor in i386 and x86_64 a gate_desc type is introduced. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/traps_32.c | 3 ++- include/asm-x86/desc_32.h | 15 ++++++++------- include/asm-x86/desc_64.h | 4 ++-- include/asm-x86/desc_defs.h | 8 +++++++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 94c5aea..6b03d88 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -76,8 +76,8 @@ char ignore_fpu_irq = 0; * F0 0F bug workaround.. We have a special link segment * for this. */ -struct desc_struct idt_table[256] - __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; +gate_desc idt_table[256] + __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; asmlinkage void divide_error(void); asmlinkage void debug(void); diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index bc5ca34..77f1e5a 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -3,6 +3,7 @@ #include <asm/ldt.h> #include <asm/segment.h> +#include <asm/desc_defs.h> #ifndef __ASSEMBLY__ @@ -24,7 +25,7 @@ static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) } extern struct desc_ptr idt_descr; -extern struct desc_struct idt_table[]; +extern gate_desc idt_table[]; extern void set_intr_gate(unsigned int irq, void * addr); static inline void pack_descriptor(__u32 *a, __u32 *b, @@ -35,11 +36,11 @@ static inline void pack_descriptor(__u32 *a, __u32 *b, (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20); } -static inline void pack_gate(__u32 *a, __u32 *b, +static inline void pack_gate(gate_desc *gate, unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) { - *a = (seg << 16) | (base & 0xffff); - *b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); + gate->a = (seg << 16) | (base & 0xffff); + gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } #define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ @@ -139,9 +140,9 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) { - __u32 a, b; - pack_gate(&a, &b, (unsigned long)addr, seg, type, 0); - write_idt_entry(idt_table, gate, a, b); + gate_desc g; + pack_gate(&g, (unsigned long)addr, seg, type, 0); + write_idt_entry(idt_table, gate, g.a, g.b); } static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 660cc84..ffc6c06 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -30,7 +30,7 @@ static inline unsigned long __store_tr(void) #define store_tr(tr) (tr) = __store_tr() -extern struct gate_struct idt_table[]; +extern gate_desc idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; static inline void write_ldt_entry(struct desc_struct *ldt, @@ -58,7 +58,7 @@ static inline void store_gdt(struct desc_ptr *ptr) static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist) { - struct gate_struct s; + gate_desc s; s.offset_low = PTR_LOW(func); s.segment = __KERNEL_CS; diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index f37b44c..05eff93 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -39,7 +39,7 @@ enum { }; // 16byte gate -struct gate_struct { +struct gate_struct64 { u16 offset_low; u16 segment; unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; @@ -67,6 +67,12 @@ struct ldttss_desc { u32 zero1; } __attribute__((packed)); +#ifdef CONFIG_X86_64 +typedef struct gate_struct64 gate_desc; +#else +typedef struct desc_struct gate_desc; +#endif + struct desc_ptr { unsigned short size; unsigned long address; -- 1.5.0.6
Glauber de Oliveira Costa
2007-Dec-12 07:39 UTC
[PATCH 06/19] change write_idt_entry signature
this patch changes write_idt_entry signature. It now takes a gate_desc instead of the a and b parameters. It will allow it to be later unified between i386 and x86_64. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> CC: Zachary Amsden <zach@vmware.com> CC: Jeremy Fitzhardinge <Jeremy.Fitzhardinge.citrix.com> --- arch/x86/kernel/paravirt_32.c | 2 +- arch/x86/kernel/vmi_32.c | 10 +++++++++- arch/x86/lguest/boot.c | 9 +++++---- arch/x86/xen/enlighten.c | 8 ++++---- include/asm-x86/desc_32.h | 10 ++++++++-- include/asm-x86/paravirt.h | 9 +++++---- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/paravirt_32.c b/arch/x86/kernel/paravirt_32.c index f4e3a8e..13bbc99 100644 --- a/arch/x86/kernel/paravirt_32.c +++ b/arch/x86/kernel/paravirt_32.c @@ -381,7 +381,7 @@ struct pv_cpu_ops pv_cpu_ops = { .load_tls = native_load_tls, .write_ldt_entry = write_dt_entry, .write_gdt_entry = write_dt_entry, - .write_idt_entry = write_dt_entry, + .write_idt_entry = native_write_idt_entry, .load_sp0 = native_load_sp0, .irq_enable_syscall_ret = native_irq_enable_syscall_ret, diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c index 4cfda7d..a635b22 100644 --- a/arch/x86/kernel/vmi_32.c +++ b/arch/x86/kernel/vmi_32.c @@ -62,6 +62,7 @@ static struct { void (*cpuid)(void /* non-c */); void (*_set_ldt)(u32 selector); void (*set_tr)(u32 selector); + void (*write_idt_entry)(struct desc_struct *, int, u32, u32); void (*set_kernel_stack)(u32 selector, u32 sp0); void (*allocate_page)(u32, u32, u32, u32, u32); void (*release_page)(u32, u32); @@ -214,6 +215,12 @@ static void vmi_set_tr(void) vmi_ops.set_tr(GDT_ENTRY_TSS*sizeof(struct desc_struct)); } +static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g) +{ + u32 *idt_entry = (u32 *)g; + vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[2]); +} + static void vmi_load_sp0(struct tss_struct *tss, struct thread_struct *thread) { @@ -792,7 +799,8 @@ static inline int __init activate_vmi(void) pv_cpu_ops.load_tls = vmi_load_tls; para_fill(pv_cpu_ops.write_ldt_entry, WriteLDTEntry); para_fill(pv_cpu_ops.write_gdt_entry, WriteGDTEntry); - para_fill(pv_cpu_ops.write_idt_entry, WriteIDTEntry); + para_wrap(pv_cpu_ops.write_idt_entry, vmi_write_idt_entry, + write_idt_entry, WriteIDTEntry); para_wrap(pv_cpu_ops.load_sp0, vmi_load_sp0, set_kernel_stack, UpdateKernelStack); para_fill(pv_cpu_ops.set_iopl_mask, SetIOPLMask); para_fill(pv_cpu_ops.io_delay, IODelay); diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index aa0bdd5..b50c8ad 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -217,13 +217,14 @@ static void irq_enable(void) * address of the handler, and... well, who cares? The Guest just asks the * Host to make the change anyway, because the Host controls the real IDT. */ -static void lguest_write_idt_entry(struct desc_struct *dt, - int entrynum, u32 low, u32 high) +static void lguest_write_idt_entry(gate_desc *dt, + int entrynum, const gate_desc *g) { + u32 *desc = (u32 *)g; /* Keep the local copy up to date. */ - write_dt_entry(dt, entrynum, low, high); + native_write_idt_entry(dt, entrynum, g); /* Tell Host about this new entry. */ - hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, low, high); + hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]); } /* Changing to a different IDT is very rare: we keep the IDT up-to-date every diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 8215ea6..6dd349e 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -399,8 +399,7 @@ static DEFINE_PER_CPU(struct desc_ptr, idt_desc); /* Set an IDT entry. If the entry is part of the current IDT, then also update Xen. */ -static void xen_write_idt_entry(struct desc_struct *dt, int entrynum, - u32 low, u32 high) +static void xen_write_idt_entry(gate_desc *dt, int entrynum, const gate_desc *g) { unsigned long p = (unsigned long)&dt[entrynum]; unsigned long start, end; @@ -412,14 +411,15 @@ static void xen_write_idt_entry(struct desc_struct *dt, int entrynum, xen_mc_flush(); - write_dt_entry(dt, entrynum, low, high); + native_write_idt_entry(dt, entrynum, g); if (p >= start && (p + 8) <= end) { struct trap_info info[2]; + u32 *desc = (u32 *)g; info[1].address = 0; - if (cvt_gate_to_trap(entrynum, low, high, &info[0])) + if (cvt_gate_to_trap(entrynum, desc[0], desc[1], &info[0])) if (HYPERVISOR_set_trap_table(info)) BUG(); } diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 77f1e5a..54b2314 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -70,9 +70,15 @@ static inline void pack_gate(gate_desc *gate, #define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) #define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) -#define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) +#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) #endif +static inline void native_write_idt_entry(gate_desc *idt, int entry, + const gate_desc *gate) +{ + memcpy(&idt[entry], gate, sizeof(*gate)); +} + static inline void write_dt_entry(struct desc_struct *dt, int entry, u32 entry_low, u32 entry_high) { @@ -142,7 +148,7 @@ static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned s { gate_desc g; pack_gate(&g, (unsigned long)addr, seg, type, 0); - write_idt_entry(idt_table, gate, g.a, g.b); + write_idt_entry(idt_table, gate, &g); } static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h index 0333fb6..86a9d7b 100644 --- a/include/asm-x86/paravirt.h +++ b/include/asm-x86/paravirt.h @@ -17,6 +17,7 @@ #include <linux/types.h> #include <linux/cpumask.h> #include <asm/kmap_types.h> +#include <asm/desc_defs.h> struct page; struct thread_struct; @@ -99,8 +100,8 @@ struct pv_cpu_ops { int entrynum, u32 low, u32 high); void (*write_gdt_entry)(struct desc_struct *, int entrynum, u32 low, u32 high); - void (*write_idt_entry)(struct desc_struct *, - int entrynum, u32 low, u32 high); + void (*write_idt_entry)(gate_desc *, + int entrynum, const gate_desc *gate); void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); void (*set_iopl_mask)(unsigned mask); @@ -667,9 +668,9 @@ static inline void write_gdt_entry(void *dt, int entry, u32 low, u32 high) { PVOP_VCALL4(pv_cpu_ops.write_gdt_entry, dt, entry, low, high); } -static inline void write_idt_entry(void *dt, int entry, u32 low, u32 high) +static inline void write_idt_entry(gate_desc *dt, int entry, const gate_desc *g) { - PVOP_VCALL4(pv_cpu_ops.write_idt_entry, dt, entry, low, high); + PVOP_VCALL3(pv_cpu_ops.write_idt_entry, dt, entry, g); } static inline void set_iopl_mask(unsigned mask) { -- 1.5.0.6
This patch modifies the write_ldt() function to make use of the new struct desc_struct instead of entry_1 and entry_2 entries Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/ldt.c | 15 +++++++-------- 1 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index a8cdca3..7eb0c8a 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -186,7 +186,7 @@ static int read_default_ldt(void __user *ptr, unsigned long bytecount) static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) { struct mm_struct *mm = current->mm; - __u32 entry_1, entry_2; + struct desc_struct ldt; int error; struct user_desc ldt_info; @@ -218,21 +218,20 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { if (oldmode || LDT_empty(&ldt_info)) { - entry_1 = 0; - entry_2 = 0; + memset(&ldt, 0, sizeof(ldt)); goto install; } } - entry_1 = LDT_entry_a(&ldt_info); - entry_2 = LDT_entry_b(&ldt_info); + ldt.a = LDT_entry_a(&ldt_info); + ldt.b = LDT_entry_b(&ldt_info); if (oldmode) - entry_2 &= ~(1 << 20); + ldt.avl = 0; /* Install the new entry ... */ install: - write_ldt_entry(mm->context.ldt, ldt_info.entry_number, entry_1, - entry_2); + write_ldt_entry(mm->context.ldt, ldt_info.entry_number, + ldt.a, ldt.b); error = 0; out_unlock: -- 1.5.0.6
Glauber de Oliveira Costa
2007-Dec-12 07:39 UTC
[PATCH 13/19] move constants to desc_defs.h
this patch moves constant definitions regarding descriptor types from desc_32.h to desc_defs.h. The change from defines to enum to comply with previous versions in desc_defs.h Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_32.h | 8 -------- include/asm-x86/desc_defs.h | 5 +++++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 92a72b0..14238df 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -44,14 +44,6 @@ static inline void pack_gate(gate_desc *gate, gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } -#define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ -#define DESCTYPE_TSS 0x89 /* present, system, DPL-0, 32-bit TSS */ -#define DESCTYPE_TASK 0x85 /* present, system, DPL-0, task gate */ -#define DESCTYPE_INT 0x8e /* present, system, DPL-0, interrupt gate */ -#define DESCTYPE_TRAP 0x8f /* present, system, DPL-0, trap gate */ -#define DESCTYPE_DPL3 0x60 /* DPL-3 */ -#define DESCTYPE_S 0x10 /* !system */ - #ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> #else diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index c4d7874..5ca416d 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -55,6 +55,11 @@ struct gate_struct64 { enum { DESC_TSS = 0x9, DESC_LDT = 0x2, + DESCTYPE_TASK = 0x85, /* present, system, DPL-0, task gate */ + DESCTYPE_INT = 0x8e, /* present, system, DPL-0, interrupt gate */ + DESCTYPE_TRAP = 0x8f, /* present, system, DPL-0, trap gate */ + DESCTYPE_DPL3 = 0x60, /* DPL-3 */ + DESCTYPE_S = 0x10, /* !system */ }; // LDT or TSS descriptor in the GDT. 16 bytes. -- 1.5.0.6
Glauber de Oliveira Costa
2007-Dec-12 07:39 UTC
[PATCH 15/19] use the same data type for tls_array.
This patch changes the type of tls_array in x86_64 to a desc_struct. Now, both i386 and x86_64 tls_array have the same type, and code accessing it can be shared. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 2 +- include/asm-x86/processor_64.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 2dc19e2..7fd9876 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -150,7 +150,7 @@ static inline void set_ldt(void *addr, int entries) static inline void load_TLS(struct thread_struct *t, unsigned int cpu) { unsigned int i; - u64 *gdt = (u64 *)(get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); + struct desc_struct *gdt = (get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) gdt[i] = t->tls_array[i]; diff --git a/include/asm-x86/processor_64.h b/include/asm-x86/processor_64.h index 8efdf99..51f1970 100644 --- a/include/asm-x86/processor_64.h +++ b/include/asm-x86/processor_64.h @@ -19,6 +19,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 @@ -244,7 +245,7 @@ struct thread_struct { * goes into MSR_IA32_DS_AREA */ unsigned long ds_area_msr; /* 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 { \ -- 1.5.0.6
Glauber de Oliveira Costa
2007-Dec-12 07:39 UTC
[PATCH 14/19] unify non-paravirt parts of desc.h
This patch unifies the non-paravirt part of desc_{32,64}.h into desc.h. Most of it, is simply common code, that is moved to the shared header. The only exception is the set_ldt_desc in desc_64.h, which is changed - included its name - to accomodate for the way the ldt is set up in i386. Also, constant definitions used in desc_32.h are moved to desc_defs.h Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 87 ++++++++++++++++++++++++++++++++++++++ include/asm-x86/desc_32.h | 66 ---------------------------- include/asm-x86/desc_64.h | 64 ++++----------------------- include/asm-x86/mmu_context_64.h | 4 +- 4 files changed, 99 insertions(+), 122 deletions(-) Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -1,5 +1,92 @@ +#ifndef _ASM_DESC_H_ +#define _ASM_DESC_H_ + +#include <asm/desc_defs.h> + +#ifndef __ASSEMBLY__ +#include <asm/mmu.h> + +extern struct desc_ptr idt_descr; +extern gate_desc idt_table[]; + +#endif + #ifdef CONFIG_X86_32 # include "desc_32.h" #else # include "desc_64.h" #endif + +#ifndef __ASSEMBLY__ + +#define _LDT_empty(info) (\ + (info)->base_addr == 0 && \ + (info)->limit == 0 && \ + (info)->contents == 0 && \ + (info)->read_exec_only == 1 && \ + (info)->seg_32bit == 0 && \ + (info)->limit_in_pages == 0 && \ + (info)->seg_not_present == 1 && \ + (info)->useable == 0) + +#ifdef CONFIG_X86_64 +#define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0)) +#else +#define LDT_empty(info) (_LDT_empty(info)) +#endif + +static inline void clear_LDT(void) +{ + set_ldt(NULL, 0); +} + +/* + * load one particular LDT into the current CPU + */ +static inline void load_LDT_nolock(mm_context_t *pc) +{ + set_ldt(pc->ldt, pc->size); +} + +static inline void load_LDT(mm_context_t *pc) +{ + preempt_disable(); + load_LDT_nolock(pc); + preempt_enable(); +} + +static inline unsigned long get_desc_base(unsigned long *desc) +{ + unsigned long base; + base = ((desc[0] >> 16) & 0x0000ffff) | + ((desc[1] << 16) & 0x00ff0000) | + (desc[1] & 0xff000000); + return base; +} + +#else +/* + * GET_DESC_BASE reads the descriptor base of the specified segment. + * + * Args: + * idx - descriptor index + * gdt - GDT pointer + * base - 32bit register to which the base will be written + * lo_w - lo word of the "base" register + * lo_b - lo byte of the "base" register + * hi_b - hi byte of the low word of the "base" register + * + * Example: + * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) + * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. + */ +#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ + movb idx*8+4(gdt), lo_b; \ + movb idx*8+7(gdt), hi_b; \ + shll $16, base; \ + movw idx*8+2(gdt), lo_w; + + +#endif /* __ASSEMBLY__ */ + +#endif Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ linux-2.6-x86/include/asm-x86/desc_32.h @@ -11,8 +11,6 @@ #include <linux/smp.h> #include <linux/percpu.h> -#include <asm/mmu.h> - struct gdt_page { struct desc_struct gdt[GDT_ENTRIES]; @@ -24,8 +22,6 @@ static inline struct desc_struct *get_cp return per_cpu(gdt_page, cpu).gdt; } -extern struct desc_ptr idt_descr; -extern gate_desc idt_table[]; extern void set_intr_gate(unsigned int irq, void * addr); static inline void pack_descriptor(struct desc_struct *desc, @@ -172,68 +168,6 @@ static inline void __set_tss_desc(unsign #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) -#define LDT_empty(info) (\ - (info)->base_addr == 0 && \ - (info)->limit == 0 && \ - (info)->contents == 0 && \ - (info)->read_exec_only == 1 && \ - (info)->seg_32bit == 0 && \ - (info)->limit_in_pages == 0 && \ - (info)->seg_not_present == 1 && \ - (info)->useable == 0 ) - -static inline void clear_LDT(void) -{ - set_ldt(NULL, 0); -} - -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc) -{ - set_ldt(pc->ldt, pc->size); -} - -static inline void load_LDT(mm_context_t *pc) -{ - preempt_disable(); - load_LDT_nolock(pc); - preempt_enable(); -} - -static inline unsigned long get_desc_base(unsigned long *desc) -{ - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} - -#else /* __ASSEMBLY__ */ - -/* - * GET_DESC_BASE reads the descriptor base of the specified segment. - * - * Args: - * idx - descriptor index - * gdt - GDT pointer - * base - 32bit register to which the base will be written - * lo_w - lo word of the "base" register - * lo_b - lo byte of the "base" register - * hi_b - hi byte of the low word of the "base" register - * - * Example: - * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) - * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. - */ -#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ - movb idx*8+4(gdt), lo_b; \ - movb idx*8+7(gdt), hi_b; \ - shll $16, base; \ - movw idx*8+2(gdt), lo_w; - #endif /* !__ASSEMBLY__ */ #endif Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -9,16 +9,13 @@ #include <linux/string.h> #include <linux/smp.h> -#include <asm/desc_defs.h> #include <asm/segment.h> -#include <asm/mmu.h> extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; #define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8)) #define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8)) -#define clear_LDT() asm volatile("lldt %w0"::"r" (0)) static inline unsigned long __store_tr(void) { @@ -30,7 +27,6 @@ static inline unsigned long __store_tr(v #define store_tr(tr) (tr) = __store_tr() -extern gate_desc idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; static inline void write_ldt_entry(struct desc_struct *ldt, @@ -138,23 +134,19 @@ static inline void set_tss_desc(unsigned IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); } -static inline void set_ldt_desc(unsigned cpu, void *addr, int size) +static inline void set_ldt(void *addr, int entries) { - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], - (unsigned long)addr, DESC_LDT, size * 8 - 1); + if (likely(entries == 0)) + __asm__ __volatile__("lldt %w0"::"q" (0)); + else { + unsigned cpu = smp_processor_id(); + + set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], + (unsigned long)addr, DESC_LDT, entries * 8 - 1); + __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); + } } -#define LDT_empty(info) (\ - (info)->base_addr == 0 && \ - (info)->limit == 0 && \ - (info)->contents == 0 && \ - (info)->read_exec_only == 1 && \ - (info)->seg_32bit == 0 && \ - (info)->limit_in_pages == 0 && \ - (info)->seg_not_present == 1 && \ - (info)->useable == 0 && \ - (info)->lm == 0) - static inline void load_TLS(struct thread_struct *t, unsigned int cpu) { unsigned int i; @@ -164,42 +156,6 @@ static inline void load_TLS(struct threa gdt[i] = t->tls_array[i]; } -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc, int cpu) -{ - int count = pc->size; - - if (likely(!count)) { - clear_LDT(); - return; - } - - set_ldt_desc(cpu, pc->ldt, count); - load_LDT_desc(); -} - -static inline void load_LDT(mm_context_t *pc) -{ - int cpu = get_cpu(); - - load_LDT_nolock(pc, cpu); - put_cpu(); -} - -extern struct desc_ptr idt_descr; - -static inline unsigned long get_desc_base(const void *ptr) -{ - const u32 *desc = ptr; - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} - #endif /* !__ASSEMBLY__ */ #endif Index: linux-2.6-x86/include/asm-x86/mmu_context_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/mmu_context_64.h +++ linux-2.6-x86/include/asm-x86/mmu_context_64.h @@ -43,7 +43,7 @@ static inline void switch_mm(struct mm_s load_cr3(next->pgd); if (unlikely(next->context.ldt != prev->context.ldt)) - load_LDT_nolock(&next->context, cpu); + load_LDT_nolock(&next->context); } #ifdef CONFIG_SMP else { @@ -56,7 +56,7 @@ static inline void switch_mm(struct mm_s * to make sure to use no freed page tables. */ load_cr3(next->pgd); - load_LDT_nolock(&next->context, cpu); + load_LDT_nolock(&next->context); } } #endif
Glauber de Oliveira Costa
2007-Dec-12 07:39 UTC
[PATCH 17/19] unify paravirt pieces of descriptor handling
With the types used to access descriptors in x86_64 and i386 now being the same, the code that effectively handles them can now be easily shared. This patch moves the paravirt part of desc_32.h into desc.h, and then, we get paravirt support in x86_64 for free. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 169 +++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/desc_32.h | 130 --------------------------------- include/asm-x86/desc_64.h | 104 +++------------------------ include/asm-x86/desc_defs.h | 6 +- 4 files changed, 183 insertions(+), 226 deletions(-) Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -5,11 +5,180 @@ #ifndef __ASSEMBLY__ #include <asm/mmu.h> +#include <linux/smp.h> extern struct desc_ptr idt_descr; extern gate_desc idt_table[]; +#ifdef CONFIG_X86_64 +extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; +extern struct desc_ptr cpu_gdt_descr[]; +/* the cpu gdt accessor */ +#define get_cpu_gdt_table(x) ((struct desc_struct *)cpu_gdt_descr[x].address) +#else +struct gdt_page { + struct desc_struct gdt[GDT_ENTRIES]; +} __attribute__((aligned(PAGE_SIZE))); +DECLARE_PER_CPU(struct gdt_page, gdt_page); + +static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) +{ + return per_cpu(gdt_page, cpu).gdt; +} +#endif + +#ifdef CONFIG_PARAVIRT +#include <asm/paravirt.h> +#else +#define load_TR_desc() native_load_tr_desc() +#define load_gdt(dtr) native_load_gdt(dtr) +#define load_idt(dtr) native_load_idt(dtr) +#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) +#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) + +#define store_gdt(dtr) native_store_gdt(dtr) +#define store_idt(dtr) native_store_idt(dtr) +#define store_tr(tr) (tr = native_store_tr()) +#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) + +#define load_TLS(t, cpu) native_load_tls(t, cpu) +#define set_ldt native_set_ldt + +#define write_ldt_entry(dt, entry, desc) \ + native_write_ldt_entry(dt, entry, desc) +#define write_gdt_entry(dt, entry, desc, type) \ + native_write_gdt_entry(dt, entry, desc, type) +#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) +#endif + +static inline void native_write_idt_entry(gate_desc *idt, int entry, + const gate_desc *gate) +{ + memcpy(&idt[entry], gate, sizeof(*gate)); +} + +static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, + const void *desc) +{ + memcpy(&ldt[entry], desc, 8); +} + +static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, + const void *desc, int type) +{ + unsigned int size; + switch (type) { + case DESC_TSS: + size = sizeof(tss_desc); + break; + case DESC_LDT: + size = sizeof(ldt_desc); + break; + default: + size = sizeof(struct desc_struct); + break; + } + memcpy(&gdt[entry], desc, size); +} + +static inline void set_tssldt_descriptor(struct ldttss_desc64 *d, + unsigned long tss, unsigned type, + unsigned size) +{ + memset(d, 0, sizeof(*d)); + d->limit0 = size & 0xFFFF; + d->base0 = PTR_LOW(tss); + d->base1 = PTR_MIDDLE(tss) & 0xFF; + d->type = type; + d->p = 1; + d->limit1 = (size >> 16) & 0xF; + d->base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF; + d->base3 = PTR_HIGH(tss); +} + +static inline void pack_descriptor(struct desc_struct *desc, unsigned long base, + unsigned long limit, unsigned char type, + unsigned char flags) +{ + desc->a = ((base & 0xffff) << 16) | (limit & 0xffff); + desc->b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | + (limit & 0x000f0000) | ((type & 0xff) << 8) | + ((flags & 0xf) << 20); + desc->p = 1; +} + +static inline void pack_ldt(ldt_desc *ldt, unsigned long addr, + unsigned size) +{ + +#ifdef CONFIG_X86_64 + set_tssldt_descriptor(ldt, + addr, DESC_LDT, size); +#else + pack_descriptor(ldt, (unsigned long)addr, + size, + 0x80 | DESC_LDT, 0); #endif +} + +static inline void native_set_ldt(const void *addr, unsigned int entries) +{ + if (likely(entries == 0)) + __asm__ __volatile__("lldt %w0"::"q" (0)); + else { + unsigned cpu = smp_processor_id(); + ldt_desc ldt; + + pack_ldt(&ldt, (unsigned long)addr, + entries * sizeof(ldt) - 1); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, + &ldt, sizeof(ldt)); + __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); + } +} + +static inline void native_load_tr_desc(void) +{ + asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); +} + +static inline void native_load_gdt(const struct desc_ptr *dtr) +{ + asm volatile("lgdt %0"::"m" (*dtr)); +} + +static inline void native_load_idt(const struct desc_ptr *dtr) +{ + asm volatile("lidt %0"::"m" (*dtr)); +} + +static inline void native_store_gdt(struct desc_ptr *dtr) +{ + asm volatile("sgdt %0":"=m" (*dtr)); +} + +static inline void native_store_idt(struct desc_ptr *dtr) +{ + asm volatile("sidt %0":"=m" (*dtr)); +} + +static inline unsigned long native_store_tr(void) +{ + unsigned long tr; + asm volatile("str %0":"=r" (tr)); + return tr; +} + +static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) +{ + unsigned int i; + struct desc_struct *gdt = get_cpu_gdt_table(cpu); + + for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) + gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; +} +#endif /* __ASSEMBLY__ */ + #ifdef CONFIG_X86_32 # include "desc_32.h" Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ linux-2.6-x86/include/asm-x86/desc_32.h @@ -8,31 +8,10 @@ #ifndef __ASSEMBLY__ #include <linux/preempt.h> -#include <linux/smp.h> #include <linux/percpu.h> -struct gdt_page -{ - struct desc_struct gdt[GDT_ENTRIES]; -} __attribute__((aligned(PAGE_SIZE))); -DECLARE_PER_CPU(struct gdt_page, gdt_page); - -static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) -{ - return per_cpu(gdt_page, cpu).gdt; -} - extern void set_intr_gate(unsigned int irq, void * addr); -static inline void pack_descriptor(struct desc_struct *desc, - unsigned long base, unsigned long limit, unsigned char type, unsigned char flags) -{ - desc->a = ((base & 0xffff) << 16) | (limit & 0xffff); - desc->b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | - (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20); - desc->p = 1; -} - static inline void pack_gate(gate_desc *gate, unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) { @@ -40,115 +19,6 @@ static inline void pack_gate(gate_desc * gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } -#ifdef CONFIG_PARAVIRT -#include <asm/paravirt.h> -#else -#define load_TR_desc() native_load_tr_desc() -#define load_gdt(dtr) native_load_gdt(dtr) -#define load_idt(dtr) native_load_idt(dtr) -#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) -#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) - -#define store_gdt(dtr) native_store_gdt(dtr) -#define store_idt(dtr) native_store_idt(dtr) -#define store_tr(tr) (tr = native_store_tr()) -#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) - -#define load_TLS(t, cpu) native_load_tls(t, cpu) -#define set_ldt native_set_ldt - -#define write_ldt_entry(dt, entry, desc) \ - native_write_ldt_entry(dt, entry, desc) -#define write_gdt_entry(dt, entry, desc, type) \ - native_write_gdt_entry(dt, entry, desc, type) -#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) -#endif - -static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, - const void *desc) -{ - memcpy(&ldt[entry], desc, sizeof(struct desc_struct)); -} - -static inline void native_write_idt_entry(gate_desc *idt, int entry, - const gate_desc *gate) -{ - memcpy(&idt[entry], gate, sizeof(*gate)); -} - -static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, - const void *desc, int type) -{ - memcpy(&gdt[entry], desc, sizeof(struct desc_struct)); -} - -static inline void write_dt_entry(struct desc_struct *dt, - int entry, u32 entry_low, u32 entry_high) -{ - dt[entry].a = entry_low; - dt[entry].b = entry_high; -} - - -static inline void native_set_ldt(const void *addr, unsigned int entries) -{ - if (likely(entries == 0)) - __asm__ __volatile__("lldt %w0"::"q" (0)); - else { - unsigned cpu = smp_processor_id(); - ldt_desc ldt; - - pack_descriptor(&ldt, (unsigned long)addr, - entries * sizeof(struct desc_struct) - 1, - DESC_LDT, 0); - write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, - &ldt, DESC_LDT); - __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); - } -} - - -static inline void native_load_tr_desc(void) -{ - asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); -} - -static inline void native_load_gdt(const struct desc_ptr *dtr) -{ - asm volatile("lgdt %0"::"m" (*dtr)); -} - -static inline void native_load_idt(const struct desc_ptr *dtr) -{ - asm volatile("lidt %0"::"m" (*dtr)); -} - -static inline void native_store_gdt(struct desc_ptr *dtr) -{ - asm ("sgdt %0":"=m" (*dtr)); -} - -static inline void native_store_idt(struct desc_ptr *dtr) -{ - asm ("sidt %0":"=m" (*dtr)); -} - -static inline unsigned long native_store_tr(void) -{ - unsigned long tr; - asm ("str %0":"=r" (tr)); - return tr; -} - -static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) -{ - unsigned int i; - struct desc_struct *gdt = get_cpu_gdt_table(cpu); - - for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) - gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; -} - static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) { gate_desc g; Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -8,47 +8,10 @@ #ifndef __ASSEMBLY__ #include <linux/string.h> -#include <linux/smp.h> #include <asm/segment.h> -extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; - -#define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8)) -#define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8)) - -static inline unsigned long __store_tr(void) -{ - unsigned long tr; - - asm volatile ("str %w0":"=r" (tr)); - return tr; -} - -#define store_tr(tr) (tr) = __store_tr() - -extern struct desc_ptr cpu_gdt_descr[]; - -static inline void write_ldt_entry(struct desc_struct *ldt, - int entry, void *ptr) -{ - memcpy(&ldt[entry], ptr, 8); -} - -/* the cpu gdt accessor */ -#define get_cpu_gdt_table(x) ((struct desc_struct *)cpu_gdt_descr[x].address) - -static inline void load_gdt(const struct desc_ptr *ptr) -{ - asm volatile("lgdt %w0"::"m" (*ptr)); -} - -static inline void store_gdt(struct desc_ptr *ptr) -{ - asm("sgdt %w0":"=m" (*ptr)); -} - -static inline void _set_gate(void *adr, unsigned type, unsigned long func, +static inline void _set_gate(int gate, unsigned type, unsigned long func, unsigned dpl, unsigned ist) { gate_desc s; @@ -67,61 +30,37 @@ static inline void _set_gate(void *adr, * does not need to be atomic because it is only done once at * setup time */ - memcpy(adr, &s, 16); + write_idt_entry(idt_table, gate, &s); } static inline void set_intr_gate(int nr, void *func) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 0, 0); } static inline void set_intr_gate_ist(int nr, void *func, unsigned ist) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 0, ist); } static inline void set_system_gate(int nr, void *func) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 3, 0); } static inline void set_system_gate_ist(int nr, void *func, unsigned ist) { - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist); -} - -static inline void load_idt(const struct desc_ptr *ptr) -{ - asm volatile("lidt %w0"::"m" (*ptr)); -} - -static inline void store_idt(struct desc_ptr *dtr) -{ - asm("sidt %w0":"=m" (*dtr)); -} - -static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, - unsigned type, unsigned size) -{ - struct ldttss_desc64 d; - - memset(&d, 0, sizeof(d)); - d.limit0 = size & 0xFFFF; - d.base0 = PTR_LOW(tss); - d.base1 = PTR_MIDDLE(tss) & 0xFF; - d.type = type; - d.p = 1; - d.limit1 = (size >> 16) & 0xF; - d.base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF; - d.base3 = PTR_HIGH(tss); - memcpy(ptr, &d, 16); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 3, ist); } static inline void set_tss_desc(unsigned cpu, void *addr) { + struct desc_struct *d = get_cpu_gdt_table(cpu); + tss_desc tss; + /* * sizeof(unsigned long) coming from an extra "long" at the end * of the iobitmap. See tss_struct definition in processor.h @@ -129,31 +68,10 @@ static inline void set_tss_desc(unsigned * -1? seg base+limit should be pointing to the address of the * last valid byte */ - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS], + set_tssldt_descriptor(&tss, (unsigned long)addr, DESC_TSS, IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); -} - -static inline void set_ldt(void *addr, int entries) -{ - if (likely(entries == 0)) - __asm__ __volatile__("lldt %w0"::"q" (0)); - else { - unsigned cpu = smp_processor_id(); - - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], - (unsigned long)addr, DESC_LDT, entries * 8 - 1); - __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); - } -} - -static inline void load_TLS(struct thread_struct *t, unsigned int cpu) -{ - unsigned int i; - struct desc_struct *gdt = (get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); - - for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) - gdt[i] = t->tls_array[i]; + write_gdt_entry(d, GDT_ENTRY_TSS, &tss, sizeof(tss_desc)); } #endif /* !__ASSEMBLY__ */ Index: linux-2.6-x86/include/asm-x86/desc_defs.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_defs.h +++ linux-2.6-x86/include/asm-x86/desc_defs.h @@ -48,9 +48,9 @@ struct gate_struct64 { u32 zero1; } __attribute__((packed)); -#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF) -#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF) -#define PTR_HIGH(x) ((unsigned long)(x) >> 32) +#define PTR_LOW(x) ((unsigned long long)(x) & 0xFFFF) +#define PTR_MIDDLE(x) (((unsigned long long)(x) >> 16) & 0xFFFF) +#define PTR_HIGH(x) ((unsigned long long)(x) >> 32) enum { DESC_TSS = 0x9,
This patch makes get_desc_base() receive a struct desc_struct, and then uses its internal fields to compute the base address. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/tls.c | 2 +- arch/x86/mm/fault_32.c | 2 +- include/asm-x86/desc.h | 8 ++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 74d2b65..98f428b 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -112,7 +112,7 @@ int do_get_thread_area(struct task_struct *p, int idx, memset(&info, 0, sizeof(struct user_desc)); info.entry_number = idx; - info.base_addr = get_desc_base((void *)desc); + info.base_addr = get_desc_base((struct desc_struct *)desc); info.limit = GET_LIMIT(desc); info.seg_32bit = GET_32BIT(desc); info.contents = GET_CONTENTS(desc); diff --git a/arch/x86/mm/fault_32.c b/arch/x86/mm/fault_32.c index 6056c6d..ef5ab2b 100644 --- a/arch/x86/mm/fault_32.c +++ b/arch/x86/mm/fault_32.c @@ -115,7 +115,7 @@ static inline unsigned long get_segment_eip(struct pt_regs *regs, } /* Decode the code segment base from the descriptor */ - base = get_desc_base((unsigned long *)desc); + base = get_desc_base((struct desc_struct *)desc); if (seg & (1<<2)) { mutex_unlock(¤t->mm->context.lock); diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index 926d6f8..3480cb1 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h @@ -55,13 +55,9 @@ static inline void load_LDT(mm_context_t *pc) preempt_enable(); } -static inline unsigned long get_desc_base(unsigned long *desc) +static inline unsigned long get_desc_base(struct desc_struct *desc) { - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; + return desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24); } #else -- 1.5.0.6
This patch unifies the set_tss_desc between i386 and x86_64, which can now have a common implementation. After the old functions are removed from desc_{32,64}.h, nothing important is left, and the files can be removed. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 40 +++++++++++++++++++++++++++++++++------- include/asm-x86/desc_32.h | 27 --------------------------- include/asm-x86/desc_64.h | 34 ---------------------------------- 3 files changed, 33 insertions(+), 68 deletions(-) delete mode 100644 include/asm-x86/desc_32.h delete mode 100644 include/asm-x86/desc_64.h Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -147,6 +147,39 @@ static inline void pack_ldt(ldt_desc *ld #endif } +static inline void pack_tss(tss_desc *tss, unsigned long addr, + unsigned size, unsigned entry) +{ +#ifdef CONFIG_X86_64 + set_tssldt_descriptor(tss, + addr, entry, size); +#else + pack_descriptor(tss, (unsigned long)addr, + size, + 0x80 | entry, 0); +#endif +} + +static inline void __set_tss_desc(unsigned cpu, unsigned int entry, void *addr) +{ + struct desc_struct *d = get_cpu_gdt_table(cpu); + tss_desc tss; + + /* + * sizeof(unsigned long) coming from an extra "long" at the end + * of the iobitmap. See tss_struct definition in processor.h + * + * -1? seg base+limit should be pointing to the address of the + * last valid byte + */ + pack_tss(&tss, (unsigned long)addr, + IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1, + DESC_TSS); + write_gdt_entry(d, entry, &tss, sizeof(tss)); +} + +#define set_tss_desc(cpu, addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) + static inline void native_set_ldt(const void *addr, unsigned int entries) { if (likely(entries == 0)) @@ -205,13 +238,6 @@ static inline void native_load_tls(struc } #endif /* __ASSEMBLY__ */ - -#ifdef CONFIG_X86_32 -# include "desc_32.h" -#else -# include "desc_64.h" -#endif - #ifndef __ASSEMBLY__ #define _LDT_empty(info) (\ Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __ARCH_DESC_H -#define __ARCH_DESC_H - -#include <asm/ldt.h> -#include <asm/segment.h> -#include <asm/desc_defs.h> - -#ifndef __ASSEMBLY__ - -#include <linux/preempt.h> -#include <linux/percpu.h> - -static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) -{ - tss_desc tss; - pack_descriptor(&tss, (unsigned long)addr, - offsetof(struct tss_struct, __cacheline_filler) - 1, - DESC_TSS, 0); - write_gdt_entry(get_cpu_gdt_table(cpu), entry, &tss, DESC_TSS); -} - - -#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) - -#endif /* !__ASSEMBLY__ */ - -#endif Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Written 2000 by Andi Kleen */ -#ifndef __ARCH_DESC_H -#define __ARCH_DESC_H - -#include <linux/threads.h> -#include <asm/ldt.h> - -#ifndef __ASSEMBLY__ - -#include <linux/string.h> - -#include <asm/segment.h> - -static inline void set_tss_desc(unsigned cpu, void *addr) -{ - struct desc_struct *d = get_cpu_gdt_table(cpu); - tss_desc tss; - - /* - * sizeof(unsigned long) coming from an extra "long" at the end - * of the iobitmap. See tss_struct definition in processor.h - * - * -1? seg base+limit should be pointing to the address of the - * last valid byte - */ - set_tssldt_descriptor(&tss, - (unsigned long)addr, DESC_TSS, - IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); - write_gdt_entry(d, GDT_ENTRY_TSS, &tss, sizeof(tss_desc)); -} - -#endif /* !__ASSEMBLY__ */ - -#endif
* Ingo Molnar <mingo@elte.hu> wrote:> > > Ingo, in the absense of further complaints, could you please push > > > to the x86 tree? > > > > yeah, i've added them. > > the patches cause a spontaneous reboot on x86 64-bit, around the time > when bootup hits user-space. It's due to one of the 25 patches from > you today. Config attached.likely caused by this patch: Subject: unify non-paravirt parts of desc.h _please_ be more careful when unifying. Do check the before/after vmlinux - the binary size at least. And watch out for compiler warnings as well: arch/x86/kernel/process_64.c: In function 'read_32bit_tls': arch/x86/kernel/process_64.c:454: warning: passing argument 1 of 'get_desc_base' from incompatible pointer type i've pulled the patches from the tree for now. Ingo
Glauber de Oliveira Costa wrote:> Since the last version of it received no comments on the interfaces, here > it goes a version, that I feel ready for inclusion. > > The comments regarding style, specially the elimination of the #defines in > the desc_struct definition were merged. I also implemented the vmi > functions, > missing last time. > > Ingo, in the absense of further complaints, could you please push to the > x86 tree? >Looks fine to me... -hpa
Here it goes a new version of the patchset. It addresses the problems raised, namely: * it does not harm make headers_check anymore. (fill_ldt is moved to desc.h) * it fixes the x86_64 spontaneous boot problem * it does not have a warning at get_desc_base() anymore.
This variable is not used anywere, and is then removed Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 1c26dbb..660cc84 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -30,11 +30,6 @@ static inline unsigned long __store_tr(void) #define store_tr(tr) (tr) = __store_tr() -/* - * This is the ldt that every process will get unless we need - * something other than this. - */ -extern struct desc_struct default_ldt[]; extern struct gate_struct idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; -- 1.5.0.6
To account for the differences in gate descriptor in i386 and x86_64 a gate_desc type is introduced. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/traps_32.c | 3 ++- include/asm-x86/desc_32.h | 15 ++++++++------- include/asm-x86/desc_64.h | 4 ++-- include/asm-x86/desc_defs.h | 8 +++++++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 94c5aea..6b03d88 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -76,8 +76,8 @@ char ignore_fpu_irq = 0; * F0 0F bug workaround.. We have a special link segment * for this. */ -struct desc_struct idt_table[256] - __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; +gate_desc idt_table[256] + __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; asmlinkage void divide_error(void); asmlinkage void debug(void); diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index bc5ca34..77f1e5a 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -3,6 +3,7 @@ #include <asm/ldt.h> #include <asm/segment.h> +#include <asm/desc_defs.h> #ifndef __ASSEMBLY__ @@ -24,7 +25,7 @@ static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) } extern struct desc_ptr idt_descr; -extern struct desc_struct idt_table[]; +extern gate_desc idt_table[]; extern void set_intr_gate(unsigned int irq, void * addr); static inline void pack_descriptor(__u32 *a, __u32 *b, @@ -35,11 +36,11 @@ static inline void pack_descriptor(__u32 *a, __u32 *b, (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20); } -static inline void pack_gate(__u32 *a, __u32 *b, +static inline void pack_gate(gate_desc *gate, unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) { - *a = (seg << 16) | (base & 0xffff); - *b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); + gate->a = (seg << 16) | (base & 0xffff); + gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } #define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ @@ -139,9 +140,9 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) { - __u32 a, b; - pack_gate(&a, &b, (unsigned long)addr, seg, type, 0); - write_idt_entry(idt_table, gate, a, b); + gate_desc g; + pack_gate(&g, (unsigned long)addr, seg, type, 0); + write_idt_entry(idt_table, gate, g.a, g.b); } static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 660cc84..ffc6c06 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -30,7 +30,7 @@ static inline unsigned long __store_tr(void) #define store_tr(tr) (tr) = __store_tr() -extern struct gate_struct idt_table[]; +extern gate_desc idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; static inline void write_ldt_entry(struct desc_struct *ldt, @@ -58,7 +58,7 @@ static inline void store_gdt(struct desc_ptr *ptr) static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist) { - struct gate_struct s; + gate_desc s; s.offset_low = PTR_LOW(func); s.segment = __KERNEL_CS; diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index f37b44c..05eff93 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -39,7 +39,7 @@ enum { }; // 16byte gate -struct gate_struct { +struct gate_struct64 { u16 offset_low; u16 segment; unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; @@ -67,6 +67,12 @@ struct ldttss_desc { u32 zero1; } __attribute__((packed)); +#ifdef CONFIG_X86_64 +typedef struct gate_struct64 gate_desc; +#else +typedef struct desc_struct gate_desc; +#endif + struct desc_ptr { unsigned short size; unsigned long address; -- 1.5.0.6
This patch modifies the write_ldt() function to make use of the new struct desc_struct instead of entry_1 and entry_2 entries Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/ldt.c | 15 +++++++-------- 1 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index a8cdca3..7eb0c8a 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -186,7 +186,7 @@ static int read_default_ldt(void __user *ptr, unsigned long bytecount) static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) { struct mm_struct *mm = current->mm; - __u32 entry_1, entry_2; + struct desc_struct ldt; int error; struct user_desc ldt_info; @@ -218,21 +218,20 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { if (oldmode || LDT_empty(&ldt_info)) { - entry_1 = 0; - entry_2 = 0; + memset(&ldt, 0, sizeof(ldt)); goto install; } } - entry_1 = LDT_entry_a(&ldt_info); - entry_2 = LDT_entry_b(&ldt_info); + ldt.a = LDT_entry_a(&ldt_info); + ldt.b = LDT_entry_b(&ldt_info); if (oldmode) - entry_2 &= ~(1 << 20); + ldt.avl = 0; /* Install the new entry ... */ install: - write_ldt_entry(mm->context.ldt, ldt_info.entry_number, entry_1, - entry_2); + write_ldt_entry(mm->context.ldt, ldt_info.entry_number, + ldt.a, ldt.b); error = 0; out_unlock: -- 1.5.0.6
this patch introduces ldt_desc type to account for the differences in the ldt descriptor in x86_64 and i386 Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 2 +- include/asm-x86/desc_defs.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index ffc6c06..8fe1b4c 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -113,7 +113,7 @@ static inline void store_idt(struct desc_ptr *dtr) static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type, unsigned size) { - struct ldttss_desc d; + struct ldttss_desc64 d; memset(&d, 0, sizeof(d)); d.limit0 = size & 0xFFFF; diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index 05eff93..5a58fc1 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -58,7 +58,7 @@ enum { }; // LDT or TSS descriptor in the GDT. 16 bytes. -struct ldttss_desc { +struct ldttss_desc64 { u16 limit0; u16 base0; unsigned base1 : 8, type : 5, dpl : 2, p : 1; @@ -69,8 +69,10 @@ struct ldttss_desc { #ifdef CONFIG_X86_64 typedef struct gate_struct64 gate_desc; +typedef struct ldttss_desc64 ldt_desc; #else typedef struct desc_struct gate_desc; +typedef struct desc_struct ldt_desc; #endif struct desc_ptr { -- 1.5.0.6
Glauber de Oliveira Costa
2007-Dec-12 20:46 UTC
[PATCH 06/19] change write_idt_entry signature
this patch changes write_idt_entry signature. It now takes a gate_desc instead of the a and b parameters. It will allow it to be later unified between i386 and x86_64. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> CC: Zachary Amsden <zach@vmware.com> CC: Jeremy Fitzhardinge <Jeremy.Fitzhardinge.citrix.com> --- arch/x86/kernel/paravirt_32.c | 2 +- arch/x86/kernel/vmi_32.c | 10 +++++++++- arch/x86/lguest/boot.c | 9 +++++---- arch/x86/xen/enlighten.c | 8 ++++---- include/asm-x86/desc_32.h | 10 ++++++++-- include/asm-x86/paravirt.h | 9 +++++---- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/paravirt_32.c b/arch/x86/kernel/paravirt_32.c index f4e3a8e..13bbc99 100644 --- a/arch/x86/kernel/paravirt_32.c +++ b/arch/x86/kernel/paravirt_32.c @@ -381,7 +381,7 @@ struct pv_cpu_ops pv_cpu_ops = { .load_tls = native_load_tls, .write_ldt_entry = write_dt_entry, .write_gdt_entry = write_dt_entry, - .write_idt_entry = write_dt_entry, + .write_idt_entry = native_write_idt_entry, .load_sp0 = native_load_sp0, .irq_enable_syscall_ret = native_irq_enable_syscall_ret, diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c index 4cfda7d..a635b22 100644 --- a/arch/x86/kernel/vmi_32.c +++ b/arch/x86/kernel/vmi_32.c @@ -62,6 +62,7 @@ static struct { void (*cpuid)(void /* non-c */); void (*_set_ldt)(u32 selector); void (*set_tr)(u32 selector); + void (*write_idt_entry)(struct desc_struct *, int, u32, u32); void (*set_kernel_stack)(u32 selector, u32 sp0); void (*allocate_page)(u32, u32, u32, u32, u32); void (*release_page)(u32, u32); @@ -214,6 +215,12 @@ static void vmi_set_tr(void) vmi_ops.set_tr(GDT_ENTRY_TSS*sizeof(struct desc_struct)); } +static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g) +{ + u32 *idt_entry = (u32 *)g; + vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[2]); +} + static void vmi_load_sp0(struct tss_struct *tss, struct thread_struct *thread) { @@ -792,7 +799,8 @@ static inline int __init activate_vmi(void) pv_cpu_ops.load_tls = vmi_load_tls; para_fill(pv_cpu_ops.write_ldt_entry, WriteLDTEntry); para_fill(pv_cpu_ops.write_gdt_entry, WriteGDTEntry); - para_fill(pv_cpu_ops.write_idt_entry, WriteIDTEntry); + para_wrap(pv_cpu_ops.write_idt_entry, vmi_write_idt_entry, + write_idt_entry, WriteIDTEntry); para_wrap(pv_cpu_ops.load_sp0, vmi_load_sp0, set_kernel_stack, UpdateKernelStack); para_fill(pv_cpu_ops.set_iopl_mask, SetIOPLMask); para_fill(pv_cpu_ops.io_delay, IODelay); diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index aa0bdd5..b50c8ad 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -217,13 +217,14 @@ static void irq_enable(void) * address of the handler, and... well, who cares? The Guest just asks the * Host to make the change anyway, because the Host controls the real IDT. */ -static void lguest_write_idt_entry(struct desc_struct *dt, - int entrynum, u32 low, u32 high) +static void lguest_write_idt_entry(gate_desc *dt, + int entrynum, const gate_desc *g) { + u32 *desc = (u32 *)g; /* Keep the local copy up to date. */ - write_dt_entry(dt, entrynum, low, high); + native_write_idt_entry(dt, entrynum, g); /* Tell Host about this new entry. */ - hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, low, high); + hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]); } /* Changing to a different IDT is very rare: we keep the IDT up-to-date every diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 8215ea6..6dd349e 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -399,8 +399,7 @@ static DEFINE_PER_CPU(struct desc_ptr, idt_desc); /* Set an IDT entry. If the entry is part of the current IDT, then also update Xen. */ -static void xen_write_idt_entry(struct desc_struct *dt, int entrynum, - u32 low, u32 high) +static void xen_write_idt_entry(gate_desc *dt, int entrynum, const gate_desc *g) { unsigned long p = (unsigned long)&dt[entrynum]; unsigned long start, end; @@ -412,14 +411,15 @@ static void xen_write_idt_entry(struct desc_struct *dt, int entrynum, xen_mc_flush(); - write_dt_entry(dt, entrynum, low, high); + native_write_idt_entry(dt, entrynum, g); if (p >= start && (p + 8) <= end) { struct trap_info info[2]; + u32 *desc = (u32 *)g; info[1].address = 0; - if (cvt_gate_to_trap(entrynum, low, high, &info[0])) + if (cvt_gate_to_trap(entrynum, desc[0], desc[1], &info[0])) if (HYPERVISOR_set_trap_table(info)) BUG(); } diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 77f1e5a..54b2314 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -70,9 +70,15 @@ static inline void pack_gate(gate_desc *gate, #define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) #define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) -#define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) +#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) #endif +static inline void native_write_idt_entry(gate_desc *idt, int entry, + const gate_desc *gate) +{ + memcpy(&idt[entry], gate, sizeof(*gate)); +} + static inline void write_dt_entry(struct desc_struct *dt, int entry, u32 entry_low, u32 entry_high) { @@ -142,7 +148,7 @@ static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned s { gate_desc g; pack_gate(&g, (unsigned long)addr, seg, type, 0); - write_idt_entry(idt_table, gate, g.a, g.b); + write_idt_entry(idt_table, gate, &g); } static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h index 0333fb6..86a9d7b 100644 --- a/include/asm-x86/paravirt.h +++ b/include/asm-x86/paravirt.h @@ -17,6 +17,7 @@ #include <linux/types.h> #include <linux/cpumask.h> #include <asm/kmap_types.h> +#include <asm/desc_defs.h> struct page; struct thread_struct; @@ -99,8 +100,8 @@ struct pv_cpu_ops { int entrynum, u32 low, u32 high); void (*write_gdt_entry)(struct desc_struct *, int entrynum, u32 low, u32 high); - void (*write_idt_entry)(struct desc_struct *, - int entrynum, u32 low, u32 high); + void (*write_idt_entry)(gate_desc *, + int entrynum, const gate_desc *gate); void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); void (*set_iopl_mask)(unsigned mask); @@ -667,9 +668,9 @@ static inline void write_gdt_entry(void *dt, int entry, u32 low, u32 high) { PVOP_VCALL4(pv_cpu_ops.write_gdt_entry, dt, entry, low, high); } -static inline void write_idt_entry(void *dt, int entry, u32 low, u32 high) +static inline void write_idt_entry(gate_desc *dt, int entry, const gate_desc *g) { - PVOP_VCALL4(pv_cpu_ops.write_idt_entry, dt, entry, low, high); + PVOP_VCALL3(pv_cpu_ops.write_idt_entry, dt, entry, g); } static inline void set_iopl_mask(unsigned mask) { -- 1.5.0.6
Glauber de Oliveira Costa
2007-Dec-12 20:47 UTC
[PATCH 14/19] unify non-paravirt parts of desc.h
This patch unifies the non-paravirt part of desc_{32,64}.h into desc.h. Most of it, is simply common code, that is moved to the shared header. The only exception is the set_ldt_desc in desc_64.h, which is changed - included its name - to accomodate for the way the ldt is set up in i386. Also, constant definitions used in desc_32.h are moved to desc_defs.h Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 87 ++++++++++++++++++++++++++++++++++++++ include/asm-x86/desc_32.h | 66 ---------------------------- include/asm-x86/desc_64.h | 64 ++++----------------------- include/asm-x86/mmu_context_64.h | 4 +- 4 files changed, 99 insertions(+), 122 deletions(-) Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -4,6 +4,7 @@ #ifndef __ASSEMBLY__ #include <asm/desc_defs.h> #include <asm/ldt.h> +#include <asm/mmu.h> static inline void fill_ldt(struct desc_struct *desc, struct user_desc *info) { @@ -23,7 +24,8 @@ static inline void fill_ldt(struct desc_ desc->base2 = (info->base_addr & 0xff000000) >> 24; } -#endif +extern struct desc_ptr idt_descr; +extern gate_desc idt_table[]; #ifdef CONFIG_X86_32 # include "desc_32.h" @@ -31,4 +33,65 @@ static inline void fill_ldt(struct desc_ # include "desc_64.h" #endif +#define _LDT_empty(info) (\ + (info)->base_addr == 0 && \ + (info)->limit == 0 && \ + (info)->contents == 0 && \ + (info)->read_exec_only == 1 && \ + (info)->seg_32bit == 0 && \ + (info)->limit_in_pages == 0 && \ + (info)->seg_not_present == 1 && \ + (info)->useable == 0) + +#ifdef CONFIG_X86_64 +#define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0)) +#else +#define LDT_empty(info) (_LDT_empty(info)) +#endif + +static inline void clear_LDT(void) +{ + set_ldt(NULL, 0); +} + +/* + * load one particular LDT into the current CPU + */ +static inline void load_LDT_nolock(mm_context_t *pc) +{ + set_ldt(pc->ldt, pc->size); +} + +static inline void load_LDT(mm_context_t *pc) +{ + preempt_disable(); + load_LDT_nolock(pc); + preempt_enable(); +} + +#else +/* + * GET_DESC_BASE reads the descriptor base of the specified segment. + * + * Args: + * idx - descriptor index + * gdt - GDT pointer + * base - 32bit register to which the base will be written + * lo_w - lo word of the "base" register + * lo_b - lo byte of the "base" register + * hi_b - hi byte of the low word of the "base" register + * + * Example: + * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) + * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. + */ +#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ + movb idx*8+4(gdt), lo_b; \ + movb idx*8+7(gdt), hi_b; \ + shll $16, base; \ + movw idx*8+2(gdt), lo_w; + + +#endif /* __ASSEMBLY__ */ + #endif Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ linux-2.6-x86/include/asm-x86/desc_32.h @@ -11,8 +11,6 @@ #include <linux/smp.h> #include <linux/percpu.h> -#include <asm/mmu.h> - struct gdt_page { struct desc_struct gdt[GDT_ENTRIES]; @@ -24,8 +22,6 @@ static inline struct desc_struct *get_cp return per_cpu(gdt_page, cpu).gdt; } -extern struct desc_ptr idt_descr; -extern gate_desc idt_table[]; extern void set_intr_gate(unsigned int irq, void * addr); static inline void pack_descriptor(struct desc_struct *desc, @@ -172,36 +168,6 @@ static inline void __set_tss_desc(unsign #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) -#define LDT_empty(info) (\ - (info)->base_addr == 0 && \ - (info)->limit == 0 && \ - (info)->contents == 0 && \ - (info)->read_exec_only == 1 && \ - (info)->seg_32bit == 0 && \ - (info)->limit_in_pages == 0 && \ - (info)->seg_not_present == 1 && \ - (info)->useable == 0 ) - -static inline void clear_LDT(void) -{ - set_ldt(NULL, 0); -} - -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc) -{ - set_ldt(pc->ldt, pc->size); -} - -static inline void load_LDT(mm_context_t *pc) -{ - preempt_disable(); - load_LDT_nolock(pc); - preempt_enable(); -} - static inline unsigned long get_desc_base(unsigned long *desc) { unsigned long base; @@ -210,30 +176,6 @@ static inline unsigned long get_desc_bas (desc[1] & 0xff000000); return base; } - -#else /* __ASSEMBLY__ */ - -/* - * GET_DESC_BASE reads the descriptor base of the specified segment. - * - * Args: - * idx - descriptor index - * gdt - GDT pointer - * base - 32bit register to which the base will be written - * lo_w - lo word of the "base" register - * lo_b - lo byte of the "base" register - * hi_b - hi byte of the low word of the "base" register - * - * Example: - * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) - * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. - */ -#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ - movb idx*8+4(gdt), lo_b; \ - movb idx*8+7(gdt), hi_b; \ - shll $16, base; \ - movw idx*8+2(gdt), lo_w; - #endif /* !__ASSEMBLY__ */ #endif Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -9,16 +9,13 @@ #include <linux/string.h> #include <linux/smp.h> -#include <asm/desc_defs.h> #include <asm/segment.h> -#include <asm/mmu.h> extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; #define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8)) #define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8)) -#define clear_LDT() asm volatile("lldt %w0"::"r" (0)) static inline unsigned long __store_tr(void) { @@ -30,7 +27,6 @@ static inline unsigned long __store_tr(v #define store_tr(tr) (tr) = __store_tr() -extern gate_desc idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; static inline void write_ldt_entry(struct desc_struct *ldt, @@ -138,23 +134,19 @@ static inline void set_tss_desc(unsigned IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); } -static inline void set_ldt_desc(unsigned cpu, void *addr, int size) +static inline void set_ldt(void *addr, int entries) { - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], - (unsigned long)addr, DESC_LDT, size * 8 - 1); + if (likely(entries == 0)) + __asm__ __volatile__("lldt %w0"::"q" (0)); + else { + unsigned cpu = smp_processor_id(); + + set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], + (unsigned long)addr, DESC_LDT, entries * 8 - 1); + __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); + } } -#define LDT_empty(info) (\ - (info)->base_addr == 0 && \ - (info)->limit == 0 && \ - (info)->contents == 0 && \ - (info)->read_exec_only == 1 && \ - (info)->seg_32bit == 0 && \ - (info)->limit_in_pages == 0 && \ - (info)->seg_not_present == 1 && \ - (info)->useable == 0 && \ - (info)->lm == 0) - static inline void load_TLS(struct thread_struct *t, unsigned int cpu) { unsigned int i; @@ -164,32 +156,6 @@ static inline void load_TLS(struct threa gdt[i] = t->tls_array[i]; } -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc, int cpu) -{ - int count = pc->size; - - if (likely(!count)) { - clear_LDT(); - return; - } - - set_ldt_desc(cpu, pc->ldt, count); - load_LDT_desc(); -} - -static inline void load_LDT(mm_context_t *pc) -{ - int cpu = get_cpu(); - - load_LDT_nolock(pc, cpu); - put_cpu(); -} - -extern struct desc_ptr idt_descr; - static inline unsigned long get_desc_base(const void *ptr) { const u32 *desc = ptr; @@ -199,7 +165,6 @@ static inline unsigned long get_desc_bas (desc[1] & 0xff000000); return base; } - #endif /* !__ASSEMBLY__ */ #endif Index: linux-2.6-x86/include/asm-x86/mmu_context_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/mmu_context_64.h +++ linux-2.6-x86/include/asm-x86/mmu_context_64.h @@ -43,7 +43,7 @@ static inline void switch_mm(struct mm_s load_cr3(next->pgd); if (unlikely(next->context.ldt != prev->context.ldt)) - load_LDT_nolock(&next->context, cpu); + load_LDT_nolock(&next->context); } #ifdef CONFIG_SMP else { @@ -56,7 +56,7 @@ static inline void switch_mm(struct mm_s * to make sure to use no freed page tables. */ load_cr3(next->pgd); - load_LDT_nolock(&next->context, cpu); + load_LDT_nolock(&next->context); } } #endif
Glauber de Oliveira Costa
2007-Dec-12 20:47 UTC
[PATCH 13/19] move constants to desc_defs.h
this patch moves constant definitions regarding descriptor types from desc_32.h to desc_defs.h. The change from defines to enum to comply with previous versions in desc_defs.h Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_32.h | 8 -------- include/asm-x86/desc_defs.h | 5 +++++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 92a72b0..14238df 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -44,14 +44,6 @@ static inline void pack_gate(gate_desc *gate, gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } -#define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ -#define DESCTYPE_TSS 0x89 /* present, system, DPL-0, 32-bit TSS */ -#define DESCTYPE_TASK 0x85 /* present, system, DPL-0, task gate */ -#define DESCTYPE_INT 0x8e /* present, system, DPL-0, interrupt gate */ -#define DESCTYPE_TRAP 0x8f /* present, system, DPL-0, trap gate */ -#define DESCTYPE_DPL3 0x60 /* DPL-3 */ -#define DESCTYPE_S 0x10 /* !system */ - #ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> #else diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index c4d7874..5ca416d 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -55,6 +55,11 @@ struct gate_struct64 { enum { DESC_TSS = 0x9, DESC_LDT = 0x2, + DESCTYPE_TASK = 0x85, /* present, system, DPL-0, task gate */ + DESCTYPE_INT = 0x8e, /* present, system, DPL-0, interrupt gate */ + DESCTYPE_TRAP = 0x8f, /* present, system, DPL-0, trap gate */ + DESCTYPE_DPL3 = 0x60, /* DPL-3 */ + DESCTYPE_S = 0x10, /* !system */ }; // LDT or TSS descriptor in the GDT. 16 bytes. -- 1.5.0.6
This patch unifies the set_tss_desc between i386 and x86_64, which can now have a common implementation. After the old functions are removed from desc_{32,64}.h, nothing important is left, and the files can be removed. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 40 +++++++++++++++++++++++++++++++++------- include/asm-x86/desc_32.h | 27 --------------------------- include/asm-x86/desc_64.h | 34 ---------------------------------- 3 files changed, 33 insertions(+), 68 deletions(-) delete mode 100644 include/asm-x86/desc_32.h delete mode 100644 include/asm-x86/desc_64.h Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -165,6 +165,39 @@ static inline void pack_ldt(ldt_desc *ld #endif } +static inline void pack_tss(tss_desc *tss, unsigned long addr, + unsigned size, unsigned entry) +{ +#ifdef CONFIG_X86_64 + set_tssldt_descriptor(tss, + addr, entry, size); +#else + pack_descriptor(tss, (unsigned long)addr, + size, + 0x80 | entry, 0); +#endif +} + +static inline void __set_tss_desc(unsigned cpu, unsigned int entry, void *addr) +{ + struct desc_struct *d = get_cpu_gdt_table(cpu); + tss_desc tss; + + /* + * sizeof(unsigned long) coming from an extra "long" at the end + * of the iobitmap. See tss_struct definition in processor.h + * + * -1? seg base+limit should be pointing to the address of the + * last valid byte + */ + pack_tss(&tss, (unsigned long)addr, + IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1, + DESC_TSS); + write_gdt_entry(d, entry, &tss, DESC_TSS); +} + +#define set_tss_desc(cpu, addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) + static inline void native_set_ldt(const void *addr, unsigned int entries) { if (likely(entries == 0)) @@ -222,12 +255,6 @@ static inline void native_load_tls(struc gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; } -#ifdef CONFIG_X86_32 -# include "desc_32.h" -#else -# include "desc_64.h" -#endif - #define _LDT_empty(info) (\ (info)->base_addr == 0 && \ (info)->limit == 0 && \ Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __ARCH_DESC_H -#define __ARCH_DESC_H - -#include <asm/ldt.h> -#include <asm/segment.h> -#include <asm/desc_defs.h> - -#ifndef __ASSEMBLY__ - -#include <linux/preempt.h> -#include <linux/percpu.h> - -static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) -{ - tss_desc tss; - pack_descriptor(&tss, (unsigned long)addr, - offsetof(struct tss_struct, __cacheline_filler) - 1, - DESC_TSS, 0); - write_gdt_entry(get_cpu_gdt_table(cpu), entry, &tss, DESC_TSS); -} - - -#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) - -#endif /* !__ASSEMBLY__ */ - -#endif Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -1,34 +1 @@ -/* Written 2000 by Andi Kleen */ -#ifndef __ARCH_DESC_H -#define __ARCH_DESC_H -#include <linux/threads.h> -#include <asm/ldt.h> - -#ifndef __ASSEMBLY__ - -#include <linux/string.h> - -#include <asm/segment.h> - -static inline void set_tss_desc(unsigned cpu, void *addr) -{ - struct desc_struct *d = get_cpu_gdt_table(cpu); - tss_desc tss; - - /* - * sizeof(unsigned long) coming from an extra "long" at the end - * of the iobitmap. See tss_struct definition in processor.h - * - * -1? seg base+limit should be pointing to the address of the - * last valid byte - */ - set_tssldt_descriptor(&tss, - (unsigned long)addr, DESC_TSS, - IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); - write_gdt_entry(d, GDT_ENTRY_TSS, &tss, DESC_TSS); -} - -#endif /* !__ASSEMBLY__ */ - -#endif
Glauber de Oliveira Costa
2007-Dec-12 21:17 UTC
[PATCH 15/19] use the same data type for tls_array.
This patch changes the type of tls_array in x86_64 to a desc_struct. Now, both i386 and x86_64 tls_array have the same type, and code accessing it can be shared. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 2 +- include/asm-x86/processor_64.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 2dc19e2..7fd9876 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -150,7 +150,7 @@ static inline void set_ldt(void *addr, int entries) static inline void load_TLS(struct thread_struct *t, unsigned int cpu) { unsigned int i; - u64 *gdt = (u64 *)(get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); + struct desc_struct *gdt = (get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) gdt[i] = t->tls_array[i]; diff --git a/include/asm-x86/processor_64.h b/include/asm-x86/processor_64.h index 8efdf99..51f1970 100644 --- a/include/asm-x86/processor_64.h +++ b/include/asm-x86/processor_64.h @@ -19,6 +19,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 @@ -244,7 +245,7 @@ struct thread_struct { * goes into MSR_IA32_DS_AREA */ unsigned long ds_area_msr; /* 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 { \ -- 1.5.0.6
This patch makes get_desc_base() receive a struct desc_struct, and then uses its internal fields to compute the base address. This is done at both i386 and x86_64, and then it is moved to common header Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/tls.c | 2 +- arch/x86/mm/fault_32.c | 2 +- include/asm-x86/desc.h | 8 ++------ 3 files changed, 4 insertions(+), 8 deletions(-) Index: linux-2.6-x86/arch/x86/kernel/tls.c ==================================================================--- linux-2.6-x86.orig/arch/x86/kernel/tls.c +++ linux-2.6-x86/arch/x86/kernel/tls.c @@ -112,7 +112,7 @@ int do_get_thread_area(struct task_struc memset(&info, 0, sizeof(struct user_desc)); info.entry_number = idx; - info.base_addr = get_desc_base((void *)desc); + info.base_addr = get_desc_base((struct desc_struct *)desc); info.limit = GET_LIMIT(desc); info.seg_32bit = GET_32BIT(desc); info.contents = GET_CONTENTS(desc); Index: linux-2.6-x86/arch/x86/mm/fault_32.c ==================================================================--- linux-2.6-x86.orig/arch/x86/mm/fault_32.c +++ linux-2.6-x86/arch/x86/mm/fault_32.c @@ -115,7 +115,7 @@ static inline unsigned long get_segment_ } /* Decode the code segment base from the descriptor */ - base = get_desc_base((unsigned long *)desc); + base = get_desc_base((struct desc_struct *)desc); if (seg & (1<<2)) { mutex_unlock(¤t->mm->context.lock); Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -69,6 +69,11 @@ static inline void load_LDT(mm_context_t preempt_enable(); } +static inline unsigned long get_desc_base(struct desc_struct *desc) +{ + return desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24); +} + #else /* * GET_DESC_BASE reads the descriptor base of the specified segment. Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ linux-2.6-x86/include/asm-x86/desc_32.h @@ -168,14 +168,6 @@ static inline void __set_tss_desc(unsign #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) -static inline unsigned long get_desc_base(unsigned long *desc) -{ - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} #endif /* !__ASSEMBLY__ */ #endif Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -156,15 +156,6 @@ static inline void load_TLS(struct threa gdt[i] = t->tls_array[i]; } -static inline unsigned long get_desc_base(const void *ptr) -{ - const u32 *desc = ptr; - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} #endif /* !__ASSEMBLY__ */ #endif
Glauber de Oliveira Costa
2007-Dec-12 21:18 UTC
[PATCH 17/19] unify paravirt pieces of descriptor handling
With the types used to access descriptors in x86_64 and i386 now being the same, the code that effectively handles them can now be easily shared. This patch moves the paravirt part of desc_32.h into desc.h, and then, we get paravirt support in x86_64 for free. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 169 +++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/desc_32.h | 130 --------------------------------- include/asm-x86/desc_64.h | 104 +++------------------------ include/asm-x86/desc_defs.h | 6 +- 4 files changed, 183 insertions(+), 226 deletions(-) Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ linux-2.6-x86/include/asm-x86/desc_32.h @@ -8,31 +8,10 @@ #ifndef __ASSEMBLY__ #include <linux/preempt.h> -#include <linux/smp.h> #include <linux/percpu.h> -struct gdt_page -{ - struct desc_struct gdt[GDT_ENTRIES]; -} __attribute__((aligned(PAGE_SIZE))); -DECLARE_PER_CPU(struct gdt_page, gdt_page); - -static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) -{ - return per_cpu(gdt_page, cpu).gdt; -} - extern void set_intr_gate(unsigned int irq, void * addr); -static inline void pack_descriptor(struct desc_struct *desc, - unsigned long base, unsigned long limit, unsigned char type, unsigned char flags) -{ - desc->a = ((base & 0xffff) << 16) | (limit & 0xffff); - desc->b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | - (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20); - desc->p = 1; -} - static inline void pack_gate(gate_desc *gate, unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) { @@ -40,115 +19,6 @@ static inline void pack_gate(gate_desc * gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } -#ifdef CONFIG_PARAVIRT -#include <asm/paravirt.h> -#else -#define load_TR_desc() native_load_tr_desc() -#define load_gdt(dtr) native_load_gdt(dtr) -#define load_idt(dtr) native_load_idt(dtr) -#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) -#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) - -#define store_gdt(dtr) native_store_gdt(dtr) -#define store_idt(dtr) native_store_idt(dtr) -#define store_tr(tr) (tr = native_store_tr()) -#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) - -#define load_TLS(t, cpu) native_load_tls(t, cpu) -#define set_ldt native_set_ldt - -#define write_ldt_entry(dt, entry, desc) \ - native_write_ldt_entry(dt, entry, desc) -#define write_gdt_entry(dt, entry, desc, type) \ - native_write_gdt_entry(dt, entry, desc, type) -#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) -#endif - -static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, - const void *desc) -{ - memcpy(&ldt[entry], desc, sizeof(struct desc_struct)); -} - -static inline void native_write_idt_entry(gate_desc *idt, int entry, - const gate_desc *gate) -{ - memcpy(&idt[entry], gate, sizeof(*gate)); -} - -static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, - const void *desc, int type) -{ - memcpy(&gdt[entry], desc, sizeof(struct desc_struct)); -} - -static inline void write_dt_entry(struct desc_struct *dt, - int entry, u32 entry_low, u32 entry_high) -{ - dt[entry].a = entry_low; - dt[entry].b = entry_high; -} - - -static inline void native_set_ldt(const void *addr, unsigned int entries) -{ - if (likely(entries == 0)) - __asm__ __volatile__("lldt %w0"::"q" (0)); - else { - unsigned cpu = smp_processor_id(); - ldt_desc ldt; - - pack_descriptor(&ldt, (unsigned long)addr, - entries * sizeof(struct desc_struct) - 1, - DESC_LDT, 0); - write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, - &ldt, DESC_LDT); - __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); - } -} - - -static inline void native_load_tr_desc(void) -{ - asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); -} - -static inline void native_load_gdt(const struct desc_ptr *dtr) -{ - asm volatile("lgdt %0"::"m" (*dtr)); -} - -static inline void native_load_idt(const struct desc_ptr *dtr) -{ - asm volatile("lidt %0"::"m" (*dtr)); -} - -static inline void native_store_gdt(struct desc_ptr *dtr) -{ - asm ("sgdt %0":"=m" (*dtr)); -} - -static inline void native_store_idt(struct desc_ptr *dtr) -{ - asm ("sidt %0":"=m" (*dtr)); -} - -static inline unsigned long native_store_tr(void) -{ - unsigned long tr; - asm ("str %0":"=r" (tr)); - return tr; -} - -static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) -{ - unsigned int i; - struct desc_struct *gdt = get_cpu_gdt_table(cpu); - - for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) - gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; -} - static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) { gate_desc g; Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -8,47 +8,10 @@ #ifndef __ASSEMBLY__ #include <linux/string.h> -#include <linux/smp.h> #include <asm/segment.h> -extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; - -#define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8)) -#define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8)) - -static inline unsigned long __store_tr(void) -{ - unsigned long tr; - - asm volatile ("str %w0":"=r" (tr)); - return tr; -} - -#define store_tr(tr) (tr) = __store_tr() - -extern struct desc_ptr cpu_gdt_descr[]; - -static inline void write_ldt_entry(struct desc_struct *ldt, - int entry, void *ptr) -{ - memcpy(&ldt[entry], ptr, 8); -} - -/* the cpu gdt accessor */ -#define get_cpu_gdt_table(x) ((struct desc_struct *)cpu_gdt_descr[x].address) - -static inline void load_gdt(const struct desc_ptr *ptr) -{ - asm volatile("lgdt %w0"::"m" (*ptr)); -} - -static inline void store_gdt(struct desc_ptr *ptr) -{ - asm("sgdt %w0":"=m" (*ptr)); -} - -static inline void _set_gate(void *adr, unsigned type, unsigned long func, +static inline void _set_gate(int gate, unsigned type, unsigned long func, unsigned dpl, unsigned ist) { gate_desc s; @@ -67,61 +30,37 @@ static inline void _set_gate(void *adr, * does not need to be atomic because it is only done once at * setup time */ - memcpy(adr, &s, 16); + write_idt_entry(idt_table, gate, &s); } static inline void set_intr_gate(int nr, void *func) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 0, 0); } static inline void set_intr_gate_ist(int nr, void *func, unsigned ist) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 0, ist); } static inline void set_system_gate(int nr, void *func) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 3, 0); } static inline void set_system_gate_ist(int nr, void *func, unsigned ist) { - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist); -} - -static inline void load_idt(const struct desc_ptr *ptr) -{ - asm volatile("lidt %w0"::"m" (*ptr)); -} - -static inline void store_idt(struct desc_ptr *dtr) -{ - asm("sidt %w0":"=m" (*dtr)); -} - -static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, - unsigned type, unsigned size) -{ - struct ldttss_desc64 d; - - memset(&d, 0, sizeof(d)); - d.limit0 = size & 0xFFFF; - d.base0 = PTR_LOW(tss); - d.base1 = PTR_MIDDLE(tss) & 0xFF; - d.type = type; - d.p = 1; - d.limit1 = (size >> 16) & 0xF; - d.base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF; - d.base3 = PTR_HIGH(tss); - memcpy(ptr, &d, 16); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 3, ist); } static inline void set_tss_desc(unsigned cpu, void *addr) { + struct desc_struct *d = get_cpu_gdt_table(cpu); + tss_desc tss; + /* * sizeof(unsigned long) coming from an extra "long" at the end * of the iobitmap. See tss_struct definition in processor.h @@ -129,31 +68,10 @@ static inline void set_tss_desc(unsigned * -1? seg base+limit should be pointing to the address of the * last valid byte */ - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS], + set_tssldt_descriptor(&tss, (unsigned long)addr, DESC_TSS, IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); -} - -static inline void set_ldt(void *addr, int entries) -{ - if (likely(entries == 0)) - __asm__ __volatile__("lldt %w0"::"q" (0)); - else { - unsigned cpu = smp_processor_id(); - - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], - (unsigned long)addr, DESC_LDT, entries * 8 - 1); - __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); - } -} - -static inline void load_TLS(struct thread_struct *t, unsigned int cpu) -{ - unsigned int i; - struct desc_struct *gdt = (get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); - - for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) - gdt[i] = t->tls_array[i]; + write_gdt_entry(d, GDT_ENTRY_TSS, &tss, DESC_TSS); } #endif /* !__ASSEMBLY__ */ Index: linux-2.6-x86/include/asm-x86/desc_defs.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_defs.h +++ linux-2.6-x86/include/asm-x86/desc_defs.h @@ -48,9 +48,9 @@ struct gate_struct64 { u32 zero1; } __attribute__((packed)); -#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF) -#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF) -#define PTR_HIGH(x) ((unsigned long)(x) >> 32) +#define PTR_LOW(x) ((unsigned long long)(x) & 0xFFFF) +#define PTR_MIDDLE(x) (((unsigned long long)(x) >> 16) & 0xFFFF) +#define PTR_HIGH(x) ((unsigned long long)(x) >> 32) enum { DESC_TSS = 0x9, Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -5,6 +5,7 @@ #include <asm/desc_defs.h> #include <asm/ldt.h> #include <asm/mmu.h> +#include <linux/smp.h> static inline void fill_ldt(struct desc_struct *desc, struct user_desc *info) { @@ -27,6 +28,174 @@ static inline void fill_ldt(struct desc_ extern struct desc_ptr idt_descr; extern gate_desc idt_table[]; +#ifdef CONFIG_X86_64 +extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; +extern struct desc_ptr cpu_gdt_descr[]; +/* the cpu gdt accessor */ +#define get_cpu_gdt_table(x) ((struct desc_struct *)cpu_gdt_descr[x].address) +#else +struct gdt_page { + struct desc_struct gdt[GDT_ENTRIES]; +} __attribute__((aligned(PAGE_SIZE))); +DECLARE_PER_CPU(struct gdt_page, gdt_page); + +static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) +{ + return per_cpu(gdt_page, cpu).gdt; +} +#endif + +#ifdef CONFIG_PARAVIRT +#include <asm/paravirt.h> +#else +#define load_TR_desc() native_load_tr_desc() +#define load_gdt(dtr) native_load_gdt(dtr) +#define load_idt(dtr) native_load_idt(dtr) +#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) +#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) + +#define store_gdt(dtr) native_store_gdt(dtr) +#define store_idt(dtr) native_store_idt(dtr) +#define store_tr(tr) (tr = native_store_tr()) +#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) + +#define load_TLS(t, cpu) native_load_tls(t, cpu) +#define set_ldt native_set_ldt + +#define write_ldt_entry(dt, entry, desc) \ + native_write_ldt_entry(dt, entry, desc) +#define write_gdt_entry(dt, entry, desc, type) \ + native_write_gdt_entry(dt, entry, desc, type) +#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) +#endif + +static inline void native_write_idt_entry(gate_desc *idt, int entry, + const gate_desc *gate) +{ + memcpy(&idt[entry], gate, sizeof(*gate)); +} + +static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, + const void *desc) +{ + memcpy(&ldt[entry], desc, 8); +} + +static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, + const void *desc, int type) +{ + unsigned int size; + switch (type) { + case DESC_TSS: + size = sizeof(tss_desc); + break; + case DESC_LDT: + size = sizeof(ldt_desc); + break; + default: + size = sizeof(struct desc_struct); + break; + } + memcpy(&gdt[entry], desc, size); +} + +static inline void set_tssldt_descriptor(struct ldttss_desc64 *d, + unsigned long tss, unsigned type, + unsigned size) +{ + memset(d, 0, sizeof(*d)); + d->limit0 = size & 0xFFFF; + d->base0 = PTR_LOW(tss); + d->base1 = PTR_MIDDLE(tss) & 0xFF; + d->type = type; + d->p = 1; + d->limit1 = (size >> 16) & 0xF; + d->base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF; + d->base3 = PTR_HIGH(tss); +} + +static inline void pack_descriptor(struct desc_struct *desc, unsigned long base, + unsigned long limit, unsigned char type, + unsigned char flags) +{ + desc->a = ((base & 0xffff) << 16) | (limit & 0xffff); + desc->b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | + (limit & 0x000f0000) | ((type & 0xff) << 8) | + ((flags & 0xf) << 20); + desc->p = 1; +} + +static inline void pack_ldt(ldt_desc *ldt, unsigned long addr, + unsigned size) +{ + +#ifdef CONFIG_X86_64 + set_tssldt_descriptor(ldt, + addr, DESC_LDT, size); +#else + pack_descriptor(ldt, (unsigned long)addr, + size, + 0x80 | DESC_LDT, 0); +#endif +} + +static inline void native_set_ldt(const void *addr, unsigned int entries) +{ + if (likely(entries == 0)) + __asm__ __volatile__("lldt %w0"::"q" (0)); + else { + unsigned cpu = smp_processor_id(); + ldt_desc ldt; + + pack_ldt(&ldt, (unsigned long)addr, + entries * sizeof(ldt) - 1); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, + &ldt, DESC_LDT); + __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); + } +} + +static inline void native_load_tr_desc(void) +{ + asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); +} + +static inline void native_load_gdt(const struct desc_ptr *dtr) +{ + asm volatile("lgdt %0"::"m" (*dtr)); +} + +static inline void native_load_idt(const struct desc_ptr *dtr) +{ + asm volatile("lidt %0"::"m" (*dtr)); +} + +static inline void native_store_gdt(struct desc_ptr *dtr) +{ + asm volatile("sgdt %0":"=m" (*dtr)); +} + +static inline void native_store_idt(struct desc_ptr *dtr) +{ + asm volatile("sidt %0":"=m" (*dtr)); +} + +static inline unsigned long native_store_tr(void) +{ + unsigned long tr; + asm volatile("str %0":"=r" (tr)); + return tr; +} + +static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) +{ + unsigned int i; + struct desc_struct *gdt = get_cpu_gdt_table(cpu); + + for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) + gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; +} + #ifdef CONFIG_X86_32 # include "desc_32.h" #else
Since the last version of it received no comments on the interfaces, here it goes a version, that I feel ready for inclusion. The comments regarding style, specially the elimination of the #defines in the desc_struct definition were merged. I also implemented the vmi functions, missing last time. Ingo, in the absense of further complaints, could you please push to the x86 tree?
Glauber de Oliveira Costa
2007-Dec-13 08:43 UTC
[PATCH 15/19] use the same data type for tls_array.
This patch changes the type of tls_array in x86_64 to a desc_struct. Now, both i386 and x86_64 tls_array have the same type, and code accessing it can be shared. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 2 +- include/asm-x86/processor_64.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 2dc19e2..7fd9876 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -150,7 +150,7 @@ static inline void set_ldt(void *addr, int entries) static inline void load_TLS(struct thread_struct *t, unsigned int cpu) { unsigned int i; - u64 *gdt = (u64 *)(get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); + struct desc_struct *gdt = (get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) gdt[i] = t->tls_array[i]; diff --git a/include/asm-x86/processor_64.h b/include/asm-x86/processor_64.h index 8efdf99..51f1970 100644 --- a/include/asm-x86/processor_64.h +++ b/include/asm-x86/processor_64.h @@ -19,6 +19,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 @@ -244,7 +245,7 @@ struct thread_struct { * goes into MSR_IA32_DS_AREA */ unsigned long ds_area_msr; /* 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 { \ -- 1.5.0.6
Glauber de Oliveira Costa
2007-Dec-13 08:43 UTC
[PATCH 14/19] unify non-paravirt parts of desc.h
This patch unifies the non-paravirt part of desc_{32,64}.h into desc.h. Most of it, is simply common code, that is moved to the shared header. The only exception is the set_ldt_desc in desc_64.h, which is changed - included its name - to accomodate for the way the ldt is set up in i386. Also, constant definitions used in desc_32.h are moved to desc_defs.h Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 87 ++++++++++++++++++++++++++++++++++++++ include/asm-x86/desc_32.h | 66 ---------------------------- include/asm-x86/desc_64.h | 64 ++++----------------------- include/asm-x86/mmu_context_64.h | 4 +- 4 files changed, 99 insertions(+), 122 deletions(-) Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -4,6 +4,7 @@ #ifndef __ASSEMBLY__ #include <asm/desc_defs.h> #include <asm/ldt.h> +#include <asm/mmu.h> static inline void fill_ldt(struct desc_struct *desc, struct user_desc *info) { @@ -23,7 +24,8 @@ static inline void fill_ldt(struct desc_ desc->base2 = (info->base_addr & 0xff000000) >> 24; } -#endif +extern struct desc_ptr idt_descr; +extern gate_desc idt_table[]; #ifdef CONFIG_X86_32 # include "desc_32.h" @@ -31,4 +33,65 @@ static inline void fill_ldt(struct desc_ # include "desc_64.h" #endif +#define _LDT_empty(info) (\ + (info)->base_addr == 0 && \ + (info)->limit == 0 && \ + (info)->contents == 0 && \ + (info)->read_exec_only == 1 && \ + (info)->seg_32bit == 0 && \ + (info)->limit_in_pages == 0 && \ + (info)->seg_not_present == 1 && \ + (info)->useable == 0) + +#ifdef CONFIG_X86_64 +#define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0)) +#else +#define LDT_empty(info) (_LDT_empty(info)) +#endif + +static inline void clear_LDT(void) +{ + set_ldt(NULL, 0); +} + +/* + * load one particular LDT into the current CPU + */ +static inline void load_LDT_nolock(mm_context_t *pc) +{ + set_ldt(pc->ldt, pc->size); +} + +static inline void load_LDT(mm_context_t *pc) +{ + preempt_disable(); + load_LDT_nolock(pc); + preempt_enable(); +} + +#else +/* + * GET_DESC_BASE reads the descriptor base of the specified segment. + * + * Args: + * idx - descriptor index + * gdt - GDT pointer + * base - 32bit register to which the base will be written + * lo_w - lo word of the "base" register + * lo_b - lo byte of the "base" register + * hi_b - hi byte of the low word of the "base" register + * + * Example: + * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) + * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. + */ +#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ + movb idx*8+4(gdt), lo_b; \ + movb idx*8+7(gdt), hi_b; \ + shll $16, base; \ + movw idx*8+2(gdt), lo_w; + + +#endif /* __ASSEMBLY__ */ + #endif Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ linux-2.6-x86/include/asm-x86/desc_32.h @@ -11,8 +11,6 @@ #include <linux/smp.h> #include <linux/percpu.h> -#include <asm/mmu.h> - struct gdt_page { struct desc_struct gdt[GDT_ENTRIES]; @@ -24,8 +22,6 @@ static inline struct desc_struct *get_cp return per_cpu(gdt_page, cpu).gdt; } -extern struct desc_ptr idt_descr; -extern gate_desc idt_table[]; extern void set_intr_gate(unsigned int irq, void * addr); static inline void pack_descriptor(struct desc_struct *desc, @@ -172,36 +168,6 @@ static inline void __set_tss_desc(unsign #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) -#define LDT_empty(info) (\ - (info)->base_addr == 0 && \ - (info)->limit == 0 && \ - (info)->contents == 0 && \ - (info)->read_exec_only == 1 && \ - (info)->seg_32bit == 0 && \ - (info)->limit_in_pages == 0 && \ - (info)->seg_not_present == 1 && \ - (info)->useable == 0 ) - -static inline void clear_LDT(void) -{ - set_ldt(NULL, 0); -} - -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc) -{ - set_ldt(pc->ldt, pc->size); -} - -static inline void load_LDT(mm_context_t *pc) -{ - preempt_disable(); - load_LDT_nolock(pc); - preempt_enable(); -} - static inline unsigned long get_desc_base(unsigned long *desc) { unsigned long base; @@ -210,30 +176,6 @@ static inline unsigned long get_desc_bas (desc[1] & 0xff000000); return base; } - -#else /* __ASSEMBLY__ */ - -/* - * GET_DESC_BASE reads the descriptor base of the specified segment. - * - * Args: - * idx - descriptor index - * gdt - GDT pointer - * base - 32bit register to which the base will be written - * lo_w - lo word of the "base" register - * lo_b - lo byte of the "base" register - * hi_b - hi byte of the low word of the "base" register - * - * Example: - * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) - * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. - */ -#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ - movb idx*8+4(gdt), lo_b; \ - movb idx*8+7(gdt), hi_b; \ - shll $16, base; \ - movw idx*8+2(gdt), lo_w; - #endif /* !__ASSEMBLY__ */ #endif Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -9,16 +9,13 @@ #include <linux/string.h> #include <linux/smp.h> -#include <asm/desc_defs.h> #include <asm/segment.h> -#include <asm/mmu.h> extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; #define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8)) #define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8)) -#define clear_LDT() asm volatile("lldt %w0"::"r" (0)) static inline unsigned long __store_tr(void) { @@ -30,7 +27,6 @@ static inline unsigned long __store_tr(v #define store_tr(tr) (tr) = __store_tr() -extern gate_desc idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; static inline void write_ldt_entry(struct desc_struct *ldt, @@ -138,23 +134,19 @@ static inline void set_tss_desc(unsigned IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); } -static inline void set_ldt_desc(unsigned cpu, void *addr, int size) +static inline void set_ldt(void *addr, int entries) { - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], - (unsigned long)addr, DESC_LDT, size * 8 - 1); + if (likely(entries == 0)) + __asm__ __volatile__("lldt %w0"::"q" (0)); + else { + unsigned cpu = smp_processor_id(); + + set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], + (unsigned long)addr, DESC_LDT, entries * 8 - 1); + __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); + } } -#define LDT_empty(info) (\ - (info)->base_addr == 0 && \ - (info)->limit == 0 && \ - (info)->contents == 0 && \ - (info)->read_exec_only == 1 && \ - (info)->seg_32bit == 0 && \ - (info)->limit_in_pages == 0 && \ - (info)->seg_not_present == 1 && \ - (info)->useable == 0 && \ - (info)->lm == 0) - static inline void load_TLS(struct thread_struct *t, unsigned int cpu) { unsigned int i; @@ -164,32 +156,6 @@ static inline void load_TLS(struct threa gdt[i] = t->tls_array[i]; } -/* - * load one particular LDT into the current CPU - */ -static inline void load_LDT_nolock(mm_context_t *pc, int cpu) -{ - int count = pc->size; - - if (likely(!count)) { - clear_LDT(); - return; - } - - set_ldt_desc(cpu, pc->ldt, count); - load_LDT_desc(); -} - -static inline void load_LDT(mm_context_t *pc) -{ - int cpu = get_cpu(); - - load_LDT_nolock(pc, cpu); - put_cpu(); -} - -extern struct desc_ptr idt_descr; - static inline unsigned long get_desc_base(const void *ptr) { const u32 *desc = ptr; @@ -199,7 +165,6 @@ static inline unsigned long get_desc_bas (desc[1] & 0xff000000); return base; } - #endif /* !__ASSEMBLY__ */ #endif Index: linux-2.6-x86/include/asm-x86/mmu_context_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/mmu_context_64.h +++ linux-2.6-x86/include/asm-x86/mmu_context_64.h @@ -43,7 +43,7 @@ static inline void switch_mm(struct mm_s load_cr3(next->pgd); if (unlikely(next->context.ldt != prev->context.ldt)) - load_LDT_nolock(&next->context, cpu); + load_LDT_nolock(&next->context); } #ifdef CONFIG_SMP else { @@ -56,7 +56,7 @@ static inline void switch_mm(struct mm_s * to make sure to use no freed page tables. */ load_cr3(next->pgd); - load_LDT_nolock(&next->context, cpu); + load_LDT_nolock(&next->context); } } #endif
This patch makes get_desc_base() receive a struct desc_struct, and then uses its internal fields to compute the base address. This is done at both i386 and x86_64, and then it is moved to common header Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/tls.c | 2 +- arch/x86/mm/fault_32.c | 2 +- include/asm-x86/desc.h | 8 ++------ 3 files changed, 4 insertions(+), 8 deletions(-) Index: linux-2.6-x86/arch/x86/kernel/tls.c ==================================================================--- linux-2.6-x86.orig/arch/x86/kernel/tls.c +++ linux-2.6-x86/arch/x86/kernel/tls.c @@ -112,7 +112,7 @@ int do_get_thread_area(struct task_struc memset(&info, 0, sizeof(struct user_desc)); info.entry_number = idx; - info.base_addr = get_desc_base((void *)desc); + info.base_addr = get_desc_base((struct desc_struct *)desc); info.limit = GET_LIMIT(desc); info.seg_32bit = GET_32BIT(desc); info.contents = GET_CONTENTS(desc); Index: linux-2.6-x86/arch/x86/mm/fault_32.c ==================================================================--- linux-2.6-x86.orig/arch/x86/mm/fault_32.c +++ linux-2.6-x86/arch/x86/mm/fault_32.c @@ -115,7 +115,7 @@ static inline unsigned long get_segment_ } /* Decode the code segment base from the descriptor */ - base = get_desc_base((unsigned long *)desc); + base = get_desc_base((struct desc_struct *)desc); if (seg & (1<<2)) { mutex_unlock(¤t->mm->context.lock); Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -69,6 +69,11 @@ static inline void load_LDT(mm_context_t preempt_enable(); } +static inline unsigned long get_desc_base(struct desc_struct *desc) +{ + return desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24); +} + #else /* * GET_DESC_BASE reads the descriptor base of the specified segment. Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ linux-2.6-x86/include/asm-x86/desc_32.h @@ -168,14 +168,6 @@ static inline void __set_tss_desc(unsign #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) -static inline unsigned long get_desc_base(unsigned long *desc) -{ - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} #endif /* !__ASSEMBLY__ */ #endif Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -156,15 +156,6 @@ static inline void load_TLS(struct threa gdt[i] = t->tls_array[i]; } -static inline unsigned long get_desc_base(const void *ptr) -{ - const u32 *desc = ptr; - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} #endif /* !__ASSEMBLY__ */ #endif
Glauber de Oliveira Costa
2007-Dec-13 08:43 UTC
[PATCH 13/19] move constants to desc_defs.h
this patch moves constant definitions regarding descriptor types from desc_32.h to desc_defs.h. The change from defines to enum to comply with previous versions in desc_defs.h Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_32.h | 8 -------- include/asm-x86/desc_defs.h | 5 +++++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 92a72b0..14238df 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -44,14 +44,6 @@ static inline void pack_gate(gate_desc *gate, gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } -#define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ -#define DESCTYPE_TSS 0x89 /* present, system, DPL-0, 32-bit TSS */ -#define DESCTYPE_TASK 0x85 /* present, system, DPL-0, task gate */ -#define DESCTYPE_INT 0x8e /* present, system, DPL-0, interrupt gate */ -#define DESCTYPE_TRAP 0x8f /* present, system, DPL-0, trap gate */ -#define DESCTYPE_DPL3 0x60 /* DPL-3 */ -#define DESCTYPE_S 0x10 /* !system */ - #ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> #else diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index c4d7874..5ca416d 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -55,6 +55,11 @@ struct gate_struct64 { enum { DESC_TSS = 0x9, DESC_LDT = 0x2, + DESCTYPE_TASK = 0x85, /* present, system, DPL-0, task gate */ + DESCTYPE_INT = 0x8e, /* present, system, DPL-0, interrupt gate */ + DESCTYPE_TRAP = 0x8f, /* present, system, DPL-0, trap gate */ + DESCTYPE_DPL3 = 0x60, /* DPL-3 */ + DESCTYPE_S = 0x10, /* !system */ }; // LDT or TSS descriptor in the GDT. 16 bytes. -- 1.5.0.6
Glauber de Oliveira Costa
2007-Dec-13 08:43 UTC
[PATCH 17/19] unify paravirt pieces of descriptor handling
With the types used to access descriptors in x86_64 and i386 now being the same, the code that effectively handles them can now be easily shared. This patch moves the paravirt part of desc_32.h into desc.h, and then, we get paravirt support in x86_64 for free. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 169 +++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/desc_32.h | 130 --------------------------------- include/asm-x86/desc_64.h | 104 +++------------------------ include/asm-x86/desc_defs.h | 6 +- 4 files changed, 183 insertions(+), 226 deletions(-) Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ linux-2.6-x86/include/asm-x86/desc_32.h @@ -8,31 +8,10 @@ #ifndef __ASSEMBLY__ #include <linux/preempt.h> -#include <linux/smp.h> #include <linux/percpu.h> -struct gdt_page -{ - struct desc_struct gdt[GDT_ENTRIES]; -} __attribute__((aligned(PAGE_SIZE))); -DECLARE_PER_CPU(struct gdt_page, gdt_page); - -static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) -{ - return per_cpu(gdt_page, cpu).gdt; -} - extern void set_intr_gate(unsigned int irq, void * addr); -static inline void pack_descriptor(struct desc_struct *desc, - unsigned long base, unsigned long limit, unsigned char type, unsigned char flags) -{ - desc->a = ((base & 0xffff) << 16) | (limit & 0xffff); - desc->b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | - (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20); - desc->p = 1; -} - static inline void pack_gate(gate_desc *gate, unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) { @@ -40,115 +19,6 @@ static inline void pack_gate(gate_desc * gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } -#ifdef CONFIG_PARAVIRT -#include <asm/paravirt.h> -#else -#define load_TR_desc() native_load_tr_desc() -#define load_gdt(dtr) native_load_gdt(dtr) -#define load_idt(dtr) native_load_idt(dtr) -#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) -#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) - -#define store_gdt(dtr) native_store_gdt(dtr) -#define store_idt(dtr) native_store_idt(dtr) -#define store_tr(tr) (tr = native_store_tr()) -#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) - -#define load_TLS(t, cpu) native_load_tls(t, cpu) -#define set_ldt native_set_ldt - -#define write_ldt_entry(dt, entry, desc) \ - native_write_ldt_entry(dt, entry, desc) -#define write_gdt_entry(dt, entry, desc, type) \ - native_write_gdt_entry(dt, entry, desc, type) -#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) -#endif - -static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, - const void *desc) -{ - memcpy(&ldt[entry], desc, sizeof(struct desc_struct)); -} - -static inline void native_write_idt_entry(gate_desc *idt, int entry, - const gate_desc *gate) -{ - memcpy(&idt[entry], gate, sizeof(*gate)); -} - -static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, - const void *desc, int type) -{ - memcpy(&gdt[entry], desc, sizeof(struct desc_struct)); -} - -static inline void write_dt_entry(struct desc_struct *dt, - int entry, u32 entry_low, u32 entry_high) -{ - dt[entry].a = entry_low; - dt[entry].b = entry_high; -} - - -static inline void native_set_ldt(const void *addr, unsigned int entries) -{ - if (likely(entries == 0)) - __asm__ __volatile__("lldt %w0"::"q" (0)); - else { - unsigned cpu = smp_processor_id(); - ldt_desc ldt; - - pack_descriptor(&ldt, (unsigned long)addr, - entries * sizeof(struct desc_struct) - 1, - DESC_LDT, 0); - write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, - &ldt, DESC_LDT); - __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); - } -} - - -static inline void native_load_tr_desc(void) -{ - asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); -} - -static inline void native_load_gdt(const struct desc_ptr *dtr) -{ - asm volatile("lgdt %0"::"m" (*dtr)); -} - -static inline void native_load_idt(const struct desc_ptr *dtr) -{ - asm volatile("lidt %0"::"m" (*dtr)); -} - -static inline void native_store_gdt(struct desc_ptr *dtr) -{ - asm ("sgdt %0":"=m" (*dtr)); -} - -static inline void native_store_idt(struct desc_ptr *dtr) -{ - asm ("sidt %0":"=m" (*dtr)); -} - -static inline unsigned long native_store_tr(void) -{ - unsigned long tr; - asm ("str %0":"=r" (tr)); - return tr; -} - -static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) -{ - unsigned int i; - struct desc_struct *gdt = get_cpu_gdt_table(cpu); - - for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) - gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; -} - static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) { gate_desc g; Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -8,47 +8,10 @@ #ifndef __ASSEMBLY__ #include <linux/string.h> -#include <linux/smp.h> #include <asm/segment.h> -extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; - -#define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8)) -#define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8)) - -static inline unsigned long __store_tr(void) -{ - unsigned long tr; - - asm volatile ("str %w0":"=r" (tr)); - return tr; -} - -#define store_tr(tr) (tr) = __store_tr() - -extern struct desc_ptr cpu_gdt_descr[]; - -static inline void write_ldt_entry(struct desc_struct *ldt, - int entry, void *ptr) -{ - memcpy(&ldt[entry], ptr, 8); -} - -/* the cpu gdt accessor */ -#define get_cpu_gdt_table(x) ((struct desc_struct *)cpu_gdt_descr[x].address) - -static inline void load_gdt(const struct desc_ptr *ptr) -{ - asm volatile("lgdt %w0"::"m" (*ptr)); -} - -static inline void store_gdt(struct desc_ptr *ptr) -{ - asm("sgdt %w0":"=m" (*ptr)); -} - -static inline void _set_gate(void *adr, unsigned type, unsigned long func, +static inline void _set_gate(int gate, unsigned type, unsigned long func, unsigned dpl, unsigned ist) { gate_desc s; @@ -67,61 +30,37 @@ static inline void _set_gate(void *adr, * does not need to be atomic because it is only done once at * setup time */ - memcpy(adr, &s, 16); + write_idt_entry(idt_table, gate, &s); } static inline void set_intr_gate(int nr, void *func) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 0, 0); } static inline void set_intr_gate_ist(int nr, void *func, unsigned ist) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 0, ist); } static inline void set_system_gate(int nr, void *func) { BUG_ON((unsigned)nr > 0xFF); - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 3, 0); } static inline void set_system_gate_ist(int nr, void *func, unsigned ist) { - _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist); -} - -static inline void load_idt(const struct desc_ptr *ptr) -{ - asm volatile("lidt %w0"::"m" (*ptr)); -} - -static inline void store_idt(struct desc_ptr *dtr) -{ - asm("sidt %w0":"=m" (*dtr)); -} - -static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, - unsigned type, unsigned size) -{ - struct ldttss_desc64 d; - - memset(&d, 0, sizeof(d)); - d.limit0 = size & 0xFFFF; - d.base0 = PTR_LOW(tss); - d.base1 = PTR_MIDDLE(tss) & 0xFF; - d.type = type; - d.p = 1; - d.limit1 = (size >> 16) & 0xF; - d.base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF; - d.base3 = PTR_HIGH(tss); - memcpy(ptr, &d, 16); + _set_gate(nr, GATE_INTERRUPT, (unsigned long) func, 3, ist); } static inline void set_tss_desc(unsigned cpu, void *addr) { + struct desc_struct *d = get_cpu_gdt_table(cpu); + tss_desc tss; + /* * sizeof(unsigned long) coming from an extra "long" at the end * of the iobitmap. See tss_struct definition in processor.h @@ -129,31 +68,10 @@ static inline void set_tss_desc(unsigned * -1? seg base+limit should be pointing to the address of the * last valid byte */ - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS], + set_tssldt_descriptor(&tss, (unsigned long)addr, DESC_TSS, IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); -} - -static inline void set_ldt(void *addr, int entries) -{ - if (likely(entries == 0)) - __asm__ __volatile__("lldt %w0"::"q" (0)); - else { - unsigned cpu = smp_processor_id(); - - set_tssldt_descriptor(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], - (unsigned long)addr, DESC_LDT, entries * 8 - 1); - __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); - } -} - -static inline void load_TLS(struct thread_struct *t, unsigned int cpu) -{ - unsigned int i; - struct desc_struct *gdt = (get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN); - - for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) - gdt[i] = t->tls_array[i]; + write_gdt_entry(d, GDT_ENTRY_TSS, &tss, DESC_TSS); } #endif /* !__ASSEMBLY__ */ Index: linux-2.6-x86/include/asm-x86/desc_defs.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_defs.h +++ linux-2.6-x86/include/asm-x86/desc_defs.h @@ -48,9 +48,9 @@ struct gate_struct64 { u32 zero1; } __attribute__((packed)); -#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF) -#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF) -#define PTR_HIGH(x) ((unsigned long)(x) >> 32) +#define PTR_LOW(x) ((unsigned long long)(x) & 0xFFFF) +#define PTR_MIDDLE(x) (((unsigned long long)(x) >> 16) & 0xFFFF) +#define PTR_HIGH(x) ((unsigned long long)(x) >> 32) enum { DESC_TSS = 0x9, Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -5,6 +5,7 @@ #include <asm/desc_defs.h> #include <asm/ldt.h> #include <asm/mmu.h> +#include <linux/smp.h> static inline void fill_ldt(struct desc_struct *desc, struct user_desc *info) { @@ -27,6 +28,166 @@ static inline void fill_ldt(struct desc_ extern struct desc_ptr idt_descr; extern gate_desc idt_table[]; +#ifdef CONFIG_X86_64 +extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; +extern struct desc_ptr cpu_gdt_descr[]; +/* the cpu gdt accessor */ +#define get_cpu_gdt_table(x) ((struct desc_struct *)cpu_gdt_descr[x].address) +#else +struct gdt_page { + struct desc_struct gdt[GDT_ENTRIES]; +} __attribute__((aligned(PAGE_SIZE))); +DECLARE_PER_CPU(struct gdt_page, gdt_page); + +static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) +{ + return per_cpu(gdt_page, cpu).gdt; +} +#endif + +#ifdef CONFIG_PARAVIRT +#include <asm/paravirt.h> +#else +#define load_TR_desc() native_load_tr_desc() +#define load_gdt(dtr) native_load_gdt(dtr) +#define load_idt(dtr) native_load_idt(dtr) +#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) +#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) + +#define store_gdt(dtr) native_store_gdt(dtr) +#define store_idt(dtr) native_store_idt(dtr) +#define store_tr(tr) (tr = native_store_tr()) +#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) + +#define load_TLS(t, cpu) native_load_tls(t, cpu) +#define set_ldt native_set_ldt + +#define write_ldt_entry(dt, entry, desc) \ + native_write_ldt_entry(dt, entry, desc) +#define write_gdt_entry(dt, entry, desc, type) \ + native_write_gdt_entry(dt, entry, desc, type) +#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) +#endif + +static inline void native_write_idt_entry(gate_desc *idt, int entry, + const gate_desc *gate) +{ + memcpy(&idt[entry], gate, sizeof(*gate)); +} + +static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, + const void *desc) +{ + memcpy(&ldt[entry], desc, 8); +} + +static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, + const void *desc, int type) +{ + unsigned int size; + switch (type) { + case DESC_TSS: + size = sizeof(tss_desc); + break; + case DESC_LDT: + size = sizeof(ldt_desc); + break; + default: + size = sizeof(struct desc_struct); + break; + } + memcpy(&gdt[entry], desc, size); +} + +static inline void pack_descriptor(struct desc_struct *desc, unsigned long base, + unsigned long limit, unsigned char type, + unsigned char flags) +{ + desc->a = ((base & 0xffff) << 16) | (limit & 0xffff); + desc->b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | + (limit & 0x000f0000) | ((type & 0xff) << 8) | + ((flags & 0xf) << 20); + desc->p = 1; +} + + +static inline void set_tssldt_descriptor(void *d, unsigned long addr, + unsigned type, unsigned size) +{ +#ifdef CONFIG_X86_64 + struct ldttss_desc64 *desc = d; + memset(desc, 0, sizeof(*desc)); + desc->limit0 = size & 0xFFFF; + desc->base0 = PTR_LOW(addr); + desc->base1 = PTR_MIDDLE(addr) & 0xFF; + desc->type = type; + desc->p = 1; + desc->limit1 = (size >> 16) & 0xF; + desc->base2 = (PTR_MIDDLE(addr) >> 8) & 0xFF; + desc->base3 = PTR_HIGH(addr); +#else + + pack_descriptor((struct desc_struct *)d, addr, size, 0x80 | type, 0); +#endif +} + +static inline void native_set_ldt(const void *addr, unsigned int entries) +{ + if (likely(entries == 0)) + __asm__ __volatile__("lldt %w0"::"q" (0)); + else { + unsigned cpu = smp_processor_id(); + ldt_desc ldt; + + set_tssldt_descriptor(&ldt, (unsigned long)addr, + DESC_LDT, entries * sizeof(ldt) - 1); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, + &ldt, DESC_LDT); + __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); + } +} + +static inline void native_load_tr_desc(void) +{ + asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); +} + +static inline void native_load_gdt(const struct desc_ptr *dtr) +{ + asm volatile("lgdt %0"::"m" (*dtr)); +} + +static inline void native_load_idt(const struct desc_ptr *dtr) +{ + asm volatile("lidt %0"::"m" (*dtr)); +} + +static inline void native_store_gdt(struct desc_ptr *dtr) +{ + asm volatile("sgdt %0":"=m" (*dtr)); +} + +static inline void native_store_idt(struct desc_ptr *dtr) +{ + asm volatile("sidt %0":"=m" (*dtr)); +} + +static inline unsigned long native_store_tr(void) +{ + unsigned long tr; + asm volatile("str %0":"=r" (tr)); + return tr; +} + +static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) +{ + unsigned int i; + struct desc_struct *gdt = get_cpu_gdt_table(cpu); + + for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) + gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; +} + #ifdef CONFIG_X86_32 # include "desc_32.h" #else
This patch unifies the set_tss_desc between i386 and x86_64, which can now have a common implementation. After the old functions are removed from desc_{32,64}.h, nothing important is left, and the files can be removed. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc.h | 40 +++++++++++++++++++++++++++++++++------- include/asm-x86/desc_32.h | 27 --------------------------- include/asm-x86/desc_64.h | 34 ---------------------------------- 3 files changed, 33 insertions(+), 68 deletions(-) delete mode 100644 include/asm-x86/desc_32.h delete mode 100644 include/asm-x86/desc_64.h Index: linux-2.6-x86/include/asm-x86/desc.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc.h +++ linux-2.6-x86/include/asm-x86/desc.h @@ -157,6 +157,26 @@ static inline void set_tssldt_descriptor #endif } +static inline void __set_tss_desc(unsigned cpu, unsigned int entry, void *addr) +{ + struct desc_struct *d = get_cpu_gdt_table(cpu); + tss_desc tss; + + /* + * sizeof(unsigned long) coming from an extra "long" at the end + * of the iobitmap. See tss_struct definition in processor.h + * + * -1? seg base+limit should be pointing to the address of the + * last valid byte + */ + set_tssldt_descriptor(&tss, (unsigned long)addr, + IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1, + DESC_TSS); + write_gdt_entry(d, entry, &tss, DESC_TSS); +} + +#define set_tss_desc(cpu, addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) + static inline void native_set_ldt(const void *addr, unsigned int entries) { if (likely(entries == 0)) @@ -214,12 +234,6 @@ static inline void native_load_tls(struc gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; } -#ifdef CONFIG_X86_32 -# include "desc_32.h" -#else -# include "desc_64.h" -#endif - #define _LDT_empty(info) (\ (info)->base_addr == 0 && \ (info)->limit == 0 && \ Index: linux-2.6-x86/include/asm-x86/desc_32.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_32.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __ARCH_DESC_H -#define __ARCH_DESC_H - -#include <asm/ldt.h> -#include <asm/segment.h> -#include <asm/desc_defs.h> - -#ifndef __ASSEMBLY__ - -#include <linux/preempt.h> -#include <linux/percpu.h> - -static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) -{ - tss_desc tss; - pack_descriptor(&tss, (unsigned long)addr, - offsetof(struct tss_struct, __cacheline_filler) - 1, - DESC_TSS, 0); - write_gdt_entry(get_cpu_gdt_table(cpu), entry, &tss, DESC_TSS); -} - - -#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) - -#endif /* !__ASSEMBLY__ */ - -#endif Index: linux-2.6-x86/include/asm-x86/desc_64.h ==================================================================--- linux-2.6-x86.orig/include/asm-x86/desc_64.h +++ linux-2.6-x86/include/asm-x86/desc_64.h @@ -1,34 +1 @@ -/* Written 2000 by Andi Kleen */ -#ifndef __ARCH_DESC_H -#define __ARCH_DESC_H -#include <linux/threads.h> -#include <asm/ldt.h> - -#ifndef __ASSEMBLY__ - -#include <linux/string.h> - -#include <asm/segment.h> - -static inline void set_tss_desc(unsigned cpu, void *addr) -{ - struct desc_struct *d = get_cpu_gdt_table(cpu); - tss_desc tss; - - /* - * sizeof(unsigned long) coming from an extra "long" at the end - * of the iobitmap. See tss_struct definition in processor.h - * - * -1? seg base+limit should be pointing to the address of the - * last valid byte - */ - set_tssldt_descriptor(&tss, - (unsigned long)addr, DESC_TSS, - IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); - write_gdt_entry(d, GDT_ENTRY_TSS, &tss, DESC_TSS); -} - -#endif /* !__ASSEMBLY__ */ - -#endif
This variable is not used anywere, and is then removed Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 1c26dbb..660cc84 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -30,11 +30,6 @@ static inline unsigned long __store_tr(void) #define store_tr(tr) (tr) = __store_tr() -/* - * This is the ldt that every process will get unless we need - * something other than this. - */ -extern struct desc_struct default_ldt[]; extern struct gate_struct idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; -- 1.5.0.6
this patch introduces ldt_desc type to account for the differences in the ldt descriptor in x86_64 and i386 Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- include/asm-x86/desc_64.h | 2 +- include/asm-x86/desc_defs.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index ffc6c06..8fe1b4c 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -113,7 +113,7 @@ static inline void store_idt(struct desc_ptr *dtr) static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type, unsigned size) { - struct ldttss_desc d; + struct ldttss_desc64 d; memset(&d, 0, sizeof(d)); d.limit0 = size & 0xFFFF; diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index 05eff93..5a58fc1 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -58,7 +58,7 @@ enum { }; // LDT or TSS descriptor in the GDT. 16 bytes. -struct ldttss_desc { +struct ldttss_desc64 { u16 limit0; u16 base0; unsigned base1 : 8, type : 5, dpl : 2, p : 1; @@ -69,8 +69,10 @@ struct ldttss_desc { #ifdef CONFIG_X86_64 typedef struct gate_struct64 gate_desc; +typedef struct ldttss_desc64 ldt_desc; #else typedef struct desc_struct gate_desc; +typedef struct desc_struct ldt_desc; #endif struct desc_ptr { -- 1.5.0.6
This patch modifies the write_ldt() function to make use of the new struct desc_struct instead of entry_1 and entry_2 entries Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/ldt.c | 15 +++++++-------- 1 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index a8cdca3..7eb0c8a 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -186,7 +186,7 @@ static int read_default_ldt(void __user *ptr, unsigned long bytecount) static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) { struct mm_struct *mm = current->mm; - __u32 entry_1, entry_2; + struct desc_struct ldt; int error; struct user_desc ldt_info; @@ -218,21 +218,20 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { if (oldmode || LDT_empty(&ldt_info)) { - entry_1 = 0; - entry_2 = 0; + memset(&ldt, 0, sizeof(ldt)); goto install; } } - entry_1 = LDT_entry_a(&ldt_info); - entry_2 = LDT_entry_b(&ldt_info); + ldt.a = LDT_entry_a(&ldt_info); + ldt.b = LDT_entry_b(&ldt_info); if (oldmode) - entry_2 &= ~(1 << 20); + ldt.avl = 0; /* Install the new entry ... */ install: - write_ldt_entry(mm->context.ldt, ldt_info.entry_number, entry_1, - entry_2); + write_ldt_entry(mm->context.ldt, ldt_info.entry_number, + ldt.a, ldt.b); error = 0; out_unlock: -- 1.5.0.6
To account for the differences in gate descriptor in i386 and x86_64 a gate_desc type is introduced. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> --- arch/x86/kernel/traps_32.c | 3 ++- include/asm-x86/desc_32.h | 15 ++++++++------- include/asm-x86/desc_64.h | 4 ++-- include/asm-x86/desc_defs.h | 8 +++++++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 94c5aea..6b03d88 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -76,8 +76,8 @@ char ignore_fpu_irq = 0; * F0 0F bug workaround.. We have a special link segment * for this. */ -struct desc_struct idt_table[256] - __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; +gate_desc idt_table[256] + __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; asmlinkage void divide_error(void); asmlinkage void debug(void); diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index bc5ca34..77f1e5a 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -3,6 +3,7 @@ #include <asm/ldt.h> #include <asm/segment.h> +#include <asm/desc_defs.h> #ifndef __ASSEMBLY__ @@ -24,7 +25,7 @@ static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) } extern struct desc_ptr idt_descr; -extern struct desc_struct idt_table[]; +extern gate_desc idt_table[]; extern void set_intr_gate(unsigned int irq, void * addr); static inline void pack_descriptor(__u32 *a, __u32 *b, @@ -35,11 +36,11 @@ static inline void pack_descriptor(__u32 *a, __u32 *b, (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20); } -static inline void pack_gate(__u32 *a, __u32 *b, +static inline void pack_gate(gate_desc *gate, unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) { - *a = (seg << 16) | (base & 0xffff); - *b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); + gate->a = (seg << 16) | (base & 0xffff); + gate->b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); } #define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ @@ -139,9 +140,9 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) { - __u32 a, b; - pack_gate(&a, &b, (unsigned long)addr, seg, type, 0); - write_idt_entry(idt_table, gate, a, b); + gate_desc g; + pack_gate(&g, (unsigned long)addr, seg, type, 0); + write_idt_entry(idt_table, gate, g.a, g.b); } static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 660cc84..ffc6c06 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -30,7 +30,7 @@ static inline unsigned long __store_tr(void) #define store_tr(tr) (tr) = __store_tr() -extern struct gate_struct idt_table[]; +extern gate_desc idt_table[]; extern struct desc_ptr cpu_gdt_descr[]; static inline void write_ldt_entry(struct desc_struct *ldt, @@ -58,7 +58,7 @@ static inline void store_gdt(struct desc_ptr *ptr) static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist) { - struct gate_struct s; + gate_desc s; s.offset_low = PTR_LOW(func); s.segment = __KERNEL_CS; diff --git a/include/asm-x86/desc_defs.h b/include/asm-x86/desc_defs.h index f37b44c..05eff93 100644 --- a/include/asm-x86/desc_defs.h +++ b/include/asm-x86/desc_defs.h @@ -39,7 +39,7 @@ enum { }; // 16byte gate -struct gate_struct { +struct gate_struct64 { u16 offset_low; u16 segment; unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; @@ -67,6 +67,12 @@ struct ldttss_desc { u32 zero1; } __attribute__((packed)); +#ifdef CONFIG_X86_64 +typedef struct gate_struct64 gate_desc; +#else +typedef struct desc_struct gate_desc; +#endif + struct desc_ptr { unsigned short size; unsigned long address; -- 1.5.0.6
Glauber de Oliveira Costa
2007-Dec-13 08:58 UTC
[PATCH 06/19] change write_idt_entry signature
this patch changes write_idt_entry signature. It now takes a gate_desc instead of the a and b parameters. It will allow it to be later unified between i386 and x86_64. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> CC: Zachary Amsden <zach@vmware.com> CC: Jeremy Fitzhardinge <Jeremy.Fitzhardinge.citrix.com> --- arch/x86/kernel/paravirt_32.c | 2 +- arch/x86/kernel/vmi_32.c | 10 +++++++++- arch/x86/lguest/boot.c | 9 +++++---- arch/x86/xen/enlighten.c | 8 ++++---- include/asm-x86/desc_32.h | 10 ++++++++-- include/asm-x86/paravirt.h | 9 +++++---- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/paravirt_32.c b/arch/x86/kernel/paravirt_32.c index f4e3a8e..13bbc99 100644 --- a/arch/x86/kernel/paravirt_32.c +++ b/arch/x86/kernel/paravirt_32.c @@ -381,7 +381,7 @@ struct pv_cpu_ops pv_cpu_ops = { .load_tls = native_load_tls, .write_ldt_entry = write_dt_entry, .write_gdt_entry = write_dt_entry, - .write_idt_entry = write_dt_entry, + .write_idt_entry = native_write_idt_entry, .load_sp0 = native_load_sp0, .irq_enable_syscall_ret = native_irq_enable_syscall_ret, diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c index 4cfda7d..a635b22 100644 --- a/arch/x86/kernel/vmi_32.c +++ b/arch/x86/kernel/vmi_32.c @@ -62,6 +62,7 @@ static struct { void (*cpuid)(void /* non-c */); void (*_set_ldt)(u32 selector); void (*set_tr)(u32 selector); + void (*write_idt_entry)(struct desc_struct *, int, u32, u32); void (*set_kernel_stack)(u32 selector, u32 sp0); void (*allocate_page)(u32, u32, u32, u32, u32); void (*release_page)(u32, u32); @@ -214,6 +215,12 @@ static void vmi_set_tr(void) vmi_ops.set_tr(GDT_ENTRY_TSS*sizeof(struct desc_struct)); } +static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g) +{ + u32 *idt_entry = (u32 *)g; + vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[2]); +} + static void vmi_load_sp0(struct tss_struct *tss, struct thread_struct *thread) { @@ -792,7 +799,8 @@ static inline int __init activate_vmi(void) pv_cpu_ops.load_tls = vmi_load_tls; para_fill(pv_cpu_ops.write_ldt_entry, WriteLDTEntry); para_fill(pv_cpu_ops.write_gdt_entry, WriteGDTEntry); - para_fill(pv_cpu_ops.write_idt_entry, WriteIDTEntry); + para_wrap(pv_cpu_ops.write_idt_entry, vmi_write_idt_entry, + write_idt_entry, WriteIDTEntry); para_wrap(pv_cpu_ops.load_sp0, vmi_load_sp0, set_kernel_stack, UpdateKernelStack); para_fill(pv_cpu_ops.set_iopl_mask, SetIOPLMask); para_fill(pv_cpu_ops.io_delay, IODelay); diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index aa0bdd5..b50c8ad 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -217,13 +217,14 @@ static void irq_enable(void) * address of the handler, and... well, who cares? The Guest just asks the * Host to make the change anyway, because the Host controls the real IDT. */ -static void lguest_write_idt_entry(struct desc_struct *dt, - int entrynum, u32 low, u32 high) +static void lguest_write_idt_entry(gate_desc *dt, + int entrynum, const gate_desc *g) { + u32 *desc = (u32 *)g; /* Keep the local copy up to date. */ - write_dt_entry(dt, entrynum, low, high); + native_write_idt_entry(dt, entrynum, g); /* Tell Host about this new entry. */ - hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, low, high); + hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]); } /* Changing to a different IDT is very rare: we keep the IDT up-to-date every diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 8215ea6..6dd349e 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -399,8 +399,7 @@ static DEFINE_PER_CPU(struct desc_ptr, idt_desc); /* Set an IDT entry. If the entry is part of the current IDT, then also update Xen. */ -static void xen_write_idt_entry(struct desc_struct *dt, int entrynum, - u32 low, u32 high) +static void xen_write_idt_entry(gate_desc *dt, int entrynum, const gate_desc *g) { unsigned long p = (unsigned long)&dt[entrynum]; unsigned long start, end; @@ -412,14 +411,15 @@ static void xen_write_idt_entry(struct desc_struct *dt, int entrynum, xen_mc_flush(); - write_dt_entry(dt, entrynum, low, high); + native_write_idt_entry(dt, entrynum, g); if (p >= start && (p + 8) <= end) { struct trap_info info[2]; + u32 *desc = (u32 *)g; info[1].address = 0; - if (cvt_gate_to_trap(entrynum, low, high, &info[0])) + if (cvt_gate_to_trap(entrynum, desc[0], desc[1], &info[0])) if (HYPERVISOR_set_trap_table(info)) BUG(); } diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 77f1e5a..54b2314 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -70,9 +70,15 @@ static inline void pack_gate(gate_desc *gate, #define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) #define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) -#define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) +#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) #endif +static inline void native_write_idt_entry(gate_desc *idt, int entry, + const gate_desc *gate) +{ + memcpy(&idt[entry], gate, sizeof(*gate)); +} + static inline void write_dt_entry(struct desc_struct *dt, int entry, u32 entry_low, u32 entry_high) { @@ -142,7 +148,7 @@ static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned s { gate_desc g; pack_gate(&g, (unsigned long)addr, seg, type, 0); - write_idt_entry(idt_table, gate, g.a, g.b); + write_idt_entry(idt_table, gate, &g); } static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h index 0333fb6..86a9d7b 100644 --- a/include/asm-x86/paravirt.h +++ b/include/asm-x86/paravirt.h @@ -17,6 +17,7 @@ #include <linux/types.h> #include <linux/cpumask.h> #include <asm/kmap_types.h> +#include <asm/desc_defs.h> struct page; struct thread_struct; @@ -99,8 +100,8 @@ struct pv_cpu_ops { int entrynum, u32 low, u32 high); void (*write_gdt_entry)(struct desc_struct *, int entrynum, u32 low, u32 high); - void (*write_idt_entry)(struct desc_struct *, - int entrynum, u32 low, u32 high); + void (*write_idt_entry)(gate_desc *, + int entrynum, const gate_desc *gate); void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); void (*set_iopl_mask)(unsigned mask); @@ -667,9 +668,9 @@ static inline void write_gdt_entry(void *dt, int entry, u32 low, u32 high) { PVOP_VCALL4(pv_cpu_ops.write_gdt_entry, dt, entry, low, high); } -static inline void write_idt_entry(void *dt, int entry, u32 low, u32 high) +static inline void write_idt_entry(gate_desc *dt, int entry, const gate_desc *g) { - PVOP_VCALL4(pv_cpu_ops.write_idt_entry, dt, entry, low, high); + PVOP_VCALL3(pv_cpu_ops.write_idt_entry, dt, entry, g); } static inline void set_iopl_mask(unsigned mask) { -- 1.5.0.6