Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 269516
b: refs/heads/master
c: dfb09f9
h: refs/heads/master
v: v3
  • Loading branch information
Borislav Petkov authored and H. Peter Anvin committed Aug 5, 2011
1 parent a2741e5 commit 94e5578
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 13f9a3737c903ace57d8aaebe81a3bbaeb0aa0a2
refs/heads/master: dfb09f9b7ab03fd367740e541a5caf830ed56726
13 changes: 13 additions & 0 deletions trunk/Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,19 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
behaviour to be specified. Bit 0 enables warnings,
bit 1 enables fixups, and bit 2 sends a segfault.

align_va_addr= [X86-64]
Align virtual addresses by clearing slice [14:12] when
allocating a VMA at process creation time. This option
gives you up to 3% performance improvement on AMD F15h
machines (where it is enabled by default) for a
CPU-intensive style benchmark, and it can vary highly in
a microbenchmark depending on workload and compiler.

1: only for 32-bit processes
2: only for 64-bit processes
on: enable for both 32- and 64-bit processes
off: disable for both 32- and 64-bit processes

amd_iommu= [HW,X86-84]
Pass parameters to the AMD IOMMU driver in the system.
Possible values are:
Expand Down
31 changes: 31 additions & 0 deletions trunk/arch/x86/include/asm/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/*
* ELF register definitions..
*/
#include <linux/thread_info.h>

#include <asm/ptrace.h>
#include <asm/user.h>
Expand Down Expand Up @@ -320,4 +321,34 @@ extern int syscall32_setup_pages(struct linux_binprm *, int exstack);
extern unsigned long arch_randomize_brk(struct mm_struct *mm);
#define arch_randomize_brk arch_randomize_brk

/*
* True on X86_32 or when emulating IA32 on X86_64
*/
static inline int mmap_is_ia32(void)
{
#ifdef CONFIG_X86_32
return 1;
#endif
#ifdef CONFIG_IA32_EMULATION
if (test_thread_flag(TIF_IA32))
return 1;
#endif
return 0;
}

/* The first two values are special, do not change. See align_addr() */
enum align_flags {
ALIGN_VA_32 = BIT(0),
ALIGN_VA_64 = BIT(1),
ALIGN_VDSO = BIT(2),
ALIGN_TOPDOWN = BIT(3),
};

struct va_alignment {
int flags;
unsigned long mask;
} ____cacheline_aligned;

extern struct va_alignment va_align;
extern unsigned long align_addr(unsigned long, struct file *, enum align_flags);
#endif /* _ASM_X86_ELF_H */
13 changes: 13 additions & 0 deletions trunk/arch/x86/kernel/cpu/amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,19 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
"with P0 frequency!\n");
}
}

if (c->x86 == 0x15) {
unsigned long upperbit;
u32 cpuid, assoc;

cpuid = cpuid_edx(0x80000005);
assoc = cpuid >> 16 & 0xff;
upperbit = ((cpuid >> 24) << 10) / assoc;

va_align.mask = (upperbit - 1) & PAGE_MASK;
va_align.flags = ALIGN_VA_32 | ALIGN_VA_64;

}
}

static void __cpuinit init_amd(struct cpuinfo_x86 *c)
Expand Down
81 changes: 78 additions & 3 deletions trunk/arch/x86/kernel/sys_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,72 @@
#include <asm/ia32.h>
#include <asm/syscalls.h>

struct __read_mostly va_alignment va_align = {
.flags = -1,
};

/*
* Align a virtual address to avoid aliasing in the I$ on AMD F15h.
*
* @flags denotes the allocation direction - bottomup or topdown -
* or vDSO; see call sites below.
*/
unsigned long align_addr(unsigned long addr, struct file *filp,
enum align_flags flags)
{
unsigned long tmp_addr;

/* handle 32- and 64-bit case with a single conditional */
if (va_align.flags < 0 || !(va_align.flags & (2 - mmap_is_ia32())))
return addr;

if (!(current->flags & PF_RANDOMIZE))
return addr;

if (!((flags & ALIGN_VDSO) || filp))
return addr;

tmp_addr = addr;

/*
* We need an address which is <= than the original
* one only when in topdown direction.
*/
if (!(flags & ALIGN_TOPDOWN))
tmp_addr += va_align.mask;

tmp_addr &= ~va_align.mask;

return tmp_addr;
}

static int __init control_va_addr_alignment(char *str)
{
/* guard against enabling this on other CPU families */
if (va_align.flags < 0)
return 1;

if (*str == 0)
return 1;

if (*str == '=')
str++;

if (!strcmp(str, "32"))
va_align.flags = ALIGN_VA_32;
else if (!strcmp(str, "64"))
va_align.flags = ALIGN_VA_64;
else if (!strcmp(str, "off"))
va_align.flags = 0;
else if (!strcmp(str, "on"))
va_align.flags = ALIGN_VA_32 | ALIGN_VA_64;
else
return 0;

return 1;
}
__setup("align_va_addr", control_va_addr_alignment);

SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags,
unsigned long, fd, unsigned long, off)
Expand Down Expand Up @@ -92,6 +158,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
start_addr = addr;

full_search:

addr = align_addr(addr, filp, 0);

for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
/* At this point: (!vma || addr < vma->vm_end). */
if (end - len < addr) {
Expand All @@ -117,6 +186,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
mm->cached_hole_size = vma->vm_start - addr;

addr = vma->vm_end;
addr = align_addr(addr, filp, 0);
}
}

Expand Down Expand Up @@ -161,10 +231,13 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,

/* make sure it can fit in the remaining address space */
if (addr > len) {
vma = find_vma(mm, addr-len);
if (!vma || addr <= vma->vm_start)
unsigned long tmp_addr = align_addr(addr - len, filp,
ALIGN_TOPDOWN);

vma = find_vma(mm, tmp_addr);
if (!vma || tmp_addr + len <= vma->vm_start)
/* remember the address as a hint for next time */
return mm->free_area_cache = addr-len;
return mm->free_area_cache = tmp_addr;
}

if (mm->mmap_base < len)
Expand All @@ -173,6 +246,8 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
addr = mm->mmap_base-len;

do {
addr = align_addr(addr, filp, ALIGN_TOPDOWN);

/*
* Lookup failure means no vma is above this address,
* else if new region fits below vma->vm_start,
Expand Down
15 changes: 0 additions & 15 deletions trunk/arch/x86/mm/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,6 @@ static unsigned int stack_maxrandom_size(void)
#define MIN_GAP (128*1024*1024UL + stack_maxrandom_size())
#define MAX_GAP (TASK_SIZE/6*5)

/*
* True on X86_32 or when emulating IA32 on X86_64
*/
static int mmap_is_ia32(void)
{
#ifdef CONFIG_X86_32
return 1;
#endif
#ifdef CONFIG_IA32_EMULATION
if (test_thread_flag(TIF_IA32))
return 1;
#endif
return 0;
}

static int mmap_is_legacy(void)
{
if (current->personality & ADDR_COMPAT_LAYOUT)
Expand Down
9 changes: 9 additions & 0 deletions trunk/arch/x86/vdso/vma.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ static unsigned long vdso_addr(unsigned long start, unsigned len)
addr = start + (offset << PAGE_SHIFT);
if (addr >= end)
addr = end;

/*
* page-align it here so that get_unmapped_area doesn't
* align it wrongfully again to the next page. addr can come in 4K
* unaligned here as a result of stack start randomization.
*/
addr = PAGE_ALIGN(addr);
addr = align_addr(addr, NULL, ALIGN_VDSO);

return addr;
}

Expand Down

0 comments on commit 94e5578

Please sign in to comment.