forked from Minki/linux
e754aedc26
I've had this code for a while, but never submitted it upstream. Now that Skylake hardware is out in the wild, folks can actually run this for real. It tests the following: 1. The MPX hardware is enabled by the kernel and doing what it is supposed to 2. The MPX management code is present and enabled in the kernel 3. MPX Signal handling 4. The MPX bounds table population code (on-demand population) 5. The MPX bounds table unmapping code (kernel-initiated freeing when unused) This has also caught bugs in the XSAVE code because MPX state is saved/restored with XSAVE. I'm submitting it now because it would have caught the recent issues with the compat_siginfo code not being properly augmented when new siginfo state is added. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Dave Hansen <dave@sr71.net> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Shuah Khan <shuahkh@osg.samsung.com> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/20160608172535.5B40B0EE@viggo.jf.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
124 lines
3.4 KiB
C
124 lines
3.4 KiB
C
#ifndef _MPX_HW_H
|
|
#define _MPX_HW_H
|
|
|
|
#include <assert.h>
|
|
|
|
/* Describe the MPX Hardware Layout in here */
|
|
|
|
#define NR_MPX_BOUNDS_REGISTERS 4
|
|
|
|
#ifdef __i386__
|
|
|
|
#define MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES 16 /* 4 * 32-bits */
|
|
#define MPX_BOUNDS_TABLE_SIZE_BYTES (1ULL << 14) /* 16k */
|
|
#define MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES 4
|
|
#define MPX_BOUNDS_DIR_SIZE_BYTES (1ULL << 22) /* 4MB */
|
|
|
|
#define MPX_BOUNDS_TABLE_BOTTOM_BIT 2
|
|
#define MPX_BOUNDS_TABLE_TOP_BIT 11
|
|
#define MPX_BOUNDS_DIR_BOTTOM_BIT 12
|
|
#define MPX_BOUNDS_DIR_TOP_BIT 31
|
|
|
|
#else
|
|
|
|
/*
|
|
* Linear Address of "pointer" (LAp)
|
|
* 0 -> 2: ignored
|
|
* 3 -> 19: index in to bounds table
|
|
* 20 -> 47: index in to bounds directory
|
|
* 48 -> 63: ignored
|
|
*/
|
|
|
|
#define MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES 32
|
|
#define MPX_BOUNDS_TABLE_SIZE_BYTES (1ULL << 22) /* 4MB */
|
|
#define MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES 8
|
|
#define MPX_BOUNDS_DIR_SIZE_BYTES (1ULL << 31) /* 2GB */
|
|
|
|
#define MPX_BOUNDS_TABLE_BOTTOM_BIT 3
|
|
#define MPX_BOUNDS_TABLE_TOP_BIT 19
|
|
#define MPX_BOUNDS_DIR_BOTTOM_BIT 20
|
|
#define MPX_BOUNDS_DIR_TOP_BIT 47
|
|
|
|
#endif
|
|
|
|
#define MPX_BOUNDS_DIR_NR_ENTRIES \
|
|
(MPX_BOUNDS_DIR_SIZE_BYTES/MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES)
|
|
#define MPX_BOUNDS_TABLE_NR_ENTRIES \
|
|
(MPX_BOUNDS_TABLE_SIZE_BYTES/MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES)
|
|
|
|
#define MPX_BOUNDS_TABLE_ENTRY_VALID_BIT 0x1
|
|
|
|
struct mpx_bd_entry {
|
|
union {
|
|
char x[MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES];
|
|
void *contents[1];
|
|
};
|
|
} __attribute__((packed));
|
|
|
|
struct mpx_bt_entry {
|
|
union {
|
|
char x[MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES];
|
|
unsigned long contents[1];
|
|
};
|
|
} __attribute__((packed));
|
|
|
|
struct mpx_bounds_dir {
|
|
struct mpx_bd_entry entries[MPX_BOUNDS_DIR_NR_ENTRIES];
|
|
} __attribute__((packed));
|
|
|
|
struct mpx_bounds_table {
|
|
struct mpx_bt_entry entries[MPX_BOUNDS_TABLE_NR_ENTRIES];
|
|
} __attribute__((packed));
|
|
|
|
static inline unsigned long GET_BITS(unsigned long val, int bottombit, int topbit)
|
|
{
|
|
int total_nr_bits = topbit - bottombit;
|
|
unsigned long mask = (1UL << total_nr_bits)-1;
|
|
return (val >> bottombit) & mask;
|
|
}
|
|
|
|
static inline unsigned long __vaddr_bounds_table_index(void *vaddr)
|
|
{
|
|
return GET_BITS((unsigned long)vaddr, MPX_BOUNDS_TABLE_BOTTOM_BIT,
|
|
MPX_BOUNDS_TABLE_TOP_BIT);
|
|
}
|
|
|
|
static inline unsigned long __vaddr_bounds_directory_index(void *vaddr)
|
|
{
|
|
return GET_BITS((unsigned long)vaddr, MPX_BOUNDS_DIR_BOTTOM_BIT,
|
|
MPX_BOUNDS_DIR_TOP_BIT);
|
|
}
|
|
|
|
static inline struct mpx_bd_entry *mpx_vaddr_to_bd_entry(void *vaddr,
|
|
struct mpx_bounds_dir *bounds_dir)
|
|
{
|
|
unsigned long index = __vaddr_bounds_directory_index(vaddr);
|
|
return &bounds_dir->entries[index];
|
|
}
|
|
|
|
static inline int bd_entry_valid(struct mpx_bd_entry *bounds_dir_entry)
|
|
{
|
|
unsigned long __bd_entry = (unsigned long)bounds_dir_entry->contents;
|
|
return (__bd_entry & MPX_BOUNDS_TABLE_ENTRY_VALID_BIT);
|
|
}
|
|
|
|
static inline struct mpx_bounds_table *
|
|
__bd_entry_to_bounds_table(struct mpx_bd_entry *bounds_dir_entry)
|
|
{
|
|
unsigned long __bd_entry = (unsigned long)bounds_dir_entry->contents;
|
|
assert(__bd_entry & MPX_BOUNDS_TABLE_ENTRY_VALID_BIT);
|
|
__bd_entry &= ~MPX_BOUNDS_TABLE_ENTRY_VALID_BIT;
|
|
return (struct mpx_bounds_table *)__bd_entry;
|
|
}
|
|
|
|
static inline struct mpx_bt_entry *
|
|
mpx_vaddr_to_bt_entry(void *vaddr, struct mpx_bounds_dir *bounds_dir)
|
|
{
|
|
struct mpx_bd_entry *bde = mpx_vaddr_to_bd_entry(vaddr, bounds_dir);
|
|
struct mpx_bounds_table *bt = __bd_entry_to_bounds_table(bde);
|
|
unsigned long index = __vaddr_bounds_table_index(vaddr);
|
|
return &bt->entries[index];
|
|
}
|
|
|
|
#endif /* _MPX_HW_H */
|