1
0
Files
kernel-49/arch/powerpc/kernel/module_64.c
Greg Kroah-Hartman fc73f0764a Merge 4.9.283 into android-4.9-q
Changes in 4.9.283
	ext4: fix race writing to an inline_data file while its xattrs are changing
	mtd: nand: atmel_nand: remove build warning in atmel_nand_remove()
	xtensa: fix kconfig unmet dependency warning for HAVE_FUTEX_CMPXCHG
	qed: Fix the VF msix vectors flow
	qede: Fix memset corruption
	perf/x86/amd/ibs: Work around erratum #1197
	cryptoloop: add a deprecation warning
	ARM: 8918/2: only build return_address() if needed
	ALSA: pcm: fix divide error in snd_pcm_lib_ioctl
	ath: Use safer key clearing with key cache entries
	ath9k: Clear key cache explicitly on disabling hardware
	ath: Export ath_hw_keysetmac()
	ath: Modify ath_key_delete() to not need full key entry
	ath9k: Postpone key cache entry deletion for TXQ frames reference it
	media: stkwebcam: fix memory leak in stk_camera_probe
	igmp: Add ip_mc_list lock in ip_check_mc_rcu
	usb: phy: isp1301: Fix build warning when CONFIG_OF is disabled
	USB: serial: mos7720: improve OOM-handling in read_mos_reg()
	net/sched: cls_flower: Use mask for addr_type
	PM / wakeirq: Enable dedicated wakeirq for suspend
	tc358743: fix register i2c_rd/wr function fix
	nvme-pci: Fix an error handling path in 'nvme_probe()'
	gfs2: Don't clear SGID when inheriting ACLs
	ipv4/icmp: l3mdev: Perform icmp error route lookup on source device routing table (v2)
	s390/disassembler: correct disassembly lines alignment
	mm/kmemleak.c: make cond_resched() rate-limiting more efficient
	crypto: talitos - reduce max key size for SEC1
	powerpc/module64: Fix comment in R_PPC64_ENTRY handling
	powerpc/boot: Delete unneeded .globl _zimage_start
	net: ll_temac: Remove left-over debug message
	mm/page_alloc: speed up the iteration of max_order
	Revert "btrfs: compression: don't try to compress if we don't have enough pages"
	x86/reboot: Limit Dell Optiplex 990 quirk to early BIOS versions
	PCI: Call Max Payload Size-related fixup quirks early
	regmap: fix the offset of register error log
	crypto: mxs-dcp - Check for DMA mapping errors
	power: supply: axp288_fuel_gauge: Report register-address on readb / writeb errors
	crypto: omap-sham - clear dma flags only after omap_sham_update_dma_stop()
	udf: Check LVID earlier
	power: supply: max17042_battery: fix typo in MAx17042_TOFF
	libata: fix ata_host_start()
	crypto: qat - do not ignore errors from enable_vf2pf_comms()
	crypto: qat - handle both source of interrupt in VF ISR
	crypto: qat - fix reuse of completion variable
	crypto: qat - fix naming for init/shutdown VF to PF notifications
	crypto: qat - do not export adf_iov_putmsg()
	udf_get_extendedattr() had no boundary checks.
	m68k: emu: Fix invalid free in nfeth_cleanup()
	spi: spi-pic32: Fix issue with uninitialized dma_slave_config
	crypto: qat - use proper type for vf_mask
	certs: Trigger creation of RSA module signing key if it's not an RSA key
	media: dvb-usb: fix uninit-value in dvb_usb_adapter_dvb_init
	media: dvb-usb: fix uninit-value in vp702x_read_mac_addr
	media: go7007: remove redundant initialization
	Bluetooth: sco: prevent information leak in sco_conn_defer_accept()
	tcp: seq_file: Avoid skipping sk during tcp_seek_last_pos
	net: cipso: fix warnings in netlbl_cipsov4_add_std
	i2c: highlander: add IRQ check
	PCI: PM: Enable PME if it can be signaled from D3cold
	soc: qcom: smsm: Fix missed interrupts if state changes while masked
	Bluetooth: increase BTNAMSIZ to 21 chars to fix potential buffer overflow
	arm64: dts: exynos: correct GIC CPU interfaces address range on Exynos7
	Bluetooth: fix repeated calls to sco_sock_kill
	drm/msm/dsi: Fix some reference counted resource leaks
	usb: gadget: udc: at91: add IRQ check
	usb: phy: fsl-usb: add IRQ check
	usb: phy: twl6030: add IRQ checks
	Bluetooth: Move shutdown callback before flushing tx and rx queue
	usb: host: ohci-tmio: add IRQ check
	usb: phy: tahvo: add IRQ check
	usb: gadget: mv_u3d: request_irq() after initializing UDC
	Bluetooth: add timeout sanity check to hci_inquiry
	i2c: iop3xx: fix deferred probing
	i2c: s3c2410: fix IRQ check
	mmc: dw_mmc: Fix issue with uninitialized dma_slave_config
	mmc: moxart: Fix issue with uninitialized dma_slave_config
	CIFS: Fix a potencially linear read overflow
	i2c: mt65xx: fix IRQ check
	usb: ehci-orion: Handle errors of clk_prepare_enable() in probe
	ath6kl: wmi: fix an error code in ath6kl_wmi_sync_point()
	bcma: Fix memory leak for internally-handled cores
	ipv4: make exception cache less predictible
	tty: Fix data race between tiocsti() and flush_to_ldisc()
	KVM: x86: Update vCPU's hv_clock before back to guest when tsc_offset is adjusted
	IMA: remove -Wmissing-prototypes warning
	clk: kirkwood: Fix a clocking boot regression
	fbmem: don't allow too huge resolutions
	rtc: tps65910: Correct driver module alias
	PCI/MSI: Skip masking MSI-X on Xen PV
	powerpc/perf/hv-gpci: Fix counter value parsing
	xen: fix setting of max_pfn in shared_info
	crypto: public_key: fix overflow during implicit conversion
	power: supply: max17042: handle fails of reading status register
	VMCI: fix NULL pointer dereference when unmapping queue pair
	media: uvc: don't do DMA on stack
	media: rc-loopback: return number of emitters rather than error
	libata: add ATA_HORKAGE_NO_NCQ_TRIM for Samsung 860 and 870 SSDs
	ARM: 9105/1: atags_to_fdt: don't warn about stack size
	PCI: Restrict ASMedia ASM1062 SATA Max Payload Size Supported
	PCI: Return ~0 data on pciconfig_read() CAP_SYS_ADMIN failure
	vfio: Use config not menuconfig for VFIO_NOIOMMU
	openrisc: don't printk() unconditionally
	pinctrl: single: Fix error return code in pcs_parse_bits_in_pinctrl_entry()
	MIPS: Malta: fix alignment of the devicetree buffer
	crypto: mxs-dcp - Use sg_mapping_iter to copy data
	PCI: Use pci_update_current_state() in pci_enable_device_flags()
	iio: dac: ad5624r: Fix incorrect handling of an optional regulator.
	video: fbdev: kyro: fix a DoS bug by restricting user input
	netlink: Deal with ESRCH error in nlmsg_notify()
	Smack: Fix wrong semantics in smk_access_entry()
	usb: host: fotg210: fix the endpoint's transactional opportunities calculation
	usb: host: fotg210: fix the actual_length of an iso packet
	usb: gadget: u_ether: fix a potential null pointer dereference
	usb: gadget: composite: Allow bMaxPower=0 if self-powered
	staging: board: Fix uninitialized spinlock when attaching genpd
	tty: serial: jsm: hold port lock when reporting modem line changes
	bpf/tests: Fix copy-and-paste error in double word test
	bpf/tests: Do not PASS tests without actually testing the result
	video: fbdev: asiliantfb: Error out if 'pixclock' equals zero
	video: fbdev: kyro: Error out if 'pixclock' equals zero
	video: fbdev: riva: Error out if 'pixclock' equals zero
	ipv4: ip_output.c: Fix out-of-bounds warning in ip_copy_addrs()
	flow_dissector: Fix out-of-bounds warnings
	s390/jump_label: print real address in a case of a jump label bug
	serial: 8250: Define RX trigger levels for OxSemi 950 devices
	xtensa: ISS: don't panic in rs_init
	hvsi: don't panic on tty_register_driver failure
	serial: 8250_pci: make setup_port() parameters explicitly unsigned
	staging: ks7010: Fix the initialization of the 'sleep_status' structure
	ata: sata_dwc_460ex: No need to call phy_exit() befre phy_init()
	Bluetooth: skip invalid hci_sync_conn_complete_evt
	ASoC: Intel: bytcr_rt5640: Move "Platform Clock" routes to the maps for the matching in-/output
	net: ethernet: stmmac: Do not use unreachable() in ipq806x_gmac_probe()
	Bluetooth: avoid circular locks in sco_sock_connect
	gpu: drm: amd: amdgpu: amdgpu_i2c: fix possible uninitialized-variable access in amdgpu_i2c_router_select_ddc_port()
	ARM: tegra: tamonten: Fix UART pad setting
	rpc: fix gss_svc_init cleanup on failure
	gfs2: Don't call dlm after protocol is unmounted
	mmc: rtsx_pci: Fix long reads when clock is prescaled
	cifs: fix wrong release in sess_alloc_buffer() failed path
	Revert "USB: xhci: fix U1/U2 handling for hardware with XHCI_INTEL_HOST quirk set"
	usbip: give back URBs for unsent unlink requests during cleanup
	parport: remove non-zero check on count
	ath9k: fix OOB read ar9300_eeprom_restore_internal
	ath9k: fix sleeping in atomic context
	net: fix NULL pointer reference in cipso_v4_doi_free
	net: w5100: check return value after calling platform_get_resource()
	parisc: fix crash with signals and alloca
	scsi: BusLogic: Fix missing pr_cont() use
	mm/hugetlb: initialize hugetlb_usage in mm_init
	memcg: enable accounting for pids in nested pid namespaces
	platform/chrome: cros_ec_proto: Send command again when timeout occurs
	xen: reset legacy rtc flag for PV domU
	bnx2x: Fix enabling network interfaces without VFs
	net-caif: avoid user-triggerable WARN_ON(1)
	ptp: dp83640: don't define PAGE0
	dccp: don't duplicate ccid when cloning dccp sock
	net/l2tp: Fix reference count leak in l2tp_udp_recv_core
	r6040: Restore MDIO clock frequency after MAC reset
	tipc: increase timeout in tipc_sk_enqueue()
	events: Reuse value read using READ_ONCE instead of re-reading it
	net/af_unix: fix a data-race in unix_dgram_poll
	tcp: fix tp->undo_retrans accounting in tcp_sacktag_one()
	x86/mm: Fix kern_addr_valid() to cope with existing but not present entries
	dt-bindings: mtd: gpmc: Fix the ECC bytes vs. OOB bytes equation
	mfd: Don't use irq_create_mapping() to resolve a mapping
	net: usb: cdc_mbim: avoid altsetting toggling for Telit LN920
	ethtool: Fix an error code in cxgb2.c
	PCI: Sync __pci_register_driver() stub for CONFIG_PCI=n
	mtd: rawnand: cafe: Fix a resource leak in the error handling path of 'cafe_nand_probe()'
	ARC: export clear_user_page() for modules
	net: dsa: b53: Fix calculating number of switch ports
	qlcnic: Remove redundant unlock in qlcnic_pinit_from_rom
	net: renesas: sh_eth: Fix freeing wrong tx descriptor
	s390/bpf: Fix 64-bit subtraction of the -0x80000000 constant
	Linux 4.9.283

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I9e2017cce36805d71566ea1f265974a43bae33d1
2021-09-23 10:21:59 +03:00

