diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/amd64/elf_machdep.c | 29 | ||||
-rw-r--r-- | sys/amd64/amd64/machdep.c | 19 | ||||
-rw-r--r-- | sys/arm/include/atomic-v4.h | 44 | ||||
-rw-r--r-- | sys/arm/include/atomic-v6.h | 46 | ||||
-rw-r--r-- | sys/conf/newvers.sh | 2 | ||||
-rw-r--r-- | sys/dev/mmc/mmcsd.c | 18 | ||||
-rw-r--r-- | sys/dev/sdhci/sdhci_acpi.c | 10 | ||||
-rw-r--r-- | sys/dev/sdhci/sdhci_pci.c | 4 | ||||
-rw-r--r-- | sys/dev/vxge/vxge.c | 1 | ||||
-rw-r--r-- | sys/i386/i386/elf_machdep.c | 30 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 4 | ||||
-rw-r--r-- | sys/kern/link_elf.c | 80 | ||||
-rw-r--r-- | sys/kern/link_elf_obj.c | 22 | ||||
-rw-r--r-- | sys/net/if_ipsec.c | 2 | ||||
-rw-r--r-- | sys/sys/linker.h | 9 | ||||
-rw-r--r-- | sys/x86/include/ifunc.h | 58 |
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 |