Commit 7e3a68be authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc/64: vmlinux support building with PCREL addresing



PC-Relative or PCREL addressing is an extension to the ELF ABI which
uses Power ISA v3.1 PC-relative instructions to calculate addresses,
rather than the traditional TOC scheme.

Add an option to build vmlinux using pcrel addressing. Modules continue
to use TOC addressing.

- TOC address helpers and r2 are poisoned with -1 when running vmlinux.
  r2 could be used for something useful once things are ironed out.

- Assembly must call C functions with @notoc annotation, or the linker
  complains aobut a missing nop after the call. This is done with the
  CFUNC macro introduced earlier.

- Boot: with the exception of prom_init, the execution branches to the
  kernel virtual address early in boot, before any addresses are
  generated, which ensures 34-bit pcrel addressing does not miss the
  high PAGE_OFFSET bits. TOC relative addressing has a similar
  requirement. prom_init does not go to the virtual address and its
  addresses should not carry over to the post-prom kernel.

- Ftrace trampolines are converted from TOC addressing to pcrel
  addressing, including module ftrace trampolines that currently use the
  kernel TOC to find ftrace target functions.

- BPF function prologue and function calling generation are converted
  from TOC to pcrel.

- copypage_64.S has an interesting problem, prefixed instructions have
  alignment restrictions so the linker can add padding, which makes the
  assembler treat the difference between two local labels as
  non-constant even if alignment is arranged so padding is not required.
  This may need toolchain help to solve nicely, for now move the prefix
  instruction out of the alternate patch section to work around it.

This reduces kernel text size by about 6%.

Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230408021752.862660-6-npiggin@gmail.com
parent 4e991e3c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -7,6 +7,9 @@ config CC_HAS_ELFV2
config CC_HAS_PREFIXED
	def_bool PPC64 && $(cc-option, -mcpu=power10 -mprefixed)

config CC_HAS_PCREL
	def_bool PPC64 && $(cc-option, -mcpu=power10 -mpcrel)

config 32BIT
	bool
	default y if PPC32
+7 −0
Original line number Diff line number Diff line
@@ -107,6 +107,9 @@ LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) += -z notext
LDFLAGS_vmlinux	:= $(LDFLAGS_vmlinux-y)

ifdef CONFIG_PPC64
ifdef CONFIG_PPC_KERNEL_PCREL
	KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-pcrel)
endif
ifeq ($(call cc-option-yn,-mcmodel=medium),y)
	# -mcmodel=medium breaks modules because it uses 32bit offsets from
	# the TOC pointer to create pointers where possible. Pointers into the
@@ -185,7 +188,11 @@ KBUILD_CFLAGS += $(call cc-option,-mprefixed)
else
KBUILD_CFLAGS += $(call cc-option,-mno-prefixed)
endif
ifdef CONFIG_PPC_KERNEL_PCREL
KBUILD_CFLAGS += $(call cc-option,-mpcrel)
else
KBUILD_CFLAGS += $(call cc-option,-mno-pcrel)
endif

# No AltiVec or VSX or MMA instructions when building kernel
KBUILD_CFLAGS += $(call cc-option,-mno-altivec)
+2 −0
Original line number Diff line number Diff line
@@ -88,7 +88,9 @@ struct paca_struct {
	u16 lock_token;			/* Constant 0x8000, used in locks */
#endif

#ifndef CONFIG_PPC_KERNEL_PCREL
	u64 kernel_toc;			/* Kernel TOC address */
#endif
	u64 kernelbase;			/* Base address of kernel */
	u64 kernel_msr;			/* MSR while running in kernel */
	void *emergency_sp;		/* pointer to emergency stack */
+8 −0
Original line number Diff line number Diff line
@@ -120,11 +120,18 @@
 * 16-bit immediate helper macros: HA() is for use with sign-extending instrs
 * (e.g. LD, ADDI).  If the bottom 16 bits is "-ve", add another bit into the
 * top half to negate the effect (i.e. 0xffff + 1 = 0x(1)0000).
 *
 * XXX: should these mask out possible sign bits?
 */
#define IMM_H(i)                ((uintptr_t)(i)>>16)
#define IMM_HA(i)               (((uintptr_t)(i)>>16) +                       \
					(((uintptr_t)(i) & 0x8000) >> 15))

/*
 * 18-bit immediate helper for prefix 18-bit upper immediate si0 field.
 */
#define IMM_H18(i)              (((uintptr_t)(i)>>16) & 0x3ffff)


/* opcode and xopcode for instructions */
#define OP_PREFIX	1
@@ -306,6 +313,7 @@
#define PPC_PREFIX_8LS			0x04000000

/* Prefixed instructions */
#define PPC_INST_PADDI			0x38000000
#define PPC_INST_PLD			0xe4000000
#define PPC_INST_PSTD			0xf4000000

+19 −0
Original line number Diff line number Diff line
@@ -183,7 +183,11 @@
/*
 * Used to name C functions called from asm
 */
#if defined(CONFIG_PPC_KERNEL_PCREL) && !defined(MODULE)
#define CFUNC(name) name@notoc
#else
#define CFUNC(name) name
#endif

/*
 * We use __powerpc64__ here because we want the compat VDSO to use the 32-bit
@@ -212,6 +216,9 @@
	.globl name; \
name:

#if defined(CONFIG_PPC_KERNEL_PCREL) && !defined(MODULE)
#define _GLOBAL_TOC _GLOBAL
#else
#define _GLOBAL_TOC(name) \
	.align 2 ; \
	.type name,@function; \
@@ -220,6 +227,7 @@ name: \
0:	addis r2,r12,(.TOC.-0b)@ha; \
	addi r2,r2,(.TOC.-0b)@l; \
	.localentry name,.-name
#endif

#define DOTSYM(a)	a

@@ -351,8 +359,13 @@ GLUE(.,name):

#ifdef __powerpc64__

#ifdef CONFIG_PPC_KERNEL_PCREL
#define __LOAD_PACA_TOC(reg)			\
	li	reg,-1
#else
#define __LOAD_PACA_TOC(reg)			\
	ld	reg,PACATOC(r13)
#endif

#define LOAD_PACA_TOC()				\
	__LOAD_PACA_TOC(r2)
@@ -366,9 +379,15 @@ GLUE(.,name):
	ori	reg, reg, (expr)@l;		\
	rldimi	reg, tmp, 32, 0

#if defined(CONFIG_PPC_KERNEL_PCREL) && !defined(MODULE)
#define LOAD_REG_ADDR(reg,name)			\
	pla	reg,name@pcrel

#else
#define LOAD_REG_ADDR(reg,name)			\
	addis	reg,r2,name@toc@ha;		\
	addi	reg,reg,name@toc@l
#endif

#ifdef CONFIG_PPC_BOOK3E_64
/*
Loading