Commit 718f5d00 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Ingo Molnar

x86/fpu: Use bitfield accessors for desc_struct

desc_struct is a union of u32 fields and bitfields. The access to the u32
fields is done with magic macros.

Convert it to use the bitfields and replace the macro magic with parseable
inline functions.
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/20170828064958.042406718@linutronix.deSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 1dd439fe
...@@ -147,7 +147,7 @@ void math_emulate(struct math_emu_info *info) ...@@ -147,7 +147,7 @@ void math_emulate(struct math_emu_info *info)
} }
code_descriptor = FPU_get_ldt_descriptor(FPU_CS); code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
if (SEG_D_SIZE(code_descriptor)) { if (code_descriptor.d) {
/* The above test may be wrong, the book is not clear */ /* The above test may be wrong, the book is not clear */
/* Segmented 32 bit protected mode */ /* Segmented 32 bit protected mode */
addr_modes.default_mode = SEG32; addr_modes.default_mode = SEG32;
...@@ -155,11 +155,10 @@ void math_emulate(struct math_emu_info *info) ...@@ -155,11 +155,10 @@ void math_emulate(struct math_emu_info *info)
/* 16 bit protected mode */ /* 16 bit protected mode */
addr_modes.default_mode = PM16; addr_modes.default_mode = PM16;
} }
FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor); FPU_EIP += code_base = seg_get_base(&code_descriptor);
code_limit = code_base code_limit = seg_get_limit(&code_descriptor) + 1;
+ (SEG_LIMIT(code_descriptor) + code_limit *= seg_get_granularity(&code_descriptor);
1) * SEG_GRANULARITY(code_descriptor) code_limit += code_base - 1;
- 1;
if (code_limit < code_base) if (code_limit < code_base)
code_limit = 0xffffffff; code_limit = 0xffffffff;
} }
......
...@@ -34,17 +34,43 @@ static inline struct desc_struct FPU_get_ldt_descriptor(unsigned seg) ...@@ -34,17 +34,43 @@ static inline struct desc_struct FPU_get_ldt_descriptor(unsigned seg)
return ret; return ret;
} }
#define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_TYPE_WRITABLE (1U << 1)
#define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_TYPE_EXPANDS_DOWN (1U << 2)
#define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) #define SEG_TYPE_EXECUTE (1U << 3)
#define SEG_286_MODE(x) ((x).b & ( 0xff000000 | 0xf0000 | (1 << 23))) #define SEG_TYPE_EXPAND_MASK (SEG_TYPE_EXPANDS_DOWN | SEG_TYPE_EXECUTE)
#define SEG_BASE_ADDR(s) (((s).b & 0xff000000) \ #define SEG_TYPE_EXECUTE_MASK (SEG_TYPE_WRITABLE | SEG_TYPE_EXECUTE)
| (((s).b & 0xff) << 16) | ((s).a >> 16))
#define SEG_LIMIT(s) (((s).b & 0xff0000) | ((s).a & 0xffff)) static inline unsigned long seg_get_base(struct desc_struct *d)
#define SEG_EXECUTE_ONLY(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 11)) {
#define SEG_WRITE_PERM(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 9)) unsigned long base = (unsigned long)d->base2 << 24;
#define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \
== (1 << 10)) return base | ((unsigned long)d->base1 << 16) | d->base0;
}
static inline unsigned long seg_get_limit(struct desc_struct *d)
{
return ((unsigned long)d->limit << 16) | d->limit0;
}
static inline unsigned long seg_get_granularity(struct desc_struct *d)
{
return d->g ? 4096 : 1;
}
static inline bool seg_expands_down(struct desc_struct *d)
{
return (d->type & SEG_TYPE_EXPAND_MASK) == SEG_TYPE_EXPANDS_DOWN;
}
static inline bool seg_execute_only(struct desc_struct *d)
{
return (d->type & SEG_TYPE_EXECUTE_MASK) == SEG_TYPE_EXECUTE;
}
static inline bool seg_writable(struct desc_struct *d)
{
return (d->type & SEG_TYPE_EXECUTE_MASK) == SEG_TYPE_WRITABLE;
}
#define I387 (&current->thread.fpu.state) #define I387 (&current->thread.fpu.state)
#define FPU_info (I387->soft.info) #define FPU_info (I387->soft.info)
......
...@@ -159,17 +159,18 @@ static long pm_address(u_char FPU_modrm, u_char segment, ...@@ -159,17 +159,18 @@ static long pm_address(u_char FPU_modrm, u_char segment,
} }
descriptor = FPU_get_ldt_descriptor(addr->selector); descriptor = FPU_get_ldt_descriptor(addr->selector);
base_address = SEG_BASE_ADDR(descriptor); base_address = seg_get_base(&descriptor);
address = base_address + offset; address = base_address + offset;
limit = base_address limit = seg_get_limit(&descriptor) + 1;
+ (SEG_LIMIT(descriptor) + 1) * SEG_GRANULARITY(descriptor) - 1; limit *= seg_get_granularity(&descriptor);
limit += base_address - 1;
if (limit < base_address) if (limit < base_address)
limit = 0xffffffff; limit = 0xffffffff;
if (SEG_EXPAND_DOWN(descriptor)) { if (seg_expands_down(&descriptor)) {
if (SEG_G_BIT(descriptor)) if (descriptor.g) {
seg_top = 0xffffffff; seg_top = 0xffffffff;
else { } else {
seg_top = base_address + (1 << 20); seg_top = base_address + (1 << 20);
if (seg_top < base_address) if (seg_top < base_address)
seg_top = 0xffffffff; seg_top = 0xffffffff;
...@@ -182,8 +183,8 @@ static long pm_address(u_char FPU_modrm, u_char segment, ...@@ -182,8 +183,8 @@ static long pm_address(u_char FPU_modrm, u_char segment,
(address > limit) || (address < base_address) ? 0 : (address > limit) || (address < base_address) ? 0 :
((limit - address) >= 254 ? 255 : limit - address + 1); ((limit - address) >= 254 ? 255 : limit - address + 1);
} }
if (SEG_EXECUTE_ONLY(descriptor) || if (seg_execute_only(&descriptor) ||
(!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT))) { (!seg_writable(&descriptor) && (FPU_modrm & FPU_WRITE_BIT))) {
access_limit = 0; access_limit = 0;
} }
return address; return address;
......
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