806 lines
22 KiB
C

/* Kernel module help for PPC64.
Copyright (C) 2001, 2003 Rusty Russell IBM Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/elf.h>
#include <linux/moduleloader.h>
#include <linux/err.h>
#include <linux/vmalloc.h>
#include <linux/ftrace.h>
#include <linux/bug.h>
#include <linux/uaccess.h>
#include <asm/module.h>
#include <asm/firmware.h>
#include <asm/code-patching.h>
#include <linux/sort.h>
#include <asm/setup.h>
#include <asm/sections.h>
/* FIXME: We don't do .init separately. To do this, we'd need to have
a separate r2 value in the init and core section, and stub between
them, too.
Using a magic allocator which places modules within 32MB solves
this, and makes other things simpler. Anton?
--RR. */
#ifdef PPC64_ELF_ABI_v2
/* An address is simply the address of the function. */
typedef unsigned long func_desc_t;
static func_desc_t func_desc(unsigned long addr)
{
return addr;
}
static unsigned long func_addr(unsigned long addr)
{
return addr;
}
static unsigned long stub_func_addr(func_desc_t func)
{
return func;
}
/* PowerPC64 specific values for the Elf64_Sym st_other field. */
#define STO_PPC64_LOCAL_BIT 5
#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)
#define PPC64_LOCAL_ENTRY_OFFSET(other) \
(((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2)
static unsigned int local_entry_offset(const Elf64_Sym *sym)
{
/* sym->st_other indicates offset to local entry point
* (otherwise it will assume r12 is the address of the start
* of function and try to derive r2 from it). */
return PPC64_LOCAL_ENTRY_OFFSET(sym->st_other);
}
#else
/* An address is address of the OPD entry, which contains address of fn. */
typedef struct ppc64_opd_entry func_desc_t;
static func_desc_t func_desc(unsigned long addr)
{
return *(struct ppc64_opd_entry *)addr;
}
static unsigned long func_addr(unsigned long addr)
{
return func_desc(addr).funcaddr;
}
static unsigned long stub_func_addr(func_desc_t func)
{
return func.funcaddr;
}
static unsigned int local_entry_offset(const Elf64_Sym *sym)
{
return 0;
}
#endif
#define STUB_MAGIC 0x73747562 /* stub */
/* Like PPC32, we need little trampolines to do > 24-bit jumps (into
the kernel itself). But on PPC64, these need to be used for every
jump, actually, to reset r2 (TOC+0x8000). */
struct ppc64_stub_entry
{
/* 28 byte jump instruction sequence (7 instructions). We only
* need 6 instructions on ABIv2 but we always allocate 7 so
* so we don't have to modify the trampoline load instruction. */
u32 jump[7];
/* Used by ftrace to identify stubs */
u32 magic;
/* Data for the above code */
func_desc_t funcdata;
};
/*
* PPC64 uses 24 bit jumps, but we need to jump into other modules or
* the kernel which may be further. So we jump to a stub.
*
* For ELFv1 we need to use this to set up the new r2 value (aka TOC
* pointer). For ELFv2 it's the callee's responsibility to set up the
* new r2, but for both we need to save the old r2.
*
* We could simply patch the new r2 value and function pointer into
* the stub, but it's significantly shorter to put these values at the
* end of the stub code, and patch the stub address (32-bits relative
* to the TOC ptr, r2) into the stub.
*/
static u32 ppc64_stub_insns[] = {
0x3d620000, /* addis r11,r2, <high> */
0x396b0000, /* addi r11,r11, <low> */
/* Save current r2 value in magic place on the stack. */
0xf8410000|R2_STACK_OFFSET, /* std r2,R2_STACK_OFFSET(r1) */
0xe98b0020, /* ld r12,32(r11) */
#ifdef PPC64_ELF_ABI_v1
/* Set up new r2 from function descriptor */
0xe84b0028, /* ld r2,40(r11) */
#endif
0x7d8903a6, /* mtctr r12 */
0x4e800420 /* bctr */
};
#ifdef CONFIG_DYNAMIC_FTRACE
int module_trampoline_target(struct module *mod, unsigned long addr,
unsigned long *target)
{
struct ppc64_stub_entry *stub;
func_desc_t funcdata;
u32 magic;
if (!within_module_core(addr, mod)) {
pr_err("%s: stub %lx not in module %s\n", __func__, addr, mod->name);
return -EFAULT;
}
stub = (struct ppc64_stub_entry *)addr;
if (probe_kernel_read(&magic, &stub->magic, sizeof(magic))) {
pr_err("%s: fault reading magic for stub %lx for %s\n", __func__, addr, mod->name);
return -EFAULT;
}
if (magic != STUB_MAGIC) {
pr_err("%s: bad magic for stub %lx for %s\n", __func__, addr, mod->name);
return -EFAULT;
}
if (probe_kernel_read(&funcdata, &stub->funcdata, sizeof(funcdata))) {
pr_err("%s: fault reading funcdata for stub %lx for %s\n", __func__, addr, mod->name);
return -EFAULT;
}
*target = stub_func_addr(funcdata);
return 0;
}
#endif
/* Count how many different 24-bit relocations (different symbol,
different addend) */
static unsigned int count_relocs(const Elf64_Rela *rela, unsigned int num)
{
unsigned int i, r_info, r_addend, _count_relocs;
/* FIXME: Only count external ones --RR */
_count_relocs = 0;
r_info = 0;
r_addend = 0;
for (i = 0; i < num; i++)
/* Only count 24-bit relocs, others don't need stubs */
if (ELF64_R_TYPE(rela[i].r_info) == R_PPC_REL24 &&
(r_info != ELF64_R_SYM(rela[i].r_info) ||
r_addend != rela[i].r_addend)) {
_count_relocs++;
r_info = ELF64_R_SYM(rela[i].r_info);
r_addend = rela[i].r_addend;
}
return _count_relocs;
}
static int relacmp(const void *_x, const void *_y)
{
const Elf64_Rela *x, *y;
y = (Elf64_Rela *)_x;
x = (Elf64_Rela *)_y;
/* Compare the entire r_info (as opposed to ELF64_R_SYM(r_info) only) to
* make the comparison cheaper/faster. It won't affect the sorting or
* the counting algorithms' performance
*/
if (x->r_info < y->r_info)
return -1;
else if (x->r_info > y->r_info)
return 1;
else if (x->r_addend < y->r_addend)
return -1;
else if (x->r_addend > y->r_addend)
return 1;
else
return 0;
}
static void relaswap(void *_x, void *_y, int size)
{
uint64_t *x, *y, tmp;
int i;
y = (uint64_t *)_x;
x = (uint64_t *)_y;
for (i = 0; i < sizeof(Elf64_Rela) / sizeof(uint64_t); i++) {
tmp = x[i];
x[i] = y[i];
y[i] = tmp;
}
}
/* Get size of potential trampolines required. */
static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
const Elf64_Shdr *sechdrs)
{
/* One extra reloc so it's always 0-funcaddr terminated */
unsigned long relocs = 1;
unsigned i;
/* Every relocated section... */
for (i = 1; i < hdr->e_shnum; i++) {
if (sechdrs[i].sh_type == SHT_RELA) {
pr_debug("Found relocations in section %u\n", i);
pr_debug("Ptr: %p. Number: %Lu\n",
(void *)sechdrs[i].sh_addr,
sechdrs[i].sh_size / sizeof(Elf64_Rela));
/* Sort the relocation information based on a symbol and
* addend key. This is a stable O(n*log n) complexity
* alogrithm but it will reduce the complexity of
* count_relocs() to linear complexity O(n)
*/
sort((void *)sechdrs[i].sh_addr,
sechdrs[i].sh_size / sizeof(Elf64_Rela),
sizeof(Elf64_Rela), relacmp, relaswap);
relocs += count_relocs((void *)sechdrs[i].sh_addr,
sechdrs[i].sh_size
/ sizeof(Elf64_Rela));
}
}
#ifdef CONFIG_DYNAMIC_FTRACE
/* make the trampoline to the ftrace_caller */
relocs++;
#endif
pr_debug("Looks like a total of %lu stubs, max\n", relocs);
return relocs * sizeof(struct ppc64_stub_entry);
}
/* Still needed for ELFv2, for .TOC. */
static void dedotify_versions(struct modversion_info *vers,
unsigned long size)
{
struct modversion_info *end;
for (end = (void *)vers + size; vers < end; vers++)
if (vers->name[0] == '.') {
memmove(vers->name, vers->name+1, strlen(vers->name));
#ifdef ARCH_RELOCATES_KCRCTAB
/* The TOC symbol has no CRC computed. To avoid CRC
* check failing, we must force it to the expected
* value (see CRC check in module.c).
*/
if (!strcmp(vers->name, "TOC."))
vers->crc = -(unsigned long)reloc_start;
#endif
}
}
/*
* Undefined symbols which refer to .funcname, hack to funcname. Make .TOC.
* seem to be defined (value set later).
*/
static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
{
unsigned int i;
for (i = 1; i < numsyms; i++) {
if (syms[i].st_shndx == SHN_UNDEF) {
char *name = strtab + syms[i].st_name;
if (name[0] == '.') {
if (strcmp(name+1, "TOC.") == 0)
syms[i].st_shndx = SHN_ABS;
syms[i].st_name++;
}
}
}
}
static Elf64_Sym *find_dot_toc(Elf64_Shdr *sechdrs,
const char *strtab,
unsigned int symindex)
{
unsigned int i, numsyms;
Elf64_Sym *syms;
syms = (Elf64_Sym *)sechdrs[symindex].sh_addr;
numsyms = sechdrs[symindex].sh_size / sizeof(Elf64_Sym);
for (i = 1; i < numsyms; i++) {
if (syms[i].st_shndx == SHN_ABS
&& strcmp(strtab + syms[i].st_name, "TOC.") == 0)
return &syms[i];
}
return NULL;
}
int module_frob_arch_sections(Elf64_Ehdr *hdr,
Elf64_Shdr *sechdrs,
char *secstrings,
struct module *me)
{
unsigned int i;
/* Find .toc and .stubs sections, symtab and strtab */
for (i = 1; i < hdr->e_shnum; i++) {
char *p;
if (strcmp(secstrings + sechdrs[i].sh_name, ".stubs") == 0)
me->arch.stubs_section = i;
else if (strcmp(secstrings + sechdrs[i].sh_name, ".toc") == 0)
me->arch.toc_section = i;
else if (strcmp(secstrings+sechdrs[i].sh_name,"__versions")==0)
dedotify_versions((void *)hdr + sechdrs[i].sh_offset,
sechdrs[i].sh_size);
/* We don't handle .init for the moment: rename to _init */
while ((p = strstr(secstrings + sechdrs[i].sh_name, ".init")))
p[0] = '_';
if (sechdrs[i].sh_type == SHT_SYMTAB)
dedotify((void *)hdr + sechdrs[i].sh_offset,
sechdrs[i].sh_size / sizeof(Elf64_Sym),
(void *)hdr
+ sechdrs[sechdrs[i].sh_link].sh_offset);
}
if (!me->arch.stubs_section) {
pr_err("%s: doesn't contain .stubs.\n", me->name);
return -ENOEXEC;
}
/* If we don't have a .toc, just use .stubs. We need to set r2
to some reasonable value in case the module calls out to
other functions via a stub, or if a function pointer escapes
the module by some means. */
if (!me->arch.toc_section)
me->arch.toc_section = me->arch.stubs_section;
/* Override the stubs size */
sechdrs[me->arch.stubs_section].sh_size = get_stubs_size(hdr, sechdrs);
return 0;
}
/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this
gives the value maximum span in an instruction which uses a signed
offset) */
static inline unsigned long my_r2(const Elf64_Shdr *sechdrs, struct module *me)
{
return sechdrs[me->arch.toc_section].sh_addr + 0x8000;
}
/* Both low and high 16 bits are added as SIGNED additions, so if low
16 bits has high bit set, high 16 bits must be adjusted. These
macros do that (stolen from binutils). */
#define PPC_LO(v) ((v) & 0xffff)
#define PPC_HI(v) (((v) >> 16) & 0xffff)
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
/* Patch stub to reference function and correct r2 value. */
static inline int create_stub(const Elf64_Shdr *sechdrs,
struct ppc64_stub_entry *entry,
unsigned long addr,
struct module *me)
{
long reladdr;
memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns));
/* Stub uses address relative to r2. */
reladdr = (unsigned long)entry - my_r2(sechdrs, me);
if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) {
pr_err("%s: Address %p of stub out of range of %p.\n",
me->name, (void *)reladdr, (void *)my_r2);
return 0;
}
pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr);
entry->jump[0] |= PPC_HA(reladdr);
entry->jump[1] |= PPC_LO(reladdr);
entry->funcdata = func_desc(addr);
entry->magic = STUB_MAGIC;
return 1;
}
/* Create stub to jump to function described in this OPD/ptr: we need the
stub to set up the TOC ptr (r2) for the function. */
static unsigned long stub_for_addr(const Elf64_Shdr *sechdrs,
unsigned long addr,
struct module *me)
{
struct ppc64_stub_entry *stubs;
unsigned int i, num_stubs;
num_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*stubs);
/* Find this stub, or if that fails, the next avail. entry */
stubs = (void *)sechdrs[me->arch.stubs_section].sh_addr;
for (i = 0; stub_func_addr(stubs[i].funcdata); i++) {
BUG_ON(i >= num_stubs);
if (stub_func_addr(stubs[i].funcdata) == func_addr(addr))
return (unsigned long)&stubs[i];
}
if (!create_stub(sechdrs, &stubs[i], addr, me))
return 0;
return (unsigned long)&stubs[i];
}
#ifdef CC_USING_MPROFILE_KERNEL
static bool is_early_mcount_callsite(u32 *instruction)
{
/*
* Check if this is one of the -mprofile-kernel sequences.
*/
if (instruction[-1] == PPC_INST_STD_LR &&
instruction[-2] == PPC_INST_MFLR)
return true;
if (instruction[-1] == PPC_INST_MFLR)
return true;
return false;
}
/*
* In case of _mcount calls, do not save the current callee's TOC (in r2) into
* the original caller's stack frame. If we did we would clobber the saved TOC
* value of the original caller.
*/
static void squash_toc_save_inst(const char *name, unsigned long addr)
{
struct ppc64_stub_entry *stub = (struct ppc64_stub_entry *)addr;
/* Only for calls to _mcount */
if (strcmp("_mcount", name) != 0)
return;
stub->jump[2] = PPC_INST_NOP;
}
#else
static void squash_toc_save_inst(const char *name, unsigned long addr) { }
/* without -mprofile-kernel, mcount calls are never early */
static bool is_early_mcount_callsite(u32 *instruction)
{
return false;
}
#endif
/* We expect a noop next: if it is, replace it with instruction to
restore r2. */
static int restore_r2(u32 *instruction, struct module *me)
{
u32 *prev_insn = instruction - 1;
if (is_early_mcount_callsite(prev_insn))
return 1;
/*
* Make sure the branch isn't a sibling call. Sibling calls aren't
* "link" branches and they don't return, so they don't need the r2
* restore afterwards.
*/
if (!instr_is_relative_link_branch(*prev_insn))
return 1;
if (*instruction != PPC_INST_NOP) {
pr_err("%s: Expect noop after relocate, got %08x\n",
me->name, *instruction);
return 0;
}
/* ld r2,R2_STACK_OFFSET(r1) */
*instruction = PPC_INST_LD_TOC;
return 1;
}
int apply_relocate_add(Elf64_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
unsigned int i;
Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr;
Elf64_Sym *sym;
unsigned long *location;
unsigned long value;
pr_debug("Applying ADD relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
/* First time we're called, we can fix up .TOC. */
if (!me->arch.toc_fixed) {
sym = find_dot_toc(sechdrs, strtab, symindex);
/* It's theoretically possible that a module doesn't want a
* .TOC. so don't fail it just for that. */
if (sym)
sym->st_value = my_r2(sechdrs, me);
me->arch.toc_fixed = true;
}
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rela[i].r_offset;
/* This is the symbol it is referring to */
sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
+ ELF64_R_SYM(rela[i].r_info);
pr_debug("RELOC at %p: %li-type as %s (0x%lx) + %li\n",
location, (long)ELF64_R_TYPE(rela[i].r_info),
strtab + sym->st_name, (unsigned long)sym->st_value,
(long)rela[i].r_addend);
/* `Everything is relative'. */
value = sym->st_value + rela[i].r_addend;
switch (ELF64_R_TYPE(rela[i].r_info)) {
case R_PPC64_ADDR32:
/* Simply set it */
*(u32 *)location = value;
break;
case R_PPC64_ADDR64:
/* Simply set it */
*(unsigned long *)location = value;
break;
case R_PPC64_TOC:
*(unsigned long *)location = my_r2(sechdrs, me);
break;
case R_PPC64_TOC16:
/* Subtract TOC pointer */
value -= my_r2(sechdrs, me);
if (value + 0x8000 > 0xffff) {
pr_err("%s: bad TOC16 relocation (0x%lx)\n",
me->name, value);
return -ENOEXEC;
}
*((uint16_t *) location)
= (*((uint16_t *) location) & ~0xffff)
| (value & 0xffff);
break;
case R_PPC64_TOC16_LO:
/* Subtract TOC pointer */
value -= my_r2(sechdrs, me);
*((uint16_t *) location)
= (*((uint16_t *) location) & ~0xffff)
| (value & 0xffff);
break;
case R_PPC64_TOC16_DS:
/* Subtract TOC pointer */
value -= my_r2(sechdrs, me);
if ((value & 3) != 0 || value + 0x8000 > 0xffff) {
pr_err("%s: bad TOC16_DS relocation (0x%lx)\n",
me->name, value);
return -ENOEXEC;
}
*((uint16_t *) location)
= (*((uint16_t *) location) & ~0xfffc)
| (value & 0xfffc);
break;
case R_PPC64_TOC16_LO_DS:
/* Subtract TOC pointer */
value -= my_r2(sechdrs, me);
if ((value & 3) != 0) {
pr_err("%s: bad TOC16_LO_DS relocation (0x%lx)\n",
me->name, value);
return -ENOEXEC;
}
*((uint16_t *) location)
= (*((uint16_t *) location) & ~0xfffc)
| (value & 0xfffc);
break;
case R_PPC64_TOC16_HA:
/* Subtract TOC pointer */
value -= my_r2(sechdrs, me);
value = ((value + 0x8000) >> 16);
*((uint16_t *) location)
= (*((uint16_t *) location) & ~0xffff)
| (value & 0xffff);
break;
case R_PPC_REL24:
/* FIXME: Handle weak symbols here --RR */
if (sym->st_shndx == SHN_UNDEF) {
/* External: go via stub */
value = stub_for_addr(sechdrs, value, me);
if (!value)
return -ENOENT;
if (!restore_r2((u32 *)location + 1, me))
return -ENOEXEC;
squash_toc_save_inst(strtab + sym->st_name, value);
} else
value += local_entry_offset(sym);
/* Convert value to relative */
value -= (unsigned long)location;
if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){
pr_err("%s: REL24 %li out of range!\n",
me->name, (long int)value);
return -ENOEXEC;
}
/* Only replace bits 2 through 26 */
*(uint32_t *)location
= (*(uint32_t *)location & ~0x03fffffc)
| (value & 0x03fffffc);
break;
case R_PPC64_REL64:
/* 64 bits relative (used by features fixups) */
*location = value - (unsigned long)location;
break;
case R_PPC64_TOCSAVE:
/*
* Marker reloc indicates we don't have to save r2.
* That would only save us one instruction, so ignore
* it.
*/
break;
case R_PPC64_ENTRY:
/*
* Optimize ELFv2 large code model entry point if
* the TOC is within 2GB range of current location.
*/
value = my_r2(sechdrs, me) - (unsigned long)location;
if (value + 0x80008000 > 0xffffffff)
break;
/*
* Check for the large code model prolog sequence:
* ld r2, ...(r12)
* add r2, r2, r12
*/
if ((((uint32_t *)location)[0] & ~0xfffc)
!= 0xe84c0000)
break;
if (((uint32_t *)location)[1] != 0x7c426214)
break;
/*
* If found, replace it with:
* addis r2, r12, (.TOC.-func)@ha
* addi r2, r2, (.TOC.-func)@l
*/
((uint32_t *)location)[0] = 0x3c4c0000 + PPC_HA(value);
((uint32_t *)location)[1] = 0x38420000 + PPC_LO(value);
break;
case R_PPC64_REL16_HA:
/* Subtract location pointer */
value -= (unsigned long)location;
value = ((value + 0x8000) >> 16);
*((uint16_t *) location)
= (*((uint16_t *) location) & ~0xffff)
| (value & 0xffff);
break;
case R_PPC64_REL16_LO:
/* Subtract location pointer */
value -= (unsigned long)location;
*((uint16_t *) location)
= (*((uint16_t *) location) & ~0xffff)
| (value & 0xffff);
break;
default:
pr_err("%s: Unknown ADD relocation: %lu\n",
me->name,
(unsigned long)ELF64_R_TYPE(rela[i].r_info));
return -ENOEXEC;
}
}
return 0;
}
#ifdef CONFIG_DYNAMIC_FTRACE
#ifdef CC_USING_MPROFILE_KERNEL
#define PACATOC offsetof(struct paca_struct, kernel_toc)
/*
* For mprofile-kernel we use a special stub for ftrace_caller() because we
* can't rely on r2 containing this module's TOC when we enter the stub.
*
* That can happen if the function calling us didn't need to use the toc. In
* that case it won't have setup r2, and the r2 value will be either the
* kernel's toc, or possibly another modules toc.
*
* To deal with that this stub uses the kernel toc, which is always accessible
* via the paca (in r13). The target (ftrace_caller()) is responsible for
* saving and restoring the toc before returning.
*/
static unsigned long create_ftrace_stub(const Elf64_Shdr *sechdrs, struct module *me)
{
struct ppc64_stub_entry *entry;
unsigned int i, num_stubs;
static u32 stub_insns[] = {
0xe98d0000 | PACATOC, /* ld r12,PACATOC(r13) */
0x3d8c0000, /* addis r12,r12,<high> */
0x398c0000, /* addi r12,r12,<low> */
0x7d8903a6, /* mtctr r12 */
0x4e800420, /* bctr */
};
long reladdr;
num_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*entry);
/* Find the next available stub entry */
entry = (void *)sechdrs[me->arch.stubs_section].sh_addr;
for (i = 0; i < num_stubs && stub_func_addr(entry->funcdata); i++, entry++);
if (i >= num_stubs) {
pr_err("%s: Unable to find a free slot for ftrace stub.\n", me->name);
return 0;
}
memcpy(entry->jump, stub_insns, sizeof(stub_insns));
/* Stub uses address relative to kernel toc (from the paca) */
reladdr = (unsigned long)ftrace_caller - kernel_toc_addr();
if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) {
pr_err("%s: Address of ftrace_caller out of range of kernel_toc.\n", me->name);
return 0;
}
entry->jump[1] |= PPC_HA(reladdr);
entry->jump[2] |= PPC_LO(reladdr);
/* Eventhough we don't use funcdata in the stub, it's needed elsewhere. */
entry->funcdata = func_desc((unsigned long)ftrace_caller);
entry->magic = STUB_MAGIC;
return (unsigned long)entry;
}
#else
static unsigned long create_ftrace_stub(const Elf64_Shdr *sechdrs, struct module *me)
{
return stub_for_addr(sechdrs, (unsigned long)ftrace_caller, me);
}
#endif
int module_finalize_ftrace(struct module *mod, const Elf_Shdr *sechdrs)
{
mod->arch.toc = my_r2(sechdrs, mod);
mod->arch.tramp = create_ftrace_stub(sechdrs, mod);
if (!mod->arch.tramp)
return -ENOENT;
return 0;
}
#endif