summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/amd64/elf_machdep.c29
-rw-r--r--sys/amd64/amd64/machdep.c19
-rw-r--r--sys/arm/include/atomic-v4.h44
-rw-r--r--sys/arm/include/atomic-v6.h46
-rw-r--r--sys/conf/newvers.sh2
-rw-r--r--sys/dev/mmc/mmcsd.c18
-rw-r--r--sys/dev/sdhci/sdhci_acpi.c10
-rw-r--r--sys/dev/sdhci/sdhci_pci.c4
-rw-r--r--sys/dev/vxge/vxge.c1
-rw-r--r--sys/i386/i386/elf_machdep.c30
-rw-r--r--sys/i386/i386/machdep.c4
-rw-r--r--sys/kern/link_elf.c80
-rw-r--r--sys/kern/link_elf_obj.c22
-rw-r--r--sys/net/if_ipsec.c2
-rw-r--r--sys/sys/linker.h9
-rw-r--r--sys/x86/include/ifunc.h58
16 files changed, 300 insertions, 78 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c
index f82c084..66aa3bd 100644
--- a/sys/amd64/amd64/elf_machdep.c
+++ b/sys/amd64/amd64/elf_machdep.c
@@ -173,10 +173,13 @@ elf64_dump_thread(struct thread *td, void *dst, size_t *off)
*off = len;
}
+#define ERI_LOCAL 0x0001
+#define ERI_ONLYIFUNC 0x0002
+
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
- int type, int local, elf_lookup_fn lookup)
+ int type, elf_lookup_fn lookup, int flags)
{
Elf64_Addr *where, val;
Elf32_Addr *where32, val32;
@@ -215,6 +218,9 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
panic("unknown reloc type %d\n", type);
}
+ if (((flags & ERI_ONLYIFUNC) == 0) ^ (rtype != R_X86_64_IRELATIVE))
+ return (0);
+
switch (rtype) {
case R_X86_64_NONE: /* none */
break;
@@ -273,6 +279,13 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
*where = val;
break;
+ case R_X86_64_IRELATIVE:
+ addr = relocbase + addend;
+ val = ((Elf64_Addr (*)(void))addr)();
+ if (*where != val)
+ *where = val;
+ break;
+
default:
printf("kldload: unexpected relocation type %ld\n",
rtype);
@@ -282,11 +295,20 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
}
int
+elf_reloc_ifunc(linker_file_t lf, Elf_Addr relocbase, const void *data,
+ int type, elf_lookup_fn lookup)
+{
+
+ return (elf_reloc_internal(lf, relocbase, data, type, lookup,
+ ERI_ONLYIFUNC));
+}
+
+int
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
- return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
+ return (elf_reloc_internal(lf, relocbase, data, type, lookup, 0));
}
int
@@ -294,7 +316,8 @@ elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
- return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
+ return (elf_reloc_internal(lf, relocbase, data, type, lookup,
+ ERI_LOCAL));
}
int
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 4972173..07373c0 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -1564,16 +1564,23 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
size_t kstack0_sz;
int late_console;
- /*
- * This may be done better later if it gets more high level
- * components in it. If so just link td->td_proc here.
- */
- proc_linkup0(&proc0, &thread0);
-
kmdp = init_ops.parse_preload_data(modulep);
identify_cpu1();
identify_hypervisor();
+ /*
+ * hw.cpu_stdext_disable is ignored by the call, it will be
+ * re-evaluted by the below call to finishidentcpu().
+ */
+ identify_cpu2();
+
+ link_elf_ireloc(kmdp);
+
+ /*
+ * This may be done better later if it gets more high level
+ * components in it. If so just link td->td_proc here.
+ */
+ proc_linkup0(&proc0, &thread0);
/* Init basic tunables, hz etc */
init_param1();
diff --git a/sys/arm/include/atomic-v4.h b/sys/arm/include/atomic-v4.h
index 71587f4..cc7780f 100644
--- a/sys/arm/include/atomic-v4.h
+++ b/sys/arm/include/atomic-v4.h
@@ -115,7 +115,7 @@ atomic_clear_64(volatile uint64_t *address, uint64_t clearmask)
static __inline int
atomic_fcmpset_32(volatile u_int32_t *p, volatile u_int32_t *cmpval, volatile u_int32_t newval)
{
- u_int32_t ret;
+ int ret;
__with_interrupts_disabled(
{
@@ -134,7 +134,7 @@ atomic_fcmpset_32(volatile u_int32_t *p, volatile u_int32_t *cmpval, volatile u_
static __inline int
atomic_fcmpset_64(volatile u_int64_t *p, volatile u_int64_t *cmpval, volatile u_int64_t newval)
{
- u_int64_t ret;
+ int ret;
__with_interrupts_disabled(
{
@@ -149,7 +149,7 @@ atomic_fcmpset_64(volatile u_int64_t *p, volatile u_int64_t *cmpval, volatile u_
return (ret);
}
-static __inline u_int32_t
+static __inline int
atomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
{
int ret;
@@ -166,7 +166,7 @@ atomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_in
return (ret);
}
-static __inline u_int64_t
+static __inline int
atomic_cmpset_64(volatile u_int64_t *p, volatile u_int64_t cmpval, volatile u_int64_t newval)
{
int ret;
@@ -296,7 +296,7 @@ atomic_clear_32(volatile uint32_t *address, uint32_t clearmask)
}
-static __inline u_int32_t
+static __inline int
atomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
{
int done, ras_start = ARM_RAS_START;
@@ -321,6 +321,33 @@ atomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_in
return (done);
}
+static __inline int
+atomic_fcmpset_32(volatile u_int32_t *p, volatile u_int32_t *cmpval, volatile u_int32_t newval)
+{
+ int done, oldval, ras_start = ARM_RAS_START;
+
+ __asm __volatile("1:\n"
+ "adr %1, 1b\n"
+ "str %1, [%0]\n"
+ "adr %1, 2f\n"
+ "str %1, [%0, #4]\n"
+ "ldr %1, [%2]\n"
+ "ldr %5, [%3]\n"
+ "cmp %1, %5\n"
+ "streq %4, [%2]\n"
+ "2:\n"
+ "mov %5, #0\n"
+ "str %5, [%0]\n"
+ "mov %5, #0xffffffff\n"
+ "str %5, [%0, #4]\n"
+ "strne %1, [%3]\n"
+ "moveq %1, #1\n"
+ "movne %1, #0\n"
+ : "+r" (ras_start), "=r" (done) ,"+r" (p)
+ , "+r" (cmpval), "+r" (newval), "+r" (oldval) : : "cc", "memory");
+ return (done);
+}
+
static __inline uint32_t
atomic_fetchadd_32(volatile uint32_t *p, uint32_t v)
{
@@ -409,14 +436,18 @@ atomic_swap_32(volatile u_int32_t *p, u_int32_t v)
#define atomic_fcmpset_rel_32 atomic_fcmpset_32
#define atomic_fcmpset_acq_32 atomic_fcmpset_32
+#ifdef _KERNEL
#define atomic_fcmpset_rel_64 atomic_fcmpset_64
#define atomic_fcmpset_acq_64 atomic_fcmpset_64
+#endif
#define atomic_fcmpset_acq_long atomic_fcmpset_long
#define atomic_fcmpset_rel_long atomic_fcmpset_long
#define atomic_cmpset_rel_32 atomic_cmpset_32
#define atomic_cmpset_acq_32 atomic_cmpset_32
+#ifdef _KERNEL
#define atomic_cmpset_rel_64 atomic_cmpset_64
#define atomic_cmpset_acq_64 atomic_cmpset_64
+#endif
#define atomic_set_rel_32 atomic_set_32
#define atomic_set_acq_32 atomic_set_32
#define atomic_clear_rel_32 atomic_clear_32
@@ -463,8 +494,6 @@ atomic_cmpset_long(volatile u_long *dst, u_long old, u_long newe)
return (atomic_cmpset_32((volatile uint32_t *)dst, old, newe));
}
-#ifdef _KERNEL
-/* atomic_fcmpset_32 is only defined for the kernel */
static __inline u_long
atomic_fcmpset_long(volatile u_long *dst, u_long *old, u_long newe)
{
@@ -472,7 +501,6 @@ atomic_fcmpset_long(volatile u_long *dst, u_long *old, u_long newe)
return (atomic_fcmpset_32((volatile uint32_t *)dst,
(uint32_t *)old, newe));
}
-#endif
static __inline u_long
atomic_fetchadd_long(volatile u_long *p, u_long v)
diff --git a/sys/arm/include/atomic-v6.h b/sys/arm/include/atomic-v6.h
index 2a579db..b0cb408 100644
--- a/sys/arm/include/atomic-v6.h
+++ b/sys/arm/include/atomic-v6.h
@@ -209,7 +209,7 @@ atomic_fcmpset_32(volatile uint32_t *p, uint32_t *cmpval, uint32_t newval)
return (!ret);
}
-static __inline uint64_t
+static __inline int
atomic_fcmpset_64(volatile uint64_t *p, uint64_t *cmpval, uint64_t newval)
{
uint64_t tmp;
@@ -235,7 +235,7 @@ atomic_fcmpset_64(volatile uint64_t *p, uint64_t *cmpval, uint64_t newval)
return (!ret);
}
-static __inline u_long
+static __inline int
atomic_fcmpset_long(volatile u_long *p, u_long *cmpval, u_long newval)
{
@@ -243,38 +243,38 @@ atomic_fcmpset_long(volatile u_long *p, u_long *cmpval, u_long newval)
(uint32_t *)cmpval, newval));
}
-static __inline uint64_t
+static __inline int
atomic_fcmpset_acq_64(volatile uint64_t *p, uint64_t *cmpval, uint64_t newval)
{
- uint64_t ret;
+ int ret;
ret = atomic_fcmpset_64(p, cmpval, newval);
dmb();
return (ret);
}
-static __inline u_long
+static __inline int
atomic_fcmpset_acq_long(volatile u_long *p, u_long *cmpval, u_long newval)
{
- u_long ret;
+ int ret;
ret = atomic_fcmpset_long(p, cmpval, newval);
dmb();
return (ret);
}
-static __inline uint32_t
+static __inline int
atomic_fcmpset_acq_32(volatile uint32_t *p, uint32_t *cmpval, uint32_t newval)
{
- uint32_t ret;
+ int ret;
ret = atomic_fcmpset_32(p, cmpval, newval);
dmb();
return (ret);
}
-static __inline uint32_t
+static __inline int
atomic_fcmpset_rel_32(volatile uint32_t *p, uint32_t *cmpval, uint32_t newval)
{
@@ -282,7 +282,7 @@ atomic_fcmpset_rel_32(volatile uint32_t *p, uint32_t *cmpval, uint32_t newval)
return (atomic_fcmpset_32(p, cmpval, newval));
}
-static __inline uint64_t
+static __inline int
atomic_fcmpset_rel_64(volatile uint64_t *p, uint64_t *cmpval, uint64_t newval)
{
@@ -290,7 +290,7 @@ atomic_fcmpset_rel_64(volatile uint64_t *p, uint64_t *cmpval, uint64_t newval)
return (atomic_fcmpset_64(p, cmpval, newval));
}
-static __inline u_long
+static __inline int
atomic_fcmpset_rel_long(volatile u_long *p, u_long *cmpval, u_long newval)
{
@@ -298,10 +298,10 @@ atomic_fcmpset_rel_long(volatile u_long *p, u_long *cmpval, u_long newval)
return (atomic_fcmpset_long(p, cmpval, newval));
}
-static __inline uint32_t
+static __inline int
atomic_cmpset_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
{
- uint32_t ret;
+ int ret;
__asm __volatile(
"1: ldrex %0, [%1] \n"
@@ -349,44 +349,44 @@ atomic_cmpset_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
return (ret);
}
-static __inline u_long
+static __inline int
atomic_cmpset_long(volatile u_long *p, u_long cmpval, u_long newval)
{
return (atomic_cmpset_32((volatile uint32_t *)p, cmpval, newval));
}
-static __inline uint32_t
+static __inline int
atomic_cmpset_acq_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
{
- uint32_t ret;
+ int ret;
ret = atomic_cmpset_32(p, cmpval, newval);
dmb();
return (ret);
}
-static __inline uint64_t
+static __inline int
atomic_cmpset_acq_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
{
- uint64_t ret;
+ int ret;
ret = atomic_cmpset_64(p, cmpval, newval);
dmb();
return (ret);
}
-static __inline u_long
+static __inline int
atomic_cmpset_acq_long(volatile u_long *p, u_long cmpval, u_long newval)
{
- u_long ret;
+ int ret;
ret = atomic_cmpset_long(p, cmpval, newval);
dmb();
return (ret);
}
-static __inline uint32_t
+static __inline int
atomic_cmpset_rel_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
{
@@ -394,7 +394,7 @@ atomic_cmpset_rel_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
return (atomic_cmpset_32(p, cmpval, newval));
}
-static __inline uint64_t
+static __inline int
atomic_cmpset_rel_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
{
@@ -402,7 +402,7 @@ atomic_cmpset_rel_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
return (atomic_cmpset_64(p, cmpval, newval));
}
-static __inline u_long
+static __inline int
atomic_cmpset_rel_long(volatile u_long *p, u_long cmpval, u_long newval)
{
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index 17ec13d..3117f67 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -44,7 +44,7 @@
TYPE="FreeBSD"
REVISION="11.2"
-BRANCH="BETA1"
+BRANCH="BETA2"
if [ -n "${BRANCH_OVERRIDE}" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
diff --git a/sys/dev/mmc/mmcsd.c b/sys/dev/mmc/mmcsd.c
index 274f4d7..ca02dfd 100644
--- a/sys/dev/mmc/mmcsd.c
+++ b/sys/dev/mmc/mmcsd.c
@@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
+#include <sys/priv.h>
#include <sys/slicer.h>
#include <sys/time.h>
@@ -177,7 +178,7 @@ static int mmcsd_bus_bit_width(device_t dev);
static daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp);
static const char *mmcsd_errmsg(int e);
static int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data,
- int fflag);
+ int fflag, struct thread *td);
static int mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic,
int fflag);
static uintmax_t mmcsd_pretty_size(off_t size, char *unit);
@@ -771,22 +772,23 @@ mmcsd_strategy(struct bio *bp)
static int
mmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data,
- int fflag, struct thread *td __unused)
+ int fflag, struct thread *td)
{
- return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag));
+ return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag, td));
}
static int
mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, int fflag,
- struct thread *td __unused)
+ struct thread *td)
{
- return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag));
+ return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag, td));
}
static int
-mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag)
+mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag,
+ struct thread *td)
{
struct mmc_ioc_cmd *mic;
struct mmc_ioc_multi_cmd *mimc;
@@ -796,6 +798,10 @@ mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag)
if ((fflag & FREAD) == 0)
return (EBADF);
+ err = priv_check(td, PRIV_DRIVER);
+ if (err != 0)
+ return (err);
+
err = 0;
switch (cmd) {
case MMC_IOC_CMD:
diff --git a/sys/dev/sdhci/sdhci_acpi.c b/sys/dev/sdhci/sdhci_acpi.c
index 16e29f8..b7074c3 100644
--- a/sys/dev/sdhci/sdhci_acpi.c
+++ b/sys/dev/sdhci/sdhci_acpi.c
@@ -60,7 +60,6 @@ static const struct sdhci_acpi_device {
{ "80860F14", 1, "Intel Bay Trail/Braswell eMMC 4.5/4.5.1 Controller",
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
SDHCI_QUIRK_WAIT_WHILE_BUSY |
- SDHCI_QUIRK_MMC_DDR52 |
SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
{ "80860F14", 3, "Intel Bay Trail/Braswell SDXC Controller",
@@ -261,11 +260,16 @@ sdhci_acpi_attach(device_t dev)
return (ENOMEM);
}
- /* Intel Braswell eMMC 4.5.1 controller quirk */
+ /*
+ * Intel Bay Trail and Braswell eMMC controllers share the same IDs,
+ * but while with these former DDR52 is affected by the VLI54 erratum,
+ * these latter require the timeout clock to be hardcoded to 1 MHz.
+ */
if (strcmp(acpi_dev->hid, "80860F14") == 0 && acpi_dev->uid == 1 &&
SDHCI_READ_4(dev, &sc->slot, SDHCI_CAPABILITIES) == 0x446cc8b2 &&
SDHCI_READ_4(dev, &sc->slot, SDHCI_CAPABILITIES2) == 0x00000807)
- sc->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_1MHZ;
+ sc->quirks |= SDHCI_QUIRK_MMC_DDR52 |
+ SDHCI_QUIRK_DATA_TIMEOUT_1MHZ;
sc->quirks &= ~sdhci_quirk_clear;
sc->quirks |= sdhci_quirk_set;
sc->slot.quirks = sc->quirks;
diff --git a/sys/dev/sdhci/sdhci_pci.c b/sys/dev/sdhci/sdhci_pci.c
index 00a3b8b..030e7a8 100644
--- a/sys/dev/sdhci/sdhci_pci.c
+++ b/sys/dev/sdhci/sdhci_pci.c
@@ -104,18 +104,18 @@ static const struct sdhci_device {
{ 0x16bc14e4, 0xffff, "Broadcom BCM577xx SDXC/MMC Card Reader",
SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC },
{ 0x0f148086, 0xffff, "Intel Bay Trail eMMC 4.5 Controller",
+ /* DDR52 is supported but affected by the VLI54 erratum */
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
SDHCI_QUIRK_WAIT_WHILE_BUSY |
- SDHCI_QUIRK_MMC_DDR52 |
SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
SDHCI_QUIRK_PRESET_VALUE_BROKEN},
{ 0x0f158086, 0xffff, "Intel Bay Trail SDXC Controller",
SDHCI_QUIRK_WAIT_WHILE_BUSY |
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
{ 0x0f508086, 0xffff, "Intel Bay Trail eMMC 4.5 Controller",
+ /* DDR52 is supported but affected by the VLI54 erratum */
SDHCI_QUIRK_INTEL_POWER_UP_RESET |
SDHCI_QUIRK_WAIT_WHILE_BUSY |
- SDHCI_QUIRK_MMC_DDR52 |
SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
SDHCI_QUIRK_PRESET_VALUE_BROKEN },
{ 0x19db8086, 0xffff, "Intel Denverton eMMC 5.0 Controller",
diff --git a/sys/dev/vxge/vxge.c b/sys/dev/vxge/vxge.c
index b098460..b4fca5a 100644
--- a/sys/dev/vxge/vxge.c
+++ b/sys/dev/vxge/vxge.c
@@ -234,6 +234,7 @@ _exit0:
err = ENXIO;
}
+ gone_in_dev(ndev, 12, "vxge(4) driver");
return (err);
}
diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c
index fcac38a..b05b5ef 100644
--- a/sys/i386/i386/elf_machdep.c
+++ b/sys/i386/i386/elf_machdep.c
@@ -158,10 +158,13 @@ elf32_dump_thread(struct thread *td, void *dst, size_t *off)
*off = len;
}
+#define ERI_LOCAL 0x0001
+#define ERI_ONLYIFUNC 0x0002
+
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
- int type, int local, elf_lookup_fn lookup)
+ int type, elf_lookup_fn lookup, int flags)
{
Elf_Addr *where;
Elf_Addr addr;
@@ -190,7 +193,10 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
panic("unknown reloc type %d\n", type);
}
- if (local) {
+ if (((flags & ERI_ONLYIFUNC) == 0) ^ (rtype != R_386_IRELATIVE))
+ return (0);
+
+ if ((flags & ERI_LOCAL) != 0) {
if (rtype == R_386_RELATIVE) { /* A + B */
addr = elf_relocaddr(lf, relocbase + addend);
if (*where != addr)
@@ -242,6 +248,12 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
case R_386_RELATIVE:
break;
+ case R_386_IRELATIVE:
+ addr = relocbase + addend;
+ addr = ((Elf_Addr (*)(void))addr)();
+ if (*where != addr)
+ *where = addr;
+ break;
default:
printf("kldload: unexpected relocation type %d\n",
rtype);
@@ -251,11 +263,20 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
}
int
+elf_reloc_ifunc(linker_file_t lf, Elf_Addr relocbase, const void *data,
+ int type, elf_lookup_fn lookup)
+{
+
+ return (elf_reloc_internal(lf, relocbase, data, type, lookup,
+ ERI_ONLYIFUNC));
+}
+
+int
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
- return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
+ return (elf_reloc_internal(lf, relocbase, data, type, lookup, 0));
}
int
@@ -263,7 +284,8 @@ elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
- return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
+ return (elf_reloc_internal(lf, relocbase, data, type, lookup,
+ ERI_LOCAL));
}
int
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index cd41673..8fdccfb 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -2441,6 +2441,7 @@ init386(int first)
int gsel_tss, metadata_missing, x, pa;
struct pcpu *pc;
struct xstate_hdr *xhdr;
+ caddr_t kmdp;
int late_console;
thread0.td_kstack = proc0kstack;
@@ -2688,6 +2689,9 @@ init386(int first)
i386_kdb_init();
}
+ kmdp = preload_search_by_type("elf kernel");
+ link_elf_ireloc(kmdp);
+
vm86_initialize();
getmemsize(first);
init_param2(physmem);
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 349a95e..213b50f 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -188,6 +188,9 @@ static struct linker_class link_elf_class = {
static int parse_dynamic(elf_file_t);
static int relocate_file(elf_file_t);
+static int relocate_file1(elf_file_t ef, int (*elf_reloc_func)(
+ linker_file_t lf, Elf_Addr relocbase, const void *data,
+ int type, elf_lookup_fn lookup));
static int link_elf_preload_parse_symbols(elf_file_t);
static struct elf_set_head set_pcpu_list;
@@ -1183,7 +1186,8 @@ symbol_name(elf_file_t ef, Elf_Size r_info)
}
static int
-relocate_file(elf_file_t ef)
+relocate_file1(elf_file_t ef, int (*elf_reloc_func)(linker_file_t lf,
+ Elf_Addr relocbase, const void *data, int type, elf_lookup_fn lookup))
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
@@ -1197,7 +1201,7 @@ relocate_file(elf_file_t ef)
rellim = (const Elf_Rel *)
((const char *)ef->rel + ef->relsize);
while (rel < rellim) {
- if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel,
+ if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rel,
ELF_RELOC_REL, elf_lookup)) {
symname = symbol_name(ef, rel->r_info);
printf("link_elf: symbol %s undefined\n", symname);
@@ -1213,7 +1217,7 @@ relocate_file(elf_file_t ef)
relalim = (const Elf_Rela *)
((const char *)ef->rela + ef->relasize);
while (rela < relalim) {
- if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela,
+ if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rela,
ELF_RELOC_RELA, elf_lookup)) {
symname = symbol_name(ef, rela->r_info);
printf("link_elf: symbol %s undefined\n",
@@ -1230,7 +1234,7 @@ relocate_file(elf_file_t ef)
rellim = (const Elf_Rel *)
((const char *)ef->pltrel + ef->pltrelsize);
while (rel < rellim) {
- if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel,
+ if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rel,
ELF_RELOC_REL, elf_lookup)) {
symname = symbol_name(ef, rel->r_info);
printf("link_elf: symbol %s undefined\n",
@@ -1247,7 +1251,7 @@ relocate_file(elf_file_t ef)
relalim = (const Elf_Rela *)
((const char *)ef->pltrela + ef->pltrelasize);
while (rela < relalim) {
- if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela,
+ if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rela,
ELF_RELOC_RELA, elf_lookup)) {
symname = symbol_name(ef, rela->r_info);
printf("link_elf: symbol %s undefined\n",
@@ -1261,6 +1265,19 @@ relocate_file(elf_file_t ef)
return (0);
}
+static int
+relocate_file(elf_file_t ef)
+{
+ int e;
+
+ e = relocate_file1(ef, elf_reloc);
+#if defined(__i386__) || defined(__amd64__)
+ if (e == 0)
+ e = relocate_file1(ef, elf_reloc_ifunc);
+#endif
+ return (e);
+}
+
/*
* Hash function for symbol table lookup. Don't even think about changing
* this. It is specified by the System V ABI.
@@ -1318,7 +1335,8 @@ link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
if (strcmp(name, strp) == 0) {
if (symp->st_shndx != SHN_UNDEF ||
(symp->st_value != 0 &&
- ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
+ (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+ ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC))) {
*sym = (c_linker_sym_t) symp;
return (0);
}
@@ -1338,7 +1356,8 @@ link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
if (strcmp(name, strp) == 0) {
if (symp->st_shndx != SHN_UNDEF ||
(symp->st_value != 0 &&
- ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
+ (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+ ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC))) {
*sym = (c_linker_sym_t) symp;
return (0);
}
@@ -1353,12 +1372,18 @@ static int
link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
linker_symval_t *symval)
{
- elf_file_t ef = (elf_file_t) lf;
- const Elf_Sym* es = (const Elf_Sym*) sym;
+ elf_file_t ef;
+ const Elf_Sym *es;
+ caddr_t val;
+ ef = (elf_file_t)lf;
+ es = (const Elf_Sym *)sym;
if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) {
symval->name = ef->strtab + es->st_name;
- symval->value = (caddr_t) ef->address + es->st_value;
+ val = (caddr_t)ef->address + es->st_value;
+ if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
+ val = ((caddr_t (*)(void))val)();
+ symval->value = val;
symval->size = es->st_size;
return (0);
}
@@ -1366,7 +1391,10 @@ link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
return (ENOENT);
if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
symval->name = ef->ddbstrtab + es->st_name;
- symval->value = (caddr_t) ef->address + es->st_value;
+ val = (caddr_t)ef->address + es->st_value;
+ if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
+ val = ((caddr_t (*)(void))val)();
+ symval->value = val;
symval->size = es->st_size;
return (0);
}
@@ -1476,7 +1504,8 @@ link_elf_each_function_name(linker_file_t file,
/* Exhaustive search */
for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
if (symp->st_value != 0 &&
- ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
+ (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+ ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
error = callback(ef->ddbstrtab + symp->st_name, opaque);
if (error != 0)
return (error);
@@ -1497,7 +1526,8 @@ link_elf_each_function_nameval(linker_file_t file,
/* Exhaustive search */
for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
if (symp->st_value != 0 &&
- ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
+ (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+ ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
error = link_elf_symbol_values(file,
(c_linker_sym_t) symp, &symval);
if (error != 0)
@@ -1656,3 +1686,27 @@ link_elf_strtab_get(linker_file_t lf, caddr_t *strtab)
return (ef->ddbstrcnt);
}
+
+#if defined(__i386__) || defined(__amd64__)
+void
+link_elf_ireloc(caddr_t kmdp)
+{
+ struct elf_file eff;
+ elf_file_t ef;
+ volatile char *c;
+ size_t i;
+
+ ef = &eff;
+
+ /* Do not use bzero/memset before ireloc is done. */
+ for (c = (char *)ef, i = 0; i < sizeof(*ef); i++)
+ c[i] = 0;
+
+ ef->modptr = kmdp;
+ ef->dynamic = (Elf_Dyn *)&_DYNAMIC;
+ parse_dynamic(ef);
+ ef->address = 0;
+ link_elf_preload_parse_symbols(ef);
+ relocate_file1(ef, elf_reloc_ifunc);
+}
+#endif
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index ad415ce..0953eb0 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -1194,12 +1194,19 @@ static int
link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
linker_symval_t *symval)
{
- elf_file_t ef = (elf_file_t) lf;
- const Elf_Sym *es = (const Elf_Sym*) sym;
+ elf_file_t ef;
+ const Elf_Sym *es;
+ caddr_t val;
+ ef = (elf_file_t) lf;
+ es = (const Elf_Sym*) sym;
+ val = (caddr_t)es->st_value;
if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
symval->name = ef->ddbstrtab + es->st_name;
- symval->value = (caddr_t)es->st_value;
+ val = (caddr_t)es->st_value;
+ if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
+ val = ((caddr_t (*)(void))val)();
+ symval->value = val;
symval->size = es->st_size;
return 0;
}
@@ -1284,7 +1291,8 @@ link_elf_each_function_name(linker_file_t file,
/* Exhaustive search */
for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
if (symp->st_value != 0 &&
- ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
+ (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+ ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
error = callback(ef->ddbstrtab + symp->st_name, opaque);
if (error)
return (error);
@@ -1305,8 +1313,10 @@ link_elf_each_function_nameval(linker_file_t file,
/* Exhaustive search */
for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
if (symp->st_value != 0 &&
- ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
- error = link_elf_symbol_values(file, (c_linker_sym_t) symp, &symval);
+ (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+ ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
+ error = link_elf_symbol_values(file,
+ (c_linker_sym_t)symp, &symval);
if (error)
return (error);
error = callback(file, i, &symval, opaque);
diff --git a/sys/net/if_ipsec.c b/sys/net/if_ipsec.c
index 7ae27a0..c9dcbc6 100644
--- a/sys/net/if_ipsec.c
+++ b/sys/net/if_ipsec.c
@@ -434,7 +434,7 @@ ipsec_if_input(struct mbuf *m, struct secasvar *sav, uint32_t af)
m->m_pkthdr.rcvif = ifp;
IPSEC_SC_RUNLOCK();
- /* m_clrprotoflags(m); */
+ m_clrprotoflags(m);
M_SETFIB(m, ifp->if_fib);
BPF_MTAP2(ifp, &af, sizeof(af), m);
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
index 349bfeb..de40b09 100644
--- a/sys/sys/linker.h
+++ b/sys/sys/linker.h
@@ -269,11 +269,16 @@ extern int kld_debug;
typedef int elf_lookup_fn(linker_file_t, Elf_Size, int, Elf_Addr *);
/* Support functions */
-int elf_reloc(linker_file_t _lf, Elf_Addr base, const void *_rel, int _type, elf_lookup_fn _lu);
-int elf_reloc_local(linker_file_t _lf, Elf_Addr base, const void *_rel, int _type, elf_lookup_fn _lu);
+int elf_reloc(linker_file_t _lf, Elf_Addr base, const void *_rel,
+ int _type, elf_lookup_fn _lu);
+int elf_reloc_ifunc(linker_file_t _lf, Elf_Addr base, const void *_rel,
+ int _type, elf_lookup_fn _lu);
+int elf_reloc_local(linker_file_t _lf, Elf_Addr base, const void *_rel,
+ int _type, elf_lookup_fn _lu);
Elf_Addr elf_relocaddr(linker_file_t _lf, Elf_Addr addr);
const Elf_Sym *elf_get_sym(linker_file_t _lf, Elf_Size _symidx);
const char *elf_get_symname(linker_file_t _lf, Elf_Size _symidx);
+void link_elf_ireloc(caddr_t kmdp);
typedef struct linker_ctf {
const uint8_t *ctftab; /* Decompressed CTF data. */
diff --git a/sys/x86/include/ifunc.h b/sys/x86/include/ifunc.h
new file mode 100644
index 0000000..13f4b88
--- /dev/null
+++ b/sys/x86/include/ifunc.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2015, 2017 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __X86_IFUNC_H
+#define __X86_IFUNC_H
+
+#define DECLARE_LIFUNC(ret_type, name, args) \
+ret_type name args
+
+#define DEFINE_LIFUNC(scope, selector_qual, ret_type, name, args) \
+__asm__ (scope "\t" #name "\n" \
+ "\t.type\t" #name ",@function\n" \
+ #name ":\n" \
+ "\tjmp *" #name "_selector\n" \
+ "\t.size\t" #name ",\t. - "#name); \
+selector_qual ret_type (*name##_selector)args __used; \
+DECLARE_LIFUNC(ret_type, name, args)
+
+#define DEFINE_STATIC_LIFUNC(ret_type, name, args) \
+ DEFINE_LIFUNC(".local", static, ret_type, name, args)
+
+#define DEFINE_GLOBAL_LIFUNC(ret_type, name, args) \
+ DEFINE_LIFUNC(".globl", , ret_type, name, args)
+
+#define DEFINE_IFUNC(qual, ret_type, name, args, resolver_qual) \
+ resolver_qual ret_type (*name##_resolver(void))args __used; \
+ qual ret_type name args __attribute__((ifunc(#name "_resolver"))); \
+ resolver_qual ret_type (*name##_resolver(void))args
+
+#endif
OpenPOWER on IntegriCloud