mirror of
https://github.com/torvalds/linux.git
synced 2025-11-05 19:19:43 +02:00
powerpc: Work around gcc miscompilation of __pa() on 64-bit
On 64-bit, __pa(&static_var) gets miscompiled by recent versions of
gcc as something like:
addis 3,2,.LANCHOR1+4611686018427387904@toc@ha
addi 3,3,.LANCHOR1+4611686018427387904@toc@l
This ends up effectively ignoring the offset, since its bottom 32 bits
are zero, and means that the result of __pa() still has 0xC in the top
nibble. This happens with gcc 4.8.1, at least.
To work around this, for 64-bit we make __pa() use an AND operator,
and for symmetry, we make __va() use an OR operator. Using an AND
operator rather than a subtraction ends up with slightly shorter code
since it can be done with a single clrldi instruction, whereas it
takes three instructions to form the constant (-PAGE_OFFSET) and add
it on. (Note that MEMORY_START is always 0 on 64-bit.)
CC: <stable@vger.kernel.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
f5f6cbb616
commit
bdbc29c19b
2 changed files with 11 additions and 0 deletions
|
|
@ -979,6 +979,7 @@ config RELOCATABLE
|
||||||
must live at a different physical address than the primary
|
must live at a different physical address than the primary
|
||||||
kernel.
|
kernel.
|
||||||
|
|
||||||
|
# This value must have zeroes in the bottom 60 bits otherwise lots will break
|
||||||
config PAGE_OFFSET
|
config PAGE_OFFSET
|
||||||
hex
|
hex
|
||||||
default "0xc000000000000000"
|
default "0xc000000000000000"
|
||||||
|
|
|
||||||
|
|
@ -211,9 +211,19 @@ extern long long virt_phys_offset;
|
||||||
#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + VIRT_PHYS_OFFSET))
|
#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + VIRT_PHYS_OFFSET))
|
||||||
#define __pa(x) ((unsigned long)(x) - VIRT_PHYS_OFFSET)
|
#define __pa(x) ((unsigned long)(x) - VIRT_PHYS_OFFSET)
|
||||||
#else
|
#else
|
||||||
|
#ifdef CONFIG_PPC64
|
||||||
|
/*
|
||||||
|
* gcc miscompiles (unsigned long)(&static_var) - PAGE_OFFSET
|
||||||
|
* with -mcmodel=medium, so we use & and | instead of - and + on 64-bit.
|
||||||
|
*/
|
||||||
|
#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) | PAGE_OFFSET))
|
||||||
|
#define __pa(x) ((unsigned long)(x) & 0x0fffffffffffffffUL)
|
||||||
|
|
||||||
|
#else /* 32-bit, non book E */
|
||||||
#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + PAGE_OFFSET - MEMORY_START))
|
#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + PAGE_OFFSET - MEMORY_START))
|
||||||
#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + MEMORY_START)
|
#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + MEMORY_START)
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
|
* Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue