Commit 64b163fa authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Ingo Molnar

x86/idt: Unify gate_struct handling for 32/64-bit kernels

The first 32 bits of gate struct are the same for 32 and 64 bit kernels.

The 32-bit version uses desc_struct and no designated data structure,
so we need different accessors for 32 and 64 bit kernels.

Aside of that the macros which are necessary to build the 32-bit
gate descriptor are horrible to read.

Unify the gate structs and switch all code fiddling with it over.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/20170828064957.861974317@linutronix.deSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 73285527
...@@ -1058,7 +1058,7 @@ struct boot_params *efi_main(struct efi_config *c, ...@@ -1058,7 +1058,7 @@ struct boot_params *efi_main(struct efi_config *c,
desc->s = DESC_TYPE_CODE_DATA; desc->s = DESC_TYPE_CODE_DATA;
desc->dpl = 0; desc->dpl = 0;
desc->p = 1; desc->p = 1;
desc->limit = 0xf; desc->limit1 = 0xf;
desc->avl = 0; desc->avl = 0;
desc->l = 0; desc->l = 0;
desc->d = SEG_OP_SIZE_32BIT; desc->d = SEG_OP_SIZE_32BIT;
...@@ -1078,7 +1078,7 @@ struct boot_params *efi_main(struct efi_config *c, ...@@ -1078,7 +1078,7 @@ struct boot_params *efi_main(struct efi_config *c,
desc->s = DESC_TYPE_CODE_DATA; desc->s = DESC_TYPE_CODE_DATA;
desc->dpl = 0; desc->dpl = 0;
desc->p = 1; desc->p = 1;
desc->limit = 0xf; desc->limit1 = 0xf;
desc->avl = 0; desc->avl = 0;
if (IS_ENABLED(CONFIG_X86_64)) { if (IS_ENABLED(CONFIG_X86_64)) {
desc->l = 1; desc->l = 1;
...@@ -1099,7 +1099,7 @@ struct boot_params *efi_main(struct efi_config *c, ...@@ -1099,7 +1099,7 @@ struct boot_params *efi_main(struct efi_config *c,
desc->s = DESC_TYPE_CODE_DATA; desc->s = DESC_TYPE_CODE_DATA;
desc->dpl = 0; desc->dpl = 0;
desc->p = 1; desc->p = 1;
desc->limit = 0xf; desc->limit1 = 0xf;
desc->avl = 0; desc->avl = 0;
desc->l = 0; desc->l = 0;
desc->d = SEG_OP_SIZE_32BIT; desc->d = SEG_OP_SIZE_32BIT;
...@@ -1116,7 +1116,7 @@ struct boot_params *efi_main(struct efi_config *c, ...@@ -1116,7 +1116,7 @@ struct boot_params *efi_main(struct efi_config *c,
desc->s = 0; desc->s = 0;
desc->dpl = 0; desc->dpl = 0;
desc->p = 1; desc->p = 1;
desc->limit = 0x0; desc->limit1 = 0x0;
desc->avl = 0; desc->avl = 0;
desc->l = 0; desc->l = 0;
desc->d = 0; desc->d = 0;
......
...@@ -84,33 +84,25 @@ static inline phys_addr_t get_cpu_gdt_paddr(unsigned int cpu) ...@@ -84,33 +84,25 @@ static inline phys_addr_t get_cpu_gdt_paddr(unsigned int cpu)
return per_cpu_ptr_to_phys(get_cpu_gdt_rw(cpu)); return per_cpu_ptr_to_phys(get_cpu_gdt_rw(cpu));
} }
#ifdef CONFIG_X86_64
static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func, static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
unsigned dpl, unsigned ist, unsigned seg) unsigned dpl, unsigned ist, unsigned seg)
{ {
gate->offset_low = PTR_LOW(func); gate->offset_low = (u16) func;
gate->bits.p = 1;
gate->bits.dpl = dpl;
gate->bits.zero = 0;
gate->bits.type = type;
gate->offset_middle = (u16) (func >> 16);
#ifdef CONFIG_X86_64
gate->segment = __KERNEL_CS; gate->segment = __KERNEL_CS;
gate->ist = ist; gate->bits.ist = ist;
gate->p = 1; gate->reserved = 0;
gate->dpl = dpl; gate->offset_high = (u32) (func >> 32);
gate->zero0 = 0;
gate->zero1 = 0;
gate->type = type;
gate->offset_middle = PTR_MIDDLE(func);
gate->offset_high = PTR_HIGH(func);
}
#else #else
static inline void pack_gate(gate_desc *gate, unsigned char type, gate->segment = seg;
unsigned long base, unsigned dpl, unsigned flags, gate->bits.ist = 0;
unsigned short seg)
{
gate->a = (seg << 16) | (base & 0xffff);
gate->b = (base & 0xffff0000) | (((0x80 | type | (dpl << 5)) & 0xff) << 8);
}
#endif #endif
}
static inline int desc_empty(const void *ptr) static inline int desc_empty(const void *ptr)
{ {
...@@ -186,7 +178,8 @@ static inline void pack_descriptor(struct desc_struct *desc, unsigned long base, ...@@ -186,7 +178,8 @@ static inline void pack_descriptor(struct desc_struct *desc, unsigned long base,
} }
static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned type, unsigned size) static inline void set_tssldt_descriptor(void *d, unsigned long addr,
unsigned type, unsigned size)
{ {
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
struct ldttss_desc64 *desc = d; struct ldttss_desc64 *desc = d;
...@@ -194,13 +187,13 @@ static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned t ...@@ -194,13 +187,13 @@ static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned t
memset(desc, 0, sizeof(*desc)); memset(desc, 0, sizeof(*desc));
desc->limit0 = size & 0xFFFF; desc->limit0 = size & 0xFFFF;
desc->base0 = PTR_LOW(addr); desc->base0 = (u16) addr;
desc->base1 = PTR_MIDDLE(addr) & 0xFF; desc->base1 = (addr >> 16) & 0xFF;
desc->type = type; desc->type = type;
desc->p = 1; desc->p = 1;
desc->limit1 = (size >> 16) & 0xF; desc->limit1 = (size >> 16) & 0xF;
desc->base2 = (PTR_MIDDLE(addr) >> 8) & 0xFF; desc->base2 = (addr >> 24) & 0xFF;
desc->base3 = PTR_HIGH(addr); desc->base3 = (u32) (addr >> 32);
#else #else
pack_descriptor((struct desc_struct *)d, addr, size, 0x80 | type, 0); pack_descriptor((struct desc_struct *)d, addr, size, 0x80 | type, 0);
#endif #endif
......
...@@ -47,20 +47,6 @@ enum { ...@@ -47,20 +47,6 @@ enum {
GATE_TASK = 0x5, GATE_TASK = 0x5,
}; };
/* 16byte gate */
struct gate_struct64 {
u16 offset_low;
u16 segment;
unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
u16 offset_middle;
u32 offset_high;
u32 zero1;
} __attribute__((packed));
#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 { enum {
DESC_TSS = 0x9, DESC_TSS = 0x9,
DESC_LDT = 0x2, DESC_LDT = 0x2,
...@@ -77,20 +63,51 @@ struct ldttss_desc64 { ...@@ -77,20 +63,51 @@ struct ldttss_desc64 {
u32 zero1; u32 zero1;
} __attribute__((packed)); } __attribute__((packed));
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
typedef struct gate_struct64 gate_desc;
typedef struct ldttss_desc64 ldt_desc; typedef struct ldttss_desc64 ldt_desc;
typedef struct ldttss_desc64 tss_desc; typedef struct ldttss_desc64 tss_desc;
#define gate_offset(g) ((g).offset_low | ((unsigned long)(g).offset_middle << 16) | ((unsigned long)(g).offset_high << 32))
#define gate_segment(g) ((g).segment)
#else #else
typedef struct desc_struct gate_desc;
typedef struct desc_struct ldt_desc; typedef struct desc_struct ldt_desc;
typedef struct desc_struct tss_desc; typedef struct desc_struct tss_desc;
#define gate_offset(g) (((g).b & 0xffff0000) | ((g).a & 0x0000ffff))
#define gate_segment(g) ((g).a >> 16)
#endif #endif
struct idt_bits {
u16 ist : 3,
zero : 5,
type : 5,
dpl : 2,
p : 1;
} __attribute__((packed));
struct gate_struct {
u16 offset_low;
u16 segment;
struct idt_bits bits;
u16 offset_middle;
#ifdef CONFIG_X86_64
u32 offset_high;
u32 reserved;
#endif
} __attribute__((packed));
typedef struct gate_struct gate_desc;
static inline unsigned long gate_offset(const gate_desc *g)
{
#ifdef CONFIG_X86_64
return g->offset_low | ((unsigned long)g->offset_middle << 16) |
((unsigned long) g->offset_high << 32);
#else
return g->offset_low | ((unsigned long)g->offset_middle << 16);
#endif
}
static inline unsigned long gate_segment(const gate_desc *g)
{
return g->segment;
}
struct desc_ptr { struct desc_ptr {
unsigned short size; unsigned short size;
unsigned long address; unsigned long address;
......
...@@ -8779,7 +8779,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu) ...@@ -8779,7 +8779,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
vector = exit_intr_info & INTR_INFO_VECTOR_MASK; vector = exit_intr_info & INTR_INFO_VECTOR_MASK;
desc = (gate_desc *)vmx->host_idt_base + vector; desc = (gate_desc *)vmx->host_idt_base + vector;
entry = gate_offset(*desc); entry = gate_offset(desc);
asm volatile( asm volatile(
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
"mov %%" _ASM_SP ", %[sp]\n\t" "mov %%" _ASM_SP ", %[sp]\n\t"
......
...@@ -584,12 +584,12 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val, ...@@ -584,12 +584,12 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
{ {
unsigned long addr; unsigned long addr;
if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT) if (val->bits.type != GATE_TRAP && val->bits.type != GATE_INTERRUPT)
return 0; return 0;
info->vector = vector; info->vector = vector;
addr = gate_offset(*val); addr = gate_offset(val);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
/* /*
* Look for known traps using IST, and substitute them * Look for known traps using IST, and substitute them
...@@ -622,16 +622,16 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val, ...@@ -622,16 +622,16 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
; ;
else { else {
/* Some other trap using IST? */ /* Some other trap using IST? */
if (WARN_ON(val->ist != 0)) if (WARN_ON(val->bits.ist != 0))
return 0; return 0;
} }
#endif /* CONFIG_X86_64 */ #endif /* CONFIG_X86_64 */
info->address = addr; info->address = addr;
info->cs = gate_segment(*val); info->cs = gate_segment(val);
info->flags = val->dpl; info->flags = val->bits.dpl;
/* interrupt gates clear IF */ /* interrupt gates clear IF */
if (val->type == GATE_INTERRUPT) if (val->bits.type == GATE_INTERRUPT)
info->flags |= 1 << 2; info->flags |= 1 << 2;
return 1; return 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment