From ebd89c9b73a73bada602d7905a5072f5334e8428 Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Thu, 14 Jun 2018 13:30:47 +0200 Subject: [PATCH] Odroid XU4 NEXT upstream patches --- config/kernel/linux-odroidxu4-next.config | 2 +- .../0004-patch-4.9.103-104.patch | 13079 +++++++++++++++ .../0004-patch-4.9.104-105.patch | 24 + .../0004-patch-4.9.105-106.patch | 13260 ++++++++++++++++ .../0004-patch-4.9.106-107.patch | 3059 ++++ .../0004-patch-4.9.107-108.patch | 775 + 6 files changed, 30198 insertions(+), 1 deletion(-) create mode 100644 patch/kernel/odroidxu4-next/0004-patch-4.9.103-104.patch create mode 100644 patch/kernel/odroidxu4-next/0004-patch-4.9.104-105.patch create mode 100644 patch/kernel/odroidxu4-next/0004-patch-4.9.105-106.patch create mode 100644 patch/kernel/odroidxu4-next/0004-patch-4.9.106-107.patch create mode 100644 patch/kernel/odroidxu4-next/0004-patch-4.9.107-108.patch diff --git a/config/kernel/linux-odroidxu4-next.config b/config/kernel/linux-odroidxu4-next.config index dfefa1a199..f5452d65c3 100644 --- a/config/kernel/linux-odroidxu4-next.config +++ b/config/kernel/linux-odroidxu4-next.config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 4.9.102 Kernel Configuration +# Linux/arm 4.9.108 Kernel Configuration # CONFIG_ARM=y CONFIG_ARM_HAS_SG_CHAIN=y diff --git a/patch/kernel/odroidxu4-next/0004-patch-4.9.103-104.patch b/patch/kernel/odroidxu4-next/0004-patch-4.9.103-104.patch new file mode 100644 index 0000000000..9f689d2072 --- /dev/null +++ b/patch/kernel/odroidxu4-next/0004-patch-4.9.103-104.patch @@ -0,0 +1,13079 @@ +diff --git a/Documentation/device-mapper/thin-provisioning.txt b/Documentation/device-mapper/thin-provisioning.txt +index 1699a55b7b70..ef639960b272 100644 +--- a/Documentation/device-mapper/thin-provisioning.txt ++++ b/Documentation/device-mapper/thin-provisioning.txt +@@ -112,9 +112,11 @@ $low_water_mark is expressed in blocks of size $data_block_size. If + free space on the data device drops below this level then a dm event + will be triggered which a userspace daemon should catch allowing it to + extend the pool device. Only one such event will be sent. +-Resuming a device with a new table itself triggers an event so the +-userspace daemon can use this to detect a situation where a new table +-already exceeds the threshold. ++ ++No special event is triggered if a just resumed device's free space is below ++the low water mark. However, resuming a device always triggers an ++event; a userspace daemon should verify that free space exceeds the low ++water mark when handling this event. + + A low water mark for the metadata device is maintained in the kernel and + will trigger a dm event if free space on the metadata device drops below +diff --git a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt +index 217a90eaabe7..9c38bbe7e6d7 100644 +--- a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt ++++ b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt +@@ -11,7 +11,11 @@ Required properties: + interrupts. + + Optional properties: +-- clocks: Optional reference to the clock used by the XOR engine. ++- clocks: Optional reference to the clocks used by the XOR engine. ++- clock-names: mandatory if there is a second clock, in this case the ++ name must be "core" for the first clock and "reg" for the second ++ one ++ + + Example: + +diff --git a/Makefile b/Makefile +index 6090f655fb32..780dcc8033b2 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 4 + PATCHLEVEL = 9 +-SUBLEVEL = 103 ++SUBLEVEL = 104 + EXTRAVERSION = + NAME = Roaring Lionus + +diff --git a/arch/alpha/include/asm/xchg.h b/arch/alpha/include/asm/xchg.h +index 0ca9724597c1..7081e52291d0 100644 +--- a/arch/alpha/include/asm/xchg.h ++++ b/arch/alpha/include/asm/xchg.h +@@ -11,6 +11,10 @@ + * Atomic exchange. + * Since it can be used to implement critical sections + * it must clobber "memory" (also for interrupts in UP). ++ * ++ * The leading and the trailing memory barriers guarantee that these ++ * operations are fully ordered. ++ * + */ + + static inline unsigned long +@@ -18,6 +22,7 @@ ____xchg(_u8, volatile char *m, unsigned long val) + { + unsigned long ret, tmp, addr64; + ++ smp_mb(); + __asm__ __volatile__( + " andnot %4,7,%3\n" + " insbl %1,%4,%1\n" +@@ -42,6 +47,7 @@ ____xchg(_u16, volatile short *m, unsigned long val) + { + unsigned long ret, tmp, addr64; + ++ smp_mb(); + __asm__ __volatile__( + " andnot %4,7,%3\n" + " inswl %1,%4,%1\n" +@@ -66,6 +72,7 @@ ____xchg(_u32, volatile int *m, unsigned long val) + { + unsigned long dummy; + ++ smp_mb(); + __asm__ __volatile__( + "1: ldl_l %0,%4\n" + " bis $31,%3,%1\n" +@@ -86,6 +93,7 @@ ____xchg(_u64, volatile long *m, unsigned long val) + { + unsigned long dummy; + ++ smp_mb(); + __asm__ __volatile__( + "1: ldq_l %0,%4\n" + " bis $31,%3,%1\n" +@@ -127,10 +135,12 @@ ____xchg(, volatile void *ptr, unsigned long x, int size) + * store NEW in MEM. Return the initial value in MEM. Success is + * indicated by comparing RETURN with OLD. + * +- * The memory barrier should be placed in SMP only when we actually +- * make the change. If we don't change anything (so if the returned +- * prev is equal to old) then we aren't acquiring anything new and +- * we don't need any memory barrier as far I can tell. ++ * The leading and the trailing memory barriers guarantee that these ++ * operations are fully ordered. ++ * ++ * The trailing memory barrier is placed in SMP unconditionally, in ++ * order to guarantee that dependency ordering is preserved when a ++ * dependency is headed by an unsuccessful operation. + */ + + static inline unsigned long +@@ -138,6 +148,7 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new) + { + unsigned long prev, tmp, cmp, addr64; + ++ smp_mb(); + __asm__ __volatile__( + " andnot %5,7,%4\n" + " insbl %1,%5,%1\n" +@@ -149,8 +160,8 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new) + " or %1,%2,%2\n" + " stq_c %2,0(%4)\n" + " beq %2,3f\n" +- __ASM__MB + "2:\n" ++ __ASM__MB + ".subsection 2\n" + "3: br 1b\n" + ".previous" +@@ -165,6 +176,7 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new) + { + unsigned long prev, tmp, cmp, addr64; + ++ smp_mb(); + __asm__ __volatile__( + " andnot %5,7,%4\n" + " inswl %1,%5,%1\n" +@@ -176,8 +188,8 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new) + " or %1,%2,%2\n" + " stq_c %2,0(%4)\n" + " beq %2,3f\n" +- __ASM__MB + "2:\n" ++ __ASM__MB + ".subsection 2\n" + "3: br 1b\n" + ".previous" +@@ -192,6 +204,7 @@ ____cmpxchg(_u32, volatile int *m, int old, int new) + { + unsigned long prev, cmp; + ++ smp_mb(); + __asm__ __volatile__( + "1: ldl_l %0,%5\n" + " cmpeq %0,%3,%1\n" +@@ -199,8 +212,8 @@ ____cmpxchg(_u32, volatile int *m, int old, int new) + " mov %4,%1\n" + " stl_c %1,%2\n" + " beq %1,3f\n" +- __ASM__MB + "2:\n" ++ __ASM__MB + ".subsection 2\n" + "3: br 1b\n" + ".previous" +@@ -215,6 +228,7 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new) + { + unsigned long prev, cmp; + ++ smp_mb(); + __asm__ __volatile__( + "1: ldq_l %0,%5\n" + " cmpeq %0,%3,%1\n" +@@ -222,8 +236,8 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new) + " mov %4,%1\n" + " stq_c %1,%2\n" + " beq %1,3f\n" +- __ASM__MB + "2:\n" ++ __ASM__MB + ".subsection 2\n" + "3: br 1b\n" + ".previous" +diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig +index 249e10190d20..b7b78cb09a37 100644 +--- a/arch/arc/Kconfig ++++ b/arch/arc/Kconfig +@@ -495,7 +495,6 @@ config ARC_CURR_IN_REG + + config ARC_EMUL_UNALIGNED + bool "Emulate unaligned memory access (userspace only)" +- default N + select SYSCTL_ARCH_UNALIGN_NO_WARN + select SYSCTL_ARCH_UNALIGN_ALLOW + depends on ISA_ARCOMPACT +diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi +index 74dd21b7373c..c51b88ee3cec 100644 +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -146,8 +146,8 @@ + + i2s: i2s@7e203000 { + compatible = "brcm,bcm2835-i2s"; +- reg = <0x7e203000 0x20>, +- <0x7e101098 0x02>; ++ reg = <0x7e203000 0x24>; ++ clocks = <&clocks BCM2835_CLOCK_PCM>; + + dmas = <&dma 2>, + <&dma 3>; +diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts +index a1658d0721b8..cf0de77f09c4 100644 +--- a/arch/arm/boot/dts/bcm958625hr.dts ++++ b/arch/arm/boot/dts/bcm958625hr.dts +@@ -49,7 +49,7 @@ + + memory { + device_type = "memory"; +- reg = <0x60000000 0x80000000>; ++ reg = <0x60000000 0x20000000>; + }; + + gpio-restart { +diff --git a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts +index 58b09bf1ba2d..205130600853 100644 +--- a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts ++++ b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts +@@ -213,37 +213,37 @@ + &iomuxc { + pinctrl_enet1: enet1grp { + fsl,pins = < +- MX7D_PAD_SD2_CD_B__ENET1_MDIO 0x3 +- MX7D_PAD_SD2_WP__ENET1_MDC 0x3 +- MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x1 +- MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x1 +- MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x1 +- MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x1 +- MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x1 +- MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x1 +- MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x1 +- MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x1 +- MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x1 +- MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x1 +- MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x1 +- MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x1 ++ MX7D_PAD_SD2_CD_B__ENET1_MDIO 0x30 ++ MX7D_PAD_SD2_WP__ENET1_MDC 0x30 ++ MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x11 ++ MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x11 ++ MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x11 ++ MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x11 ++ MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x11 ++ MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x11 ++ MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x11 ++ MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x11 ++ MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x11 ++ MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x11 ++ MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x11 ++ MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x11 + >; + }; + + pinctrl_enet2: enet2grp { + fsl,pins = < +- MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC 0x1 +- MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0 0x1 +- MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1 0x1 +- MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2 0x1 +- MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3 0x1 +- MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL 0x1 +- MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC 0x1 +- MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0 0x1 +- MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1 0x1 +- MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2 0x1 +- MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3 0x1 +- MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL 0x1 ++ MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC 0x11 ++ MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0 0x11 ++ MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1 0x11 ++ MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2 0x11 ++ MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3 0x11 ++ MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL 0x11 ++ MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC 0x11 ++ MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0 0x11 ++ MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1 0x11 ++ MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2 0x11 ++ MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3 0x11 ++ MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL 0x11 + >; + }; + +diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts +index 6761d11d3f9e..db0239c7e6c7 100644 +--- a/arch/arm/boot/dts/r8a7791-porter.dts ++++ b/arch/arm/boot/dts/r8a7791-porter.dts +@@ -428,7 +428,7 @@ + "dclkin.0", "dclkin.1"; + + ports { +- port@1 { ++ port@0 { + endpoint { + remote-endpoint = <&adv7511_in>; + }; +diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi +index 9f48141270b8..f0702d8063d9 100644 +--- a/arch/arm/boot/dts/socfpga.dtsi ++++ b/arch/arm/boot/dts/socfpga.dtsi +@@ -759,7 +759,7 @@ + timer@fffec600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xfffec600 0x100>; +- interrupts = <1 13 0xf04>; ++ interrupts = <1 13 0xf01>; + clocks = <&mpu_periph_clk>; + }; + +diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h +index d0295f1dd1a3..ff65b6d96c7e 100644 +--- a/arch/arm/include/asm/vdso.h ++++ b/arch/arm/include/asm/vdso.h +@@ -11,8 +11,6 @@ struct mm_struct; + + void arm_install_vdso(struct mm_struct *mm, unsigned long addr); + +-extern char vdso_start, vdso_end; +- + extern unsigned int vdso_total_pages; + + #else /* CONFIG_VDSO */ +diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c +index 53cf86cf2d1a..890439737374 100644 +--- a/arch/arm/kernel/vdso.c ++++ b/arch/arm/kernel/vdso.c +@@ -39,6 +39,8 @@ + + static struct page **vdso_text_pagelist; + ++extern char vdso_start[], vdso_end[]; ++ + /* Total number of pages needed for the data and text portions of the VDSO. */ + unsigned int vdso_total_pages __ro_after_init; + +@@ -179,13 +181,13 @@ static int __init vdso_init(void) + unsigned int text_pages; + int i; + +- if (memcmp(&vdso_start, "\177ELF", 4)) { ++ if (memcmp(vdso_start, "\177ELF", 4)) { + pr_err("VDSO is not a valid ELF object!\n"); + return -ENOEXEC; + } + +- text_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT; +- pr_debug("vdso: %i text pages at base %p\n", text_pages, &vdso_start); ++ text_pages = (vdso_end - vdso_start) >> PAGE_SHIFT; ++ pr_debug("vdso: %i text pages at base %p\n", text_pages, vdso_start); + + /* Allocate the VDSO text pagelist */ + vdso_text_pagelist = kcalloc(text_pages, sizeof(struct page *), +@@ -200,7 +202,7 @@ static int __init vdso_init(void) + for (i = 0; i < text_pages; i++) { + struct page *page; + +- page = virt_to_page(&vdso_start + i * PAGE_SIZE); ++ page = virt_to_page(vdso_start + i * PAGE_SIZE); + vdso_text_pagelist[i] = page; + } + +@@ -211,7 +213,7 @@ static int __init vdso_init(void) + + cntvct_ok = cntvct_functional(); + +- patch_vdso(&vdso_start); ++ patch_vdso(vdso_start); + + return 0; + } +diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c +index 4f5fd4a084c0..034b89499bd7 100644 +--- a/arch/arm/mach-omap1/clock.c ++++ b/arch/arm/mach-omap1/clock.c +@@ -1031,17 +1031,17 @@ static int clk_debugfs_register_one(struct clk *c) + return -ENOMEM; + c->dent = d; + +- d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount); ++ d = debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount); + if (!d) { + err = -ENOMEM; + goto err_out; + } +- d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); ++ d = debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate); + if (!d) { + err = -ENOMEM; + goto err_out; + } +- d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags); ++ d = debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags); + if (!d) { + err = -ENOMEM; + goto err_out; +diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c +index 678d2a31dcb8..3202015ecb83 100644 +--- a/arch/arm/mach-omap2/pm.c ++++ b/arch/arm/mach-omap2/pm.c +@@ -225,7 +225,7 @@ static void omap_pm_end(void) + cpu_idle_poll_ctrl(false); + } + +-static void omap_pm_finish(void) ++static void omap_pm_wake(void) + { + if (cpu_is_omap34xx()) + omap_prcm_irq_complete(); +@@ -235,7 +235,7 @@ static const struct platform_suspend_ops omap_pm_ops = { + .begin = omap_pm_begin, + .end = omap_pm_end, + .enter = omap_pm_enter, +- .finish = omap_pm_finish, ++ .wake = omap_pm_wake, + .valid = suspend_valid_only_mem, + }; + +diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c +index b2f2448bfa6d..a4cab2814655 100644 +--- a/arch/arm/mach-omap2/timer.c ++++ b/arch/arm/mach-omap2/timer.c +@@ -136,12 +136,6 @@ static struct clock_event_device clockevent_gpt = { + .tick_resume = omap2_gp_timer_shutdown, + }; + +-static struct property device_disabled = { +- .name = "status", +- .length = sizeof("disabled"), +- .value = "disabled", +-}; +- + static const struct of_device_id omap_timer_match[] __initconst = { + { .compatible = "ti,omap2420-timer", }, + { .compatible = "ti,omap3430-timer", }, +@@ -183,8 +177,17 @@ static struct device_node * __init omap_get_timer_dt(const struct of_device_id * + of_get_property(np, "ti,timer-secure", NULL))) + continue; + +- if (!of_device_is_compatible(np, "ti,omap-counter32k")) +- of_add_property(np, &device_disabled); ++ if (!of_device_is_compatible(np, "ti,omap-counter32k")) { ++ struct property *prop; ++ ++ prop = kzalloc(sizeof(*prop), GFP_KERNEL); ++ if (!prop) ++ return NULL; ++ prop->name = "status"; ++ prop->value = "disabled"; ++ prop->length = strlen(prop->value); ++ of_add_property(np, prop); ++ } + return np; + } + +diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig +index 89bb0fc796bd..72905a442106 100644 +--- a/arch/arm/mach-orion5x/Kconfig ++++ b/arch/arm/mach-orion5x/Kconfig +@@ -57,7 +57,6 @@ config MACH_KUROBOX_PRO + + config MACH_DNS323 + bool "D-Link DNS-323" +- select GENERIC_NET_UTILS + select I2C_BOARDINFO if I2C + help + Say 'Y' here if you want your kernel to support the +@@ -65,7 +64,6 @@ config MACH_DNS323 + + config MACH_TS209 + bool "QNAP TS-109/TS-209" +- select GENERIC_NET_UTILS + help + Say 'Y' here if you want your kernel to support the + QNAP TS-109/TS-209 platform. +@@ -107,7 +105,6 @@ config MACH_LINKSTATION_LS_HGL + + config MACH_TS409 + bool "QNAP TS-409" +- select GENERIC_NET_UTILS + help + Say 'Y' here if you want your kernel to support the + QNAP TS-409 platform. +diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c +index cd483bfb5ca8..d13344b2ddcd 100644 +--- a/arch/arm/mach-orion5x/dns323-setup.c ++++ b/arch/arm/mach-orion5x/dns323-setup.c +@@ -173,10 +173,42 @@ static struct mv643xx_eth_platform_data dns323_eth_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(8), + }; + ++/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these ++ * functions be kept somewhere? ++ */ ++static int __init dns323_parse_hex_nibble(char n) ++{ ++ if (n >= '0' && n <= '9') ++ return n - '0'; ++ ++ if (n >= 'A' && n <= 'F') ++ return n - 'A' + 10; ++ ++ if (n >= 'a' && n <= 'f') ++ return n - 'a' + 10; ++ ++ return -1; ++} ++ ++static int __init dns323_parse_hex_byte(const char *b) ++{ ++ int hi; ++ int lo; ++ ++ hi = dns323_parse_hex_nibble(b[0]); ++ lo = dns323_parse_hex_nibble(b[1]); ++ ++ if (hi < 0 || lo < 0) ++ return -1; ++ ++ return (hi << 4) | lo; ++} ++ + static int __init dns323_read_mac_addr(void) + { + u_int8_t addr[6]; +- void __iomem *mac_page; ++ int i; ++ char *mac_page; + + /* MAC address is stored as a regular ol' string in /dev/mtdblock4 + * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80). +@@ -185,8 +217,23 @@ static int __init dns323_read_mac_addr(void) + if (!mac_page) + return -ENOMEM; + +- if (!mac_pton((__force const char *) mac_page, addr)) +- goto error_fail; ++ /* Sanity check the string we're looking at */ ++ for (i = 0; i < 5; i++) { ++ if (*(mac_page + (i * 3) + 2) != ':') { ++ goto error_fail; ++ } ++ } ++ ++ for (i = 0; i < 6; i++) { ++ int byte; ++ ++ byte = dns323_parse_hex_byte(mac_page + (i * 3)); ++ if (byte < 0) { ++ goto error_fail; ++ } ++ ++ addr[i] = byte; ++ } + + iounmap(mac_page); + printk("DNS-323: Found ethernet MAC address: %pM\n", addr); +diff --git a/arch/arm/mach-orion5x/tsx09-common.c b/arch/arm/mach-orion5x/tsx09-common.c +index 89774985d380..905d4f2dd0b8 100644 +--- a/arch/arm/mach-orion5x/tsx09-common.c ++++ b/arch/arm/mach-orion5x/tsx09-common.c +@@ -53,12 +53,53 @@ struct mv643xx_eth_platform_data qnap_tsx09_eth_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(8), + }; + ++static int __init qnap_tsx09_parse_hex_nibble(char n) ++{ ++ if (n >= '0' && n <= '9') ++ return n - '0'; ++ ++ if (n >= 'A' && n <= 'F') ++ return n - 'A' + 10; ++ ++ if (n >= 'a' && n <= 'f') ++ return n - 'a' + 10; ++ ++ return -1; ++} ++ ++static int __init qnap_tsx09_parse_hex_byte(const char *b) ++{ ++ int hi; ++ int lo; ++ ++ hi = qnap_tsx09_parse_hex_nibble(b[0]); ++ lo = qnap_tsx09_parse_hex_nibble(b[1]); ++ ++ if (hi < 0 || lo < 0) ++ return -1; ++ ++ return (hi << 4) | lo; ++} ++ + static int __init qnap_tsx09_check_mac_addr(const char *addr_str) + { + u_int8_t addr[6]; ++ int i; + +- if (!mac_pton(addr_str, addr)) +- return -1; ++ for (i = 0; i < 6; i++) { ++ int byte; ++ ++ /* ++ * Enforce "xx:xx:xx:xx:xx:xx\n" format. ++ */ ++ if (addr_str[(i * 3) + 2] != ((i < 5) ? ':' : '\n')) ++ return -1; ++ ++ byte = qnap_tsx09_parse_hex_byte(addr_str + (i * 3)); ++ if (byte < 0) ++ return -1; ++ addr[i] = byte; ++ } + + printk(KERN_INFO "tsx09: found ethernet mac address %pM\n", addr); + +@@ -77,12 +118,12 @@ void __init qnap_tsx09_find_mac_addr(u32 mem_base, u32 size) + unsigned long addr; + + for (addr = mem_base; addr < (mem_base + size); addr += 1024) { +- void __iomem *nor_page; ++ char *nor_page; + int ret = 0; + + nor_page = ioremap(addr, 1024); + if (nor_page != NULL) { +- ret = qnap_tsx09_check_mac_addr((__force const char *)nor_page); ++ ret = qnap_tsx09_check_mac_addr(nor_page); + iounmap(nor_page); + } + +diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c +index 7a327bd32521..ebef8aacea83 100644 +--- a/arch/arm/plat-omap/dmtimer.c ++++ b/arch/arm/plat-omap/dmtimer.c +@@ -890,11 +890,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev) + timer->irq = irq->start; + timer->pdev = pdev; + +- /* Skip pm_runtime_enable for OMAP1 */ +- if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { +- pm_runtime_enable(dev); +- pm_runtime_irq_safe(dev); +- } ++ pm_runtime_enable(dev); ++ pm_runtime_irq_safe(dev); + + if (!timer->reserved) { + ret = pm_runtime_get_sync(dev); +diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi +index 338f82a7fdc7..2c93de7fffe5 100644 +--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi +@@ -326,8 +326,8 @@ + blsp2_spi5: spi@075ba000{ + compatible = "qcom,spi-qup-v2.2.1"; + reg = <0x075ba000 0x600>; +- interrupts = ; +- clocks = <&gcc GCC_BLSP2_QUP5_SPI_APPS_CLK>, ++ interrupts = ; ++ clocks = <&gcc GCC_BLSP2_QUP6_SPI_APPS_CLK>, + <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "core", "iface"; + pinctrl-names = "default", "sleep"; +diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h +index cae331d553f8..a9d2dd03c977 100644 +--- a/arch/arm64/include/asm/spinlock.h ++++ b/arch/arm64/include/asm/spinlock.h +@@ -141,8 +141,8 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) + " cbnz %w1, 1f\n" + " add %w1, %w0, %3\n" + " casa %w0, %w1, %2\n" +- " and %w1, %w1, #0xffff\n" +- " eor %w1, %w1, %w0, lsr #16\n" ++ " sub %w1, %w1, %3\n" ++ " eor %w1, %w1, %w0\n" + "1:") + : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock) + : "I" (1 << TICKET_SHIFT) +diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h +index 801a16dbbdf6..7d2a15a0f625 100644 +--- a/arch/arm64/include/asm/stacktrace.h ++++ b/arch/arm64/include/asm/stacktrace.h +@@ -23,7 +23,7 @@ struct stackframe { + unsigned long sp; + unsigned long pc; + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +- unsigned int graph; ++ int graph; + #endif + }; + +diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c +index 74107134cc30..2de62aa91303 100644 +--- a/arch/arm64/kernel/cpu_errata.c ++++ b/arch/arm64/kernel/cpu_errata.c +@@ -160,7 +160,7 @@ static int enable_smccc_arch_workaround_1(void *data) + case PSCI_CONDUIT_HVC: + arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); +- if (res.a0) ++ if ((int)res.a0 < 0) + return 0; + cb = call_hvc_arch_workaround_1; + smccc_start = __smccc_workaround_1_hvc_start; +@@ -170,7 +170,7 @@ static int enable_smccc_arch_workaround_1(void *data) + case PSCI_CONDUIT_SMC: + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); +- if (res.a0) ++ if ((int)res.a0 < 0) + return 0; + cb = call_smc_arch_workaround_1; + smccc_start = __smccc_workaround_1_smc_start; +diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c +index c2efddfca18c..0cc01e0d38eb 100644 +--- a/arch/arm64/kernel/stacktrace.c ++++ b/arch/arm64/kernel/stacktrace.c +@@ -72,6 +72,11 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) + #ifdef CONFIG_FUNCTION_GRAPH_TRACER + if (tsk->ret_stack && + (frame->pc == (unsigned long)return_to_handler)) { ++ if (WARN_ON_ONCE(frame->graph == -1)) ++ return -EINVAL; ++ if (frame->graph < -1) ++ frame->graph += FTRACE_NOTRACE_DEPTH; ++ + /* + * This is a case where function graph tracer has + * modified a return address (LR) in a stack frame +diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c +index 59779699a1a4..5d9076e86200 100644 +--- a/arch/arm64/kernel/time.c ++++ b/arch/arm64/kernel/time.c +@@ -53,7 +53,7 @@ unsigned long profile_pc(struct pt_regs *regs) + frame.sp = regs->sp; + frame.pc = regs->pc; + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +- frame.graph = -1; /* no task info */ ++ frame.graph = current->curr_ret_stack; + #endif + do { + int ret = unwind_frame(NULL, &frame); +diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c +index 5ed0ea92c5bf..f851c9d651f0 100644 +--- a/arch/ia64/kernel/err_inject.c ++++ b/arch/ia64/kernel/err_inject.c +@@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr, + u64 virt_addr=simple_strtoull(buf, NULL, 16); + int ret; + +- ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL); ++ ret = get_user_pages_fast(virt_addr, 1, FOLL_WRITE, NULL); + if (ret<=0) { + #ifdef ERR_INJ_DEBUG + printk("Virtual address %lx is not existing.\n",virt_addr); +diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c +index a0fc0c192427..3e8be0f54a44 100644 +--- a/arch/m68k/coldfire/device.c ++++ b/arch/m68k/coldfire/device.c +@@ -135,7 +135,11 @@ static struct platform_device mcf_fec0 = { + .id = 0, + .num_resources = ARRAY_SIZE(mcf_fec0_resources), + .resource = mcf_fec0_resources, +- .dev.platform_data = FEC_PDATA, ++ .dev = { ++ .dma_mask = &mcf_fec0.dev.coherent_dma_mask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = FEC_PDATA, ++ } + }; + + #ifdef MCFFEC_BASE1 +@@ -167,7 +171,11 @@ static struct platform_device mcf_fec1 = { + .id = 1, + .num_resources = ARRAY_SIZE(mcf_fec1_resources), + .resource = mcf_fec1_resources, +- .dev.platform_data = FEC_PDATA, ++ .dev = { ++ .dma_mask = &mcf_fec1.dev.coherent_dma_mask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = FEC_PDATA, ++ } + }; + #endif /* MCFFEC_BASE1 */ + #endif /* CONFIG_FEC */ +diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c +index 6ed1ded87b8f..6420c83c29d1 100644 +--- a/arch/mips/cavium-octeon/octeon-irq.c ++++ b/arch/mips/cavium-octeon/octeon-irq.c +@@ -2271,7 +2271,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, + + parent_irq = irq_of_parse_and_map(ciu_node, 0); + if (!parent_irq) { +- pr_err("ERROR: Couldn't acquire parent_irq for %s\n.", ++ pr_err("ERROR: Couldn't acquire parent_irq for %s\n", + ciu_node->name); + return -EINVAL; + } +@@ -2283,7 +2283,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, + + addr = of_get_address(ciu_node, 0, NULL, NULL); + if (!addr) { +- pr_err("ERROR: Couldn't acquire reg(0) %s\n.", ciu_node->name); ++ pr_err("ERROR: Couldn't acquire reg(0) %s\n", ciu_node->name); + return -EINVAL; + } + host_data->raw_reg = (u64)phys_to_virt( +@@ -2291,7 +2291,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, + + addr = of_get_address(ciu_node, 1, NULL, NULL); + if (!addr) { +- pr_err("ERROR: Couldn't acquire reg(1) %s\n.", ciu_node->name); ++ pr_err("ERROR: Couldn't acquire reg(1) %s\n", ciu_node->name); + return -EINVAL; + } + host_data->en_reg = (u64)phys_to_virt( +@@ -2299,7 +2299,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, + + r = of_property_read_u32(ciu_node, "cavium,max-bits", &val); + if (r) { +- pr_err("ERROR: Couldn't read cavium,max-bits from %s\n.", ++ pr_err("ERROR: Couldn't read cavium,max-bits from %s\n", + ciu_node->name); + return r; + } +@@ -2309,7 +2309,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, + &octeon_irq_domain_cib_ops, + host_data); + if (!cib_domain) { +- pr_err("ERROR: Couldn't irq_domain_add_linear()\n."); ++ pr_err("ERROR: Couldn't irq_domain_add_linear()\n"); + return -ENOMEM; + } + +diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +index aa3800c82332..d99ca862dae3 100644 +--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h ++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +@@ -167,7 +167,7 @@ + #define AR71XX_AHB_DIV_MASK 0x7 + + #define AR724X_PLL_REG_CPU_CONFIG 0x00 +-#define AR724X_PLL_REG_PCIE_CONFIG 0x18 ++#define AR724X_PLL_REG_PCIE_CONFIG 0x10 + + #define AR724X_PLL_FB_SHIFT 0 + #define AR724X_PLL_FB_MASK 0x3ff +diff --git a/arch/mips/include/asm/machine.h b/arch/mips/include/asm/machine.h +index 6b444cd9526f..db930cdc715f 100644 +--- a/arch/mips/include/asm/machine.h ++++ b/arch/mips/include/asm/machine.h +@@ -52,7 +52,7 @@ mips_machine_is_compatible(const struct mips_machine *mach, const void *fdt) + if (!mach->matches) + return NULL; + +- for (match = mach->matches; match->compatible; match++) { ++ for (match = mach->matches; match->compatible[0]; match++) { + if (fdt_node_check_compatible(fdt, 0, match->compatible) == 0) + return match; + } +diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c +index 0c8ae2cc6380..8f7bf74d1c0b 100644 +--- a/arch/mips/kernel/ptrace.c ++++ b/arch/mips/kernel/ptrace.c +@@ -483,7 +483,7 @@ static int fpr_get_msa(struct task_struct *target, + /* + * Copy the floating-point context to the supplied NT_PRFPREG buffer. + * Choose the appropriate helper for general registers, and then copy +- * the FCSR register separately. ++ * the FCSR and FIR registers separately. + */ + static int fpr_get(struct task_struct *target, + const struct user_regset *regset, +@@ -491,6 +491,7 @@ static int fpr_get(struct task_struct *target, + void *kbuf, void __user *ubuf) + { + const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); ++ const int fir_pos = fcr31_pos + sizeof(u32); + int err; + + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) +@@ -503,6 +504,12 @@ static int fpr_get(struct task_struct *target, + err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.fpu.fcr31, + fcr31_pos, fcr31_pos + sizeof(u32)); ++ if (err) ++ return err; ++ ++ err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ++ &boot_cpu_data.fpu_id, ++ fir_pos, fir_pos + sizeof(u32)); + + return err; + } +@@ -551,7 +558,8 @@ static int fpr_set_msa(struct task_struct *target, + /* + * Copy the supplied NT_PRFPREG buffer to the floating-point context. + * Choose the appropriate helper for general registers, and then copy +- * the FCSR register separately. ++ * the FCSR register separately. Ignore the incoming FIR register ++ * contents though, as the register is read-only. + * + * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0', + * which is supposed to have been guaranteed by the kernel before +@@ -565,6 +573,7 @@ static int fpr_set(struct task_struct *target, + const void *kbuf, const void __user *ubuf) + { + const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); ++ const int fir_pos = fcr31_pos + sizeof(u32); + u32 fcr31; + int err; + +@@ -592,6 +601,11 @@ static int fpr_set(struct task_struct *target, + ptrace_setfcr31(target, fcr31); + } + ++ if (count > 0) ++ err = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, ++ fir_pos, ++ fir_pos + sizeof(u32)); ++ + return err; + } + +@@ -813,7 +827,7 @@ long arch_ptrace(struct task_struct *child, long request, + fregs = get_fpu_regs(child); + + #ifdef CONFIG_32BIT +- if (test_thread_flag(TIF_32BIT_FPREGS)) { ++ if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { + /* + * The odd registers are actually the high + * order bits of the values stored in the even +@@ -902,7 +916,7 @@ long arch_ptrace(struct task_struct *child, long request, + + init_fp_ctx(child); + #ifdef CONFIG_32BIT +- if (test_thread_flag(TIF_32BIT_FPREGS)) { ++ if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { + /* + * The odd registers are actually the high + * order bits of the values stored in the even +diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c +index 5fcbdcd7abd0..bc9afbabbe14 100644 +--- a/arch/mips/kernel/ptrace32.c ++++ b/arch/mips/kernel/ptrace32.c +@@ -97,7 +97,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, + break; + } + fregs = get_fpu_regs(child); +- if (test_thread_flag(TIF_32BIT_FPREGS)) { ++ if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { + /* + * The odd registers are actually the high + * order bits of the values stored in the even +@@ -204,7 +204,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, + sizeof(child->thread.fpu)); + child->thread.fpu.fcr31 = 0; + } +- if (test_thread_flag(TIF_32BIT_FPREGS)) { ++ if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { + /* + * The odd registers are actually the high + * order bits of the values stored in the even +diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c +index 29ec9ab3fd55..a2c46f539e3e 100644 +--- a/arch/mips/kvm/mips.c ++++ b/arch/mips/kvm/mips.c +@@ -42,7 +42,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { + { "cache", VCPU_STAT(cache_exits), KVM_STAT_VCPU }, + { "signal", VCPU_STAT(signal_exits), KVM_STAT_VCPU }, + { "interrupt", VCPU_STAT(int_exits), KVM_STAT_VCPU }, +- { "cop_unsuable", VCPU_STAT(cop_unusable_exits), KVM_STAT_VCPU }, ++ { "cop_unusable", VCPU_STAT(cop_unusable_exits), KVM_STAT_VCPU }, + { "tlbmod", VCPU_STAT(tlbmod_exits), KVM_STAT_VCPU }, + { "tlbmiss_ld", VCPU_STAT(tlbmiss_ld_exits), KVM_STAT_VCPU }, + { "tlbmiss_st", VCPU_STAT(tlbmiss_st_exits), KVM_STAT_VCPU }, +diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c +index 9d0107fbb169..43fa682e55da 100644 +--- a/arch/mips/mm/c-r4k.c ++++ b/arch/mips/mm/c-r4k.c +@@ -851,9 +851,12 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) + /* + * Either no secondary cache or the available caches don't have the + * subset property so we have to flush the primary caches +- * explicitly ++ * explicitly. ++ * If we would need IPI to perform an INDEX-type operation, then ++ * we have to use the HIT-type alternative as IPI cannot be used ++ * here due to interrupts possibly being disabled. + */ +- if (size >= dcache_size) { ++ if (!r4k_op_needs_ipi(R4K_INDEX) && size >= dcache_size) { + r4k_blast_dcache(); + } else { + R4600_HIT_CACHEOP_WAR_IMPL; +@@ -890,7 +893,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) + return; + } + +- if (size >= dcache_size) { ++ if (!r4k_op_needs_ipi(R4K_INDEX) && size >= dcache_size) { + r4k_blast_dcache(); + } else { + R4600_HIT_CACHEOP_WAR_IMPL; +diff --git a/arch/mips/txx9/rbtx4939/setup.c b/arch/mips/txx9/rbtx4939/setup.c +index 8b937300fb7f..fd26fadc8617 100644 +--- a/arch/mips/txx9/rbtx4939/setup.c ++++ b/arch/mips/txx9/rbtx4939/setup.c +@@ -186,7 +186,7 @@ static void __init rbtx4939_update_ioc_pen(void) + + #define RBTX4939_MAX_7SEGLEDS 8 + +-#if IS_ENABLED(CONFIG_LEDS_CLASS) ++#if IS_BUILTIN(CONFIG_LEDS_CLASS) + static u8 led_val[RBTX4939_MAX_7SEGLEDS]; + struct rbtx4939_led_data { + struct led_classdev cdev; +@@ -261,7 +261,7 @@ static inline void rbtx4939_led_setup(void) + + static void __rbtx4939_7segled_putc(unsigned int pos, unsigned char val) + { +-#if IS_ENABLED(CONFIG_LEDS_CLASS) ++#if IS_BUILTIN(CONFIG_LEDS_CLASS) + unsigned long flags; + local_irq_save(flags); + /* bit7: reserved for LED class */ +diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile +index 9d47f2efa830..bb69f3955b59 100644 +--- a/arch/powerpc/boot/Makefile ++++ b/arch/powerpc/boot/Makefile +@@ -92,7 +92,8 @@ $(addprefix $(obj)/,$(zlib-y)): \ + libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c + libfdtheader := fdt.h libfdt.h libfdt_internal.h + +-$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \ ++$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o \ ++ treeboot-akebono.o treeboot-currituck.o treeboot-iss4xx.o): \ + $(addprefix $(obj)/,$(libfdtheader)) + + src-wlib-y := string.S crt0.S crtsavres.S stdio.c decompress.c main.c \ +diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h +index 744fd54de374..1bcc84903930 100644 +--- a/arch/powerpc/include/asm/irq_work.h ++++ b/arch/powerpc/include/asm/irq_work.h +@@ -5,5 +5,6 @@ static inline bool arch_irq_work_has_interrupt(void) + { + return true; + } ++extern void arch_irq_work_raise(void); + + #endif /* _ASM_POWERPC_IRQ_WORK_H */ +diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c +index 218cba2f5699..0a2b247dbc6b 100644 +--- a/arch/powerpc/kvm/book3s_hv.c ++++ b/arch/powerpc/kvm/book3s_hv.c +@@ -3107,15 +3107,17 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) + goto up_out; + + psize = vma_kernel_pagesize(vma); +- porder = __ilog2(psize); + + up_read(¤t->mm->mmap_sem); + + /* We can handle 4k, 64k or 16M pages in the VRMA */ +- err = -EINVAL; +- if (!(psize == 0x1000 || psize == 0x10000 || +- psize == 0x1000000)) +- goto out_srcu; ++ if (psize >= 0x1000000) ++ psize = 0x1000000; ++ else if (psize >= 0x10000) ++ psize = 0x10000; ++ else ++ psize = 0x1000; ++ porder = __ilog2(psize); + + /* Update VRMASD field in the LPCR */ + senc = slb_pgsize_encoding(psize); +diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c +index a51c188b81f3..6cff96e0d77b 100644 +--- a/arch/powerpc/mm/numa.c ++++ b/arch/powerpc/mm/numa.c +@@ -551,7 +551,7 @@ static int numa_setup_cpu(unsigned long lcpu) + nid = of_node_to_nid_single(cpu); + + out_present: +- if (nid < 0 || !node_online(nid)) ++ if (nid < 0 || !node_possible(nid)) + nid = first_online_node; + + map_cpu_to_node(lcpu, nid); +@@ -904,6 +904,32 @@ static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn) + NODE_DATA(nid)->node_spanned_pages = spanned_pages; + } + ++static void __init find_possible_nodes(void) ++{ ++ struct device_node *rtas; ++ u32 numnodes, i; ++ ++ if (min_common_depth <= 0) ++ return; ++ ++ rtas = of_find_node_by_path("/rtas"); ++ if (!rtas) ++ return; ++ ++ if (of_property_read_u32_index(rtas, ++ "ibm,max-associativity-domains", ++ min_common_depth, &numnodes)) ++ goto out; ++ ++ for (i = 0; i < numnodes; i++) { ++ if (!node_possible(i)) ++ node_set(i, node_possible_map); ++ } ++ ++out: ++ of_node_put(rtas); ++} ++ + void __init initmem_init(void) + { + int nid, cpu; +@@ -917,12 +943,15 @@ void __init initmem_init(void) + memblock_dump_all(); + + /* +- * Reduce the possible NUMA nodes to the online NUMA nodes, +- * since we do not support node hotplug. This ensures that we +- * lower the maximum NUMA node ID to what is actually present. ++ * Modify the set of possible NUMA nodes to reflect information ++ * available about the set of online nodes, and the set of nodes ++ * that we expect to make use of for this platform's affinity ++ * calculations. + */ + nodes_and(node_possible_map, node_possible_map, node_online_map); + ++ find_possible_nodes(); ++ + for_each_online_node(nid) { + unsigned long start_pfn, end_pfn; + +@@ -1274,6 +1303,40 @@ static long vphn_get_associativity(unsigned long cpu, + return rc; + } + ++static inline int find_and_online_cpu_nid(int cpu) ++{ ++ __be32 associativity[VPHN_ASSOC_BUFSIZE] = {0}; ++ int new_nid; ++ ++ /* Use associativity from first thread for all siblings */ ++ vphn_get_associativity(cpu, associativity); ++ new_nid = associativity_to_nid(associativity); ++ if (new_nid < 0 || !node_possible(new_nid)) ++ new_nid = first_online_node; ++ ++ if (NODE_DATA(new_nid) == NULL) { ++#ifdef CONFIG_MEMORY_HOTPLUG ++ /* ++ * Need to ensure that NODE_DATA is initialized for a node from ++ * available memory (see memblock_alloc_try_nid). If unable to ++ * init the node, then default to nearest node that has memory ++ * installed. ++ */ ++ if (try_online_node(new_nid)) ++ new_nid = first_online_node; ++#else ++ /* ++ * Default to using the nearest node that has memory installed. ++ * Otherwise, it would be necessary to patch the kernel MM code ++ * to deal with more memoryless-node error conditions. ++ */ ++ new_nid = first_online_node; ++#endif ++ } ++ ++ return new_nid; ++} ++ + /* + * Update the CPU maps and sysfs entries for a single CPU when its NUMA + * characteristics change. This function doesn't perform any locking and is +@@ -1339,7 +1402,6 @@ int arch_update_cpu_topology(void) + { + unsigned int cpu, sibling, changed = 0; + struct topology_update_data *updates, *ud; +- __be32 associativity[VPHN_ASSOC_BUFSIZE] = {0}; + cpumask_t updated_cpus; + struct device *dev; + int weight, new_nid, i = 0; +@@ -1374,11 +1436,7 @@ int arch_update_cpu_topology(void) + continue; + } + +- /* Use associativity from first thread for all siblings */ +- vphn_get_associativity(cpu, associativity); +- new_nid = associativity_to_nid(associativity); +- if (new_nid < 0 || !node_online(new_nid)) +- new_nid = first_online_node; ++ new_nid = find_and_online_cpu_nid(cpu); + + if (new_nid == numa_cpu_lookup_table[cpu]) { + cpumask_andnot(&cpu_associativity_changes_mask, +diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c +index 7e706f36e364..9c58194c7ea5 100644 +--- a/arch/powerpc/net/bpf_jit_comp.c ++++ b/arch/powerpc/net/bpf_jit_comp.c +@@ -329,6 +329,9 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); + PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, len)); + break; ++ case BPF_LDX | BPF_W | BPF_ABS: /* A = *((u32 *)(seccomp_data + K)); */ ++ PPC_LWZ_OFFS(r_A, r_skb, K); ++ break; + case BPF_LDX | BPF_W | BPF_LEN: /* X = skb->len; */ + PPC_LWZ_OFFS(r_X, r_skb, offsetof(struct sk_buff, len)); + break; +diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c +index bf949623de90..771edffa2d40 100644 +--- a/arch/powerpc/perf/core-book3s.c ++++ b/arch/powerpc/perf/core-book3s.c +@@ -448,6 +448,16 @@ static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) + /* invalid entry */ + continue; + ++ /* ++ * BHRB rolling buffer could very much contain the kernel ++ * addresses at this point. Check the privileges before ++ * exporting it to userspace (avoid exposure of regions ++ * where we could have speculative execution) ++ */ ++ if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN) && ++ is_kernel_addr(addr)) ++ continue; ++ + /* Branches are read most recent first (ie. mfbhrb 0 is + * the most recent branch). + * There are two types of valid entries: +@@ -1188,6 +1198,7 @@ static void power_pmu_disable(struct pmu *pmu) + */ + write_mmcr0(cpuhw, val); + mb(); ++ isync(); + + /* + * Disable instruction sampling if it was enabled +@@ -1196,12 +1207,26 @@ static void power_pmu_disable(struct pmu *pmu) + mtspr(SPRN_MMCRA, + cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE); + mb(); ++ isync(); + } + + cpuhw->disabled = 1; + cpuhw->n_added = 0; + + ebb_switch_out(mmcr0); ++ ++#ifdef CONFIG_PPC64 ++ /* ++ * These are readable by userspace, may contain kernel ++ * addresses and are not switched by context switch, so clear ++ * them now to avoid leaking anything to userspace in general ++ * including to another process. ++ */ ++ if (ppmu->flags & PPMU_ARCH_207S) { ++ mtspr(SPRN_SDAR, 0); ++ mtspr(SPRN_SIAR, 0); ++ } ++#endif + } + + local_irq_restore(flags); +diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c +index b9aac951a90f..f37567ed640c 100644 +--- a/arch/powerpc/sysdev/mpic.c ++++ b/arch/powerpc/sysdev/mpic.c +@@ -626,7 +626,7 @@ static inline u32 mpic_physmask(u32 cpumask) + int i; + u32 mask = 0; + +- for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) ++ for (i = 0; i < min(32, NR_CPUS) && cpu_possible(i); ++i, cpumask >>= 1) + mask |= (cpumask & 1) << get_hard_smp_processor_id(i); + return mask; + } +diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c +index ced6c9b8f04d..51f842c0a175 100644 +--- a/arch/s390/kvm/vsie.c ++++ b/arch/s390/kvm/vsie.c +@@ -549,7 +549,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) + + gpa = scb_o->itdba & ~0xffUL; + if (gpa && (scb_s->ecb & 0x10U)) { +- if (!(gpa & ~0x1fffU)) { ++ if (!(gpa & ~0x1fffUL)) { + rc = set_validity_icpt(scb_s, 0x0080U); + goto unpin; + } +diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S +index c001f782c5f1..28cc61216b64 100644 +--- a/arch/sh/kernel/entry-common.S ++++ b/arch/sh/kernel/entry-common.S +@@ -255,7 +255,7 @@ debug_trap: + mov.l @r8, r8 + jsr @r8 + nop +- bra __restore_all ++ bra ret_from_exception + nop + CFI_ENDPROC + +diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h +index 24827a3f733a..89d299ccdfa6 100644 +--- a/arch/sparc/include/asm/atomic_64.h ++++ b/arch/sparc/include/asm/atomic_64.h +@@ -82,7 +82,11 @@ ATOMIC_OPS(xor) + #define atomic64_add_negative(i, v) (atomic64_add_return(i, v) < 0) + + #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) +-#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) ++ ++static inline int atomic_xchg(atomic_t *v, int new) ++{ ++ return xchg(&v->counter, new); ++} + + static inline int __atomic_add_unless(atomic_t *v, int a, int u) + { +diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h +index b6802b978140..81ad06a1672f 100644 +--- a/arch/sparc/include/asm/pgtable_64.h ++++ b/arch/sparc/include/asm/pgtable_64.h +@@ -952,7 +952,7 @@ void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, + pmd_t *pmd); + + #define __HAVE_ARCH_PMDP_INVALIDATE +-extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, ++extern pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, + pmd_t *pmdp); + + #define __HAVE_ARCH_PGTABLE_DEPOSIT +diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c +index c56a195c9071..b2722ed31053 100644 +--- a/arch/sparc/mm/tlb.c ++++ b/arch/sparc/mm/tlb.c +@@ -219,17 +219,28 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, + } + } + ++static inline pmd_t pmdp_establish(struct vm_area_struct *vma, ++ unsigned long address, pmd_t *pmdp, pmd_t pmd) ++{ ++ pmd_t old; ++ ++ do { ++ old = *pmdp; ++ } while (cmpxchg64(&pmdp->pmd, old.pmd, pmd.pmd) != old.pmd); ++ ++ return old; ++} ++ + /* + * This routine is only called when splitting a THP + */ +-void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, ++pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, + pmd_t *pmdp) + { +- pmd_t entry = *pmdp; +- +- pmd_val(entry) &= ~_PAGE_VALID; ++ pmd_t old, entry; + +- set_pmd_at(vma->vm_mm, address, pmdp, entry); ++ entry = __pmd(pmd_val(*pmdp) & ~_PAGE_VALID); ++ old = pmdp_establish(vma, address, pmdp, entry); + flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); + + /* +@@ -240,6 +251,8 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, + if ((pmd_val(entry) & _PAGE_PMD_HUGE) && + !is_huge_zero_page(pmd_page(entry))) + (vma->vm_mm)->context.thp_pte_count--; ++ ++ return old; + } + + void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, +diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c +index 02e547f9ca3f..655a65eaf105 100644 +--- a/arch/x86/events/core.c ++++ b/arch/x86/events/core.c +@@ -1155,16 +1155,13 @@ int x86_perf_event_set_period(struct perf_event *event) + + per_cpu(pmc_prev_left[idx], smp_processor_id()) = left; + +- if (!(hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) || +- local64_read(&hwc->prev_count) != (u64)-left) { +- /* +- * The hw event starts counting from this event offset, +- * mark it to be able to extra future deltas: +- */ +- local64_set(&hwc->prev_count, (u64)-left); ++ /* ++ * The hw event starts counting from this event offset, ++ * mark it to be able to extra future deltas: ++ */ ++ local64_set(&hwc->prev_count, (u64)-left); + +- wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask); +- } ++ wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask); + + /* + * Due to erratum on certan cpu we need +diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c +index 6f353a874178..815039327932 100644 +--- a/arch/x86/events/intel/core.c ++++ b/arch/x86/events/intel/core.c +@@ -2066,9 +2066,15 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) + int bit, loops; + u64 status; + int handled; ++ int pmu_enabled; + + cpuc = this_cpu_ptr(&cpu_hw_events); + ++ /* ++ * Save the PMU state. ++ * It needs to be restored when leaving the handler. ++ */ ++ pmu_enabled = cpuc->enabled; + /* + * No known reason to not always do late ACK, + * but just in case do it opt-in. +@@ -2076,6 +2082,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) + if (!x86_pmu.late_ack) + apic_write(APIC_LVTPC, APIC_DM_NMI); + intel_bts_disable_local(); ++ cpuc->enabled = 0; + __intel_pmu_disable_all(); + handled = intel_pmu_drain_bts_buffer(); + handled += intel_bts_interrupt(); +@@ -2173,7 +2180,8 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) + + done: + /* Only restore PMU state when it's active. See x86_pmu_disable(). */ +- if (cpuc->enabled) ++ cpuc->enabled = pmu_enabled; ++ if (pmu_enabled) + __intel_pmu_enable_all(0, true); + intel_bts_enable_local(); + +@@ -3019,7 +3027,7 @@ hsw_get_event_constraints(struct cpu_hw_events *cpuc, int idx, + * Therefore the effective (average) period matches the requested period, + * despite coarser hardware granularity. + */ +-static unsigned bdw_limit_period(struct perf_event *event, unsigned left) ++static u64 bdw_limit_period(struct perf_event *event, u64 left) + { + if ((event->hw.config & INTEL_ARCH_EVENT_MASK) == + X86_CONFIG(.event=0xc0, .umask=0x01)) { +diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c +index 8e7a3f1df3a5..f26e26e4d84f 100644 +--- a/arch/x86/events/intel/ds.c ++++ b/arch/x86/events/intel/ds.c +@@ -1110,6 +1110,7 @@ static void setup_pebs_sample_data(struct perf_event *event, + if (pebs == NULL) + return; + ++ regs->flags &= ~PERF_EFLAGS_EXACT; + sample_type = event->attr.sample_type; + dsrc = sample_type & PERF_SAMPLE_DATA_SRC; + +@@ -1154,7 +1155,6 @@ static void setup_pebs_sample_data(struct perf_event *event, + */ + *regs = *iregs; + regs->flags = pebs->flags; +- set_linear_ip(regs, pebs->ip); + + if (sample_type & PERF_SAMPLE_REGS_INTR) { + regs->ax = pebs->ax; +@@ -1190,13 +1190,22 @@ static void setup_pebs_sample_data(struct perf_event *event, + #endif + } + +- if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) { +- regs->ip = pebs->real_ip; +- regs->flags |= PERF_EFLAGS_EXACT; +- } else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(regs)) +- regs->flags |= PERF_EFLAGS_EXACT; +- else +- regs->flags &= ~PERF_EFLAGS_EXACT; ++ if (event->attr.precise_ip > 1) { ++ /* Haswell and later have the eventing IP, so use it: */ ++ if (x86_pmu.intel_cap.pebs_format >= 2) { ++ set_linear_ip(regs, pebs->real_ip); ++ regs->flags |= PERF_EFLAGS_EXACT; ++ } else { ++ /* Otherwise use PEBS off-by-1 IP: */ ++ set_linear_ip(regs, pebs->ip); ++ ++ /* ... and try to fix it up using the LBR entries: */ ++ if (intel_pmu_pebs_fixup_ip(regs)) ++ regs->flags |= PERF_EFLAGS_EXACT; ++ } ++ } else ++ set_linear_ip(regs, pebs->ip); ++ + + if ((sample_type & PERF_SAMPLE_ADDR) && + x86_pmu.intel_cap.pebs_format >= 1) +@@ -1263,17 +1272,84 @@ get_next_pebs_record_by_bit(void *base, void *top, int bit) + return NULL; + } + ++/* ++ * Special variant of intel_pmu_save_and_restart() for auto-reload. ++ */ ++static int ++intel_pmu_save_and_restart_reload(struct perf_event *event, int count) ++{ ++ struct hw_perf_event *hwc = &event->hw; ++ int shift = 64 - x86_pmu.cntval_bits; ++ u64 period = hwc->sample_period; ++ u64 prev_raw_count, new_raw_count; ++ s64 new, old; ++ ++ WARN_ON(!period); ++ ++ /* ++ * drain_pebs() only happens when the PMU is disabled. ++ */ ++ WARN_ON(this_cpu_read(cpu_hw_events.enabled)); ++ ++ prev_raw_count = local64_read(&hwc->prev_count); ++ rdpmcl(hwc->event_base_rdpmc, new_raw_count); ++ local64_set(&hwc->prev_count, new_raw_count); ++ ++ /* ++ * Since the counter increments a negative counter value and ++ * overflows on the sign switch, giving the interval: ++ * ++ * [-period, 0] ++ * ++ * the difference between two consequtive reads is: ++ * ++ * A) value2 - value1; ++ * when no overflows have happened in between, ++ * ++ * B) (0 - value1) + (value2 - (-period)); ++ * when one overflow happened in between, ++ * ++ * C) (0 - value1) + (n - 1) * (period) + (value2 - (-period)); ++ * when @n overflows happened in between. ++ * ++ * Here A) is the obvious difference, B) is the extension to the ++ * discrete interval, where the first term is to the top of the ++ * interval and the second term is from the bottom of the next ++ * interval and C) the extension to multiple intervals, where the ++ * middle term is the whole intervals covered. ++ * ++ * An equivalent of C, by reduction, is: ++ * ++ * value2 - value1 + n * period ++ */ ++ new = ((s64)(new_raw_count << shift) >> shift); ++ old = ((s64)(prev_raw_count << shift) >> shift); ++ local64_add(new - old + count * period, &event->count); ++ ++ perf_event_update_userpage(event); ++ ++ return 0; ++} ++ + static void __intel_pmu_pebs_event(struct perf_event *event, + struct pt_regs *iregs, + void *base, void *top, + int bit, int count) + { ++ struct hw_perf_event *hwc = &event->hw; + struct perf_sample_data data; + struct pt_regs regs; + void *at = get_next_pebs_record_by_bit(base, top, bit); + +- if (!intel_pmu_save_and_restart(event) && +- !(event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD)) ++ if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) { ++ /* ++ * Now, auto-reload is only enabled in fixed period mode. ++ * The reload value is always hwc->sample_period. ++ * May need to change it, if auto-reload is enabled in ++ * freq mode later. ++ */ ++ intel_pmu_save_and_restart_reload(event, count); ++ } else if (!intel_pmu_save_and_restart(event)) + return; + + while (count > 1) { +@@ -1325,8 +1401,11 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs) + return; + + n = top - at; +- if (n <= 0) ++ if (n <= 0) { ++ if (event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD) ++ intel_pmu_save_and_restart_reload(event, 0); + return; ++ } + + __intel_pmu_pebs_event(event, iregs, at, top, 0, n); + } +@@ -1349,8 +1428,22 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) + + ds->pebs_index = ds->pebs_buffer_base; + +- if (unlikely(base >= top)) ++ if (unlikely(base >= top)) { ++ /* ++ * The drain_pebs() could be called twice in a short period ++ * for auto-reload event in pmu::read(). There are no ++ * overflows have happened in between. ++ * It needs to call intel_pmu_save_and_restart_reload() to ++ * update the event->count for this case. ++ */ ++ for_each_set_bit(bit, (unsigned long *)&cpuc->pebs_enabled, ++ x86_pmu.max_pebs_events) { ++ event = cpuc->events[bit]; ++ if (event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD) ++ intel_pmu_save_and_restart_reload(event, 0); ++ } + return; ++ } + + for (at = base; at < top; at += x86_pmu.pebs_record_size) { + struct pebs_record_nhm *p = at; +diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h +index bcbb1d2ae10b..f3563179290b 100644 +--- a/arch/x86/events/perf_event.h ++++ b/arch/x86/events/perf_event.h +@@ -548,7 +548,7 @@ struct x86_pmu { + struct x86_pmu_quirk *quirks; + int perfctr_second_write; + bool late_ack; +- unsigned (*limit_period)(struct perf_event *event, unsigned l); ++ u64 (*limit_period)(struct perf_event *event, u64 l); + + /* + * sysfs attrs +diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h +index 39bcefc20de7..bb078786a323 100644 +--- a/arch/x86/include/asm/i8259.h ++++ b/arch/x86/include/asm/i8259.h +@@ -68,6 +68,11 @@ struct legacy_pic { + extern struct legacy_pic *legacy_pic; + extern struct legacy_pic null_legacy_pic; + ++static inline bool has_legacy_pic(void) ++{ ++ return legacy_pic != &null_legacy_pic; ++} ++ + static inline int nr_legacy_irqs(void) + { + return legacy_pic->nr_legacy_irqs; +diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c +index c6583efdbdaf..76cf21f887bd 100644 +--- a/arch/x86/kernel/apic/apic.c ++++ b/arch/x86/kernel/apic/apic.c +@@ -1403,7 +1403,7 @@ void setup_local_APIC(void) + * TODO: set up through-local-APIC from through-I/O-APIC? --macro + */ + value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; +- if (!cpu && (pic_mode || !value)) { ++ if (!cpu && (pic_mode || !value || skip_ioapic_setup)) { + value = APIC_DM_EXTINT; + apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", cpu); + } else { +diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c +index 3fe45f84ced4..7a07b15b451c 100644 +--- a/arch/x86/kernel/devicetree.c ++++ b/arch/x86/kernel/devicetree.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -199,19 +200,22 @@ static struct of_ioapic_type of_ioapic_type[] = + static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *arg) + { +- struct of_phandle_args *irq_data = (void *)arg; ++ struct irq_fwspec *fwspec = (struct irq_fwspec *)arg; + struct of_ioapic_type *it; + struct irq_alloc_info tmp; ++ int type_index; + +- if (WARN_ON(irq_data->args_count < 2)) ++ if (WARN_ON(fwspec->param_count < 2)) + return -EINVAL; +- if (irq_data->args[1] >= ARRAY_SIZE(of_ioapic_type)) ++ ++ type_index = fwspec->param[1]; ++ if (type_index >= ARRAY_SIZE(of_ioapic_type)) + return -EINVAL; + +- it = &of_ioapic_type[irq_data->args[1]]; ++ it = &of_ioapic_type[type_index]; + ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->trigger, it->polarity); + tmp.ioapic_id = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain)); +- tmp.ioapic_pin = irq_data->args[0]; ++ tmp.ioapic_pin = fwspec->param[0]; + + return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp); + } +@@ -276,14 +280,15 @@ static void __init x86_flattree_get_config(void) + + map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), (u64)128); + +- initial_boot_params = dt = early_memremap(initial_dtb, map_len); +- size = of_get_flat_dt_size(); ++ dt = early_memremap(initial_dtb, map_len); ++ size = fdt_totalsize(dt); + if (map_len < size) { + early_memunmap(dt, map_len); +- initial_boot_params = dt = early_memremap(initial_dtb, size); ++ dt = early_memremap(initial_dtb, size); + map_len = size; + } + ++ early_init_dt_verify(dt); + unflatten_and_copy_device_tree(); + early_memunmap(dt, map_len); + } +diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c +index cb945146b7c8..10b22fc6ef5a 100644 +--- a/arch/x86/kernel/smpboot.c ++++ b/arch/x86/kernel/smpboot.c +@@ -1497,6 +1497,7 @@ static void remove_siblinginfo(int cpu) + cpumask_clear(topology_core_cpumask(cpu)); + c->phys_proc_id = 0; + c->cpu_core_id = 0; ++ c->booted_cores = 0; + cpumask_clear_cpu(cpu, cpu_sibling_setup_mask); + recompute_smt_state(); + } +diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c +index da6a287a11e4..769c370011d6 100644 +--- a/arch/x86/kernel/tsc.c ++++ b/arch/x86/kernel/tsc.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */ + EXPORT_SYMBOL(cpu_khz); +@@ -456,6 +457,20 @@ static unsigned long pit_calibrate_tsc(u32 latch, unsigned long ms, int loopmin) + unsigned long tscmin, tscmax; + int pitcnt; + ++ if (!has_legacy_pic()) { ++ /* ++ * Relies on tsc_early_delay_calibrate() to have given us semi ++ * usable udelay(), wait for the same 50ms we would have with ++ * the PIT loop below. ++ */ ++ udelay(10 * USEC_PER_MSEC); ++ udelay(10 * USEC_PER_MSEC); ++ udelay(10 * USEC_PER_MSEC); ++ udelay(10 * USEC_PER_MSEC); ++ udelay(10 * USEC_PER_MSEC); ++ return ULONG_MAX; ++ } ++ + /* Set the Gate high, disable speaker */ + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + +@@ -580,6 +595,9 @@ static unsigned long quick_pit_calibrate(void) + u64 tsc, delta; + unsigned long d1, d2; + ++ if (!has_legacy_pic()) ++ return 0; ++ + /* Set the Gate high, disable speaker */ + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + +diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c +index a69f18d4676c..7e5119c1d15c 100644 +--- a/arch/x86/kvm/cpuid.c ++++ b/arch/x86/kvm/cpuid.c +@@ -382,7 +382,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, + + /* cpuid 7.0.edx*/ + const u32 kvm_cpuid_7_0_edx_x86_features = +- F(SPEC_CTRL) | F(SSBD) | F(ARCH_CAPABILITIES); ++ F(SPEC_CTRL) | F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES); + + /* all calls to cpuid_count() should be made on the same cpu */ + get_cpu(); +@@ -468,6 +468,11 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, + entry->ecx &= ~F(PKU); + entry->edx &= kvm_cpuid_7_0_edx_x86_features; + cpuid_mask(&entry->edx, CPUID_7_EDX); ++ /* ++ * We emulate ARCH_CAPABILITIES in software even ++ * if the host doesn't support it. ++ */ ++ entry->edx |= F(ARCH_CAPABILITIES); + } else { + entry->ebx = 0; + entry->ecx = 0; +diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c +index 5c3d416fff17..a8a86be8cf15 100644 +--- a/arch/x86/kvm/lapic.c ++++ b/arch/x86/kvm/lapic.c +@@ -299,8 +299,16 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu) + if (!lapic_in_kernel(vcpu)) + return; + ++ /* ++ * KVM emulates 82093AA datasheet (with in-kernel IOAPIC implementation) ++ * which doesn't have EOI register; Some buggy OSes (e.g. Windows with ++ * Hyper-V role) disable EOI broadcast in lapic not checking for IOAPIC ++ * version first and level-triggered interrupts never get EOIed in ++ * IOAPIC. ++ */ + feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0); +- if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31)))) ++ if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31))) && ++ !ioapic_in_kernel(vcpu->kvm)) + v |= APIC_LVR_DIRECTED_EOI; + kvm_lapic_set_reg(apic, APIC_LVR, v); + } +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index d92523afb425..2827a9622d97 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -2558,6 +2558,8 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, + return; + } + ++ WARN_ON_ONCE(vmx->emulation_required); ++ + if (kvm_exception_is_soft(nr)) { + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, + vmx->vcpu.arch.event_exit_inst_len); +@@ -6430,12 +6432,12 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) + goto out; + } + +- if (err != EMULATE_DONE) { +- vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; +- vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; +- vcpu->run->internal.ndata = 0; +- return 0; +- } ++ if (err != EMULATE_DONE) ++ goto emulation_error; ++ ++ if (vmx->emulation_required && !vmx->rmode.vm86_active && ++ vcpu->arch.exception.pending) ++ goto emulation_error; + + if (vcpu->arch.halt_request) { + vcpu->arch.halt_request = 0; +@@ -6451,6 +6453,12 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) + + out: + return ret; ++ ++emulation_error: ++ vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; ++ vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; ++ vcpu->run->internal.ndata = 0; ++ return 0; + } + + static int __grow_ple_window(int val) +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index a0cb85f30c94..4aa265ae8cf7 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -4131,13 +4131,14 @@ long kvm_arch_vm_ioctl(struct file *filp, + mutex_unlock(&kvm->lock); + break; + case KVM_XEN_HVM_CONFIG: { ++ struct kvm_xen_hvm_config xhc; + r = -EFAULT; +- if (copy_from_user(&kvm->arch.xen_hvm_config, argp, +- sizeof(struct kvm_xen_hvm_config))) ++ if (copy_from_user(&xhc, argp, sizeof(xhc))) + goto out; + r = -EINVAL; +- if (kvm->arch.xen_hvm_config.flags) ++ if (xhc.flags) + goto out; ++ memcpy(&kvm->arch.xen_hvm_config, &xhc, sizeof(xhc)); + r = 0; + break; + } +@@ -7258,6 +7259,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, + { + struct msr_data apic_base_msr; + int mmu_reset_needed = 0; ++ int cpuid_update_needed = 0; + int pending_vec, max_bits, idx; + struct desc_ptr dt; + +@@ -7289,8 +7291,10 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, + vcpu->arch.cr0 = sregs->cr0; + + mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4; ++ cpuid_update_needed |= ((kvm_read_cr4(vcpu) ^ sregs->cr4) & ++ (X86_CR4_OSXSAVE | X86_CR4_PKE)); + kvm_x86_ops->set_cr4(vcpu, sregs->cr4); +- if (sregs->cr4 & (X86_CR4_OSXSAVE | X86_CR4_PKE)) ++ if (cpuid_update_needed) + kvm_update_cpuid(vcpu); + + idx = srcu_read_lock(&vcpu->kvm->srcu); +diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c +index 7df8e3a79dc0..d35d0e4bbf99 100644 +--- a/arch/x86/mm/init_64.c ++++ b/arch/x86/mm/init_64.c +@@ -1014,8 +1014,7 @@ void __init mem_init(void) + after_bootmem = 1; + + /* Register memory areas for /proc/kcore */ +- kclist_add(&kcore_vsyscall, (void *)VSYSCALL_ADDR, +- PAGE_SIZE, KCORE_OTHER); ++ kclist_add(&kcore_vsyscall, (void *)VSYSCALL_ADDR, PAGE_SIZE, KCORE_USER); + + mem_init_print_info(NULL); + } +diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c +index 73dcb0e18c1b..dcd671467154 100644 +--- a/arch/x86/mm/pageattr.c ++++ b/arch/x86/mm/pageattr.c +@@ -279,9 +279,11 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, + + /* + * The .rodata section needs to be read-only. Using the pfn +- * catches all aliases. ++ * catches all aliases. This also includes __ro_after_init, ++ * so do not enforce until kernel_set_to_readonly is true. + */ +- if (within(pfn, __pa_symbol(__start_rodata) >> PAGE_SHIFT, ++ if (kernel_set_to_readonly && ++ within(pfn, __pa_symbol(__start_rodata) >> PAGE_SHIFT, + __pa_symbol(__end_rodata) >> PAGE_SHIFT)) + pgprot_val(forbidden) |= _PAGE_RW; + +diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c +index b97ef29c940f..a3b63e5a527c 100644 +--- a/arch/x86/mm/pgtable.c ++++ b/arch/x86/mm/pgtable.c +@@ -1,5 +1,6 @@ + #include + #include ++#include + #include + #include + #include +@@ -577,6 +578,10 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot) + (mtrr != MTRR_TYPE_WRBACK)) + return 0; + ++ /* Bail out if we are we on a populated non-leaf entry: */ ++ if (pud_present(*pud) && !pud_huge(*pud)) ++ return 0; ++ + prot = pgprot_4k_2_large(prot); + + set_pte((pte_t *)pud, pfn_pte( +@@ -605,6 +610,10 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot) + return 0; + } + ++ /* Bail out if we are we on a populated non-leaf entry: */ ++ if (pmd_present(*pmd) && !pmd_huge(*pmd)) ++ return 0; ++ + prot = pgprot_4k_2_large(prot); + + set_pte((pte_t *)pmd, pfn_pte( +diff --git a/arch/x86/power/hibernate_32.c b/arch/x86/power/hibernate_32.c +index 9f14bd34581d..74b516cb39df 100644 +--- a/arch/x86/power/hibernate_32.c ++++ b/arch/x86/power/hibernate_32.c +@@ -142,7 +142,7 @@ static inline void resume_init_first_level_page_table(pgd_t *pg_dir) + #endif + } + +-int swsusp_arch_resume(void) ++asmlinkage int swsusp_arch_resume(void) + { + int error; + +diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c +index 9634557a5444..0cb1dd461529 100644 +--- a/arch/x86/power/hibernate_64.c ++++ b/arch/x86/power/hibernate_64.c +@@ -149,7 +149,7 @@ static int relocate_restore_code(void) + return 0; + } + +-int swsusp_arch_resume(void) ++asmlinkage int swsusp_arch_resume(void) + { + int error; + +diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c +index f6a009d88a33..52e5ea3b8e40 100644 +--- a/crypto/asymmetric_keys/pkcs7_trust.c ++++ b/crypto/asymmetric_keys/pkcs7_trust.c +@@ -106,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, + pr_devel("sinfo %u: Direct signer is key %x\n", + sinfo->index, key_serial(key)); + x509 = NULL; ++ sig = sinfo->sig; + goto matched; + } + if (PTR_ERR(key) != -ENOKEY) +diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c +index eb76a4c10dbf..8ce203f84ec4 100644 +--- a/drivers/acpi/acpi_pad.c ++++ b/drivers/acpi/acpi_pad.c +@@ -109,6 +109,7 @@ static void round_robin_cpu(unsigned int tsk_index) + cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus); + if (cpumask_empty(tmp)) { + mutex_unlock(&round_robin_lock); ++ free_cpumask_var(tmp); + return; + } + for_each_cpu(cpu, tmp) { +@@ -126,6 +127,8 @@ static void round_robin_cpu(unsigned int tsk_index) + mutex_unlock(&round_robin_lock); + + set_cpus_allowed_ptr(current, cpumask_of(preferred_cpu)); ++ ++ free_cpumask_var(tmp); + } + + static void exit_round_robin(unsigned int tsk_index) +diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c +index 80fc0b9b11e5..f362841881e6 100644 +--- a/drivers/acpi/acpica/evevent.c ++++ b/drivers/acpi/acpica/evevent.c +@@ -204,6 +204,7 @@ u32 acpi_ev_fixed_event_detect(void) + u32 fixed_status; + u32 fixed_enable; + u32 i; ++ acpi_status status; + + ACPI_FUNCTION_NAME(ev_fixed_event_detect); + +@@ -211,8 +212,12 @@ u32 acpi_ev_fixed_event_detect(void) + * Read the fixed feature status and enable registers, as all the cases + * depend on their values. Ignore errors here. + */ +- (void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); +- (void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); ++ status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); ++ status |= ++ acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); ++ if (ACPI_FAILURE(status)) { ++ return (int_status); ++ } + + ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, + "Fixed Event Block: Enable %08X Status %08X\n", +diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c +index 5d59cfcef6f4..c5d6701a5ad2 100644 +--- a/drivers/acpi/acpica/nseval.c ++++ b/drivers/acpi/acpica/nseval.c +@@ -308,6 +308,14 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) + /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ + + status = AE_OK; ++ } else if (ACPI_FAILURE(status)) { ++ ++ /* If return_object exists, delete it */ ++ ++ if (info->return_object) { ++ acpi_ut_remove_reference(info->return_object); ++ info->return_object = NULL; ++ } + } + + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, +diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c +index bb01dea39fdc..9825780a1cd2 100644 +--- a/drivers/acpi/processor_perflib.c ++++ b/drivers/acpi/processor_perflib.c +@@ -161,7 +161,7 @@ int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) + { + int ret; + +- if (ignore_ppc) { ++ if (ignore_ppc || !pr->performance) { + /* + * Only when it is notification event, the _OST object + * will be evaluated. Otherwise it is skipped. +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index cf725d581cae..145dcf293c6f 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -1422,6 +1422,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, + device_initialize(&device->dev); + dev_set_uevent_suppress(&device->dev, true); + acpi_init_coherency(device); ++ /* Assume there are unmet deps until acpi_device_dep_initialize() runs */ ++ device->dep_unmet = 1; + } + + void acpi_device_add_finalize(struct acpi_device *device) +@@ -1445,6 +1447,14 @@ static int acpi_add_single_object(struct acpi_device **child, + } + + acpi_init_device_object(device, handle, type, sta); ++ /* ++ * For ACPI_BUS_TYPE_DEVICE getting the status is delayed till here so ++ * that we can call acpi_bus_get_status() and use its quirk handling. ++ * Note this must be done before the get power-/wakeup_dev-flags calls. ++ */ ++ if (type == ACPI_BUS_TYPE_DEVICE) ++ acpi_bus_get_status(device); ++ + acpi_bus_get_power_flags(device); + acpi_bus_get_wakeup_device_flags(device); + +@@ -1517,9 +1527,11 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, + return -ENODEV; + + *type = ACPI_BUS_TYPE_DEVICE; +- status = acpi_bus_get_status_handle(handle, sta); +- if (ACPI_FAILURE(status)) +- *sta = 0; ++ /* ++ * acpi_add_single_object updates this once we've an acpi_device ++ * so that acpi_bus_get_status' quirk handling can be used. ++ */ ++ *sta = 0; + break; + case ACPI_TYPE_PROCESSOR: + *type = ACPI_BUS_TYPE_PROCESSOR; +@@ -1621,6 +1633,8 @@ static void acpi_device_dep_initialize(struct acpi_device *adev) + acpi_status status; + int i; + ++ adev->dep_unmet = 0; ++ + if (!acpi_has_method(adev->handle, "_DEP")) + return; + +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index 4fe3ec122bf0..0e2c0ac5792d 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -4366,6 +4366,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { + /* https://bugzilla.kernel.org/show_bug.cgi?id=15573 */ + { "C300-CTFDDAC128MAG", "0001", ATA_HORKAGE_NONCQ, }, + ++ /* Some Sandisk SSDs lock up hard with NCQ enabled. Reported on ++ SD7SN6S256G and SD8SN8U256G */ ++ { "SanDisk SD[78]SN*G", NULL, ATA_HORKAGE_NONCQ, }, ++ + /* devices which puke on READ_NATIVE_MAX */ + { "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, }, + { "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA }, +@@ -4426,6 +4430,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { + { "SanDisk SD7UB3Q*G1001", NULL, ATA_HORKAGE_NOLPM, }, + + /* devices that don't properly handle queued TRIM commands */ ++ { "Micron_M500IT_*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ++ ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | +diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c +index 9babbc845750..fb2c00fce8f9 100644 +--- a/drivers/ata/libata-scsi.c ++++ b/drivers/ata/libata-scsi.c +@@ -4156,7 +4156,7 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, + #ifdef ATA_DEBUG + struct scsi_device *scsidev = cmd->device; + +- DPRINTK("CDB (%u:%d,%d,%d) %9ph\n", ++ DPRINTK("CDB (%u:%d,%d,%lld) %9ph\n", + ap->print_id, + scsidev->channel, scsidev->id, scsidev->lun, + cmd->cmnd); +diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c +index a7b0fc7cb468..69c84fddfe8a 100644 +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -98,7 +98,7 @@ bool regmap_cached(struct regmap *map, unsigned int reg) + int ret; + unsigned int val; + +- if (map->cache == REGCACHE_NONE) ++ if (map->cache_type == REGCACHE_NONE) + return false; + + if (!map->cache_ops) +diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c +index 93362362aa55..8474a1b0740f 100644 +--- a/drivers/block/paride/pcd.c ++++ b/drivers/block/paride/pcd.c +@@ -230,6 +230,8 @@ static int pcd_block_open(struct block_device *bdev, fmode_t mode) + struct pcd_unit *cd = bdev->bd_disk->private_data; + int ret; + ++ check_disk_change(bdev); ++ + mutex_lock(&pcd_mutex); + ret = cdrom_open(&cd->info, bdev, mode); + mutex_unlock(&pcd_mutex); +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index 128ebd439221..07b77fb102a1 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -1154,9 +1154,6 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, + + cd_dbg(CD_OPEN, "entering cdrom_open\n"); + +- /* open is event synchronization point, check events first */ +- check_disk_change(bdev); +- + /* if this was a O_NONBLOCK open and we should honor the flags, + * do a quick open without drive/disc integrity checks. */ + cdi->use_count++; +diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c +index 584bc3126403..e2808fefbb78 100644 +--- a/drivers/cdrom/gdrom.c ++++ b/drivers/cdrom/gdrom.c +@@ -497,6 +497,9 @@ static struct cdrom_device_ops gdrom_ops = { + static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode) + { + int ret; ++ ++ check_disk_change(bdev); ++ + mutex_lock(&gdrom_mutex); + ret = cdrom_open(gd.cd_info, bdev, mode); + mutex_unlock(&gdrom_mutex); +diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c +index 63d84e6f1891..83c695938a2d 100644 +--- a/drivers/char/hw_random/stm32-rng.c ++++ b/drivers/char/hw_random/stm32-rng.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + #define RNG_CR 0x00 +@@ -46,6 +47,7 @@ struct stm32_rng_private { + struct hwrng rng; + void __iomem *base; + struct clk *clk; ++ struct reset_control *rst; + }; + + static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) +@@ -140,6 +142,13 @@ static int stm32_rng_probe(struct platform_device *ofdev) + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + ++ priv->rst = devm_reset_control_get(&ofdev->dev, NULL); ++ if (!IS_ERR(priv->rst)) { ++ reset_control_assert(priv->rst); ++ udelay(2); ++ reset_control_deassert(priv->rst); ++ } ++ + dev_set_drvdata(dev, priv); + + priv->rng.name = dev_driver_string(dev), +diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c +index 6e658aa114f1..a70518a4fcec 100644 +--- a/drivers/char/ipmi/ipmi_powernv.c ++++ b/drivers/char/ipmi/ipmi_powernv.c +@@ -251,8 +251,9 @@ static int ipmi_powernv_probe(struct platform_device *pdev) + ipmi->irq = opal_event_request(prop); + } + +- if (request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH, +- "opal-ipmi", ipmi)) { ++ rc = request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH, ++ "opal-ipmi", ipmi); ++ if (rc) { + dev_warn(dev, "Unable to request irq\n"); + goto err_dispose; + } +diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c +index f11c1c7e84c6..121319198478 100644 +--- a/drivers/char/ipmi/ipmi_ssif.c ++++ b/drivers/char/ipmi/ipmi_ssif.c +@@ -761,7 +761,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, + ssif_info->ssif_state = SSIF_NORMAL; + ipmi_ssif_unlock_cond(ssif_info, flags); + pr_warn(PFX "Error getting flags: %d %d, %x\n", +- result, len, data[2]); ++ result, len, (len >= 3) ? data[2] : 0); + } else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 + || data[1] != IPMI_GET_MSG_FLAGS_CMD) { + /* +@@ -783,7 +783,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, + if ((result < 0) || (len < 3) || (data[2] != 0)) { + /* Error clearing flags */ + pr_warn(PFX "Error clearing flags: %d %d, %x\n", +- result, len, data[2]); ++ result, len, (len >= 3) ? data[2] : 0); + } else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 + || data[1] != IPMI_CLEAR_MSG_FLAGS_CMD) { + pr_warn(PFX "Invalid response clearing flags: %x %x\n", +diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c +index 738515b89073..a22c1d704901 100644 +--- a/drivers/clocksource/fsl_ftm_timer.c ++++ b/drivers/clocksource/fsl_ftm_timer.c +@@ -281,7 +281,7 @@ static int __init __ftm_clk_init(struct device_node *np, char *cnt_name, + + static unsigned long __init ftm_clk_init(struct device_node *np) + { +- unsigned long freq; ++ long freq; + + freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt"); + if (freq <= 0) +diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c +index 4852d9efe74e..9f09752169ea 100644 +--- a/drivers/cpufreq/cppc_cpufreq.c ++++ b/drivers/cpufreq/cppc_cpufreq.c +@@ -151,9 +151,19 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) + policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num); + policy->shared_type = cpu->shared_type; + +- if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) ++ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { ++ int i; ++ + cpumask_copy(policy->cpus, cpu->shared_cpu_map); +- else if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL) { ++ ++ for_each_cpu(i, policy->cpus) { ++ if (unlikely(i == policy->cpu)) ++ continue; ++ ++ memcpy(&all_cpu_data[i]->perf_caps, &cpu->perf_caps, ++ sizeof(cpu->perf_caps)); ++ } ++ } else if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL) { + /* Support only SW_ANY for now. */ + pr_debug("Unsupported CPU co-ord type\n"); + return -EFAULT; +@@ -218,8 +228,13 @@ static int __init cppc_cpufreq_init(void) + return ret; + + out: +- for_each_possible_cpu(i) +- kfree(all_cpu_data[i]); ++ for_each_possible_cpu(i) { ++ cpu = all_cpu_data[i]; ++ if (!cpu) ++ break; ++ free_cpumask_var(cpu->shared_cpu_map); ++ kfree(cpu); ++ } + + kfree(all_cpu_data); + return -ENODEV; +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index 35e34c0e0429..7523929becdc 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -1288,14 +1288,14 @@ static int cpufreq_online(unsigned int cpu) + return 0; + + out_exit_policy: ++ for_each_cpu(j, policy->real_cpus) ++ remove_cpu_dev_symlink(policy, get_cpu_device(j)); ++ + up_write(&policy->rwsem); + + if (cpufreq_driver->exit) + cpufreq_driver->exit(policy); + +- for_each_cpu(j, policy->real_cpus) +- remove_cpu_dev_symlink(policy, get_cpu_device(j)); +- + out_free_policy: + cpufreq_policy_free(policy, !new_policy); + return ret; +diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c +index f3e211f8f6c5..71866646ffef 100644 +--- a/drivers/dma/mv_xor_v2.c ++++ b/drivers/dma/mv_xor_v2.c +@@ -152,6 +152,7 @@ struct mv_xor_v2_device { + void __iomem *dma_base; + void __iomem *glob_base; + struct clk *clk; ++ struct clk *reg_clk; + struct tasklet_struct irq_tasklet; + struct list_head free_sw_desc; + struct dma_device dmadev; +@@ -697,13 +698,26 @@ static int mv_xor_v2_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ xor_dev->reg_clk = devm_clk_get(&pdev->dev, "reg"); ++ if (PTR_ERR(xor_dev->reg_clk) != -ENOENT) { ++ if (!IS_ERR(xor_dev->reg_clk)) { ++ ret = clk_prepare_enable(xor_dev->reg_clk); ++ if (ret) ++ return ret; ++ } else { ++ return PTR_ERR(xor_dev->reg_clk); ++ } ++ } ++ + xor_dev->clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) +- return -EPROBE_DEFER; ++ if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) { ++ ret = EPROBE_DEFER; ++ goto disable_reg_clk; ++ } + if (!IS_ERR(xor_dev->clk)) { + ret = clk_prepare_enable(xor_dev->clk); + if (ret) +- return ret; ++ goto disable_reg_clk; + } + + ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1, +@@ -812,8 +826,9 @@ static int mv_xor_v2_probe(struct platform_device *pdev) + free_msi_irqs: + platform_msi_domain_free_irqs(&pdev->dev); + disable_clk: +- if (!IS_ERR(xor_dev->clk)) +- clk_disable_unprepare(xor_dev->clk); ++ clk_disable_unprepare(xor_dev->clk); ++disable_reg_clk: ++ clk_disable_unprepare(xor_dev->reg_clk); + return ret; + } + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index fb2e7476d96b..2c449bdacb91 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -1570,7 +1570,7 @@ static void pl330_dotask(unsigned long data) + /* Returns 1 if state was updated, 0 otherwise */ + static int pl330_update(struct pl330_dmac *pl330) + { +- struct dma_pl330_desc *descdone, *tmp; ++ struct dma_pl330_desc *descdone; + unsigned long flags; + void __iomem *regs; + u32 val; +@@ -1648,7 +1648,9 @@ static int pl330_update(struct pl330_dmac *pl330) + } + + /* Now that we are in no hurry, do the callbacks */ +- list_for_each_entry_safe(descdone, tmp, &pl330->req_done, rqd) { ++ while (!list_empty(&pl330->req_done)) { ++ descdone = list_first_entry(&pl330->req_done, ++ struct dma_pl330_desc, rqd); + list_del(&descdone->rqd); + spin_unlock_irqrestore(&pl330->lock, flags); + dma_pl330_rqcb(descdone, PL330_ERR_NONE); +diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c +index 03c4eb3fd314..6497f5283e3b 100644 +--- a/drivers/dma/qcom/bam_dma.c ++++ b/drivers/dma/qcom/bam_dma.c +@@ -387,6 +387,7 @@ struct bam_device { + struct device_dma_parameters dma_parms; + struct bam_chan *channels; + u32 num_channels; ++ u32 num_ees; + + /* execution environment ID, from DT */ + u32 ee; +@@ -1076,15 +1077,19 @@ static int bam_init(struct bam_device *bdev) + u32 val; + + /* read revision and configuration information */ +- val = readl_relaxed(bam_addr(bdev, 0, BAM_REVISION)) >> NUM_EES_SHIFT; +- val &= NUM_EES_MASK; ++ if (!bdev->num_ees) { ++ val = readl_relaxed(bam_addr(bdev, 0, BAM_REVISION)); ++ bdev->num_ees = (val >> NUM_EES_SHIFT) & NUM_EES_MASK; ++ } + + /* check that configured EE is within range */ +- if (bdev->ee >= val) ++ if (bdev->ee >= bdev->num_ees) + return -EINVAL; + +- val = readl_relaxed(bam_addr(bdev, 0, BAM_NUM_PIPES)); +- bdev->num_channels = val & BAM_NUM_PIPES_MASK; ++ if (!bdev->num_channels) { ++ val = readl_relaxed(bam_addr(bdev, 0, BAM_NUM_PIPES)); ++ bdev->num_channels = val & BAM_NUM_PIPES_MASK; ++ } + + if (bdev->controlled_remotely) + return 0; +@@ -1179,6 +1184,18 @@ static int bam_dma_probe(struct platform_device *pdev) + bdev->controlled_remotely = of_property_read_bool(pdev->dev.of_node, + "qcom,controlled-remotely"); + ++ if (bdev->controlled_remotely) { ++ ret = of_property_read_u32(pdev->dev.of_node, "num-channels", ++ &bdev->num_channels); ++ if (ret) ++ dev_err(bdev->dev, "num-channels unspecified in dt\n"); ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "qcom,num-ees", ++ &bdev->num_ees); ++ if (ret) ++ dev_err(bdev->dev, "num-ees unspecified in dt\n"); ++ } ++ + bdev->bamclk = devm_clk_get(bdev->dev, "bam_clk"); + if (IS_ERR(bdev->bamclk)) + return PTR_ERR(bdev->bamclk); +diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c +index 4c357d475465..d032032337e7 100644 +--- a/drivers/dma/sh/rcar-dmac.c ++++ b/drivers/dma/sh/rcar-dmac.c +@@ -870,7 +870,7 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, + + rcar_dmac_chan_configure_desc(chan, desc); + +- max_chunk_size = (RCAR_DMATCR_MASK + 1) << desc->xfer_shift; ++ max_chunk_size = RCAR_DMATCR_MASK << desc->xfer_shift; + + /* + * Allocate and fill the transfer chunk descriptors. We own the only +@@ -1246,8 +1246,17 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan, + * If the cookie doesn't correspond to the currently running transfer + * then the descriptor hasn't been processed yet, and the residue is + * equal to the full descriptor size. ++ * Also, a client driver is possible to call this function before ++ * rcar_dmac_isr_channel_thread() runs. In this case, the "desc.running" ++ * will be the next descriptor, and the done list will appear. So, if ++ * the argument cookie matches the done list's cookie, we can assume ++ * the residue is zero. + */ + if (cookie != desc->async_tx.cookie) { ++ list_for_each_entry(desc, &chan->desc.done, node) { ++ if (cookie == desc->async_tx.cookie) ++ return 0; ++ } + list_for_each_entry(desc, &chan->desc.pending, node) { + if (cookie == desc->async_tx.cookie) + return desc->size; +diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c +index 8bf89267dc25..d731b413cb2c 100644 +--- a/drivers/firewire/ohci.c ++++ b/drivers/firewire/ohci.c +@@ -1130,7 +1130,13 @@ static int context_add_buffer(struct context *ctx) + return -ENOMEM; + + offset = (void *)&desc->buffer - (void *)desc; +- desc->buffer_size = PAGE_SIZE - offset; ++ /* ++ * Some controllers, like JMicron ones, always issue 0x20-byte DMA reads ++ * for descriptors, even 0x10-byte ones. This can cause page faults when ++ * an IOMMU is in use and the oversized read crosses a page boundary. ++ * Work around this by always leaving at least 0x10 bytes of padding. ++ */ ++ desc->buffer_size = PAGE_SIZE - offset - 0x10; + desc->buffer_bus = bus_addr + offset; + desc->used = 0; + +diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c +index 88bebe1968b7..42844c318445 100644 +--- a/drivers/firmware/dmi_scan.c ++++ b/drivers/firmware/dmi_scan.c +@@ -18,7 +18,7 @@ EXPORT_SYMBOL_GPL(dmi_kobj); + * of and an antecedent to, SMBIOS, which stands for System + * Management BIOS. See further: http://www.dmtf.org/standards + */ +-static const char dmi_empty_string[] = " "; ++static const char dmi_empty_string[] = ""; + + static u32 dmi_ver __initdata; + static u32 dmi_len; +@@ -44,25 +44,21 @@ static int dmi_memdev_nr; + static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) + { + const u8 *bp = ((u8 *) dm) + dm->length; ++ const u8 *nsp; + + if (s) { +- s--; +- while (s > 0 && *bp) { ++ while (--s > 0 && *bp) + bp += strlen(bp) + 1; +- s--; +- } +- +- if (*bp != 0) { +- size_t len = strlen(bp)+1; +- size_t cmp_len = len > 8 ? 8 : len; + +- if (!memcmp(bp, dmi_empty_string, cmp_len)) +- return dmi_empty_string; ++ /* Strings containing only spaces are considered empty */ ++ nsp = bp; ++ while (*nsp == ' ') ++ nsp++; ++ if (*nsp != '\0') + return bp; +- } + } + +- return ""; ++ return dmi_empty_string; + } + + static const char * __init dmi_string(const struct dmi_header *dm, u8 s) +diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c +index 603d8425cca6..699db138c5de 100644 +--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c +@@ -926,7 +926,7 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) + struct drm_device *drm_dev = g2d->subdrv.drm_dev; + struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node; + struct drm_exynos_pending_g2d_event *e; +- struct timeval now; ++ struct timespec64 now; + + if (list_empty(&runqueue_node->event_list)) + return; +@@ -934,9 +934,9 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) + e = list_first_entry(&runqueue_node->event_list, + struct drm_exynos_pending_g2d_event, base.link); + +- do_gettimeofday(&now); ++ ktime_get_ts64(&now); + e->event.tv_sec = now.tv_sec; +- e->event.tv_usec = now.tv_usec; ++ e->event.tv_usec = now.tv_nsec / NSEC_PER_USEC; + e->event.cmdlist_no = cmdlist_no; + + drm_send_event(drm_dev, &e->base); +diff --git a/drivers/gpu/drm/exynos/regs-fimc.h b/drivers/gpu/drm/exynos/regs-fimc.h +index 30496134a3d0..d7cbe53c4c01 100644 +--- a/drivers/gpu/drm/exynos/regs-fimc.h ++++ b/drivers/gpu/drm/exynos/regs-fimc.h +@@ -569,7 +569,7 @@ + #define EXYNOS_CIIMGEFF_FIN_EMBOSSING (4 << 26) + #define EXYNOS_CIIMGEFF_FIN_SILHOUETTE (5 << 26) + #define EXYNOS_CIIMGEFF_FIN_MASK (7 << 26) +-#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0)) ++#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | (0xff << 0)) + + /* Real input DMA size register */ + #define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE (1 << 31) +diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c +index 6be515a9fb69..8dbba61a2708 100644 +--- a/drivers/gpu/drm/imx/ipuv3-crtc.c ++++ b/drivers/gpu/drm/imx/ipuv3-crtc.c +@@ -189,7 +189,11 @@ static void ipu_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) + { + drm_crtc_vblank_on(crtc); ++} + ++static void ipu_crtc_atomic_flush(struct drm_crtc *crtc, ++ struct drm_crtc_state *old_crtc_state) ++{ + spin_lock_irq(&crtc->dev->event_lock); + if (crtc->state->event) { + WARN_ON(drm_crtc_vblank_get(crtc)); +@@ -257,6 +261,7 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = { + .mode_set_nofb = ipu_crtc_mode_set_nofb, + .atomic_check = ipu_crtc_atomic_check, + .atomic_begin = ipu_crtc_atomic_begin, ++ .atomic_flush = ipu_crtc_atomic_flush, + .atomic_disable = ipu_crtc_atomic_disable, + .enable = ipu_crtc_enable, + }; +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h +index e2faccffee6f..d66e0e76faf4 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h +@@ -46,8 +46,8 @@ uint32_t gf100_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x584d454d, +- 0x00000756, +- 0x00000748, ++ 0x00000754, ++ 0x00000746, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -68,8 +68,8 @@ uint32_t gf100_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x46524550, +- 0x0000075a, + 0x00000758, ++ 0x00000756, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -90,8 +90,8 @@ uint32_t gf100_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x5f433249, +- 0x00000b8a, +- 0x00000a2d, ++ 0x00000b88, ++ 0x00000a2b, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -112,8 +112,8 @@ uint32_t gf100_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x54534554, +- 0x00000bb3, +- 0x00000b8c, ++ 0x00000bb1, ++ 0x00000b8a, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -134,8 +134,8 @@ uint32_t gf100_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x454c4449, +- 0x00000bbf, + 0x00000bbd, ++ 0x00000bbb, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -236,19 +236,19 @@ uint32_t gf100_pmu_data[] = { + 0x000005d3, + 0x00000003, + 0x00000002, +- 0x0000069d, ++ 0x0000069b, + 0x00040004, + 0x00000000, +- 0x000006b9, ++ 0x000006b7, + 0x00010005, + 0x00000000, +- 0x000006d6, ++ 0x000006d4, + 0x00010006, + 0x00000000, + 0x0000065b, + 0x00000007, + 0x00000000, +- 0x000006e1, ++ 0x000006df, + /* 0x03c4: memx_func_tail */ + /* 0x03c4: memx_ts_start */ + 0x00000000, +@@ -1372,432 +1372,432 @@ uint32_t gf100_pmu_code[] = { + /* 0x065b: memx_func_wait_vblank */ + 0x9800f840, + 0x66b00016, +- 0x130bf400, ++ 0x120bf400, + 0xf40166b0, + 0x0ef4060b, + /* 0x066d: memx_func_wait_vblank_head1 */ +- 0x2077f12e, +- 0x070ef400, +-/* 0x0674: memx_func_wait_vblank_head0 */ +- 0x000877f1, +-/* 0x0678: memx_func_wait_vblank_0 */ +- 0x07c467f1, +- 0xcf0664b6, +- 0x67fd0066, +- 0xf31bf404, +-/* 0x0688: memx_func_wait_vblank_1 */ +- 0x07c467f1, +- 0xcf0664b6, +- 0x67fd0066, +- 0xf30bf404, +-/* 0x0698: memx_func_wait_vblank_fini */ +- 0xf80410b6, +-/* 0x069d: memx_func_wr32 */ +- 0x00169800, +- 0xb6011598, +- 0x60f90810, +- 0xd0fc50f9, +- 0x21f4e0fc, +- 0x0242b640, +- 0xf8e91bf4, +-/* 0x06b9: memx_func_wait */ +- 0x2c87f000, +- 0xcf0684b6, +- 0x1e980088, +- 0x011d9800, +- 0x98021c98, +- 0x10b6031b, +- 0xa321f410, +-/* 0x06d6: memx_func_delay */ +- 0x1e9800f8, +- 0x0410b600, +- 0xf87e21f4, +-/* 0x06e1: memx_func_train */ +-/* 0x06e3: memx_exec */ +- 0xf900f800, +- 0xb9d0f9e0, +- 0xb2b902c1, +-/* 0x06ed: memx_exec_next */ +- 0x00139802, +- 0xe70410b6, +- 0xe701f034, +- 0xb601e033, +- 0x30f00132, +- 0xde35980c, +- 0x12b855f9, +- 0xe41ef406, +- 0x98f10b98, +- 0xcbbbf20c, +- 0xc4b7f102, +- 0x06b4b607, +- 0xfc00bbcf, +- 0xf5e0fcd0, +- 0xf8033621, +-/* 0x0729: memx_info */ +- 0x01c67000, +-/* 0x072f: memx_info_data */ +- 0xf10e0bf4, +- 0xf103ccc7, +- 0xf40800b7, +-/* 0x073a: memx_info_train */ +- 0xc7f10b0e, +- 0xb7f10bcc, +-/* 0x0742: memx_info_send */ +- 0x21f50100, +- 0x00f80336, +-/* 0x0748: memx_recv */ +- 0xf401d6b0, +- 0xd6b0980b, +- 0xd80bf400, +-/* 0x0756: memx_init */ +- 0x00f800f8, +-/* 0x0758: perf_recv */ +-/* 0x075a: perf_init */ ++ 0x2077f02c, ++/* 0x0673: memx_func_wait_vblank_head0 */ ++ 0xf0060ef4, ++/* 0x0676: memx_func_wait_vblank_0 */ ++ 0x67f10877, ++ 0x64b607c4, ++ 0x0066cf06, ++ 0xf40467fd, ++/* 0x0686: memx_func_wait_vblank_1 */ ++ 0x67f1f31b, ++ 0x64b607c4, ++ 0x0066cf06, ++ 0xf40467fd, ++/* 0x0696: memx_func_wait_vblank_fini */ ++ 0x10b6f30b, ++/* 0x069b: memx_func_wr32 */ ++ 0x9800f804, ++ 0x15980016, ++ 0x0810b601, ++ 0x50f960f9, ++ 0xe0fcd0fc, ++ 0xb64021f4, ++ 0x1bf40242, ++/* 0x06b7: memx_func_wait */ ++ 0xf000f8e9, ++ 0x84b62c87, ++ 0x0088cf06, ++ 0x98001e98, ++ 0x1c98011d, ++ 0x031b9802, ++ 0xf41010b6, ++ 0x00f8a321, ++/* 0x06d4: memx_func_delay */ ++ 0xb6001e98, ++ 0x21f40410, ++/* 0x06df: memx_func_train */ ++ 0xf800f87e, ++/* 0x06e1: memx_exec */ ++ 0xf9e0f900, ++ 0x02c1b9d0, ++/* 0x06eb: memx_exec_next */ ++ 0x9802b2b9, ++ 0x10b60013, ++ 0xf034e704, ++ 0xe033e701, ++ 0x0132b601, ++ 0x980c30f0, ++ 0x55f9de35, ++ 0xf40612b8, ++ 0x0b98e41e, ++ 0xf20c98f1, ++ 0xf102cbbb, ++ 0xb607c4b7, ++ 0xbbcf06b4, ++ 0xfcd0fc00, ++ 0x3621f5e0, ++/* 0x0727: memx_info */ ++ 0x7000f803, ++ 0x0bf401c6, ++/* 0x072d: memx_info_data */ ++ 0xccc7f10e, ++ 0x00b7f103, ++ 0x0b0ef408, ++/* 0x0738: memx_info_train */ ++ 0x0bccc7f1, ++ 0x0100b7f1, ++/* 0x0740: memx_info_send */ ++ 0x033621f5, ++/* 0x0746: memx_recv */ ++ 0xd6b000f8, ++ 0x980bf401, ++ 0xf400d6b0, ++ 0x00f8d80b, ++/* 0x0754: memx_init */ ++/* 0x0756: perf_recv */ + 0x00f800f8, +-/* 0x075c: i2c_drive_scl */ +- 0xf40036b0, +- 0x07f1110b, +- 0x04b607e0, +- 0x0001d006, +- 0x00f804bd, +-/* 0x0770: i2c_drive_scl_lo */ +- 0x07e407f1, +- 0xd00604b6, +- 0x04bd0001, +-/* 0x077e: i2c_drive_sda */ ++/* 0x0758: perf_init */ ++/* 0x075a: i2c_drive_scl */ + 0x36b000f8, + 0x110bf400, + 0x07e007f1, + 0xd00604b6, +- 0x04bd0002, +-/* 0x0792: i2c_drive_sda_lo */ ++ 0x04bd0001, ++/* 0x076e: i2c_drive_scl_lo */ + 0x07f100f8, + 0x04b607e4, ++ 0x0001d006, ++ 0x00f804bd, ++/* 0x077c: i2c_drive_sda */ ++ 0xf40036b0, ++ 0x07f1110b, ++ 0x04b607e0, + 0x0002d006, + 0x00f804bd, +-/* 0x07a0: i2c_sense_scl */ +- 0xf10132f4, +- 0xb607c437, +- 0x33cf0634, +- 0x0431fd00, +- 0xf4060bf4, +-/* 0x07b6: i2c_sense_scl_done */ +- 0x00f80131, +-/* 0x07b8: i2c_sense_sda */ +- 0xf10132f4, +- 0xb607c437, +- 0x33cf0634, +- 0x0432fd00, +- 0xf4060bf4, +-/* 0x07ce: i2c_sense_sda_done */ +- 0x00f80131, +-/* 0x07d0: i2c_raise_scl */ +- 0x47f140f9, +- 0x37f00898, +- 0x5c21f501, +-/* 0x07dd: i2c_raise_scl_wait */ +- 0xe8e7f107, +- 0x7e21f403, +- 0x07a021f5, +- 0xb60901f4, +- 0x1bf40142, +-/* 0x07f1: i2c_raise_scl_done */ +- 0xf840fcef, +-/* 0x07f5: i2c_start */ +- 0xa021f500, +- 0x0d11f407, +- 0x07b821f5, +- 0xf40611f4, +-/* 0x0806: i2c_start_rep */ +- 0x37f0300e, +- 0x5c21f500, +- 0x0137f007, +- 0x077e21f5, +- 0xb60076bb, +- 0x50f90465, +- 0xbb046594, +- 0x50bd0256, +- 0xfc0475fd, +- 0xd021f550, +- 0x0464b607, +-/* 0x0833: i2c_start_send */ +- 0xf01f11f4, ++/* 0x0790: i2c_drive_sda_lo */ ++ 0x07e407f1, ++ 0xd00604b6, ++ 0x04bd0002, ++/* 0x079e: i2c_sense_scl */ ++ 0x32f400f8, ++ 0xc437f101, ++ 0x0634b607, ++ 0xfd0033cf, ++ 0x0bf40431, ++ 0x0131f406, ++/* 0x07b4: i2c_sense_scl_done */ ++/* 0x07b6: i2c_sense_sda */ ++ 0x32f400f8, ++ 0xc437f101, ++ 0x0634b607, ++ 0xfd0033cf, ++ 0x0bf40432, ++ 0x0131f406, ++/* 0x07cc: i2c_sense_sda_done */ ++/* 0x07ce: i2c_raise_scl */ ++ 0x40f900f8, ++ 0x089847f1, ++ 0xf50137f0, ++/* 0x07db: i2c_raise_scl_wait */ ++ 0xf1075a21, ++ 0xf403e8e7, ++ 0x21f57e21, ++ 0x01f4079e, ++ 0x0142b609, ++/* 0x07ef: i2c_raise_scl_done */ ++ 0xfcef1bf4, ++/* 0x07f3: i2c_start */ ++ 0xf500f840, ++ 0xf4079e21, ++ 0x21f50d11, ++ 0x11f407b6, ++ 0x300ef406, ++/* 0x0804: i2c_start_rep */ ++ 0xf50037f0, ++ 0xf0075a21, ++ 0x21f50137, ++ 0x76bb077c, ++ 0x0465b600, ++ 0x659450f9, ++ 0x0256bb04, ++ 0x75fd50bd, ++ 0xf550fc04, ++ 0xb607ce21, ++ 0x11f40464, ++/* 0x0831: i2c_start_send */ ++ 0x0037f01f, ++ 0x077c21f5, ++ 0x1388e7f1, ++ 0xf07e21f4, + 0x21f50037, +- 0xe7f1077e, ++ 0xe7f1075a, + 0x21f41388, +- 0x0037f07e, +- 0x075c21f5, +- 0x1388e7f1, +-/* 0x084f: i2c_start_out */ +- 0xf87e21f4, +-/* 0x0851: i2c_stop */ +- 0x0037f000, +- 0x075c21f5, +- 0xf50037f0, +- 0xf1077e21, +- 0xf403e8e7, +- 0x37f07e21, +- 0x5c21f501, +- 0x88e7f107, +- 0x7e21f413, ++/* 0x084d: i2c_start_out */ ++/* 0x084f: i2c_stop */ ++ 0xf000f87e, ++ 0x21f50037, ++ 0x37f0075a, ++ 0x7c21f500, ++ 0xe8e7f107, ++ 0x7e21f403, + 0xf50137f0, +- 0xf1077e21, ++ 0xf1075a21, + 0xf41388e7, +- 0x00f87e21, +-/* 0x0884: i2c_bitw */ +- 0x077e21f5, +- 0x03e8e7f1, +- 0xbb7e21f4, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x07d021f5, +- 0xf40464b6, +- 0xe7f11811, +- 0x21f41388, +- 0x0037f07e, +- 0x075c21f5, +- 0x1388e7f1, +-/* 0x08c3: i2c_bitw_out */ +- 0xf87e21f4, +-/* 0x08c5: i2c_bitr */ +- 0x0137f000, +- 0x077e21f5, +- 0x03e8e7f1, +- 0xbb7e21f4, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x07d021f5, +- 0xf40464b6, +- 0x21f51b11, +- 0x37f007b8, +- 0x5c21f500, ++ 0x37f07e21, ++ 0x7c21f501, + 0x88e7f107, + 0x7e21f413, +- 0xf4013cf0, +-/* 0x090a: i2c_bitr_done */ +- 0x00f80131, +-/* 0x090c: i2c_get_byte */ +- 0xf00057f0, +-/* 0x0912: i2c_get_byte_next */ +- 0x54b60847, +- 0x0076bb01, ++/* 0x0882: i2c_bitw */ ++ 0x21f500f8, ++ 0xe7f1077c, ++ 0x21f403e8, ++ 0x0076bb7e, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, +- 0x64b608c5, +- 0x2b11f404, +- 0xb60553fd, +- 0x1bf40142, +- 0x0137f0d8, +- 0xb60076bb, +- 0x50f90465, +- 0xbb046594, +- 0x50bd0256, +- 0xfc0475fd, +- 0x8421f550, +- 0x0464b608, +-/* 0x095c: i2c_get_byte_done */ +-/* 0x095e: i2c_put_byte */ +- 0x47f000f8, +-/* 0x0961: i2c_put_byte_next */ +- 0x0142b608, +- 0xbb3854ff, ++ 0x64b607ce, ++ 0x1811f404, ++ 0x1388e7f1, ++ 0xf07e21f4, ++ 0x21f50037, ++ 0xe7f1075a, ++ 0x21f41388, ++/* 0x08c1: i2c_bitw_out */ ++/* 0x08c3: i2c_bitr */ ++ 0xf000f87e, ++ 0x21f50137, ++ 0xe7f1077c, ++ 0x21f403e8, ++ 0x0076bb7e, ++ 0xf90465b6, ++ 0x04659450, ++ 0xbd0256bb, ++ 0x0475fd50, ++ 0x21f550fc, ++ 0x64b607ce, ++ 0x1b11f404, ++ 0x07b621f5, ++ 0xf50037f0, ++ 0xf1075a21, ++ 0xf41388e7, ++ 0x3cf07e21, ++ 0x0131f401, ++/* 0x0908: i2c_bitr_done */ ++/* 0x090a: i2c_get_byte */ ++ 0x57f000f8, ++ 0x0847f000, ++/* 0x0910: i2c_get_byte_next */ ++ 0xbb0154b6, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, +- 0x088421f5, ++ 0x08c321f5, + 0xf40464b6, +- 0x46b03411, +- 0xd81bf400, +- 0xb60076bb, +- 0x50f90465, +- 0xbb046594, +- 0x50bd0256, +- 0xfc0475fd, +- 0xc521f550, +- 0x0464b608, +- 0xbb0f11f4, +- 0x36b00076, +- 0x061bf401, +-/* 0x09b7: i2c_put_byte_done */ +- 0xf80132f4, +-/* 0x09b9: i2c_addr */ +- 0x0076bb00, ++ 0x53fd2b11, ++ 0x0142b605, ++ 0xf0d81bf4, ++ 0x76bb0137, ++ 0x0465b600, ++ 0x659450f9, ++ 0x0256bb04, ++ 0x75fd50bd, ++ 0xf550fc04, ++ 0xb6088221, ++/* 0x095a: i2c_get_byte_done */ ++ 0x00f80464, ++/* 0x095c: i2c_put_byte */ ++/* 0x095f: i2c_put_byte_next */ ++ 0xb60847f0, ++ 0x54ff0142, ++ 0x0076bb38, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, +- 0x64b607f5, +- 0x2911f404, +- 0x012ec3e7, +- 0xfd0134b6, +- 0x76bb0553, ++ 0x64b60882, ++ 0x3411f404, ++ 0xf40046b0, ++ 0x76bbd81b, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, +- 0xb6095e21, +-/* 0x09fe: i2c_addr_done */ +- 0x00f80464, +-/* 0x0a00: i2c_acquire_addr */ +- 0xb6f8cec7, +- 0xe0b702e4, +- 0xee980d1c, +-/* 0x0a0f: i2c_acquire */ +- 0xf500f800, +- 0xf40a0021, +- 0xd9f00421, +- 0x4021f403, +-/* 0x0a1e: i2c_release */ +- 0x21f500f8, +- 0x21f40a00, +- 0x03daf004, +- 0xf84021f4, +-/* 0x0a2d: i2c_recv */ +- 0x0132f400, +- 0xb6f8c1c7, +- 0x16b00214, +- 0x3a1ff528, +- 0xf413a001, +- 0x0032980c, +- 0x0ccc13a0, +- 0xf4003198, +- 0xd0f90231, +- 0xd0f9e0f9, +- 0x000067f1, +- 0x100063f1, +- 0xbb016792, ++ 0xb608c321, ++ 0x11f40464, ++ 0x0076bb0f, ++ 0xf40136b0, ++ 0x32f4061b, ++/* 0x09b5: i2c_put_byte_done */ ++/* 0x09b7: i2c_addr */ ++ 0xbb00f801, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, +- 0x0a0f21f5, +- 0xfc0464b6, +- 0x00d6b0d0, +- 0x00b31bf5, +- 0xbb0057f0, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x09b921f5, +- 0xf50464b6, +- 0xc700d011, +- 0x76bbe0c5, +- 0x0465b600, +- 0x659450f9, +- 0x0256bb04, +- 0x75fd50bd, +- 0xf550fc04, +- 0xb6095e21, +- 0x11f50464, +- 0x57f000ad, ++ 0x07f321f5, ++ 0xf40464b6, ++ 0xc3e72911, ++ 0x34b6012e, ++ 0x0553fd01, ++ 0xb60076bb, ++ 0x50f90465, ++ 0xbb046594, ++ 0x50bd0256, ++ 0xfc0475fd, ++ 0x5c21f550, ++ 0x0464b609, ++/* 0x09fc: i2c_addr_done */ ++/* 0x09fe: i2c_acquire_addr */ ++ 0xcec700f8, ++ 0x02e4b6f8, ++ 0x0d1ce0b7, ++ 0xf800ee98, ++/* 0x0a0d: i2c_acquire */ ++ 0xfe21f500, ++ 0x0421f409, ++ 0xf403d9f0, ++ 0x00f84021, ++/* 0x0a1c: i2c_release */ ++ 0x09fe21f5, ++ 0xf00421f4, ++ 0x21f403da, ++/* 0x0a2b: i2c_recv */ ++ 0xf400f840, ++ 0xc1c70132, ++ 0x0214b6f8, ++ 0xf52816b0, ++ 0xa0013a1f, ++ 0x980cf413, ++ 0x13a00032, ++ 0x31980ccc, ++ 0x0231f400, ++ 0xe0f9d0f9, ++ 0x67f1d0f9, ++ 0x63f10000, ++ 0x67921000, + 0x0076bb01, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, +- 0x64b609b9, +- 0x8a11f504, ++ 0x64b60a0d, ++ 0xb0d0fc04, ++ 0x1bf500d6, ++ 0x57f000b3, + 0x0076bb00, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, +- 0x64b6090c, +- 0x6a11f404, +- 0xbbe05bcb, ++ 0x64b609b7, ++ 0xd011f504, ++ 0xe0c5c700, ++ 0xb60076bb, ++ 0x50f90465, ++ 0xbb046594, ++ 0x50bd0256, ++ 0xfc0475fd, ++ 0x5c21f550, ++ 0x0464b609, ++ 0x00ad11f5, ++ 0xbb0157f0, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, +- 0x085121f5, +- 0xb90464b6, +- 0x74bd025b, +-/* 0x0b33: i2c_recv_not_rd08 */ +- 0xb0430ef4, +- 0x1bf401d6, +- 0x0057f03d, +- 0x09b921f5, +- 0xc73311f4, +- 0x21f5e0c5, +- 0x11f4095e, +- 0x0057f029, +- 0x09b921f5, +- 0xc71f11f4, +- 0x21f5e0b5, +- 0x11f4095e, +- 0x5121f515, +- 0xc774bd08, +- 0x1bf408c5, +- 0x0232f409, +-/* 0x0b73: i2c_recv_not_wr08 */ +-/* 0x0b73: i2c_recv_done */ +- 0xc7030ef4, +- 0x21f5f8ce, +- 0xe0fc0a1e, +- 0x12f4d0fc, +- 0x027cb90a, +- 0x033621f5, +-/* 0x0b88: i2c_recv_exit */ +-/* 0x0b8a: i2c_init */ +- 0x00f800f8, +-/* 0x0b8c: test_recv */ +- 0x05d817f1, ++ 0x09b721f5, ++ 0xf50464b6, ++ 0xbb008a11, ++ 0x65b60076, ++ 0x9450f904, ++ 0x56bb0465, ++ 0xfd50bd02, ++ 0x50fc0475, ++ 0x090a21f5, ++ 0xf40464b6, ++ 0x5bcb6a11, ++ 0x0076bbe0, ++ 0xf90465b6, ++ 0x04659450, ++ 0xbd0256bb, ++ 0x0475fd50, ++ 0x21f550fc, ++ 0x64b6084f, ++ 0x025bb904, ++ 0x0ef474bd, ++/* 0x0b31: i2c_recv_not_rd08 */ ++ 0x01d6b043, ++ 0xf03d1bf4, ++ 0x21f50057, ++ 0x11f409b7, ++ 0xe0c5c733, ++ 0x095c21f5, ++ 0xf02911f4, ++ 0x21f50057, ++ 0x11f409b7, ++ 0xe0b5c71f, ++ 0x095c21f5, ++ 0xf51511f4, ++ 0xbd084f21, ++ 0x08c5c774, ++ 0xf4091bf4, ++ 0x0ef40232, ++/* 0x0b71: i2c_recv_not_wr08 */ ++/* 0x0b71: i2c_recv_done */ ++ 0xf8cec703, ++ 0x0a1c21f5, ++ 0xd0fce0fc, ++ 0xb90a12f4, ++ 0x21f5027c, ++/* 0x0b86: i2c_recv_exit */ ++ 0x00f80336, ++/* 0x0b88: i2c_init */ ++/* 0x0b8a: test_recv */ ++ 0x17f100f8, ++ 0x14b605d8, ++ 0x0011cf06, ++ 0xf10110b6, ++ 0xb605d807, ++ 0x01d00604, ++ 0xf104bd00, ++ 0xf1d900e7, ++ 0xf5134fe3, ++ 0xf8025621, ++/* 0x0bb1: test_init */ ++ 0x00e7f100, ++ 0x5621f508, ++/* 0x0bbb: idle_recv */ ++ 0xf800f802, ++/* 0x0bbd: idle */ ++ 0x0031f400, ++ 0x05d417f1, + 0xcf0614b6, + 0x10b60011, +- 0xd807f101, ++ 0xd407f101, + 0x0604b605, + 0xbd0001d0, +- 0x00e7f104, +- 0x4fe3f1d9, +- 0x5621f513, +-/* 0x0bb3: test_init */ +- 0xf100f802, +- 0xf50800e7, +- 0xf8025621, +-/* 0x0bbd: idle_recv */ +-/* 0x0bbf: idle */ +- 0xf400f800, +- 0x17f10031, +- 0x14b605d4, +- 0x0011cf06, +- 0xf10110b6, +- 0xb605d407, +- 0x01d00604, +-/* 0x0bdb: idle_loop */ +- 0xf004bd00, +- 0x32f45817, +-/* 0x0be1: idle_proc */ +-/* 0x0be1: idle_proc_exec */ +- 0xb910f902, +- 0x21f5021e, +- 0x10fc033f, +- 0xf40911f4, +- 0x0ef40231, +-/* 0x0bf5: idle_proc_next */ +- 0x5810b6ef, +- 0xf4061fb8, +- 0x02f4e61b, +- 0x0028f4dd, +- 0x00bb0ef4, ++/* 0x0bd9: idle_loop */ ++ 0x5817f004, ++/* 0x0bdf: idle_proc */ ++/* 0x0bdf: idle_proc_exec */ ++ 0xf90232f4, ++ 0x021eb910, ++ 0x033f21f5, ++ 0x11f410fc, ++ 0x0231f409, ++/* 0x0bf3: idle_proc_next */ ++ 0xb6ef0ef4, ++ 0x1fb85810, ++ 0xe61bf406, ++ 0xf4dd02f4, ++ 0x0ef40028, ++ 0x000000bb, + 0x00000000, + 0x00000000, + 0x00000000, +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h +index 3c731ff12871..958222415a34 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h +@@ -46,8 +46,8 @@ uint32_t gk208_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x584d454d, +- 0x000005f3, +- 0x000005e5, ++ 0x000005ee, ++ 0x000005e0, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -68,8 +68,8 @@ uint32_t gk208_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x46524550, +- 0x000005f7, +- 0x000005f5, ++ 0x000005f2, ++ 0x000005f0, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -90,8 +90,8 @@ uint32_t gk208_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x5f433249, +- 0x000009f8, +- 0x000008a2, ++ 0x000009f3, ++ 0x0000089d, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -112,8 +112,8 @@ uint32_t gk208_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x54534554, +- 0x00000a16, +- 0x000009fa, ++ 0x00000a11, ++ 0x000009f5, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -134,8 +134,8 @@ uint32_t gk208_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x454c4449, +- 0x00000a21, +- 0x00000a1f, ++ 0x00000a1c, ++ 0x00000a1a, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -233,22 +233,22 @@ uint32_t gk208_pmu_data[] = { + /* 0x037c: memx_func_next */ + 0x00000002, + 0x00000000, +- 0x000004cf, ++ 0x000004cc, + 0x00000003, + 0x00000002, +- 0x00000546, ++ 0x00000541, + 0x00040004, + 0x00000000, +- 0x00000563, ++ 0x0000055e, + 0x00010005, + 0x00000000, +- 0x0000057d, ++ 0x00000578, + 0x00010006, + 0x00000000, +- 0x00000541, ++ 0x0000053c, + 0x00000007, + 0x00000000, +- 0x00000589, ++ 0x00000584, + /* 0x03c4: memx_func_tail */ + /* 0x03c4: memx_ts_start */ + 0x00000000, +@@ -1238,454 +1238,454 @@ uint32_t gk208_pmu_code[] = { + 0x0001f604, + 0x00f804bd, + /* 0x045c: memx_func_enter */ +- 0x162067f1, +- 0xf55d77f1, +- 0x047e6eb2, +- 0xd8b20000, +- 0xf90487fd, +- 0xfc80f960, +- 0x7ee0fcd0, +- 0x0700002d, +- 0x7e6eb2fe, ++ 0x47162046, ++ 0x6eb2f55d, ++ 0x0000047e, ++ 0x87fdd8b2, ++ 0xf960f904, ++ 0xfcd0fc80, ++ 0x002d7ee0, ++ 0xb2fe0700, ++ 0x00047e6e, ++ 0xfdd8b200, ++ 0x60f90487, ++ 0xd0fc80f9, ++ 0x2d7ee0fc, ++ 0xf0460000, ++ 0x7e6eb226, + 0xb2000004, + 0x0487fdd8, + 0x80f960f9, + 0xe0fcd0fc, + 0x00002d7e, +- 0x26f067f1, +- 0x047e6eb2, +- 0xd8b20000, +- 0xf90487fd, +- 0xfc80f960, +- 0x7ee0fcd0, +- 0x0600002d, +- 0x07e04004, +- 0xbd0006f6, +-/* 0x04b9: memx_func_enter_wait */ +- 0x07c04604, +- 0xf00066cf, +- 0x0bf40464, +- 0xcf2c06f7, +- 0x06b50066, +-/* 0x04cf: memx_func_leave */ +- 0x0600f8f1, +- 0x0066cf2c, +- 0x06f206b5, +- 0x07e44004, +- 0xbd0006f6, +-/* 0x04e1: memx_func_leave_wait */ +- 0x07c04604, +- 0xf00066cf, +- 0x1bf40464, +- 0xf067f1f7, ++ 0xe0400406, ++ 0x0006f607, ++/* 0x04b6: memx_func_enter_wait */ ++ 0xc04604bd, ++ 0x0066cf07, ++ 0xf40464f0, ++ 0x2c06f70b, ++ 0xb50066cf, ++ 0x00f8f106, ++/* 0x04cc: memx_func_leave */ ++ 0x66cf2c06, ++ 0xf206b500, ++ 0xe4400406, ++ 0x0006f607, ++/* 0x04de: memx_func_leave_wait */ ++ 0xc04604bd, ++ 0x0066cf07, ++ 0xf40464f0, ++ 0xf046f71b, + 0xb2010726, + 0x00047e6e, + 0xfdd8b200, + 0x60f90587, + 0xd0fc80f9, + 0x2d7ee0fc, +- 0x67f10000, +- 0x6eb21620, +- 0x0000047e, +- 0x87fdd8b2, +- 0xf960f905, +- 0xfcd0fc80, +- 0x002d7ee0, +- 0x0aa24700, +- 0x047e6eb2, +- 0xd8b20000, +- 0xf90587fd, +- 0xfc80f960, +- 0x7ee0fcd0, +- 0xf800002d, +-/* 0x0541: memx_func_wait_vblank */ ++ 0x20460000, ++ 0x7e6eb216, ++ 0xb2000004, ++ 0x0587fdd8, ++ 0x80f960f9, ++ 0xe0fcd0fc, ++ 0x00002d7e, ++ 0xb20aa247, ++ 0x00047e6e, ++ 0xfdd8b200, ++ 0x60f90587, ++ 0xd0fc80f9, ++ 0x2d7ee0fc, ++ 0x00f80000, ++/* 0x053c: memx_func_wait_vblank */ ++ 0xf80410b6, ++/* 0x0541: memx_func_wr32 */ ++ 0x00169800, ++ 0xb6011598, ++ 0x60f90810, ++ 0xd0fc50f9, ++ 0x2d7ee0fc, ++ 0x42b60000, ++ 0xe81bf402, ++/* 0x055e: memx_func_wait */ ++ 0x2c0800f8, ++ 0x980088cf, ++ 0x1d98001e, ++ 0x021c9801, ++ 0xb6031b98, ++ 0x747e1010, ++ 0x00f80000, ++/* 0x0578: memx_func_delay */ ++ 0xb6001e98, ++ 0x587e0410, ++ 0x00f80000, ++/* 0x0584: memx_func_train */ ++/* 0x0586: memx_exec */ ++ 0xe0f900f8, ++ 0xc1b2d0f9, ++/* 0x058e: memx_exec_next */ ++ 0x1398b2b2, + 0x0410b600, +-/* 0x0546: memx_func_wr32 */ +- 0x169800f8, +- 0x01159800, +- 0xf90810b6, +- 0xfc50f960, ++ 0x01f034e7, ++ 0x01e033e7, ++ 0xf00132b6, ++ 0x35980c30, ++ 0xa655f9de, ++ 0xe51ef412, ++ 0x98f10b98, ++ 0xcbbbf20c, ++ 0x07c44b02, ++ 0xfc00bbcf, + 0x7ee0fcd0, +- 0xb600002d, +- 0x1bf40242, +-/* 0x0563: memx_func_wait */ +- 0x0800f8e8, +- 0x0088cf2c, +- 0x98001e98, +- 0x1c98011d, +- 0x031b9802, +- 0x7e1010b6, +- 0xf8000074, +-/* 0x057d: memx_func_delay */ +- 0x001e9800, +- 0x7e0410b6, +- 0xf8000058, +-/* 0x0589: memx_func_train */ +-/* 0x058b: memx_exec */ +- 0xf900f800, +- 0xb2d0f9e0, +-/* 0x0593: memx_exec_next */ +- 0x98b2b2c1, +- 0x10b60013, +- 0xf034e704, +- 0xe033e701, +- 0x0132b601, +- 0x980c30f0, +- 0x55f9de35, +- 0x1ef412a6, +- 0xf10b98e5, +- 0xbbf20c98, +- 0xc44b02cb, +- 0x00bbcf07, +- 0xe0fcd0fc, +- 0x00029f7e, +-/* 0x05ca: memx_info */ +- 0xc67000f8, +- 0x0c0bf401, +-/* 0x05d0: memx_info_data */ +- 0x4b03cc4c, +- 0x0ef40800, +-/* 0x05d9: memx_info_train */ +- 0x0bcc4c09, +-/* 0x05df: memx_info_send */ +- 0x7e01004b, + 0xf800029f, +-/* 0x05e5: memx_recv */ +- 0x01d6b000, +- 0xb0a30bf4, +- 0x0bf400d6, +-/* 0x05f3: memx_init */ +- 0xf800f8dc, +-/* 0x05f5: perf_recv */ +-/* 0x05f7: perf_init */ +- 0xf800f800, +-/* 0x05f9: i2c_drive_scl */ +- 0x0036b000, +- 0x400d0bf4, +- 0x01f607e0, +- 0xf804bd00, +-/* 0x0609: i2c_drive_scl_lo */ +- 0x07e44000, +- 0xbd0001f6, +-/* 0x0613: i2c_drive_sda */ +- 0xb000f804, +- 0x0bf40036, +- 0x07e0400d, +- 0xbd0002f6, +-/* 0x0623: i2c_drive_sda_lo */ +- 0x4000f804, +- 0x02f607e4, +- 0xf804bd00, +-/* 0x062d: i2c_sense_scl */ +- 0x0132f400, +- 0xcf07c443, +- 0x31fd0033, +- 0x060bf404, +-/* 0x063f: i2c_sense_scl_done */ +- 0xf80131f4, +-/* 0x0641: i2c_sense_sda */ +- 0x0132f400, +- 0xcf07c443, +- 0x32fd0033, +- 0x060bf404, +-/* 0x0653: i2c_sense_sda_done */ +- 0xf80131f4, +-/* 0x0655: i2c_raise_scl */ +- 0x4440f900, +- 0x01030898, +- 0x0005f97e, +-/* 0x0660: i2c_raise_scl_wait */ +- 0x7e03e84e, +- 0x7e000058, +- 0xf400062d, +- 0x42b60901, +- 0xef1bf401, +-/* 0x0674: i2c_raise_scl_done */ +- 0x00f840fc, +-/* 0x0678: i2c_start */ +- 0x00062d7e, +- 0x7e0d11f4, +- 0xf4000641, +- 0x0ef40611, +-/* 0x0689: i2c_start_rep */ +- 0x7e00032e, +- 0x030005f9, +- 0x06137e01, ++/* 0x05c5: memx_info */ ++ 0x01c67000, ++/* 0x05cb: memx_info_data */ ++ 0x4c0c0bf4, ++ 0x004b03cc, ++ 0x090ef408, ++/* 0x05d4: memx_info_train */ ++ 0x4b0bcc4c, ++/* 0x05da: memx_info_send */ ++ 0x9f7e0100, ++ 0x00f80002, ++/* 0x05e0: memx_recv */ ++ 0xf401d6b0, ++ 0xd6b0a30b, ++ 0xdc0bf400, ++/* 0x05ee: memx_init */ ++ 0x00f800f8, ++/* 0x05f0: perf_recv */ ++/* 0x05f2: perf_init */ ++ 0x00f800f8, ++/* 0x05f4: i2c_drive_scl */ ++ 0xf40036b0, ++ 0xe0400d0b, ++ 0x0001f607, ++ 0x00f804bd, ++/* 0x0604: i2c_drive_scl_lo */ ++ 0xf607e440, ++ 0x04bd0001, ++/* 0x060e: i2c_drive_sda */ ++ 0x36b000f8, ++ 0x0d0bf400, ++ 0xf607e040, ++ 0x04bd0002, ++/* 0x061e: i2c_drive_sda_lo */ ++ 0xe44000f8, ++ 0x0002f607, ++ 0x00f804bd, ++/* 0x0628: i2c_sense_scl */ ++ 0x430132f4, ++ 0x33cf07c4, ++ 0x0431fd00, ++ 0xf4060bf4, ++/* 0x063a: i2c_sense_scl_done */ ++ 0x00f80131, ++/* 0x063c: i2c_sense_sda */ ++ 0x430132f4, ++ 0x33cf07c4, ++ 0x0432fd00, ++ 0xf4060bf4, ++/* 0x064e: i2c_sense_sda_done */ ++ 0x00f80131, ++/* 0x0650: i2c_raise_scl */ ++ 0x984440f9, ++ 0x7e010308, ++/* 0x065b: i2c_raise_scl_wait */ ++ 0x4e0005f4, ++ 0x587e03e8, ++ 0x287e0000, ++ 0x01f40006, ++ 0x0142b609, ++/* 0x066f: i2c_raise_scl_done */ ++ 0xfcef1bf4, ++/* 0x0673: i2c_start */ ++ 0x7e00f840, ++ 0xf4000628, ++ 0x3c7e0d11, ++ 0x11f40006, ++ 0x2e0ef406, ++/* 0x0684: i2c_start_rep */ ++ 0xf47e0003, ++ 0x01030005, ++ 0x00060e7e, ++ 0xb60076bb, ++ 0x50f90465, ++ 0xbb046594, ++ 0x50bd0256, ++ 0xfc0475fd, ++ 0x06507e50, ++ 0x0464b600, ++/* 0x06af: i2c_start_send */ ++ 0x031d11f4, ++ 0x060e7e00, ++ 0x13884e00, ++ 0x0000587e, ++ 0xf47e0003, ++ 0x884e0005, ++ 0x00587e13, ++/* 0x06c9: i2c_start_out */ ++/* 0x06cb: i2c_stop */ ++ 0x0300f800, ++ 0x05f47e00, ++ 0x7e000300, ++ 0x4e00060e, ++ 0x587e03e8, ++ 0x01030000, ++ 0x0005f47e, ++ 0x7e13884e, ++ 0x03000058, ++ 0x060e7e01, ++ 0x13884e00, ++ 0x0000587e, ++/* 0x06fa: i2c_bitw */ ++ 0x0e7e00f8, ++ 0xe84e0006, ++ 0x00587e03, + 0x0076bb00, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, +- 0x557e50fc, ++ 0x507e50fc, + 0x64b60006, +- 0x1d11f404, +-/* 0x06b4: i2c_start_send */ +- 0x137e0003, +- 0x884e0006, +- 0x00587e13, +- 0x7e000300, +- 0x4e0005f9, +- 0x587e1388, +-/* 0x06ce: i2c_start_out */ +- 0x00f80000, +-/* 0x06d0: i2c_stop */ +- 0xf97e0003, +- 0x00030005, +- 0x0006137e, +- 0x7e03e84e, ++ 0x1711f404, ++ 0x7e13884e, + 0x03000058, +- 0x05f97e01, ++ 0x05f47e00, + 0x13884e00, + 0x0000587e, +- 0x137e0103, +- 0x884e0006, +- 0x00587e13, +-/* 0x06ff: i2c_bitw */ +- 0x7e00f800, +- 0x4e000613, +- 0x587e03e8, +- 0x76bb0000, ++/* 0x0738: i2c_bitw_out */ ++/* 0x073a: i2c_bitr */ ++ 0x010300f8, ++ 0x00060e7e, ++ 0x7e03e84e, ++ 0xbb000058, ++ 0x65b60076, ++ 0x9450f904, ++ 0x56bb0465, ++ 0xfd50bd02, ++ 0x50fc0475, ++ 0x0006507e, ++ 0xf40464b6, ++ 0x3c7e1a11, ++ 0x00030006, ++ 0x0005f47e, ++ 0x7e13884e, ++ 0xf0000058, ++ 0x31f4013c, ++/* 0x077d: i2c_bitr_done */ ++/* 0x077f: i2c_get_byte */ ++ 0x0500f801, ++/* 0x0783: i2c_get_byte_next */ ++ 0xb6080400, ++ 0x76bb0154, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0x7e50fc04, +- 0xb6000655, ++ 0xb600073a, + 0x11f40464, +- 0x13884e17, +- 0x0000587e, +- 0xf97e0003, +- 0x884e0005, +- 0x00587e13, +-/* 0x073d: i2c_bitw_out */ +-/* 0x073f: i2c_bitr */ +- 0x0300f800, +- 0x06137e01, +- 0x03e84e00, +- 0x0000587e, ++ 0x0553fd2a, ++ 0xf40142b6, ++ 0x0103d81b, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, +- 0x06557e50, ++ 0x06fa7e50, + 0x0464b600, +- 0x7e1a11f4, +- 0x03000641, +- 0x05f97e00, +- 0x13884e00, +- 0x0000587e, +- 0xf4013cf0, +-/* 0x0782: i2c_bitr_done */ +- 0x00f80131, +-/* 0x0784: i2c_get_byte */ +- 0x08040005, +-/* 0x0788: i2c_get_byte_next */ +- 0xbb0154b6, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x00073f7e, +- 0xf40464b6, +- 0x53fd2a11, +- 0x0142b605, +- 0x03d81bf4, +- 0x0076bb01, +- 0xf90465b6, +- 0x04659450, +- 0xbd0256bb, +- 0x0475fd50, +- 0xff7e50fc, +- 0x64b60006, +-/* 0x07d1: i2c_get_byte_done */ +-/* 0x07d3: i2c_put_byte */ +- 0x0400f804, +-/* 0x07d5: i2c_put_byte_next */ +- 0x0142b608, +- 0xbb3854ff, ++/* 0x07cc: i2c_get_byte_done */ ++/* 0x07ce: i2c_put_byte */ ++ 0x080400f8, ++/* 0x07d0: i2c_put_byte_next */ ++ 0xff0142b6, ++ 0x76bb3854, ++ 0x0465b600, ++ 0x659450f9, ++ 0x0256bb04, ++ 0x75fd50bd, ++ 0x7e50fc04, ++ 0xb60006fa, ++ 0x11f40464, ++ 0x0046b034, ++ 0xbbd81bf4, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, +- 0x0006ff7e, ++ 0x00073a7e, + 0xf40464b6, +- 0x46b03411, +- 0xd81bf400, ++ 0x76bb0f11, ++ 0x0136b000, ++ 0xf4061bf4, ++/* 0x0826: i2c_put_byte_done */ ++ 0x00f80132, ++/* 0x0828: i2c_addr */ + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, +- 0x073f7e50, ++ 0x06737e50, + 0x0464b600, +- 0xbb0f11f4, +- 0x36b00076, +- 0x061bf401, +-/* 0x082b: i2c_put_byte_done */ +- 0xf80132f4, +-/* 0x082d: i2c_addr */ +- 0x0076bb00, ++ 0xe72911f4, ++ 0xb6012ec3, ++ 0x53fd0134, ++ 0x0076bb05, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, +- 0x787e50fc, +- 0x64b60006, +- 0x2911f404, +- 0x012ec3e7, +- 0xfd0134b6, +- 0x76bb0553, +- 0x0465b600, +- 0x659450f9, +- 0x0256bb04, +- 0x75fd50bd, +- 0x7e50fc04, +- 0xb60007d3, +-/* 0x0872: i2c_addr_done */ +- 0x00f80464, +-/* 0x0874: i2c_acquire_addr */ +- 0xb6f8cec7, +- 0xe0b705e4, +- 0x00f8d014, +-/* 0x0880: i2c_acquire */ +- 0x0008747e, ++ 0xce7e50fc, ++ 0x64b60007, ++/* 0x086d: i2c_addr_done */ ++/* 0x086f: i2c_acquire_addr */ ++ 0xc700f804, ++ 0xe4b6f8ce, ++ 0x14e0b705, ++/* 0x087b: i2c_acquire */ ++ 0x7e00f8d0, ++ 0x7e00086f, ++ 0xf0000004, ++ 0x2d7e03d9, ++ 0x00f80000, ++/* 0x088c: i2c_release */ ++ 0x00086f7e, + 0x0000047e, +- 0x7e03d9f0, ++ 0x7e03daf0, + 0xf800002d, +-/* 0x0891: i2c_release */ +- 0x08747e00, +- 0x00047e00, +- 0x03daf000, +- 0x00002d7e, +-/* 0x08a2: i2c_recv */ +- 0x32f400f8, +- 0xf8c1c701, +- 0xb00214b6, +- 0x1ff52816, +- 0x13b80134, +- 0x98000cf4, +- 0x13b80032, +- 0x98000ccc, +- 0x31f40031, +- 0xf9d0f902, +- 0xd6d0f9e0, +- 0x10000000, +- 0xbb016792, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x0008807e, +- 0xfc0464b6, +- 0x00d6b0d0, +- 0x00b01bf5, +- 0x76bb0005, ++/* 0x089d: i2c_recv */ ++ 0x0132f400, ++ 0xb6f8c1c7, ++ 0x16b00214, ++ 0x341ff528, ++ 0xf413b801, ++ 0x3298000c, ++ 0xcc13b800, ++ 0x3198000c, ++ 0x0231f400, ++ 0xe0f9d0f9, ++ 0x00d6d0f9, ++ 0x92100000, ++ 0x76bb0167, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0x7e50fc04, +- 0xb600082d, +- 0x11f50464, +- 0xc5c700cc, +- 0x0076bbe0, +- 0xf90465b6, +- 0x04659450, +- 0xbd0256bb, +- 0x0475fd50, +- 0xd37e50fc, +- 0x64b60007, +- 0xa911f504, +- 0xbb010500, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x00082d7e, +- 0xf50464b6, +- 0xbb008711, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x0007847e, +- 0xf40464b6, +- 0x5bcb6711, +- 0x0076bbe0, ++ 0xb600087b, ++ 0xd0fc0464, ++ 0xf500d6b0, ++ 0x0500b01b, ++ 0x0076bb00, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, +- 0xd07e50fc, +- 0x64b60006, +- 0xbd5bb204, +- 0x410ef474, +-/* 0x09a4: i2c_recv_not_rd08 */ +- 0xf401d6b0, +- 0x00053b1b, +- 0x00082d7e, +- 0xc73211f4, +- 0xd37ee0c5, +- 0x11f40007, +- 0x7e000528, +- 0xf400082d, +- 0xb5c71f11, +- 0x07d37ee0, +- 0x1511f400, +- 0x0006d07e, +- 0xc5c774bd, +- 0x091bf408, +- 0xf40232f4, +-/* 0x09e2: i2c_recv_not_wr08 */ +-/* 0x09e2: i2c_recv_done */ +- 0xcec7030e, +- 0x08917ef8, +- 0xfce0fc00, +- 0x0912f4d0, +- 0x9f7e7cb2, +-/* 0x09f6: i2c_recv_exit */ +- 0x00f80002, +-/* 0x09f8: i2c_init */ +-/* 0x09fa: test_recv */ +- 0x584100f8, +- 0x0011cf04, +- 0x400110b6, +- 0x01f60458, +- 0xde04bd00, +- 0x134fd900, +- 0x0001de7e, +-/* 0x0a16: test_init */ +- 0x004e00f8, +- 0x01de7e08, +-/* 0x0a1f: idle_recv */ ++ 0x287e50fc, ++ 0x64b60008, ++ 0xcc11f504, ++ 0xe0c5c700, ++ 0xb60076bb, ++ 0x50f90465, ++ 0xbb046594, ++ 0x50bd0256, ++ 0xfc0475fd, ++ 0x07ce7e50, ++ 0x0464b600, ++ 0x00a911f5, ++ 0x76bb0105, ++ 0x0465b600, ++ 0x659450f9, ++ 0x0256bb04, ++ 0x75fd50bd, ++ 0x7e50fc04, ++ 0xb6000828, ++ 0x11f50464, ++ 0x76bb0087, ++ 0x0465b600, ++ 0x659450f9, ++ 0x0256bb04, ++ 0x75fd50bd, ++ 0x7e50fc04, ++ 0xb600077f, ++ 0x11f40464, ++ 0xe05bcb67, ++ 0xb60076bb, ++ 0x50f90465, ++ 0xbb046594, ++ 0x50bd0256, ++ 0xfc0475fd, ++ 0x06cb7e50, ++ 0x0464b600, ++ 0x74bd5bb2, ++/* 0x099f: i2c_recv_not_rd08 */ ++ 0xb0410ef4, ++ 0x1bf401d6, ++ 0x7e00053b, ++ 0xf4000828, ++ 0xc5c73211, ++ 0x07ce7ee0, ++ 0x2811f400, ++ 0x287e0005, ++ 0x11f40008, ++ 0xe0b5c71f, ++ 0x0007ce7e, ++ 0x7e1511f4, ++ 0xbd0006cb, ++ 0x08c5c774, ++ 0xf4091bf4, ++ 0x0ef40232, ++/* 0x09dd: i2c_recv_not_wr08 */ ++/* 0x09dd: i2c_recv_done */ ++ 0xf8cec703, ++ 0x00088c7e, ++ 0xd0fce0fc, ++ 0xb20912f4, ++ 0x029f7e7c, ++/* 0x09f1: i2c_recv_exit */ ++/* 0x09f3: i2c_init */ + 0xf800f800, +-/* 0x0a21: idle */ +- 0x0031f400, +- 0xcf045441, +- 0x10b60011, +- 0x04544001, +- 0xbd0001f6, +-/* 0x0a35: idle_loop */ +- 0xf4580104, +-/* 0x0a3a: idle_proc */ +-/* 0x0a3a: idle_proc_exec */ +- 0x10f90232, +- 0xa87e1eb2, +- 0x10fc0002, +- 0xf40911f4, +- 0x0ef40231, +-/* 0x0a4d: idle_proc_next */ +- 0x5810b6f0, +- 0x1bf41fa6, +- 0xe002f4e8, +- 0xf40028f4, +- 0x0000c60e, ++/* 0x09f5: test_recv */ ++ 0x04584100, ++ 0xb60011cf, ++ 0x58400110, ++ 0x0001f604, ++ 0x00de04bd, ++ 0x7e134fd9, ++ 0xf80001de, ++/* 0x0a11: test_init */ ++ 0x08004e00, ++ 0x0001de7e, ++/* 0x0a1a: idle_recv */ ++ 0x00f800f8, ++/* 0x0a1c: idle */ ++ 0x410031f4, ++ 0x11cf0454, ++ 0x0110b600, ++ 0xf6045440, ++ 0x04bd0001, ++/* 0x0a30: idle_loop */ ++ 0x32f45801, ++/* 0x0a35: idle_proc */ ++/* 0x0a35: idle_proc_exec */ ++ 0xb210f902, ++ 0x02a87e1e, ++ 0xf410fc00, ++ 0x31f40911, ++ 0xf00ef402, ++/* 0x0a48: idle_proc_next */ ++ 0xa65810b6, ++ 0xe81bf41f, ++ 0xf4e002f4, ++ 0x0ef40028, ++ 0x000000c6, ++ 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h +index e83341815ec6..e29b785d9f22 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h +@@ -46,8 +46,8 @@ uint32_t gt215_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x584d454d, +- 0x0000083a, +- 0x0000082c, ++ 0x00000833, ++ 0x00000825, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -68,8 +68,8 @@ uint32_t gt215_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x46524550, +- 0x0000083e, +- 0x0000083c, ++ 0x00000837, ++ 0x00000835, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -90,8 +90,8 @@ uint32_t gt215_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x5f433249, +- 0x00000c6e, +- 0x00000b11, ++ 0x00000c67, ++ 0x00000b0a, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -112,8 +112,8 @@ uint32_t gt215_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x54534554, +- 0x00000c97, +- 0x00000c70, ++ 0x00000c90, ++ 0x00000c69, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -134,8 +134,8 @@ uint32_t gt215_pmu_data[] = { + 0x00000000, + 0x00000000, + 0x454c4449, +- 0x00000ca3, +- 0x00000ca1, ++ 0x00000c9c, ++ 0x00000c9a, + 0x00000000, + 0x00000000, + 0x00000000, +@@ -233,22 +233,22 @@ uint32_t gt215_pmu_data[] = { + /* 0x037c: memx_func_next */ + 0x00000002, + 0x00000000, +- 0x000005a0, ++ 0x0000059f, + 0x00000003, + 0x00000002, +- 0x00000632, ++ 0x0000062f, + 0x00040004, + 0x00000000, +- 0x0000064e, ++ 0x0000064b, + 0x00010005, + 0x00000000, +- 0x0000066b, ++ 0x00000668, + 0x00010006, + 0x00000000, +- 0x000005f0, ++ 0x000005ef, + 0x00000007, + 0x00000000, +- 0x00000676, ++ 0x00000673, + /* 0x03c4: memx_func_tail */ + /* 0x03c4: memx_ts_start */ + 0x00000000, +@@ -1304,560 +1304,560 @@ uint32_t gt215_pmu_code[] = { + 0x67f102d7, + 0x63f1fffc, + 0x76fdffff, +- 0x0267f104, +- 0x0576fd00, +- 0x70f980f9, +- 0xe0fcd0fc, +- 0xf04021f4, ++ 0x0267f004, ++ 0xf90576fd, ++ 0xfc70f980, ++ 0xf4e0fcd0, ++ 0x67f04021, ++ 0xe007f104, ++ 0x0604b607, ++ 0xbd0006d0, ++/* 0x0581: memx_func_enter_wait */ ++ 0xc067f104, ++ 0x0664b607, ++ 0xf00066cf, ++ 0x0bf40464, ++ 0x2c67f0f3, ++ 0xcf0664b6, ++ 0x06800066, ++/* 0x059f: memx_func_leave */ ++ 0xf000f8f1, ++ 0x64b62c67, ++ 0x0066cf06, ++ 0xf0f20680, + 0x07f10467, +- 0x04b607e0, ++ 0x04b607e4, + 0x0006d006, +-/* 0x0582: memx_func_enter_wait */ ++/* 0x05ba: memx_func_leave_wait */ + 0x67f104bd, + 0x64b607c0, + 0x0066cf06, + 0xf40464f0, +- 0x67f0f30b, +- 0x0664b62c, +- 0x800066cf, +- 0x00f8f106, +-/* 0x05a0: memx_func_leave */ +- 0xb62c67f0, +- 0x66cf0664, +- 0xf2068000, +- 0xf10467f0, +- 0xb607e407, +- 0x06d00604, +-/* 0x05bb: memx_func_leave_wait */ +- 0xf104bd00, +- 0xb607c067, +- 0x66cf0664, +- 0x0464f000, +- 0xf1f31bf4, +- 0xb9161087, +- 0x21f4028e, +- 0x02d7b904, +- 0xffcc67f1, +- 0xffff63f1, +- 0xf90476fd, +- 0xfc70f980, +- 0xf4e0fcd0, +- 0x00f84021, +-/* 0x05f0: memx_func_wait_vblank */ +- 0xb0001698, +- 0x0bf40066, +- 0x0166b013, +- 0xf4060bf4, +-/* 0x0602: memx_func_wait_vblank_head1 */ +- 0x77f12e0e, +- 0x0ef40020, +-/* 0x0609: memx_func_wait_vblank_head0 */ +- 0x0877f107, +-/* 0x060d: memx_func_wait_vblank_0 */ +- 0xc467f100, +- 0x0664b607, +- 0xfd0066cf, +- 0x1bf40467, +-/* 0x061d: memx_func_wait_vblank_1 */ +- 0xc467f1f3, +- 0x0664b607, +- 0xfd0066cf, +- 0x0bf40467, +-/* 0x062d: memx_func_wait_vblank_fini */ +- 0x0410b6f3, +-/* 0x0632: memx_func_wr32 */ +- 0x169800f8, +- 0x01159800, +- 0xf90810b6, +- 0xfc50f960, +- 0xf4e0fcd0, +- 0x42b64021, +- 0xe91bf402, +-/* 0x064e: memx_func_wait */ +- 0x87f000f8, +- 0x0684b62c, +- 0x980088cf, +- 0x1d98001e, +- 0x021c9801, +- 0xb6031b98, +- 0x21f41010, +-/* 0x066b: memx_func_delay */ +- 0x9800f8a3, +- 0x10b6001e, +- 0x7e21f404, +-/* 0x0676: memx_func_train */ +- 0x57f100f8, +- 0x77f10003, +- 0x97f10000, +- 0x93f00000, +- 0x029eb970, +- 0xb90421f4, +- 0xe7f102d8, +- 0x21f42710, +-/* 0x0695: memx_func_train_loop_outer */ +- 0x0158e07e, +- 0x0083f101, +- 0xe097f102, +- 0x1193f011, +- 0x80f990f9, ++ 0x87f1f31b, ++ 0x8eb91610, ++ 0x0421f402, ++ 0xf102d7b9, ++ 0xf1ffcc67, ++ 0xfdffff63, ++ 0x80f90476, ++ 0xd0fc70f9, ++ 0x21f4e0fc, ++/* 0x05ef: memx_func_wait_vblank */ ++ 0x9800f840, ++ 0x66b00016, ++ 0x120bf400, ++ 0xf40166b0, ++ 0x0ef4060b, ++/* 0x0601: memx_func_wait_vblank_head1 */ ++ 0x2077f02c, ++/* 0x0607: memx_func_wait_vblank_head0 */ ++ 0xf0060ef4, ++/* 0x060a: memx_func_wait_vblank_0 */ ++ 0x67f10877, ++ 0x64b607c4, ++ 0x0066cf06, ++ 0xf40467fd, ++/* 0x061a: memx_func_wait_vblank_1 */ ++ 0x67f1f31b, ++ 0x64b607c4, ++ 0x0066cf06, ++ 0xf40467fd, ++/* 0x062a: memx_func_wait_vblank_fini */ ++ 0x10b6f30b, ++/* 0x062f: memx_func_wr32 */ ++ 0x9800f804, ++ 0x15980016, ++ 0x0810b601, ++ 0x50f960f9, + 0xe0fcd0fc, +- 0xf94021f4, +- 0x0067f150, +-/* 0x06b5: memx_func_train_loop_inner */ +- 0x1187f100, +- 0x9068ff11, +- 0xfd109894, +- 0x97f10589, +- 0x93f00720, +- 0xf990f910, +- 0xfcd0fc80, +- 0x4021f4e0, +- 0x008097f1, +- 0xb91093f0, +- 0x21f4029e, +- 0x02d8b904, +- 0xf92088c5, ++ 0xb64021f4, ++ 0x1bf40242, ++/* 0x064b: memx_func_wait */ ++ 0xf000f8e9, ++ 0x84b62c87, ++ 0x0088cf06, ++ 0x98001e98, ++ 0x1c98011d, ++ 0x031b9802, ++ 0xf41010b6, ++ 0x00f8a321, ++/* 0x0668: memx_func_delay */ ++ 0xb6001e98, ++ 0x21f40410, ++/* 0x0673: memx_func_train */ ++ 0xf000f87e, ++ 0x77f00357, ++ 0x0097f100, ++ 0x7093f000, ++ 0xf4029eb9, ++ 0xd8b90421, ++ 0x10e7f102, ++ 0x7e21f427, ++/* 0x0690: memx_func_train_loop_outer */ ++ 0x010158e0, ++ 0x020083f1, ++ 0x11e097f1, ++ 0xf91193f0, ++ 0xfc80f990, ++ 0xf4e0fcd0, ++ 0x50f94021, ++/* 0x06af: memx_func_train_loop_inner */ ++ 0xf10067f0, ++ 0xff111187, ++ 0x98949068, ++ 0x0589fd10, ++ 0x072097f1, ++ 0xf91093f0, + 0xfc80f990, + 0xf4e0fcd0, + 0x97f14021, +- 0x93f0053c, +- 0x0287f110, +- 0x0083f130, +- 0xf990f980, ++ 0x93f00080, ++ 0x029eb910, ++ 0xb90421f4, ++ 0x88c502d8, ++ 0xf990f920, + 0xfcd0fc80, + 0x4021f4e0, +- 0x0560e7f1, +- 0xf110e3f0, +- 0xf10000d7, +- 0x908000d3, +- 0xb7f100dc, +- 0xb3f08480, +- 0xa321f41e, +- 0x000057f1, +- 0xffff97f1, +- 0x830093f1, +-/* 0x0734: memx_func_train_loop_4x */ +- 0x0080a7f1, +- 0xb910a3f0, +- 0x21f402ae, +- 0x02d8b904, +- 0xffdfb7f1, +- 0xffffb3f1, +- 0xf9048bfd, +- 0xfc80f9a0, ++ 0x053c97f1, ++ 0xf11093f0, ++ 0xf1300287, ++ 0xf9800083, ++ 0xfc80f990, + 0xf4e0fcd0, +- 0xa7f14021, +- 0xa3f0053c, +- 0x0287f110, +- 0x0083f130, +- 0xf9a0f980, +- 0xfcd0fc80, +- 0x4021f4e0, +- 0x0560e7f1, +- 0xf110e3f0, +- 0xf10000d7, +- 0xb98000d3, +- 0xb7f102dc, +- 0xb3f02710, +- 0xa321f400, +- 0xf402eeb9, +- 0xddb90421, +- 0x949dff02, ++ 0xe7f14021, ++ 0xe3f00560, ++ 0x00d7f110, ++ 0x00d3f100, ++ 0x00dc9080, ++ 0x8480b7f1, ++ 0xf41eb3f0, ++ 0x57f0a321, ++ 0xff97f100, ++ 0x0093f1ff, ++/* 0x072d: memx_func_train_loop_4x */ ++ 0x80a7f183, ++ 0x10a3f000, ++ 0xf402aeb9, ++ 0xd8b90421, ++ 0xdfb7f102, ++ 0xffb3f1ff, ++ 0x048bfdff, ++ 0x80f9a0f9, ++ 0xe0fcd0fc, ++ 0xf14021f4, ++ 0xf0053ca7, ++ 0x87f110a3, ++ 0x83f13002, ++ 0xa0f98000, ++ 0xd0fc80f9, ++ 0x21f4e0fc, ++ 0x60e7f140, ++ 0x10e3f005, ++ 0x0000d7f1, ++ 0x8000d3f1, ++ 0xf102dcb9, ++ 0xf02710b7, ++ 0x21f400b3, ++ 0x02eeb9a3, ++ 0xb90421f4, ++ 0x9dff02dd, ++ 0x0150b694, ++ 0xf4045670, ++ 0x7aa0921e, ++ 0xa9800bcc, ++ 0x0160b600, ++ 0x700470b6, ++ 0x1ef51066, ++ 0x50fcff01, + 0x700150b6, +- 0x1ef40456, +- 0xcc7aa092, +- 0x00a9800b, +- 0xb60160b6, +- 0x66700470, +- 0x001ef510, +- 0xb650fcff, +- 0x56700150, +- 0xd41ef507, +-/* 0x07c7: memx_exec */ +- 0xf900f8fe, +- 0xb9d0f9e0, +- 0xb2b902c1, +-/* 0x07d1: memx_exec_next */ +- 0x00139802, +- 0xe70410b6, +- 0xe701f034, +- 0xb601e033, +- 0x30f00132, +- 0xde35980c, +- 0x12b855f9, +- 0xe41ef406, +- 0x98f10b98, +- 0xcbbbf20c, +- 0xc4b7f102, +- 0x06b4b607, +- 0xfc00bbcf, +- 0xf5e0fcd0, ++ 0x1ef50756, ++ 0x00f8fed6, ++/* 0x07c0: memx_exec */ ++ 0xd0f9e0f9, ++ 0xb902c1b9, ++/* 0x07ca: memx_exec_next */ ++ 0x139802b2, ++ 0x0410b600, ++ 0x01f034e7, ++ 0x01e033e7, ++ 0xf00132b6, ++ 0x35980c30, ++ 0xb855f9de, ++ 0x1ef40612, ++ 0xf10b98e4, ++ 0xbbf20c98, ++ 0xb7f102cb, ++ 0xb4b607c4, ++ 0x00bbcf06, ++ 0xe0fcd0fc, ++ 0x033621f5, ++/* 0x0806: memx_info */ ++ 0xc67000f8, ++ 0x0e0bf401, ++/* 0x080c: memx_info_data */ ++ 0x03ccc7f1, ++ 0x0800b7f1, ++/* 0x0817: memx_info_train */ ++ 0xf10b0ef4, ++ 0xf10bccc7, ++/* 0x081f: memx_info_send */ ++ 0xf50100b7, + 0xf8033621, +-/* 0x080d: memx_info */ +- 0x01c67000, +-/* 0x0813: memx_info_data */ +- 0xf10e0bf4, +- 0xf103ccc7, +- 0xf40800b7, +-/* 0x081e: memx_info_train */ +- 0xc7f10b0e, +- 0xb7f10bcc, +-/* 0x0826: memx_info_send */ +- 0x21f50100, +- 0x00f80336, +-/* 0x082c: memx_recv */ +- 0xf401d6b0, +- 0xd6b0980b, +- 0xd80bf400, +-/* 0x083a: memx_init */ +- 0x00f800f8, +-/* 0x083c: perf_recv */ +-/* 0x083e: perf_init */ +- 0x00f800f8, +-/* 0x0840: i2c_drive_scl */ +- 0xf40036b0, +- 0x07f1110b, +- 0x04b607e0, +- 0x0001d006, +- 0x00f804bd, +-/* 0x0854: i2c_drive_scl_lo */ +- 0x07e407f1, +- 0xd00604b6, +- 0x04bd0001, +-/* 0x0862: i2c_drive_sda */ +- 0x36b000f8, +- 0x110bf400, +- 0x07e007f1, +- 0xd00604b6, +- 0x04bd0002, +-/* 0x0876: i2c_drive_sda_lo */ +- 0x07f100f8, +- 0x04b607e4, +- 0x0002d006, +- 0x00f804bd, +-/* 0x0884: i2c_sense_scl */ +- 0xf10132f4, +- 0xb607c437, +- 0x33cf0634, +- 0x0431fd00, +- 0xf4060bf4, +-/* 0x089a: i2c_sense_scl_done */ +- 0x00f80131, +-/* 0x089c: i2c_sense_sda */ +- 0xf10132f4, +- 0xb607c437, +- 0x33cf0634, +- 0x0432fd00, +- 0xf4060bf4, +-/* 0x08b2: i2c_sense_sda_done */ +- 0x00f80131, +-/* 0x08b4: i2c_raise_scl */ +- 0x47f140f9, +- 0x37f00898, +- 0x4021f501, +-/* 0x08c1: i2c_raise_scl_wait */ ++/* 0x0825: memx_recv */ ++ 0x01d6b000, ++ 0xb0980bf4, ++ 0x0bf400d6, ++/* 0x0833: memx_init */ ++ 0xf800f8d8, ++/* 0x0835: perf_recv */ ++/* 0x0837: perf_init */ ++ 0xf800f800, ++/* 0x0839: i2c_drive_scl */ ++ 0x0036b000, ++ 0xf1110bf4, ++ 0xb607e007, ++ 0x01d00604, ++ 0xf804bd00, ++/* 0x084d: i2c_drive_scl_lo */ ++ 0xe407f100, ++ 0x0604b607, ++ 0xbd0001d0, ++/* 0x085b: i2c_drive_sda */ ++ 0xb000f804, ++ 0x0bf40036, ++ 0xe007f111, ++ 0x0604b607, ++ 0xbd0002d0, ++/* 0x086f: i2c_drive_sda_lo */ ++ 0xf100f804, ++ 0xb607e407, ++ 0x02d00604, ++ 0xf804bd00, ++/* 0x087d: i2c_sense_scl */ ++ 0x0132f400, ++ 0x07c437f1, ++ 0xcf0634b6, ++ 0x31fd0033, ++ 0x060bf404, ++/* 0x0893: i2c_sense_scl_done */ ++ 0xf80131f4, ++/* 0x0895: i2c_sense_sda */ ++ 0x0132f400, ++ 0x07c437f1, ++ 0xcf0634b6, ++ 0x32fd0033, ++ 0x060bf404, ++/* 0x08ab: i2c_sense_sda_done */ ++ 0xf80131f4, ++/* 0x08ad: i2c_raise_scl */ ++ 0xf140f900, ++ 0xf0089847, ++ 0x21f50137, ++/* 0x08ba: i2c_raise_scl_wait */ ++ 0xe7f10839, ++ 0x21f403e8, ++ 0x7d21f57e, ++ 0x0901f408, ++ 0xf40142b6, ++/* 0x08ce: i2c_raise_scl_done */ ++ 0x40fcef1b, ++/* 0x08d2: i2c_start */ ++ 0x21f500f8, ++ 0x11f4087d, ++ 0x9521f50d, ++ 0x0611f408, ++/* 0x08e3: i2c_start_rep */ ++ 0xf0300ef4, ++ 0x21f50037, ++ 0x37f00839, ++ 0x5b21f501, ++ 0x0076bb08, ++ 0xf90465b6, ++ 0x04659450, ++ 0xbd0256bb, ++ 0x0475fd50, ++ 0x21f550fc, ++ 0x64b608ad, ++ 0x1f11f404, ++/* 0x0910: i2c_start_send */ ++ 0xf50037f0, ++ 0xf1085b21, ++ 0xf41388e7, ++ 0x37f07e21, ++ 0x3921f500, ++ 0x88e7f108, ++ 0x7e21f413, ++/* 0x092c: i2c_start_out */ ++/* 0x092e: i2c_stop */ ++ 0x37f000f8, ++ 0x3921f500, ++ 0x0037f008, ++ 0x085b21f5, ++ 0x03e8e7f1, ++ 0xf07e21f4, ++ 0x21f50137, ++ 0xe7f10839, ++ 0x21f41388, ++ 0x0137f07e, ++ 0x085b21f5, ++ 0x1388e7f1, ++ 0xf87e21f4, ++/* 0x0961: i2c_bitw */ ++ 0x5b21f500, + 0xe8e7f108, + 0x7e21f403, +- 0x088421f5, +- 0xb60901f4, +- 0x1bf40142, +-/* 0x08d5: i2c_raise_scl_done */ +- 0xf840fcef, +-/* 0x08d9: i2c_start */ +- 0x8421f500, +- 0x0d11f408, +- 0x089c21f5, +- 0xf40611f4, +-/* 0x08ea: i2c_start_rep */ +- 0x37f0300e, +- 0x4021f500, +- 0x0137f008, +- 0x086221f5, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, +- 0xb421f550, ++ 0xad21f550, + 0x0464b608, +-/* 0x0917: i2c_start_send */ +- 0xf01f11f4, +- 0x21f50037, +- 0xe7f10862, +- 0x21f41388, +- 0x0037f07e, +- 0x084021f5, +- 0x1388e7f1, +-/* 0x0933: i2c_start_out */ +- 0xf87e21f4, +-/* 0x0935: i2c_stop */ +- 0x0037f000, +- 0x084021f5, +- 0xf50037f0, +- 0xf1086221, +- 0xf403e8e7, ++ 0xf11811f4, ++ 0xf41388e7, + 0x37f07e21, +- 0x4021f501, ++ 0x3921f500, + 0x88e7f108, + 0x7e21f413, +- 0xf50137f0, +- 0xf1086221, +- 0xf41388e7, +- 0x00f87e21, +-/* 0x0968: i2c_bitw */ +- 0x086221f5, +- 0x03e8e7f1, +- 0xbb7e21f4, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x08b421f5, +- 0xf40464b6, +- 0xe7f11811, ++/* 0x09a0: i2c_bitw_out */ ++/* 0x09a2: i2c_bitr */ ++ 0x37f000f8, ++ 0x5b21f501, ++ 0xe8e7f108, ++ 0x7e21f403, ++ 0xb60076bb, ++ 0x50f90465, ++ 0xbb046594, ++ 0x50bd0256, ++ 0xfc0475fd, ++ 0xad21f550, ++ 0x0464b608, ++ 0xf51b11f4, ++ 0xf0089521, ++ 0x21f50037, ++ 0xe7f10839, + 0x21f41388, +- 0x0037f07e, +- 0x084021f5, +- 0x1388e7f1, +-/* 0x09a7: i2c_bitw_out */ +- 0xf87e21f4, +-/* 0x09a9: i2c_bitr */ +- 0x0137f000, +- 0x086221f5, +- 0x03e8e7f1, +- 0xbb7e21f4, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x08b421f5, +- 0xf40464b6, +- 0x21f51b11, +- 0x37f0089c, +- 0x4021f500, +- 0x88e7f108, +- 0x7e21f413, +- 0xf4013cf0, +-/* 0x09ee: i2c_bitr_done */ +- 0x00f80131, +-/* 0x09f0: i2c_get_byte */ +- 0xf00057f0, +-/* 0x09f6: i2c_get_byte_next */ +- 0x54b60847, ++ 0x013cf07e, ++/* 0x09e7: i2c_bitr_done */ ++ 0xf80131f4, ++/* 0x09e9: i2c_get_byte */ ++ 0x0057f000, ++/* 0x09ef: i2c_get_byte_next */ ++ 0xb60847f0, ++ 0x76bb0154, ++ 0x0465b600, ++ 0x659450f9, ++ 0x0256bb04, ++ 0x75fd50bd, ++ 0xf550fc04, ++ 0xb609a221, ++ 0x11f40464, ++ 0x0553fd2b, ++ 0xf40142b6, ++ 0x37f0d81b, + 0x0076bb01, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, +- 0x64b609a9, +- 0x2b11f404, +- 0xb60553fd, +- 0x1bf40142, +- 0x0137f0d8, +- 0xb60076bb, +- 0x50f90465, +- 0xbb046594, +- 0x50bd0256, +- 0xfc0475fd, +- 0x6821f550, +- 0x0464b609, +-/* 0x0a40: i2c_get_byte_done */ +-/* 0x0a42: i2c_put_byte */ +- 0x47f000f8, +-/* 0x0a45: i2c_put_byte_next */ +- 0x0142b608, +- 0xbb3854ff, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x096821f5, +- 0xf40464b6, +- 0x46b03411, +- 0xd81bf400, ++ 0x64b60961, ++/* 0x0a39: i2c_get_byte_done */ ++/* 0x0a3b: i2c_put_byte */ ++ 0xf000f804, ++/* 0x0a3e: i2c_put_byte_next */ ++ 0x42b60847, ++ 0x3854ff01, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, +- 0xa921f550, ++ 0x6121f550, + 0x0464b609, +- 0xbb0f11f4, +- 0x36b00076, +- 0x061bf401, +-/* 0x0a9b: i2c_put_byte_done */ +- 0xf80132f4, +-/* 0x0a9d: i2c_addr */ +- 0x0076bb00, ++ 0xb03411f4, ++ 0x1bf40046, ++ 0x0076bbd8, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, +- 0x64b608d9, +- 0x2911f404, +- 0x012ec3e7, +- 0xfd0134b6, +- 0x76bb0553, ++ 0x64b609a2, ++ 0x0f11f404, ++ 0xb00076bb, ++ 0x1bf40136, ++ 0x0132f406, ++/* 0x0a94: i2c_put_byte_done */ ++/* 0x0a96: i2c_addr */ ++ 0x76bb00f8, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, +- 0xb60a4221, +-/* 0x0ae2: i2c_addr_done */ +- 0x00f80464, +-/* 0x0ae4: i2c_acquire_addr */ +- 0xb6f8cec7, +- 0xe0b702e4, +- 0xee980d1c, +-/* 0x0af3: i2c_acquire */ +- 0xf500f800, +- 0xf40ae421, +- 0xd9f00421, +- 0x4021f403, +-/* 0x0b02: i2c_release */ +- 0x21f500f8, +- 0x21f40ae4, +- 0x03daf004, +- 0xf84021f4, +-/* 0x0b11: i2c_recv */ +- 0x0132f400, +- 0xb6f8c1c7, +- 0x16b00214, +- 0x3a1ff528, +- 0xf413a001, +- 0x0032980c, +- 0x0ccc13a0, +- 0xf4003198, +- 0xd0f90231, +- 0xd0f9e0f9, +- 0x000067f1, +- 0x100063f1, +- 0xbb016792, ++ 0xb608d221, ++ 0x11f40464, ++ 0x2ec3e729, ++ 0x0134b601, ++ 0xbb0553fd, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, +- 0x0af321f5, +- 0xfc0464b6, +- 0x00d6b0d0, +- 0x00b31bf5, +- 0xbb0057f0, ++ 0x0a3b21f5, ++/* 0x0adb: i2c_addr_done */ ++ 0xf80464b6, ++/* 0x0add: i2c_acquire_addr */ ++ 0xf8cec700, ++ 0xb702e4b6, ++ 0x980d1ce0, ++ 0x00f800ee, ++/* 0x0aec: i2c_acquire */ ++ 0x0add21f5, ++ 0xf00421f4, ++ 0x21f403d9, ++/* 0x0afb: i2c_release */ ++ 0xf500f840, ++ 0xf40add21, ++ 0xdaf00421, ++ 0x4021f403, ++/* 0x0b0a: i2c_recv */ ++ 0x32f400f8, ++ 0xf8c1c701, ++ 0xb00214b6, ++ 0x1ff52816, ++ 0x13a0013a, ++ 0x32980cf4, ++ 0xcc13a000, ++ 0x0031980c, ++ 0xf90231f4, ++ 0xf9e0f9d0, ++ 0x0067f1d0, ++ 0x0063f100, ++ 0x01679210, ++ 0xb60076bb, ++ 0x50f90465, ++ 0xbb046594, ++ 0x50bd0256, ++ 0xfc0475fd, ++ 0xec21f550, ++ 0x0464b60a, ++ 0xd6b0d0fc, ++ 0xb31bf500, ++ 0x0057f000, ++ 0xb60076bb, ++ 0x50f90465, ++ 0xbb046594, ++ 0x50bd0256, ++ 0xfc0475fd, ++ 0x9621f550, ++ 0x0464b60a, ++ 0x00d011f5, ++ 0xbbe0c5c7, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, +- 0x0a9d21f5, ++ 0x0a3b21f5, + 0xf50464b6, +- 0xc700d011, +- 0x76bbe0c5, ++ 0xf000ad11, ++ 0x76bb0157, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, +- 0xb60a4221, ++ 0xb60a9621, + 0x11f50464, +- 0x57f000ad, +- 0x0076bb01, +- 0xf90465b6, +- 0x04659450, +- 0xbd0256bb, +- 0x0475fd50, +- 0x21f550fc, +- 0x64b60a9d, +- 0x8a11f504, +- 0x0076bb00, +- 0xf90465b6, +- 0x04659450, +- 0xbd0256bb, +- 0x0475fd50, +- 0x21f550fc, +- 0x64b609f0, +- 0x6a11f404, +- 0xbbe05bcb, +- 0x65b60076, +- 0x9450f904, +- 0x56bb0465, +- 0xfd50bd02, +- 0x50fc0475, +- 0x093521f5, +- 0xb90464b6, +- 0x74bd025b, +-/* 0x0c17: i2c_recv_not_rd08 */ +- 0xb0430ef4, +- 0x1bf401d6, +- 0x0057f03d, +- 0x0a9d21f5, +- 0xc73311f4, +- 0x21f5e0c5, +- 0x11f40a42, +- 0x0057f029, +- 0x0a9d21f5, +- 0xc71f11f4, +- 0x21f5e0b5, +- 0x11f40a42, +- 0x3521f515, +- 0xc774bd09, +- 0x1bf408c5, +- 0x0232f409, +-/* 0x0c57: i2c_recv_not_wr08 */ +-/* 0x0c57: i2c_recv_done */ +- 0xc7030ef4, +- 0x21f5f8ce, +- 0xe0fc0b02, +- 0x12f4d0fc, +- 0x027cb90a, +- 0x033621f5, +-/* 0x0c6c: i2c_recv_exit */ +-/* 0x0c6e: i2c_init */ ++ 0x76bb008a, ++ 0x0465b600, ++ 0x659450f9, ++ 0x0256bb04, ++ 0x75fd50bd, ++ 0xf550fc04, ++ 0xb609e921, ++ 0x11f40464, ++ 0xe05bcb6a, ++ 0xb60076bb, ++ 0x50f90465, ++ 0xbb046594, ++ 0x50bd0256, ++ 0xfc0475fd, ++ 0x2e21f550, ++ 0x0464b609, ++ 0xbd025bb9, ++ 0x430ef474, ++/* 0x0c10: i2c_recv_not_rd08 */ ++ 0xf401d6b0, ++ 0x57f03d1b, ++ 0x9621f500, ++ 0x3311f40a, ++ 0xf5e0c5c7, ++ 0xf40a3b21, ++ 0x57f02911, ++ 0x9621f500, ++ 0x1f11f40a, ++ 0xf5e0b5c7, ++ 0xf40a3b21, ++ 0x21f51511, ++ 0x74bd092e, ++ 0xf408c5c7, ++ 0x32f4091b, ++ 0x030ef402, ++/* 0x0c50: i2c_recv_not_wr08 */ ++/* 0x0c50: i2c_recv_done */ ++ 0xf5f8cec7, ++ 0xfc0afb21, ++ 0xf4d0fce0, ++ 0x7cb90a12, ++ 0x3621f502, ++/* 0x0c65: i2c_recv_exit */ ++/* 0x0c67: i2c_init */ ++ 0xf800f803, ++/* 0x0c69: test_recv */ ++ 0xd817f100, ++ 0x0614b605, ++ 0xb60011cf, ++ 0x07f10110, ++ 0x04b605d8, ++ 0x0001d006, ++ 0xe7f104bd, ++ 0xe3f1d900, ++ 0x21f5134f, ++ 0x00f80256, ++/* 0x0c90: test_init */ ++ 0x0800e7f1, ++ 0x025621f5, ++/* 0x0c9a: idle_recv */ + 0x00f800f8, +-/* 0x0c70: test_recv */ +- 0x05d817f1, +- 0xcf0614b6, +- 0x10b60011, +- 0xd807f101, +- 0x0604b605, +- 0xbd0001d0, +- 0x00e7f104, +- 0x4fe3f1d9, +- 0x5621f513, +-/* 0x0c97: test_init */ +- 0xf100f802, +- 0xf50800e7, +- 0xf8025621, +-/* 0x0ca1: idle_recv */ +-/* 0x0ca3: idle */ +- 0xf400f800, +- 0x17f10031, +- 0x14b605d4, +- 0x0011cf06, +- 0xf10110b6, +- 0xb605d407, +- 0x01d00604, +-/* 0x0cbf: idle_loop */ +- 0xf004bd00, +- 0x32f45817, +-/* 0x0cc5: idle_proc */ +-/* 0x0cc5: idle_proc_exec */ +- 0xb910f902, +- 0x21f5021e, +- 0x10fc033f, +- 0xf40911f4, +- 0x0ef40231, +-/* 0x0cd9: idle_proc_next */ +- 0x5810b6ef, +- 0xf4061fb8, +- 0x02f4e61b, +- 0x0028f4dd, +- 0x00bb0ef4, ++/* 0x0c9c: idle */ ++ 0xf10031f4, ++ 0xb605d417, ++ 0x11cf0614, ++ 0x0110b600, ++ 0x05d407f1, ++ 0xd00604b6, ++ 0x04bd0001, ++/* 0x0cb8: idle_loop */ ++ 0xf45817f0, ++/* 0x0cbe: idle_proc */ ++/* 0x0cbe: idle_proc_exec */ ++ 0x10f90232, ++ 0xf5021eb9, ++ 0xfc033f21, ++ 0x0911f410, ++ 0xf40231f4, ++/* 0x0cd2: idle_proc_next */ ++ 0x10b6ef0e, ++ 0x061fb858, ++ 0xf4e61bf4, ++ 0x28f4dd02, ++ 0xbb0ef400, ++ 0x00000000, ++ 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc +index ec03f9a4290b..1663bf943d77 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc +@@ -82,15 +82,15 @@ memx_train_tail: + // $r0 - zero + memx_func_enter: + #if NVKM_PPWR_CHIPSET == GT215 +- movw $r8 0x1610 ++ mov $r8 0x1610 + nv_rd32($r7, $r8) + imm32($r6, 0xfffffffc) + and $r7 $r6 +- movw $r6 0x2 ++ mov $r6 0x2 + or $r7 $r6 + nv_wr32($r8, $r7) + #else +- movw $r6 0x001620 ++ mov $r6 0x001620 + imm32($r7, ~0x00000aa2); + nv_rd32($r8, $r6) + and $r8 $r7 +@@ -101,7 +101,7 @@ memx_func_enter: + and $r8 $r7 + nv_wr32($r6, $r8) + +- movw $r6 0x0026f0 ++ mov $r6 0x0026f0 + nv_rd32($r8, $r6) + and $r8 $r7 + nv_wr32($r6, $r8) +@@ -136,19 +136,19 @@ memx_func_leave: + bra nz #memx_func_leave_wait + + #if NVKM_PPWR_CHIPSET == GT215 +- movw $r8 0x1610 ++ mov $r8 0x1610 + nv_rd32($r7, $r8) + imm32($r6, 0xffffffcc) + and $r7 $r6 + nv_wr32($r8, $r7) + #else +- movw $r6 0x0026f0 ++ mov $r6 0x0026f0 + imm32($r7, 0x00000001) + nv_rd32($r8, $r6) + or $r8 $r7 + nv_wr32($r6, $r8) + +- movw $r6 0x001620 ++ mov $r6 0x001620 + nv_rd32($r8, $r6) + or $r8 $r7 + nv_wr32($r6, $r8) +@@ -177,11 +177,11 @@ memx_func_wait_vblank: + bra #memx_func_wait_vblank_fini + + memx_func_wait_vblank_head1: +- movw $r7 0x20 ++ mov $r7 0x20 + bra #memx_func_wait_vblank_0 + + memx_func_wait_vblank_head0: +- movw $r7 0x8 ++ mov $r7 0x8 + + memx_func_wait_vblank_0: + nv_iord($r6, NV_PPWR_INPUT) +@@ -273,13 +273,13 @@ memx_func_train: + // $r5 - outer loop counter + // $r6 - inner loop counter + // $r7 - entry counter (#memx_train_head + $r7) +- movw $r5 0x3 +- movw $r7 0x0 ++ mov $r5 0x3 ++ mov $r7 0x0 + + // Read random memory to wake up... things + imm32($r9, 0x700000) + nv_rd32($r8,$r9) +- movw $r14 0x2710 ++ mov $r14 0x2710 + call(nsec) + + memx_func_train_loop_outer: +@@ -289,9 +289,9 @@ memx_func_train: + nv_wr32($r9, $r8) + push $r5 + +- movw $r6 0x0 ++ mov $r6 0x0 + memx_func_train_loop_inner: +- movw $r8 0x1111 ++ mov $r8 0x1111 + mulu $r9 $r6 $r8 + shl b32 $r8 $r9 0x10 + or $r8 $r9 +@@ -315,7 +315,7 @@ memx_func_train: + + // $r5 - inner inner loop counter + // $r9 - result +- movw $r5 0 ++ mov $r5 0 + imm32($r9, 0x8300ffff) + memx_func_train_loop_4x: + imm32($r10, 0x100080) +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 6f65846b1783..5b2a9f97ff04 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -1250,7 +1250,7 @@ static const struct panel_desc ontat_yx700wv03 = { + .width = 154, + .height = 83, + }, +- .bus_format = MEDIA_BUS_FMT_RGB888_1X24, ++ .bus_format = MEDIA_BUS_FMT_RGB666_1X18, + }; + + static const struct drm_display_mode ortustech_com43h4m85ulc_mode = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +index b70f9423379c..cab4d60060a0 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +@@ -64,7 +64,6 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, + * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap(). + */ + vma->vm_flags &= ~VM_PFNMAP; +- vma->vm_pgoff = 0; + + ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr, + obj->size, rk_obj->dma_attrs); +@@ -96,6 +95,12 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma) + if (ret) + return ret; + ++ /* ++ * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the ++ * whole buffer from the start. ++ */ ++ vma->vm_pgoff = 0; ++ + obj = vma->vm_private_data; + + return rockchip_drm_gem_object_mmap(obj, vma); +diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c +index d401156490f3..4460ca46a350 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c ++++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c +@@ -129,10 +129,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw) + static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) + { + struct sun4i_dclk *dclk = hw_to_dclk(hw); ++ u32 val = degrees / 120; ++ ++ val <<= 28; + + regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, + GENMASK(29, 28), +- degrees / 120); ++ val); + + return 0; + } +diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c +index 818478b4c4f0..54639395aba0 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c ++++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c +@@ -194,6 +194,9 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, + case VIRTGPU_PARAM_3D_FEATURES: + value = vgdev->has_virgl_3d == true ? 1 : 0; + break; ++ case VIRTGPU_PARAM_CAPSET_QUERY_FIX: ++ value = 1; ++ break; + default: + return -EINVAL; + } +@@ -469,7 +472,7 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, + { + struct virtio_gpu_device *vgdev = dev->dev_private; + struct drm_virtgpu_get_caps *args = data; +- int size; ++ unsigned size, host_caps_size; + int i; + int found_valid = -1; + int ret; +@@ -478,6 +481,10 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, + if (vgdev->num_capsets == 0) + return -ENOSYS; + ++ /* don't allow userspace to pass 0 */ ++ if (args->size == 0) ++ return -EINVAL; ++ + spin_lock(&vgdev->display_info_lock); + for (i = 0; i < vgdev->num_capsets; i++) { + if (vgdev->capsets[i].id == args->cap_set_id) { +@@ -493,11 +500,9 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, + return -EINVAL; + } + +- size = vgdev->capsets[found_valid].max_size; +- if (args->size > size) { +- spin_unlock(&vgdev->display_info_lock); +- return -EINVAL; +- } ++ host_caps_size = vgdev->capsets[found_valid].max_size; ++ /* only copy to user the minimum of the host caps size or the guest caps size */ ++ size = min(args->size, host_caps_size); + + list_for_each_entry(cache_ent, &vgdev->cap_cache, head) { + if (cache_ent->id == args->cap_set_id && +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h +index 557a033fb610..8545488aa0cf 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h +@@ -135,17 +135,24 @@ + + #else + +-/* In the 32-bit version of this macro, we use "m" because there is no +- * more register left for bp ++/* ++ * In the 32-bit version of this macro, we store bp in a memory location ++ * because we've ran out of registers. ++ * Now we can't reference that memory location while we've modified ++ * %esp or %ebp, so we first push it on the stack, just before we push ++ * %ebp, and then when we need it we read it from the stack where we ++ * just pushed it. + */ + #define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ + port_num, magic, bp, \ + eax, ebx, ecx, edx, si, di) \ + ({ \ +- asm volatile ("push %%ebp;" \ +- "mov %12, %%ebp;" \ ++ asm volatile ("push %12;" \ ++ "push %%ebp;" \ ++ "mov 0x04(%%esp), %%ebp;" \ + "rep outsb;" \ +- "pop %%ebp;" : \ ++ "pop %%ebp;" \ ++ "add $0x04, %%esp;" : \ + "=a"(eax), \ + "=b"(ebx), \ + "=c"(ecx), \ +@@ -167,10 +174,12 @@ + port_num, magic, bp, \ + eax, ebx, ecx, edx, si, di) \ + ({ \ +- asm volatile ("push %%ebp;" \ +- "mov %12, %%ebp;" \ ++ asm volatile ("push %12;" \ ++ "push %%ebp;" \ ++ "mov 0x04(%%esp), %%ebp;" \ + "rep insb;" \ +- "pop %%ebp" : \ ++ "pop %%ebp;" \ ++ "add $0x04, %%esp;" : \ + "=a"(eax), \ + "=b"(ebx), \ + "=c"(ecx), \ +diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c +index 43617fb28b87..317c9c2c0a7c 100644 +--- a/drivers/hid/hid-roccat-kovaplus.c ++++ b/drivers/hid/hid-roccat-kovaplus.c +@@ -37,6 +37,8 @@ static uint kovaplus_convert_event_cpi(uint value) + static void kovaplus_profile_activated(struct kovaplus_device *kovaplus, + uint new_profile_index) + { ++ if (new_profile_index >= ARRAY_SIZE(kovaplus->profile_settings)) ++ return; + kovaplus->actual_profile = new_profile_index; + kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level; + kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x; +diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c +index ce75dd4db7eb..2b31b84d0a5b 100644 +--- a/drivers/hwmon/nct6775.c ++++ b/drivers/hwmon/nct6775.c +@@ -1393,7 +1393,7 @@ static void nct6775_update_pwm(struct device *dev) + duty_is_dc = data->REG_PWM_MODE[i] && + (nct6775_read_value(data, data->REG_PWM_MODE[i]) + & data->PWM_MODE_MASK[i]); +- data->pwm_mode[i] = duty_is_dc; ++ data->pwm_mode[i] = !duty_is_dc; + + fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]); + for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) { +@@ -2270,7 +2270,7 @@ show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) + struct nct6775_data *data = nct6775_update_device(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + +- return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]); ++ return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]); + } + + static ssize_t +@@ -2291,9 +2291,9 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, + if (val > 1) + return -EINVAL; + +- /* Setting DC mode is not supported for all chips/channels */ ++ /* Setting DC mode (0) is not supported for all chips/channels */ + if (data->REG_PWM_MODE[nr] == 0) { +- if (val) ++ if (!val) + return -EINVAL; + return count; + } +@@ -2302,7 +2302,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, + data->pwm_mode[nr] = val; + reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]); + reg &= ~data->PWM_MODE_MASK[nr]; +- if (val) ++ if (!val) + reg |= data->PWM_MODE_MASK[nr]; + nct6775_write_value(data, data->REG_PWM_MODE[nr], reg); + mutex_unlock(&data->update_lock); +diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c +index d659a02647d4..c3a8f682f834 100644 +--- a/drivers/hwmon/pmbus/adm1275.c ++++ b/drivers/hwmon/pmbus/adm1275.c +@@ -154,7 +154,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) + const struct adm1275_data *data = to_adm1275_data(info); + int ret = 0; + +- if (page) ++ if (page > 0) + return -ENXIO; + + switch (reg) { +@@ -240,7 +240,7 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, + const struct adm1275_data *data = to_adm1275_data(info); + int ret; + +- if (page) ++ if (page > 0) + return -ENXIO; + + switch (reg) { +diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c +index dd4883a19045..e951f9b87abb 100644 +--- a/drivers/hwmon/pmbus/max8688.c ++++ b/drivers/hwmon/pmbus/max8688.c +@@ -45,7 +45,7 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg) + { + int ret; + +- if (page) ++ if (page > 0) + return -ENXIO; + + switch (reg) { +diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c +index b4dec0841bc2..5c9dea7a40bc 100644 +--- a/drivers/i2c/busses/i2c-mv64xxx.c ++++ b/drivers/i2c/busses/i2c-mv64xxx.c +@@ -848,12 +848,16 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, + */ + if (of_device_is_compatible(np, "marvell,mv78230-i2c")) { + drv_data->offload_enabled = true; +- drv_data->errata_delay = true; ++ /* The delay is only needed in standard mode (100kHz) */ ++ if (bus_freq <= 100000) ++ drv_data->errata_delay = true; + } + + if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) { + drv_data->offload_enabled = false; +- drv_data->errata_delay = true; ++ /* The delay is only needed in standard mode (100kHz) */ ++ if (bus_freq <= 100000) ++ drv_data->errata_delay = true; + } + + if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c")) +diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c +index bf9a2ad296ed..883fe2cdd42c 100644 +--- a/drivers/ide/ide-cd.c ++++ b/drivers/ide/ide-cd.c +@@ -1593,6 +1593,8 @@ static int idecd_open(struct block_device *bdev, fmode_t mode) + struct cdrom_info *info; + int rc = -ENXIO; + ++ check_disk_change(bdev); ++ + mutex_lock(&ide_cd_mutex); + info = ide_cd_get(bdev->bd_disk); + if (!info) +diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c +index 322cb67b07a9..28d18453c950 100644 +--- a/drivers/infiniband/core/multicast.c ++++ b/drivers/infiniband/core/multicast.c +@@ -724,21 +724,19 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, + { + int ret; + u16 gid_index; +- u8 p; +- +- if (rdma_protocol_roce(device, port_num)) { +- ret = ib_find_cached_gid_by_port(device, &rec->port_gid, +- gid_type, port_num, +- ndev, +- &gid_index); +- } else if (rdma_protocol_ib(device, port_num)) { +- ret = ib_find_cached_gid(device, &rec->port_gid, +- IB_GID_TYPE_IB, NULL, &p, +- &gid_index); +- } else { +- ret = -EINVAL; +- } + ++ /* GID table is not based on the netdevice for IB link layer, ++ * so ignore ndev during search. ++ */ ++ if (rdma_protocol_ib(device, port_num)) ++ ndev = NULL; ++ else if (!rdma_protocol_roce(device, port_num)) ++ return -EINVAL; ++ ++ ret = ib_find_cached_gid_by_port(device, &rec->port_gid, ++ gid_type, port_num, ++ ndev, ++ &gid_index); + if (ret) + return ret; + +diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c +index 81b742ca1639..4baf3b864a57 100644 +--- a/drivers/infiniband/core/sa_query.c ++++ b/drivers/infiniband/core/sa_query.c +@@ -1137,10 +1137,9 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num, + + resolved_dev = dev_get_by_index(dev_addr.net, + dev_addr.bound_dev_if); +- if (resolved_dev->flags & IFF_LOOPBACK) { +- dev_put(resolved_dev); +- resolved_dev = idev; +- dev_hold(resolved_dev); ++ if (!resolved_dev) { ++ dev_put(idev); ++ return -ENODEV; + } + ndev = ib_get_ndev_from_path(rec); + rcu_read_lock(); +diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c +index f2f1c9fec0b1..a036d7087ddf 100644 +--- a/drivers/infiniband/core/ucma.c ++++ b/drivers/infiniband/core/ucma.c +@@ -1296,7 +1296,7 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + +- if (unlikely(cmd.optval > KMALLOC_MAX_SIZE)) ++ if (unlikely(cmd.optlen > KMALLOC_MAX_SIZE)) + return -EINVAL; + + optval = memdup_user((void __user *) (unsigned long) cmd.optval, +diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c +index 7853b0caad32..148b313c6471 100644 +--- a/drivers/infiniband/hw/hfi1/chip.c ++++ b/drivers/infiniband/hw/hfi1/chip.c +@@ -5860,6 +5860,7 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd, + u64 status; + u32 sw_index; + int i = 0; ++ unsigned long irq_flags; + + sw_index = dd->hw_to_sw[hw_context]; + if (sw_index >= dd->num_send_contexts) { +@@ -5869,10 +5870,12 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd, + return; + } + sci = &dd->send_contexts[sw_index]; ++ spin_lock_irqsave(&dd->sc_lock, irq_flags); + sc = sci->sc; + if (!sc) { + dd_dev_err(dd, "%s: context %u(%u): no sc?\n", __func__, + sw_index, hw_context); ++ spin_unlock_irqrestore(&dd->sc_lock, irq_flags); + return; + } + +@@ -5894,6 +5897,7 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd, + */ + if (sc->type != SC_USER) + queue_work(dd->pport->hfi1_wq, &sc->halt_work); ++ spin_unlock_irqrestore(&dd->sc_lock, irq_flags); + + /* + * Update the counters for the corresponding status bits. +diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c +index 4b892ca2b13a..095912fb3201 100644 +--- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c ++++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c +@@ -1515,6 +1515,7 @@ static struct ib_mr *i40iw_alloc_mr(struct ib_pd *pd, + err_code = -EOVERFLOW; + goto err; + } ++ stag &= ~I40IW_CQPSQ_STAG_KEY_MASK; + iwmr->stag = stag; + iwmr->ibmr.rkey = stag; + iwmr->ibmr.lkey = stag; +diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c +index 19bc1c2186ff..8d59a5905ee8 100644 +--- a/drivers/infiniband/hw/mlx4/main.c ++++ b/drivers/infiniband/hw/mlx4/main.c +@@ -216,8 +216,6 @@ static int mlx4_ib_update_gids_v1_v2(struct gid_entry *gids, + gid_tbl[i].version = 2; + if (!ipv6_addr_v4mapped((struct in6_addr *)&gids[i].gid)) + gid_tbl[i].type = 1; +- else +- memset(&gid_tbl[i].gid, 0, 12); + } + } + +@@ -363,8 +361,13 @@ static int mlx4_ib_del_gid(struct ib_device *device, + if (!gids) { + ret = -ENOMEM; + } else { +- for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) +- memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid)); ++ for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) { ++ memcpy(&gids[i].gid, ++ &port_gid_table->gids[i].gid, ++ sizeof(union ib_gid)); ++ gids[i].gid_type = ++ port_gid_table->gids[i].gid_type; ++ } + } + } + spin_unlock_bh(&iboe->lock); +diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c +index 3cdcbfbd6a79..abb47e780070 100644 +--- a/drivers/infiniband/hw/mlx5/qp.c ++++ b/drivers/infiniband/hw/mlx5/qp.c +@@ -2809,8 +2809,10 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, + mlx5_ib_qp_disable_pagefaults(qp); + + if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE || +- !optab[mlx5_cur][mlx5_new]) ++ !optab[mlx5_cur][mlx5_new]) { ++ err = -EINVAL; + goto out; ++ } + + op = optab[mlx5_cur][mlx5_new]; + optpar = ib_mask_to_mlx5_opt(attr_mask); +@@ -4610,13 +4612,10 @@ int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd) + int err; + + err = mlx5_core_xrcd_dealloc(dev->mdev, xrcdn); +- if (err) { ++ if (err) + mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn); +- return err; +- } + + kfree(xrcd); +- + return 0; + } + +diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c +index 58e92bce6825..f937873e93df 100644 +--- a/drivers/infiniband/hw/qedr/main.c ++++ b/drivers/infiniband/hw/qedr/main.c +@@ -762,7 +762,8 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, + + dev->num_cnq = dev->ops->rdma_get_min_cnq_msix(cdev); + if (!dev->num_cnq) { +- DP_ERR(dev, "not enough CNQ resources.\n"); ++ DP_ERR(dev, "Failed. At least one CNQ is required.\n"); ++ rc = -ENOMEM; + goto init_err; + } + +diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c +index 35d5b89decb4..cd0408c2b376 100644 +--- a/drivers/infiniband/hw/qedr/verbs.c ++++ b/drivers/infiniband/hw/qedr/verbs.c +@@ -1888,18 +1888,23 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT, 1); + +- qp_params.ack_timeout = attr->timeout; +- if (attr->timeout) { +- u32 temp; +- +- temp = 4096 * (1UL << attr->timeout) / 1000 / 1000; +- /* FW requires [msec] */ +- qp_params.ack_timeout = temp; +- } else { +- /* Infinite */ ++ /* The received timeout value is an exponent used like this: ++ * "12.7.34 LOCAL ACK TIMEOUT ++ * Value representing the transport (ACK) timeout for use by ++ * the remote, expressed as: 4.096 * 2^timeout [usec]" ++ * The FW expects timeout in msec so we need to divide the usec ++ * result by 1000. We'll approximate 1000~2^10, and 4.096 ~ 2^2, ++ * so we get: 2^2 * 2^timeout / 2^10 = 2^(timeout - 8). ++ * The value of zero means infinite so we use a 'max_t' to make ++ * sure that sub 1 msec values will be configured as 1 msec. ++ */ ++ if (attr->timeout) ++ qp_params.ack_timeout = ++ 1 << max_t(int, attr->timeout - 8, 0); ++ else + qp_params.ack_timeout = 0; +- } + } ++ + if (attr_mask & IB_QP_RETRY_CNT) { + SET_FIELD(qp_params.modify_flags, + QED_ROCE_MODIFY_QP_VALID_RETRY_CNT, 1); +@@ -2807,6 +2812,11 @@ int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + + switch (wr->opcode) { + case IB_WR_SEND_WITH_IMM: ++ if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { ++ rc = -EINVAL; ++ *bad_wr = wr; ++ break; ++ } + wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_IMM; + swqe = (struct rdma_sq_send_wqe_1st *)wqe; + swqe->wqe_size = 2; +@@ -2848,6 +2858,11 @@ int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + break; + + case IB_WR_RDMA_WRITE_WITH_IMM: ++ if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { ++ rc = -EINVAL; ++ *bad_wr = wr; ++ break; ++ } + wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM; + rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; + +@@ -3467,7 +3482,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) + { + struct qedr_dev *dev = get_qedr_dev(ibcq->device); + struct qedr_cq *cq = get_qedr_cq(ibcq); +- union rdma_cqe *cqe = cq->latest_cqe; ++ union rdma_cqe *cqe; + u32 old_cons, new_cons; + unsigned long flags; + int update = 0; +@@ -3477,6 +3492,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) + return qedr_gsi_poll_cq(ibcq, num_entries, wc); + + spin_lock_irqsave(&cq->cq_lock, flags); ++ cqe = cq->latest_cqe; + old_cons = qed_chain_get_cons_idx_u32(&cq->pbl); + while (num_entries && is_valid_cqe(cq, cqe)) { + struct qedr_qp *qp; +diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c +index 0df7d4504c06..17c5bc7e8957 100644 +--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c ++++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c +@@ -2119,6 +2119,9 @@ static struct net_device *ipoib_add_port(const char *format, + goto event_failed; + } + ++ /* call event handler to ensure pkey in sync */ ++ queue_work(ipoib_workqueue, &priv->flush_heavy); ++ + result = register_netdev(priv->dev); + if (result) { + printk(KERN_WARNING "%s: couldn't register ipoib port %d; error %d\n", +diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c +index bee267424972..5cbf17aa8443 100644 +--- a/drivers/input/mouse/psmouse-base.c ++++ b/drivers/input/mouse/psmouse-base.c +@@ -937,6 +937,21 @@ static void psmouse_apply_defaults(struct psmouse *psmouse) + psmouse->pt_deactivate = NULL; + } + ++static bool psmouse_do_detect(int (*detect)(struct psmouse *, bool), ++ struct psmouse *psmouse, bool allow_passthrough, ++ bool set_properties) ++{ ++ if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU && ++ !allow_passthrough) { ++ return false; ++ } ++ ++ if (set_properties) ++ psmouse_apply_defaults(psmouse); ++ ++ return detect(psmouse, set_properties) == 0; ++} ++ + static bool psmouse_try_protocol(struct psmouse *psmouse, + enum psmouse_type type, + unsigned int *max_proto, +@@ -948,15 +963,8 @@ static bool psmouse_try_protocol(struct psmouse *psmouse, + if (!proto) + return false; + +- if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU && +- !proto->try_passthru) { +- return false; +- } +- +- if (set_properties) +- psmouse_apply_defaults(psmouse); +- +- if (proto->detect(psmouse, set_properties) != 0) ++ if (!psmouse_do_detect(proto->detect, psmouse, proto->try_passthru, ++ set_properties)) + return false; + + if (set_properties && proto->init && init_allowed) { +@@ -988,8 +996,8 @@ static int psmouse_extensions(struct psmouse *psmouse, + * Always check for focaltech, this is safe as it uses pnp-id + * matching. + */ +- if (psmouse_try_protocol(psmouse, PSMOUSE_FOCALTECH, +- &max_proto, set_properties, false)) { ++ if (psmouse_do_detect(focaltech_detect, ++ psmouse, false, set_properties)) { + if (max_proto > PSMOUSE_IMEX && + IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH) && + (!set_properties || focaltech_init(psmouse) == 0)) { +@@ -1035,8 +1043,8 @@ static int psmouse_extensions(struct psmouse *psmouse, + * probing for IntelliMouse. + */ + if (max_proto > PSMOUSE_PS2 && +- psmouse_try_protocol(psmouse, PSMOUSE_SYNAPTICS, &max_proto, +- set_properties, false)) { ++ psmouse_do_detect(synaptics_detect, ++ psmouse, false, set_properties)) { + synaptics_hardware = true; + + if (max_proto > PSMOUSE_IMEX) { +diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c +index 88bbc8ccc5e3..1612d3a22d42 100644 +--- a/drivers/iommu/intel-iommu.c ++++ b/drivers/iommu/intel-iommu.c +@@ -1612,8 +1612,7 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, + * flush. However, device IOTLB doesn't need to be flushed in this case. + */ + if (!cap_caching_mode(iommu->cap) || !map) +- iommu_flush_dev_iotlb(get_iommu_domain(iommu, did), +- addr, mask); ++ iommu_flush_dev_iotlb(domain, addr, mask); + } + + static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu) +diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c +index aee1c60d7ab5..cc58b1b272c0 100644 +--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c ++++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c +@@ -133,6 +133,8 @@ static int __init its_pci_of_msi_init(void) + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { ++ if (!of_device_is_available(np)) ++ continue; + if (!of_property_read_bool(np, "msi-controller")) + continue; + +diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c +index 470b4aa7d62c..e4768fcdc672 100644 +--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c ++++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c +@@ -80,6 +80,8 @@ static int __init its_pmsi_init(void) + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { ++ if (!of_device_is_available(np)) ++ continue; + if (!of_property_read_bool(np, "msi-controller")) + continue; + +diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c +index ac15e5d5d9b2..558c7589c329 100644 +--- a/drivers/irqchip/irq-gic-v3-its.c ++++ b/drivers/irqchip/irq-gic-v3-its.c +@@ -1807,6 +1807,8 @@ static int __init its_of_probe(struct device_node *node) + + for (np = of_find_matching_node(node, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { ++ if (!of_device_is_available(np)) ++ continue; + if (!of_property_read_bool(np, "msi-controller")) { + pr_warn("%s: no msi-controller property, ITS ignored\n", + np->full_name); +diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c +index 100c80e48190..0b1d5bdd0862 100644 +--- a/drivers/irqchip/irq-gic-v3.c ++++ b/drivers/irqchip/irq-gic-v3.c +@@ -601,7 +601,7 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq) + MPIDR_TO_SGI_AFFINITY(cluster_id, 1) | + tlist << ICC_SGI1R_TARGET_LIST_SHIFT); + +- pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); ++ pr_devel("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); + gic_write_sgi1r(val); + } + +diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c +index 775527135b93..25852e399ab2 100644 +--- a/drivers/macintosh/rack-meter.c ++++ b/drivers/macintosh/rack-meter.c +@@ -154,8 +154,8 @@ static void rackmeter_do_pause(struct rackmeter *rm, int pause) + DBDMA_DO_STOP(rm->dma_regs); + return; + } +- memset(rdma->buf1, 0, ARRAY_SIZE(rdma->buf1)); +- memset(rdma->buf2, 0, ARRAY_SIZE(rdma->buf2)); ++ memset(rdma->buf1, 0, sizeof(rdma->buf1)); ++ memset(rdma->buf2, 0, sizeof(rdma->buf2)); + + rm->dma_buf_v->mark = 0; + +diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c +index d23337e8c4ee..dd344ee9e62b 100644 +--- a/drivers/md/bcache/alloc.c ++++ b/drivers/md/bcache/alloc.c +@@ -284,8 +284,10 @@ do { \ + break; \ + \ + mutex_unlock(&(ca)->set->bucket_lock); \ +- if (kthread_should_stop()) \ ++ if (kthread_should_stop()) { \ ++ set_current_state(TASK_RUNNING); \ + return 0; \ ++ } \ + \ + schedule(); \ + mutex_lock(&(ca)->set->bucket_lock); \ +diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h +index 02619cabda8b..7fe7df56fa33 100644 +--- a/drivers/md/bcache/bcache.h ++++ b/drivers/md/bcache/bcache.h +@@ -904,7 +904,7 @@ void bcache_write_super(struct cache_set *); + + int bch_flash_dev_create(struct cache_set *c, uint64_t size); + +-int bch_cached_dev_attach(struct cached_dev *, struct cache_set *); ++int bch_cached_dev_attach(struct cached_dev *, struct cache_set *, uint8_t *); + void bch_cached_dev_detach(struct cached_dev *); + void bch_cached_dev_run(struct cached_dev *); + void bcache_device_stop(struct bcache_device *); +diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c +index cac297f8170e..cf7c68920b33 100644 +--- a/drivers/md/bcache/btree.c ++++ b/drivers/md/bcache/btree.c +@@ -1864,14 +1864,17 @@ void bch_initial_gc_finish(struct cache_set *c) + */ + for_each_cache(ca, c, i) { + for_each_bucket(b, ca) { +- if (fifo_full(&ca->free[RESERVE_PRIO])) ++ if (fifo_full(&ca->free[RESERVE_PRIO]) && ++ fifo_full(&ca->free[RESERVE_BTREE])) + break; + + if (bch_can_invalidate_bucket(ca, b) && + !GC_MARK(b)) { + __bch_invalidate_one_bucket(ca, b); +- fifo_push(&ca->free[RESERVE_PRIO], +- b - ca->buckets); ++ if (!fifo_push(&ca->free[RESERVE_PRIO], ++ b - ca->buckets)) ++ fifo_push(&ca->free[RESERVE_BTREE], ++ b - ca->buckets); + } + } + } +diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c +index edb8d1a1a69f..bd6f6f4b4256 100644 +--- a/drivers/md/bcache/request.c ++++ b/drivers/md/bcache/request.c +@@ -633,11 +633,11 @@ static void do_bio_hook(struct search *s, struct bio *orig_bio) + static void search_free(struct closure *cl) + { + struct search *s = container_of(cl, struct search, cl); +- bio_complete(s); + + if (s->iop.bio) + bio_put(s->iop.bio); + ++ bio_complete(s); + closure_debug_destroy(cl); + mempool_free(s, s->d->c->search); + } +diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c +index 4af7cd423c71..894992ae9be0 100644 +--- a/drivers/md/bcache/super.c ++++ b/drivers/md/bcache/super.c +@@ -938,7 +938,8 @@ void bch_cached_dev_detach(struct cached_dev *dc) + cached_dev_put(dc); + } + +-int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) ++int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, ++ uint8_t *set_uuid) + { + uint32_t rtime = cpu_to_le32(get_seconds()); + struct uuid_entry *u; +@@ -947,7 +948,8 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) + + bdevname(dc->bdev, buf); + +- if (memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16)) ++ if ((set_uuid && memcmp(set_uuid, c->sb.set_uuid, 16)) || ++ (!set_uuid && memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16))) + return -ENOENT; + + if (dc->disk.c) { +@@ -1191,7 +1193,7 @@ static void register_bdev(struct cache_sb *sb, struct page *sb_page, + + list_add(&dc->list, &uncached_devices); + list_for_each_entry(c, &bch_cache_sets, list) +- bch_cached_dev_attach(dc, c); ++ bch_cached_dev_attach(dc, c, NULL); + + if (BDEV_STATE(&dc->sb) == BDEV_STATE_NONE || + BDEV_STATE(&dc->sb) == BDEV_STATE_STALE) +@@ -1714,7 +1716,7 @@ static void run_cache_set(struct cache_set *c) + bcache_write_super(c); + + list_for_each_entry_safe(dc, t, &uncached_devices, list) +- bch_cached_dev_attach(dc, c); ++ bch_cached_dev_attach(dc, c, NULL); + + flash_devs_run(c); + +@@ -1831,6 +1833,7 @@ void bch_cache_release(struct kobject *kobj) + static int cache_alloc(struct cache *ca) + { + size_t free; ++ size_t btree_buckets; + struct bucket *b; + + __module_get(THIS_MODULE); +@@ -1840,9 +1843,19 @@ static int cache_alloc(struct cache *ca) + ca->journal.bio.bi_max_vecs = 8; + ca->journal.bio.bi_io_vec = ca->journal.bio.bi_inline_vecs; + ++ /* ++ * when ca->sb.njournal_buckets is not zero, journal exists, ++ * and in bch_journal_replay(), tree node may split, ++ * so bucket of RESERVE_BTREE type is needed, ++ * the worst situation is all journal buckets are valid journal, ++ * and all the keys need to replay, ++ * so the number of RESERVE_BTREE type buckets should be as much ++ * as journal buckets ++ */ ++ btree_buckets = ca->sb.njournal_buckets ?: 8; + free = roundup_pow_of_two(ca->sb.nbuckets) >> 10; + +- if (!init_fifo(&ca->free[RESERVE_BTREE], 8, GFP_KERNEL) || ++ if (!init_fifo(&ca->free[RESERVE_BTREE], btree_buckets, GFP_KERNEL) || + !init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) || + !init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) || + !init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) || +diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c +index 4fbb5532f24c..5a5c1f1bd8a5 100644 +--- a/drivers/md/bcache/sysfs.c ++++ b/drivers/md/bcache/sysfs.c +@@ -191,7 +191,7 @@ STORE(__cached_dev) + { + struct cached_dev *dc = container_of(kobj, struct cached_dev, + disk.kobj); +- ssize_t v = size; ++ ssize_t v; + struct cache_set *c; + struct kobj_uevent_env *env; + +@@ -263,17 +263,20 @@ STORE(__cached_dev) + } + + if (attr == &sysfs_attach) { +- if (bch_parse_uuid(buf, dc->sb.set_uuid) < 16) ++ uint8_t set_uuid[16]; ++ ++ if (bch_parse_uuid(buf, set_uuid) < 16) + return -EINVAL; + ++ v = -ENOENT; + list_for_each_entry(c, &bch_cache_sets, list) { +- v = bch_cached_dev_attach(dc, c); ++ v = bch_cached_dev_attach(dc, c, set_uuid); + if (!v) + return size; + } + + pr_err("Can't attach %s: cache set not found", buf); +- size = v; ++ return v; + } + + if (attr == &sysfs_detach && dc->disk.c) +diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c +index 4ce2b19fe120..bb7aa31c2a08 100644 +--- a/drivers/md/bcache/writeback.c ++++ b/drivers/md/bcache/writeback.c +@@ -420,18 +420,27 @@ static int bch_writeback_thread(void *arg) + + while (!kthread_should_stop()) { + down_write(&dc->writeback_lock); +- if (!atomic_read(&dc->has_dirty) || +- (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) && +- !dc->writeback_running)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ /* ++ * If the bache device is detaching, skip here and continue ++ * to perform writeback. Otherwise, if no dirty data on cache, ++ * or there is dirty data on cache but writeback is disabled, ++ * the writeback thread should sleep here and wait for others ++ * to wake up it. ++ */ ++ if (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) && ++ (!atomic_read(&dc->has_dirty) || !dc->writeback_running)) { + up_write(&dc->writeback_lock); +- set_current_state(TASK_INTERRUPTIBLE); + +- if (kthread_should_stop()) ++ if (kthread_should_stop()) { ++ set_current_state(TASK_RUNNING); + return 0; ++ } + + schedule(); + continue; + } ++ set_current_state(TASK_RUNNING); + + searched_full_index = refill_dirty(dc); + +@@ -441,6 +450,14 @@ static int bch_writeback_thread(void *arg) + cached_dev_put(dc); + SET_BDEV_STATE(&dc->sb, BDEV_STATE_CLEAN); + bch_write_bdev_super(dc, NULL); ++ /* ++ * If bcache device is detaching via sysfs interface, ++ * writeback thread should stop after there is no dirty ++ * data on cache. BCACHE_DEV_DETACHING flag is set in ++ * bch_cached_dev_detach(). ++ */ ++ if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) ++ break; + } + + up_write(&dc->writeback_lock); +diff --git a/drivers/md/md.c b/drivers/md/md.c +index a7bc70334f0e..cae8f3c12e32 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -8200,6 +8200,19 @@ void md_do_sync(struct md_thread *thread) + set_mask_bits(&mddev->flags, 0, + BIT(MD_CHANGE_PENDING) | BIT(MD_CHANGE_DEVS)); + ++ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && ++ !test_bit(MD_RECOVERY_INTR, &mddev->recovery) && ++ mddev->delta_disks > 0 && ++ mddev->pers->finish_reshape && ++ mddev->pers->size && ++ mddev->queue) { ++ mddev_lock_nointr(mddev); ++ md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0)); ++ mddev_unlock(mddev); ++ set_capacity(mddev->gendisk, mddev->array_sectors); ++ revalidate_disk(mddev->gendisk); ++ } ++ + spin_lock(&mddev->lock); + if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { + /* We completed so min/max setting can be forgotten if used. */ +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 81a78757bc78..998102697619 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -1673,6 +1673,17 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) + struct md_rdev *repl = + conf->mirrors[conf->raid_disks + number].rdev; + freeze_array(conf, 0); ++ if (atomic_read(&repl->nr_pending)) { ++ /* It means that some queued IO of retry_list ++ * hold repl. Thus, we cannot set replacement ++ * as NULL, avoiding rdev NULL pointer ++ * dereference in sync_request_write and ++ * handle_write_finished. ++ */ ++ err = -EBUSY; ++ unfreeze_array(conf); ++ goto abort; ++ } + clear_bit(Replacement, &repl->flags); + p->rdev = repl; + conf->mirrors[conf->raid_disks + number].rdev = NULL; +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index 6a7b9b1dcfe3..b138b5cba286 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -2636,7 +2636,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) + for (m = 0; m < conf->copies; m++) { + int dev = r10_bio->devs[m].devnum; + rdev = conf->mirrors[dev].rdev; +- if (r10_bio->devs[m].bio == NULL) ++ if (r10_bio->devs[m].bio == NULL || ++ r10_bio->devs[m].bio->bi_end_io == NULL) + continue; + if (!r10_bio->devs[m].bio->bi_error) { + rdev_clear_badblocks( +@@ -2651,7 +2652,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) + md_error(conf->mddev, rdev); + } + rdev = conf->mirrors[dev].replacement; +- if (r10_bio->devs[m].repl_bio == NULL) ++ if (r10_bio->devs[m].repl_bio == NULL || ++ r10_bio->devs[m].repl_bio->bi_end_io == NULL) + continue; + + if (!r10_bio->devs[m].repl_bio->bi_error) { +@@ -4682,17 +4684,11 @@ static void raid10_finish_reshape(struct mddev *mddev) + return; + + if (mddev->delta_disks > 0) { +- sector_t size = raid10_size(mddev, 0, 0); +- md_set_array_sectors(mddev, size); + if (mddev->recovery_cp > mddev->resync_max_sectors) { + mddev->recovery_cp = mddev->resync_max_sectors; + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + } +- mddev->resync_max_sectors = size; +- if (mddev->queue) { +- set_capacity(mddev->gendisk, mddev->array_sectors); +- revalidate_disk(mddev->gendisk); +- } ++ mddev->resync_max_sectors = mddev->array_sectors; + } else { + int d; + rcu_read_lock(); +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 86ba7851e881..e43b9f80bb1d 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -2049,15 +2049,16 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp) + static int grow_stripes(struct r5conf *conf, int num) + { + struct kmem_cache *sc; ++ size_t namelen = sizeof(conf->cache_name[0]); + int devs = max(conf->raid_disks, conf->previous_raid_disks); + + if (conf->mddev->gendisk) +- sprintf(conf->cache_name[0], ++ snprintf(conf->cache_name[0], namelen, + "raid%d-%s", conf->level, mdname(conf->mddev)); + else +- sprintf(conf->cache_name[0], ++ snprintf(conf->cache_name[0], namelen, + "raid%d-%p", conf->level, conf->mddev); +- sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]); ++ snprintf(conf->cache_name[1], namelen, "%.27s-alt", conf->cache_name[0]); + + conf->active_name = 0; + sc = kmem_cache_create(conf->cache_name[conf->active_name], +@@ -7614,13 +7615,7 @@ static void raid5_finish_reshape(struct mddev *mddev) + + if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { + +- if (mddev->delta_disks > 0) { +- md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); +- if (mddev->queue) { +- set_capacity(mddev->gendisk, mddev->array_sectors); +- revalidate_disk(mddev->gendisk); +- } +- } else { ++ if (mddev->delta_disks <= 0) { + int d; + spin_lock_irq(&conf->device_lock); + mddev->degraded = calc_degraded(conf); +diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c +index 50dd6bd02951..524c8e0b72fd 100644 +--- a/drivers/mmc/host/sdhci-iproc.c ++++ b/drivers/mmc/host/sdhci-iproc.c +@@ -33,6 +33,8 @@ struct sdhci_iproc_host { + const struct sdhci_iproc_data *data; + u32 shadow_cmd; + u32 shadow_blk; ++ bool is_cmd_shadowed; ++ bool is_blk_shadowed; + }; + + #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) +@@ -48,8 +50,22 @@ static inline u32 sdhci_iproc_readl(struct sdhci_host *host, int reg) + + static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg) + { +- u32 val = sdhci_iproc_readl(host, (reg & ~3)); +- u16 word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host); ++ u32 val; ++ u16 word; ++ ++ if ((reg == SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed) { ++ /* Get the saved transfer mode */ ++ val = iproc_host->shadow_cmd; ++ } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && ++ iproc_host->is_blk_shadowed) { ++ /* Get the saved block info */ ++ val = iproc_host->shadow_blk; ++ } else { ++ val = sdhci_iproc_readl(host, (reg & ~3)); ++ } ++ word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; + return word; + } + +@@ -105,13 +121,15 @@ static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg) + + if (reg == SDHCI_COMMAND) { + /* Write the block now as we are issuing a command */ +- if (iproc_host->shadow_blk != 0) { ++ if (iproc_host->is_blk_shadowed) { + sdhci_iproc_writel(host, iproc_host->shadow_blk, + SDHCI_BLOCK_SIZE); +- iproc_host->shadow_blk = 0; ++ iproc_host->is_blk_shadowed = false; + } + oldval = iproc_host->shadow_cmd; +- } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { ++ iproc_host->is_cmd_shadowed = false; ++ } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && ++ iproc_host->is_blk_shadowed) { + /* Block size and count are stored in shadow reg */ + oldval = iproc_host->shadow_blk; + } else { +@@ -123,9 +141,11 @@ static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg) + if (reg == SDHCI_TRANSFER_MODE) { + /* Save the transfer mode until the command is issued */ + iproc_host->shadow_cmd = newval; ++ iproc_host->is_cmd_shadowed = true; + } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { + /* Save the block info until the command is issued */ + iproc_host->shadow_blk = newval; ++ iproc_host->is_blk_shadowed = true; + } else { + /* Command or other regular 32-bit write */ + sdhci_iproc_writel(host, newval, reg & ~3); +@@ -176,7 +196,6 @@ static const struct sdhci_iproc_data iproc_data = { + .caps1 = SDHCI_DRIVER_TYPE_C | + SDHCI_DRIVER_TYPE_D | + SDHCI_SUPPORT_DDR50, +- .mmc_caps = MMC_CAP_1_8V_DDR, + }; + + static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = { +diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c +index 49f4cafe5438..86a32fe58468 100644 +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -529,7 +529,8 @@ static void bgmac_dma_tx_ring_free(struct bgmac *bgmac, + int i; + + for (i = 0; i < BGMAC_TX_RING_SLOTS; i++) { +- int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN; ++ u32 ctl1 = le32_to_cpu(dma_desc[i].ctl1); ++ unsigned int len = ctl1 & BGMAC_DESC_CTL1_LEN; + + slot = &ring->slots[i]; + dev_kfree_skb(slot->skb); +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 3aa993bbafd9..ca57eb56c717 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -3401,6 +3401,9 @@ static int bnxt_hwrm_vnic_set_tpa(struct bnxt *bp, u16 vnic_id, u32 tpa_flags) + struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; + struct hwrm_vnic_tpa_cfg_input req = {0}; + ++ if (vnic->fw_vnic_id == INVALID_HW_RING_ID) ++ return 0; ++ + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_TPA_CFG, -1, -1); + + if (tpa_flags) { +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +index 3ec32d7c5866..c395b21cb57b 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +@@ -836,8 +836,6 @@ static int setup_fw_sge_queues(struct adapter *adap) + + err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], + adap->msi_idx, NULL, fwevtq_handler, NULL, -1); +- if (err) +- t4_free_sge_resources(adap); + return err; + } + +@@ -4940,6 +4938,13 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + if (err) + goto out_free_dev; + ++ err = setup_fw_sge_queues(adapter); ++ if (err) { ++ dev_err(adapter->pdev_dev, ++ "FW sge queue allocation failed, err %d", err); ++ goto out_free_dev; ++ } ++ + /* + * The card is now ready to go. If any errors occur during device + * registration we do not fail the whole card but rather proceed only +@@ -4983,7 +4988,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + } + + print_adapter_info(adapter); +- setup_fw_sge_queues(adapter); + return 0; + + sriov: +@@ -5035,6 +5039,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + #endif + + out_free_dev: ++ t4_free_sge_resources(adapter); + free_some_resources(adapter); + if (adapter->flags & USING_MSIX) + free_msix_info(adapter); +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +index 2471ff465d5c..23d6c44dc459 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +@@ -342,6 +342,7 @@ static void free_queues_uld(struct adapter *adap, unsigned int uld_type) + { + struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; + ++ adap->sge.uld_rxq_info[uld_type] = NULL; + kfree(rxq_info->rspq_id); + kfree(rxq_info->uldrxq); + kfree(rxq_info); +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index 48f82ab6c25b..dda63b26e370 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -1726,6 +1726,8 @@ static int enic_open(struct net_device *netdev) + } + + for (i = 0; i < enic->rq_count; i++) { ++ /* enable rq before updating rq desc */ ++ vnic_rq_enable(&enic->rq[i]); + vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf); + /* Need at least one buffer on ring to get going */ + if (vnic_rq_desc_used(&enic->rq[i]) == 0) { +@@ -1737,8 +1739,6 @@ static int enic_open(struct net_device *netdev) + + for (i = 0; i < enic->wq_count; i++) + vnic_wq_enable(&enic->wq[i]); +- for (i = 0; i < enic->rq_count; i++) +- vnic_rq_enable(&enic->rq[i]); + + if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic)) + enic_dev_add_station_addr(enic); +@@ -1765,8 +1765,12 @@ static int enic_open(struct net_device *netdev) + return 0; + + err_out_free_rq: +- for (i = 0; i < enic->rq_count; i++) ++ for (i = 0; i < enic->rq_count; i++) { ++ err = vnic_rq_disable(&enic->rq[i]); ++ if (err) ++ return err; + vnic_rq_clean(&enic->rq[i], enic_free_rq_buf); ++ } + enic_dev_notify_unset(enic); + err_out_free_intr: + enic_unset_affinity_hint(enic); +diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c +index c88918c4c5f3..641b916f122b 100644 +--- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c ++++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c +@@ -1036,7 +1036,7 @@ int dtsec_add_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr) + set_bucket(dtsec->regs, bucket, true); + + /* Create element to be added to the driver hash table */ +- hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL); ++ hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC); + if (!hash_entry) + return -ENOMEM; + hash_entry->addr = addr; +diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c +index e3b41ba95168..60bd1b36df60 100644 +--- a/drivers/net/ethernet/freescale/gianfar.c ++++ b/drivers/net/ethernet/freescale/gianfar.c +@@ -2935,7 +2935,7 @@ static irqreturn_t gfar_transmit(int irq, void *grp_id) + static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, + struct sk_buff *skb, bool first) + { +- unsigned int size = lstatus & BD_LENGTH_MASK; ++ int size = lstatus & BD_LENGTH_MASK; + struct page *page = rxb->page; + bool last = !!(lstatus & BD_LFLAG(RXBD_LAST)); + +@@ -2950,11 +2950,16 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, + if (last) + size -= skb->len; + +- /* in case the last fragment consisted only of the FCS */ ++ /* Add the last fragment if it contains something other than ++ * the FCS, otherwise drop it and trim off any part of the FCS ++ * that was already received. ++ */ + if (size > 0) + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + rxb->page_offset + RXBUF_ALIGNMENT, + size, GFAR_RXB_TRUESIZE); ++ else if (size < 0) ++ pskb_trim(skb, skb->len + size); + } + + /* try reuse page */ +@@ -3070,9 +3075,6 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) + if (ndev->features & NETIF_F_RXCSUM) + gfar_rx_checksum(skb, fcb); + +- /* Tell the skb what kind of packet this is */ +- skb->protocol = eth_type_trans(skb, ndev); +- + /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here. + * Even if vlan rx accel is disabled, on some chips + * RXFCB_VLN is pseudo randomly set. +@@ -3143,13 +3145,15 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) + continue; + } + ++ gfar_process_frame(ndev, skb); ++ + /* Increment the number of packets */ + total_pkts++; + total_bytes += skb->len; + + skb_record_rx_queue(skb, rx_queue->qindex); + +- gfar_process_frame(ndev, skb); ++ skb->protocol = eth_type_trans(skb, ndev); + + /* Send the packet up the stack */ + napi_gro_receive(&rx_queue->grp->napi_rx, skb); +diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c +index 49094c965697..897a87ae8655 100644 +--- a/drivers/net/ethernet/ibm/ibmvnic.c ++++ b/drivers/net/ethernet/ibm/ibmvnic.c +@@ -994,6 +994,7 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget) + netdev_err(netdev, "rx error %x\n", next->rx_comp.rc); + /* free the entry */ + next->rx_comp.first = 0; ++ dev_kfree_skb_any(rx_buff->skb); + remove_buff_from_pool(adapter, rx_buff); + break; + } +diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c +index 8a48656a376b..7ddac956ffb5 100644 +--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c ++++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c +@@ -1600,7 +1600,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) +- return -E1000_ERR_CONFIG; ++ return 1; + + /* Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to +diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c +index f457c5703d0c..db735644b312 100644 +--- a/drivers/net/ethernet/intel/e1000e/mac.c ++++ b/drivers/net/ethernet/intel/e1000e/mac.c +@@ -450,7 +450,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) +- return -E1000_ERR_CONFIG; ++ return 1; + + /* Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 825ec8f710e7..9c95222e6536 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -2331,8 +2331,8 @@ static int e1000_alloc_ring_dma(struct e1000_adapter *adapter, + { + struct pci_dev *pdev = adapter->pdev; + +- ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma, +- GFP_KERNEL); ++ ring->desc = dma_zalloc_coherent(&pdev->dev, ring->size, &ring->dma, ++ GFP_KERNEL); + if (!ring->desc) + return -ENOMEM; + +diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +index 05629381be6b..ea5ea653e1db 100644 +--- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c ++++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +@@ -803,8 +803,12 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) + if (vid >= VLAN_N_VID) + return -EINVAL; + +- /* Verify we have permission to add VLANs */ +- if (hw->mac.vlan_override) ++ /* Verify that we have permission to add VLANs. If this is a request ++ * to remove a VLAN, we still want to allow the user to remove the ++ * VLAN device. In that case, we need to clear the bit in the ++ * active_vlans bitmask. ++ */ ++ if (set && hw->mac.vlan_override) + return -EACCES; + + /* update active_vlans bitmask */ +@@ -823,6 +827,12 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) + rx_ring->vid &= ~FM10K_VLAN_CLEAR; + } + ++ /* If our VLAN has been overridden, there is no reason to send VLAN ++ * removal requests as they will be silently ignored. ++ */ ++ if (hw->mac.vlan_override) ++ return 0; ++ + /* Do not remove default VLAN ID related entries from VLAN and MAC + * tables + */ +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index fa463268d019..17b81780d12f 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -1080,6 +1080,7 @@ static void mvneta_port_up(struct mvneta_port *pp) + } + mvreg_write(pp, MVNETA_TXQ_CMD, q_map); + ++ q_map = 0; + /* Enable all initialized RXQs. */ + for (queue = 0; queue < rxq_number; queue++) { + struct mvneta_rx_queue *rxq = &pp->rxqs[queue]; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +index 4c3f1cb7e2c9..6631fb0782d7 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +@@ -1765,7 +1765,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) + + cmd->checksum_disabled = 1; + cmd->max_reg_cmds = (1 << cmd->log_sz) - 1; +- cmd->bitmask = (1 << cmd->max_reg_cmds) - 1; ++ cmd->bitmask = (1UL << cmd->max_reg_cmds) - 1; + + cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16; + if (cmd->cmdif_rev > CMD_IF_REV) { +diff --git a/drivers/net/ethernet/qualcomm/emac/emac-mac.c b/drivers/net/ethernet/qualcomm/emac/emac-mac.c +index f683bfbd9986..9d223ff65071 100644 +--- a/drivers/net/ethernet/qualcomm/emac/emac-mac.c ++++ b/drivers/net/ethernet/qualcomm/emac/emac-mac.c +@@ -1250,9 +1250,9 @@ void emac_mac_tx_process(struct emac_adapter *adpt, struct emac_tx_queue *tx_q) + while (tx_q->tpd.consume_idx != hw_consume_idx) { + tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.consume_idx); + if (tpbuf->dma_addr) { +- dma_unmap_single(adpt->netdev->dev.parent, +- tpbuf->dma_addr, tpbuf->length, +- DMA_TO_DEVICE); ++ dma_unmap_page(adpt->netdev->dev.parent, ++ tpbuf->dma_addr, tpbuf->length, ++ DMA_TO_DEVICE); + tpbuf->dma_addr = 0; + } + +@@ -1409,9 +1409,11 @@ static void emac_tx_fill_tpd(struct emac_adapter *adpt, + + tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx); + tpbuf->length = mapped_len; +- tpbuf->dma_addr = dma_map_single(adpt->netdev->dev.parent, +- skb->data, tpbuf->length, +- DMA_TO_DEVICE); ++ tpbuf->dma_addr = dma_map_page(adpt->netdev->dev.parent, ++ virt_to_page(skb->data), ++ offset_in_page(skb->data), ++ tpbuf->length, ++ DMA_TO_DEVICE); + ret = dma_mapping_error(adpt->netdev->dev.parent, + tpbuf->dma_addr); + if (ret) +@@ -1427,9 +1429,12 @@ static void emac_tx_fill_tpd(struct emac_adapter *adpt, + if (mapped_len < len) { + tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx); + tpbuf->length = len - mapped_len; +- tpbuf->dma_addr = dma_map_single(adpt->netdev->dev.parent, +- skb->data + mapped_len, +- tpbuf->length, DMA_TO_DEVICE); ++ tpbuf->dma_addr = dma_map_page(adpt->netdev->dev.parent, ++ virt_to_page(skb->data + ++ mapped_len), ++ offset_in_page(skb->data + ++ mapped_len), ++ tpbuf->length, DMA_TO_DEVICE); + ret = dma_mapping_error(adpt->netdev->dev.parent, + tpbuf->dma_addr); + if (ret) +diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c +index 8b0016a785c0..734caa7a557b 100644 +--- a/drivers/net/ethernet/smsc/smsc911x.c ++++ b/drivers/net/ethernet/smsc/smsc911x.c +@@ -2330,14 +2330,14 @@ static int smsc911x_drv_remove(struct platform_device *pdev) + pdata = netdev_priv(dev); + BUG_ON(!pdata); + BUG_ON(!pdata->ioaddr); +- WARN_ON(dev->phydev); + + SMSC_TRACE(pdata, ifdown, "Stopping driver"); + ++ unregister_netdev(dev); ++ + mdiobus_unregister(pdata->mii_bus); + mdiobus_free(pdata->mii_bus); + +- unregister_netdev(dev); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "smsc911x-memory"); + if (!res) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +index ffaed1f35efe..f356a44bcb81 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +@@ -118,7 +118,7 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac) + snprintf(clk_name, sizeof(clk_name), "%s#m250_sel", dev_name(dev)); + init.name = clk_name; + init.ops = &clk_mux_ops; +- init.flags = 0; ++ init.flags = CLK_SET_RATE_PARENT; + init.parent_names = mux_parent_names; + init.num_parents = MUX_CLK_NUM_PARENTS; + +@@ -146,7 +146,9 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac) + dwmac->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT; + dwmac->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH; + dwmac->m250_div.hw.init = &init; +- dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO; ++ dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO | ++ CLK_DIVIDER_ROUND_CLOSEST; + + dwmac->m250_div_clk = devm_clk_register(dev, &dwmac->m250_div.hw); + if (WARN_ON(IS_ERR(dwmac->m250_div_clk))) +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index c212d1dd8bfd..b3bc1287b2a7 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -1343,6 +1343,11 @@ static void stmmac_tx_clean(struct stmmac_priv *priv) + if (unlikely(status & tx_dma_own)) + break; + ++ /* Make sure descriptor fields are read after reading ++ * the own bit. ++ */ ++ dma_rmb(); ++ + /* Just consider the last segment and ...*/ + if (likely(!(status & tx_not_ls))) { + /* ... verify the status error condition */ +@@ -2136,8 +2141,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) + tcp_hdrlen(skb) / 4, (skb->len - proto_hdr_len)); + + /* If context desc is used to change MSS */ +- if (mss_desc) ++ if (mss_desc) { ++ /* Make sure that first descriptor has been completely ++ * written, including its own bit. This is because MSS is ++ * actually before first descriptor, so we need to make ++ * sure that MSS's own bit is the last thing written. ++ */ ++ dma_wmb(); + priv->hw->desc->set_tx_owner(mss_desc); ++ } + + /* The own bit must be the latest setting done when prepare the + * descriptor and then barrier is needed to make sure that +diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c +index a2f9b47de187..e36c700c78d4 100644 +--- a/drivers/net/ethernet/sun/sunvnet.c ++++ b/drivers/net/ethernet/sun/sunvnet.c +@@ -198,7 +198,7 @@ static struct vnet *vnet_new(const u64 *local_mac, + dev->ethtool_ops = &vnet_ethtool_ops; + dev->watchdog_timeo = VNET_TX_TIMEOUT; + +- dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE | ++ dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_ALL_TSO | + NETIF_F_HW_CSUM | NETIF_F_SG; + dev->features = dev->hw_features; + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index e8ad4d060da7..6237236b7c4c 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -1384,7 +1384,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, + /* the macvlan port may be freed by macvlan_uninit when fail to register. + * so we destroy the macvlan port only when it's valid. + */ +- if (create && macvlan_port_get_rtnl(dev)) ++ if (create && macvlan_port_get_rtnl(lowerdev)) + macvlan_port_destroy(port->dev); + return err; + } +diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c +index b88f7d65953d..482ea404a2d4 100644 +--- a/drivers/net/phy/dp83640.c ++++ b/drivers/net/phy/dp83640.c +@@ -1205,6 +1205,23 @@ static void dp83640_remove(struct phy_device *phydev) + kfree(dp83640); + } + ++static int dp83640_soft_reset(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = genphy_soft_reset(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* From DP83640 datasheet: "Software driver code must wait 3 us ++ * following a software reset before allowing further serial MII ++ * operations with the DP83640." ++ */ ++ udelay(10); /* Taking udelay inaccuracy into account */ ++ ++ return 0; ++} ++ + static int dp83640_config_init(struct phy_device *phydev) + { + struct dp83640_private *dp83640 = phydev->priv; +@@ -1498,6 +1515,7 @@ static struct phy_driver dp83640_driver = { + .flags = PHY_HAS_INTERRUPT, + .probe = dp83640_probe, + .remove = dp83640_remove, ++ .soft_reset = dp83640_soft_reset, + .config_init = dp83640_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 8daf5db3d922..1d56c73574e8 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -889,6 +889,7 @@ static const struct usb_device_id products[] = { + {QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */ + {QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */ + {QMI_FIXED_INTF(0x2001, 0x7e35, 4)}, /* D-Link DWM-222 */ ++ {QMI_FIXED_INTF(0x2020, 0x2033, 4)}, /* BroadMobi BM806U */ + {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */ + {QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */ + {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 3cdfa2465e3f..d3d89b05f66e 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -1693,7 +1693,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) + + tx_data += len; + agg->skb_len += len; +- agg->skb_num++; ++ agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1; + + dev_kfree_skb_any(skb); + +diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c +index 4cb9b11a545a..2cc0f28f4fd2 100644 +--- a/drivers/net/usb/smsc75xx.c ++++ b/drivers/net/usb/smsc75xx.c +@@ -957,10 +957,11 @@ static int smsc75xx_set_features(struct net_device *netdev, + /* it's racing here! */ + + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); +- if (ret < 0) ++ if (ret < 0) { + netdev_warn(dev->net, "Error writing RFE_CTL\n"); +- +- return ret; ++ return ret; ++ } ++ return 0; + } + + static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm) +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 472ed6df2221..7118b8263760 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -1949,8 +1949,8 @@ static int virtnet_probe(struct virtio_device *vdev) + + /* Assume link up if device can't report link status, + otherwise get link status from config. */ ++ netif_carrier_off(dev); + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { +- netif_carrier_off(dev); + schedule_work(&vi->config_work); + } else { + vi->status = VIRTIO_NET_S_LINK_UP; +diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c +index 5aa5df24f4dc..d68f4f2965e0 100644 +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -6928,10 +6928,20 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, + { + struct ath10k *ar = hw->priv; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; ++ struct ath10k_vif *arvif = (void *)vif->drv_priv; ++ struct ath10k_peer *peer; + u32 bw, smps; + + spin_lock_bh(&ar->data_lock); + ++ peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr); ++ if (!peer) { ++ spin_unlock_bh(&ar->data_lock); ++ ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n", ++ sta->addr, arvif->vdev_id); ++ return; ++ } ++ + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", + sta->addr, changed, sta->bandwidth, sta->rx_nss, +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index f507d821aba8..c221597e2519 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -6789,7 +6789,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, + int i; + + /* ignore non-ISO3166 country codes */ +- for (i = 0; i < sizeof(req->alpha2); i++) ++ for (i = 0; i < 2; i++) + if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { + brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n", + req->alpha2[0], req->alpha2[1]); +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +index f1231c0ea336..0bffade1ea5b 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +@@ -2585,6 +2585,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, + + /* enable beacon filtering */ + WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); ++ ++ iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, ++ false); ++ + ret = 0; + } else if (old_state == IEEE80211_STA_AUTHORIZED && + new_state == IEEE80211_STA_ASSOC) { +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +index 0aea476ebf50..f251c2afebfc 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +@@ -2709,7 +2709,8 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta, + enum nl80211_band band, +- struct rs_rate *rate) ++ struct rs_rate *rate, ++ bool init) + { + int i, nentries; + unsigned long active_rate; +@@ -2763,14 +2764,25 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, + */ + if (sta->vht_cap.vht_supported && + best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { +- switch (sta->bandwidth) { +- case IEEE80211_STA_RX_BW_160: +- case IEEE80211_STA_RX_BW_80: +- case IEEE80211_STA_RX_BW_40: ++ /* ++ * In AP mode, when a new station associates, rs is initialized ++ * immediately upon association completion, before the phy ++ * context is updated with the association parameters, so the ++ * sta bandwidth might be wider than the phy context allows. ++ * To avoid this issue, always initialize rs with 20mhz ++ * bandwidth rate, and after authorization, when the phy context ++ * is already up-to-date, re-init rs with the correct bw. ++ */ ++ u32 bw = init ? RATE_MCS_CHAN_WIDTH_20 : rs_bw_from_sta_bw(sta); ++ ++ switch (bw) { ++ case RATE_MCS_CHAN_WIDTH_40: ++ case RATE_MCS_CHAN_WIDTH_80: ++ case RATE_MCS_CHAN_WIDTH_160: + initial_rates = rs_optimal_rates_vht; + nentries = ARRAY_SIZE(rs_optimal_rates_vht); + break; +- case IEEE80211_STA_RX_BW_20: ++ case RATE_MCS_CHAN_WIDTH_20: + initial_rates = rs_optimal_rates_vht_20mhz; + nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz); + break; +@@ -2781,7 +2793,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, + + active_rate = lq_sta->active_siso_rate; + rate->type = LQ_VHT_SISO; +- rate->bw = rs_bw_from_sta_bw(sta); ++ rate->bw = bw; + } else if (sta->ht_cap.ht_supported && + best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { + initial_rates = rs_optimal_rates_ht; +@@ -2863,7 +2875,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, + tbl = &(lq_sta->lq_info[active_tbl]); + rate = &tbl->rate; + +- rs_get_initial_rate(mvm, sta, lq_sta, band, rate); ++ rs_get_initial_rate(mvm, sta, lq_sta, band, rate, init); + rs_init_optimal_rate(mvm, sta, lq_sta); + + WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +index a481eb41f693..c2bbc8c17beb 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +@@ -72,6 +72,7 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb); + struct iwl_mvm_key_pn *ptk_pn; ++ int res; + u8 tid, keyidx; + u8 pn[IEEE80211_CCMP_PN_LEN]; + u8 *extiv; +@@ -128,12 +129,13 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, + pn[4] = extiv[1]; + pn[5] = extiv[0]; + +- if (memcmp(pn, ptk_pn->q[queue].pn[tid], +- IEEE80211_CCMP_PN_LEN) <= 0) ++ res = memcmp(pn, ptk_pn->q[queue].pn[tid], IEEE80211_CCMP_PN_LEN); ++ if (res < 0) ++ return -1; ++ if (!res && !(stats->flag & RX_FLAG_ALLOW_SAME_PN)) + return -1; + +- if (!(stats->flag & RX_FLAG_AMSDU_MORE)) +- memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); ++ memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); + stats->flag |= RX_FLAG_PN_VALIDATED; + + return 0; +@@ -295,28 +297,21 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, + } + + /* +- * returns true if a packet outside BA session is a duplicate and +- * should be dropped ++ * returns true if a packet is a duplicate and should be dropped. ++ * Updates AMSDU PN tracking info + */ +-static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, +- struct ieee80211_rx_status *rx_status, +- struct ieee80211_hdr *hdr, +- struct iwl_rx_mpdu_desc *desc) ++static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, ++ struct ieee80211_rx_status *rx_status, ++ struct ieee80211_hdr *hdr, ++ struct iwl_rx_mpdu_desc *desc) + { + struct iwl_mvm_sta *mvm_sta; + struct iwl_mvm_rxq_dup_data *dup_data; +- u8 baid, tid, sub_frame_idx; ++ u8 tid, sub_frame_idx; + + if (WARN_ON(IS_ERR_OR_NULL(sta))) + return false; + +- baid = (le32_to_cpu(desc->reorder_data) & +- IWL_RX_MPDU_REORDER_BAID_MASK) >> +- IWL_RX_MPDU_REORDER_BAID_SHIFT; +- +- if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) +- return false; +- + mvm_sta = iwl_mvm_sta_from_mac80211(sta); + dup_data = &mvm_sta->dup_data[queue]; + +@@ -346,6 +341,12 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, + dup_data->last_sub_frame[tid] >= sub_frame_idx)) + return true; + ++ /* Allow same PN as the first subframe for following sub frames */ ++ if (dup_data->last_seq[tid] == hdr->seq_ctrl && ++ sub_frame_idx > dup_data->last_sub_frame[tid] && ++ desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) ++ rx_status->flag |= RX_FLAG_ALLOW_SAME_PN; ++ + dup_data->last_seq[tid] = hdr->seq_ctrl; + dup_data->last_sub_frame[tid] = sub_frame_idx; + +@@ -882,7 +883,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, + if (ieee80211_is_data(hdr->frame_control)) + iwl_mvm_rx_csum(sta, skb, desc); + +- if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) { ++ if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) { + kfree_skb(skb); + rcu_read_unlock(); + return; +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +index 7465d4db136f..bd7ff562d82d 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +@@ -406,11 +406,11 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, + { + struct ieee80211_key_conf *keyconf = info->control.hw_key; + u8 *crypto_hdr = skb_frag->data + hdrlen; ++ enum iwl_tx_cmd_sec_ctrl type = TX_CMD_SEC_CCM; + u64 pn; + + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_CCMP: +- case WLAN_CIPHER_SUITE_CCMP_256: + iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); + iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); + break; +@@ -434,13 +434,16 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, + break; + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: ++ type = TX_CMD_SEC_GCMP; ++ /* Fall through */ ++ case WLAN_CIPHER_SUITE_CCMP_256: + /* TODO: Taking the key from the table might introduce a race + * when PTK rekeying is done, having an old packets with a PN + * based on the old key but the message encrypted with a new + * one. + * Need to handle this. + */ +- tx_cmd->sec_ctl |= TX_CMD_SEC_GCMP | TX_CMD_SEC_KEY_FROM_TABLE; ++ tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE; + tx_cmd->key[0] = keyconf->hw_key_idx; + iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); + break; +diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c +index 2681b5339810..95e96419b4cf 100644 +--- a/drivers/net/wireless/mac80211_hwsim.c ++++ b/drivers/net/wireless/mac80211_hwsim.c +@@ -3084,8 +3084,10 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) + if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { + u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); + +- if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) ++ if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) { ++ kfree(hwname); + return -EINVAL; ++ } + param.regd = hwsim_world_regdom_custom[idx]; + } + +diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c +index 1b287861e34f..520050eae836 100644 +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -350,6 +350,9 @@ static int xennet_open(struct net_device *dev) + unsigned int i = 0; + struct netfront_queue *queue = NULL; + ++ if (!np->queues) ++ return -ENODEV; ++ + for (i = 0; i < num_queues; ++i) { + queue = &np->queues[i]; + napi_enable(&queue->napi); +@@ -1377,18 +1380,8 @@ static int netfront_probe(struct xenbus_device *dev, + #ifdef CONFIG_SYSFS + info->netdev->sysfs_groups[0] = &xennet_dev_group; + #endif +- err = register_netdev(info->netdev); +- if (err) { +- pr_warn("%s: register_netdev err=%d\n", __func__, err); +- goto fail; +- } + + return 0; +- +- fail: +- xennet_free_netdev(netdev); +- dev_set_drvdata(&dev->dev, NULL); +- return err; + } + + static void xennet_end_access(int ref, void *page) +@@ -1757,8 +1750,6 @@ static void xennet_destroy_queues(struct netfront_info *info) + { + unsigned int i; + +- rtnl_lock(); +- + for (i = 0; i < info->netdev->real_num_tx_queues; i++) { + struct netfront_queue *queue = &info->queues[i]; + +@@ -1767,8 +1758,6 @@ static void xennet_destroy_queues(struct netfront_info *info) + netif_napi_del(&queue->napi); + } + +- rtnl_unlock(); +- + kfree(info->queues); + info->queues = NULL; + } +@@ -1784,8 +1773,6 @@ static int xennet_create_queues(struct netfront_info *info, + if (!info->queues) + return -ENOMEM; + +- rtnl_lock(); +- + for (i = 0; i < *num_queues; i++) { + struct netfront_queue *queue = &info->queues[i]; + +@@ -1794,7 +1781,7 @@ static int xennet_create_queues(struct netfront_info *info, + + ret = xennet_init_queue(queue); + if (ret < 0) { +- dev_warn(&info->netdev->dev, ++ dev_warn(&info->xbdev->dev, + "only created %d queues\n", i); + *num_queues = i; + break; +@@ -1808,10 +1795,8 @@ static int xennet_create_queues(struct netfront_info *info, + + netif_set_real_num_tx_queues(info->netdev, *num_queues); + +- rtnl_unlock(); +- + if (*num_queues == 0) { +- dev_err(&info->netdev->dev, "no queues\n"); ++ dev_err(&info->xbdev->dev, "no queues\n"); + return -EINVAL; + } + return 0; +@@ -1853,6 +1838,7 @@ static int talk_to_netback(struct xenbus_device *dev, + goto out; + } + ++ rtnl_lock(); + if (info->queues) + xennet_destroy_queues(info); + +@@ -1863,6 +1849,7 @@ static int talk_to_netback(struct xenbus_device *dev, + info->queues = NULL; + goto out; + } ++ rtnl_unlock(); + + /* Create shared ring, alloc event channel -- for each queue */ + for (i = 0; i < num_queues; ++i) { +@@ -1959,8 +1946,10 @@ static int talk_to_netback(struct xenbus_device *dev, + xenbus_transaction_end(xbt, 1); + destroy_ring: + xennet_disconnect_backend(info); ++ rtnl_lock(); + xennet_destroy_queues(info); + out: ++ rtnl_unlock(); + device_unregister(&dev->dev); + return err; + } +@@ -1996,6 +1985,15 @@ static int xennet_connect(struct net_device *dev) + netdev_update_features(dev); + rtnl_unlock(); + ++ if (dev->reg_state == NETREG_UNINITIALIZED) { ++ err = register_netdev(dev); ++ if (err) { ++ pr_warn("%s: register_netdev err=%d\n", __func__, err); ++ device_unregister(&np->xbdev->dev); ++ return err; ++ } ++ } ++ + /* + * All public and private state should now be sane. Get + * ready to start sending and receiving packets and give the driver +@@ -2186,10 +2184,14 @@ static int xennet_remove(struct xenbus_device *dev) + + xennet_disconnect_backend(info); + +- unregister_netdev(info->netdev); ++ if (info->netdev->reg_state == NETREG_REGISTERED) ++ unregister_netdev(info->netdev); + +- if (info->queues) ++ if (info->queues) { ++ rtnl_lock(); + xennet_destroy_queues(info); ++ rtnl_unlock(); ++ } + xennet_free_netdev(info->netdev); + + return 0; +diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c +index 24222a5d8df2..da95bd8f0f72 100644 +--- a/drivers/ntb/ntb_transport.c ++++ b/drivers/ntb/ntb_transport.c +@@ -996,6 +996,9 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, + mw_base = nt->mw_vec[mw_num].phys_addr; + mw_size = nt->mw_vec[mw_num].phys_size; + ++ if (max_mw_size && mw_size > max_mw_size) ++ mw_size = max_mw_size; ++ + tx_size = (unsigned int)mw_size / num_qps_mw; + qp_offset = tx_size * (qp_num / mw_count); + +diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c +index eef1a68e5d95..b634b89b4540 100644 +--- a/drivers/nvme/host/fabrics.c ++++ b/drivers/nvme/host/fabrics.c +@@ -583,8 +583,10 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, + opts->discovery_nqn = + !(strcmp(opts->subsysnqn, + NVME_DISC_SUBSYS_NAME)); +- if (opts->discovery_nqn) ++ if (opts->discovery_nqn) { ++ opts->kato = 0; + opts->nr_io_queues = 0; ++ } + break; + case NVMF_OPT_TRADDR: + p = match_strdup(args); +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 8cc856ecec95..642ee00e9143 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1120,7 +1120,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) + nvmeq->cq_vector = qid - 1; + result = adapter_alloc_cq(dev, qid, nvmeq); + if (result < 0) +- return result; ++ goto release_vector; + + result = adapter_alloc_sq(dev, qid, nvmeq); + if (result < 0) +@@ -1134,9 +1134,12 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) + return result; + + release_sq: ++ dev->online_queues--; + adapter_delete_sq(dev, qid); + release_cq: + adapter_delete_cq(dev, qid); ++ release_vector: ++ nvmeq->cq_vector = -1; + return result; + } + +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index c89d68a76f3d..3a044922b048 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -491,9 +491,12 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, + goto fail; + } + +- /* either variant of SGLs is fine, as we don't support metadata */ +- if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF && +- (flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METASEG)) { ++ /* ++ * For fabrics, PSDT field shall describe metadata pointer (MPTR) that ++ * contains an address of a single contiguous physical buffer that is ++ * byte aligned. ++ */ ++ if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF)) { + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; + goto fail; + } +diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c +index 1cced1d039d7..7e9385812bda 100644 +--- a/drivers/parisc/lba_pci.c ++++ b/drivers/parisc/lba_pci.c +@@ -1367,9 +1367,27 @@ lba_hw_init(struct lba_device *d) + WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG); + } + +- /* Set HF mode as the default (vs. -1 mode). */ ++ ++ /* ++ * Hard Fail vs. Soft Fail on PCI "Master Abort". ++ * ++ * "Master Abort" means the MMIO transaction timed out - usually due to ++ * the device not responding to an MMIO read. We would like HF to be ++ * enabled to find driver problems, though it means the system will ++ * crash with a HPMC. ++ * ++ * In SoftFail mode "~0L" is returned as a result of a timeout on the ++ * pci bus. This is like how PCI busses on x86 and most other ++ * architectures behave. In order to increase compatibility with ++ * existing (x86) PCI hardware and existing Linux drivers we enable ++ * Soft Faul mode on PA-RISC now too. ++ */ + stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); ++#if defined(ENABLE_HARDFAIL) + WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); ++#else ++ WRITE_REG32(stat & ~HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); ++#endif + + /* + ** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index d81ad841dc0c..f11c38244088 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -1147,11 +1147,14 @@ static int pci_pm_runtime_suspend(struct device *dev) + int error; + + /* +- * If pci_dev->driver is not set (unbound), the device should +- * always remain in D0 regardless of the runtime PM status ++ * If pci_dev->driver is not set (unbound), we leave the device in D0, ++ * but it may go to D3cold when the bridge above it runtime suspends. ++ * Save its config space in case that happens. + */ +- if (!pci_dev->driver) ++ if (!pci_dev->driver) { ++ pci_save_state(pci_dev); + return 0; ++ } + + if (!pm || !pm->runtime_suspend) + return -ENOSYS; +@@ -1199,16 +1202,18 @@ static int pci_pm_runtime_resume(struct device *dev) + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + /* +- * If pci_dev->driver is not set (unbound), the device should +- * always remain in D0 regardless of the runtime PM status ++ * Restoring config space is necessary even if the device is not bound ++ * to a driver because although we left it in D0, it may have gone to ++ * D3cold when the bridge above it runtime suspended. + */ ++ pci_restore_standard_config(pci_dev); ++ + if (!pci_dev->driver) + return 0; + + if (!pm || !pm->runtime_resume) + return -ENOSYS; + +- pci_restore_standard_config(pci_dev); + pci_fixup_device(pci_fixup_resume_early, pci_dev); + __pci_enable_wake(pci_dev, PCI_D0, true, false); + pci_fixup_device(pci_fixup_resume, pci_dev); +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index fb177dc576d6..b55f9179c94e 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -3857,6 +3857,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9120, + quirk_dma_func1_alias); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9123, + quirk_dma_func1_alias); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9128, ++ quirk_dma_func1_alias); + /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c14 */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9130, + quirk_dma_func1_alias); +@@ -3872,6 +3874,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9182, + /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0, + quirk_dma_func1_alias); ++/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c127 */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9220, ++ quirk_dma_func1_alias); + /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c49 */ + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230, + quirk_dma_func1_alias); +diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c +index bedce3453dd3..056845bdf67b 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm.c +@@ -790,7 +790,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) + return -EINVAL; + + chip = &pctrl->chip; +- chip->base = 0; ++ chip->base = -1; + chip->ngpio = ngpio; + chip->label = dev_name(pctrl->dev); + chip->parent = pctrl->dev; +diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +index dc9b671ccf2e..29718886989a 100644 +--- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c ++++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +@@ -1,7 +1,7 @@ + /* + * R8A7796 processor support - PFC hardware block. + * +- * Copyright (C) 2016 Renesas Electronics Corp. ++ * Copyright (C) 2016-2017 Renesas Electronics Corp. + * + * This file is based on the drivers/pinctrl/sh-pfc/pfc-r8a7795.c + * +@@ -476,7 +476,7 @@ FM(IP16_31_28) IP16_31_28 FM(IP17_31_28) IP17_31_28 + #define MOD_SEL1_26 FM(SEL_TIMER_TMU_0) FM(SEL_TIMER_TMU_1) + #define MOD_SEL1_25_24 FM(SEL_SSP1_1_0) FM(SEL_SSP1_1_1) FM(SEL_SSP1_1_2) FM(SEL_SSP1_1_3) + #define MOD_SEL1_23_22_21 FM(SEL_SSP1_0_0) FM(SEL_SSP1_0_1) FM(SEL_SSP1_0_2) FM(SEL_SSP1_0_3) FM(SEL_SSP1_0_4) F_(0, 0) F_(0, 0) F_(0, 0) +-#define MOD_SEL1_20 FM(SEL_SSI_0) FM(SEL_SSI_1) ++#define MOD_SEL1_20 FM(SEL_SSI1_0) FM(SEL_SSI1_1) + #define MOD_SEL1_19 FM(SEL_SPEED_PULSE_0) FM(SEL_SPEED_PULSE_1) + #define MOD_SEL1_18_17 FM(SEL_SIMCARD_0) FM(SEL_SIMCARD_1) FM(SEL_SIMCARD_2) FM(SEL_SIMCARD_3) + #define MOD_SEL1_16 FM(SEL_SDHI2_0) FM(SEL_SDHI2_1) +@@ -1208,7 +1208,7 @@ static const u16 pinmux_data[] = { + PINMUX_IPSR_GPSR(IP13_11_8, HSCK0), + PINMUX_IPSR_MSEL(IP13_11_8, MSIOF1_SCK_D, SEL_MSIOF1_3), + PINMUX_IPSR_MSEL(IP13_11_8, AUDIO_CLKB_A, SEL_ADG_B_0), +- PINMUX_IPSR_MSEL(IP13_11_8, SSI_SDATA1_B, SEL_SSI_1), ++ PINMUX_IPSR_MSEL(IP13_11_8, SSI_SDATA1_B, SEL_SSI1_1), + PINMUX_IPSR_MSEL(IP13_11_8, TS_SCK0_D, SEL_TSIF0_3), + PINMUX_IPSR_MSEL(IP13_11_8, STP_ISCLK_0_D, SEL_SSP1_0_3), + PINMUX_IPSR_MSEL(IP13_11_8, RIF0_CLK_C, SEL_DRIF0_2), +@@ -1216,14 +1216,14 @@ static const u16 pinmux_data[] = { + + PINMUX_IPSR_GPSR(IP13_15_12, HRX0), + PINMUX_IPSR_MSEL(IP13_15_12, MSIOF1_RXD_D, SEL_MSIOF1_3), +- PINMUX_IPSR_MSEL(IP13_15_12, SSI_SDATA2_B, SEL_SSI_1), ++ PINMUX_IPSR_MSEL(IP13_15_12, SSI_SDATA2_B, SEL_SSI2_1), + PINMUX_IPSR_MSEL(IP13_15_12, TS_SDEN0_D, SEL_TSIF0_3), + PINMUX_IPSR_MSEL(IP13_15_12, STP_ISEN_0_D, SEL_SSP1_0_3), + PINMUX_IPSR_MSEL(IP13_15_12, RIF0_D0_C, SEL_DRIF0_2), + + PINMUX_IPSR_GPSR(IP13_19_16, HTX0), + PINMUX_IPSR_MSEL(IP13_19_16, MSIOF1_TXD_D, SEL_MSIOF1_3), +- PINMUX_IPSR_MSEL(IP13_19_16, SSI_SDATA9_B, SEL_SSI_1), ++ PINMUX_IPSR_MSEL(IP13_19_16, SSI_SDATA9_B, SEL_SSI9_1), + PINMUX_IPSR_MSEL(IP13_19_16, TS_SDAT0_D, SEL_TSIF0_3), + PINMUX_IPSR_MSEL(IP13_19_16, STP_ISD_0_D, SEL_SSP1_0_3), + PINMUX_IPSR_MSEL(IP13_19_16, RIF0_D1_C, SEL_DRIF0_2), +@@ -1231,7 +1231,7 @@ static const u16 pinmux_data[] = { + PINMUX_IPSR_GPSR(IP13_23_20, HCTS0_N), + PINMUX_IPSR_MSEL(IP13_23_20, RX2_B, SEL_SCIF2_1), + PINMUX_IPSR_MSEL(IP13_23_20, MSIOF1_SYNC_D, SEL_MSIOF1_3), +- PINMUX_IPSR_MSEL(IP13_23_20, SSI_SCK9_A, SEL_SSI_0), ++ PINMUX_IPSR_MSEL(IP13_23_20, SSI_SCK9_A, SEL_SSI9_0), + PINMUX_IPSR_MSEL(IP13_23_20, TS_SPSYNC0_D, SEL_TSIF0_3), + PINMUX_IPSR_MSEL(IP13_23_20, STP_ISSYNC_0_D, SEL_SSP1_0_3), + PINMUX_IPSR_MSEL(IP13_23_20, RIF0_SYNC_C, SEL_DRIF0_2), +@@ -1240,7 +1240,7 @@ static const u16 pinmux_data[] = { + PINMUX_IPSR_GPSR(IP13_27_24, HRTS0_N), + PINMUX_IPSR_MSEL(IP13_27_24, TX2_B, SEL_SCIF2_1), + PINMUX_IPSR_MSEL(IP13_27_24, MSIOF1_SS1_D, SEL_MSIOF1_3), +- PINMUX_IPSR_MSEL(IP13_27_24, SSI_WS9_A, SEL_SSI_0), ++ PINMUX_IPSR_MSEL(IP13_27_24, SSI_WS9_A, SEL_SSI9_0), + PINMUX_IPSR_MSEL(IP13_27_24, STP_IVCXO27_0_D, SEL_SSP1_0_3), + PINMUX_IPSR_MSEL(IP13_27_24, BPFCLK_A, SEL_FM_0), + PINMUX_IPSR_GPSR(IP13_27_24, AUDIO_CLKOUT2_A), +@@ -1255,7 +1255,7 @@ static const u16 pinmux_data[] = { + PINMUX_IPSR_MSEL(IP14_3_0, RX5_A, SEL_SCIF5_0), + PINMUX_IPSR_MSEL(IP14_3_0, NFWP_N_A, SEL_NDF_0), + PINMUX_IPSR_MSEL(IP14_3_0, AUDIO_CLKA_C, SEL_ADG_A_2), +- PINMUX_IPSR_MSEL(IP14_3_0, SSI_SCK2_A, SEL_SSI_0), ++ PINMUX_IPSR_MSEL(IP14_3_0, SSI_SCK2_A, SEL_SSI2_0), + PINMUX_IPSR_MSEL(IP14_3_0, STP_IVCXO27_0_C, SEL_SSP1_0_2), + PINMUX_IPSR_GPSR(IP14_3_0, AUDIO_CLKOUT3_A), + PINMUX_IPSR_MSEL(IP14_3_0, TCLK1_B, SEL_TIMER_TMU_1), +@@ -1264,7 +1264,7 @@ static const u16 pinmux_data[] = { + PINMUX_IPSR_MSEL(IP14_7_4, TX5_A, SEL_SCIF5_0), + PINMUX_IPSR_MSEL(IP14_7_4, MSIOF1_SS2_D, SEL_MSIOF1_3), + PINMUX_IPSR_MSEL(IP14_7_4, AUDIO_CLKC_A, SEL_ADG_C_0), +- PINMUX_IPSR_MSEL(IP14_7_4, SSI_WS2_A, SEL_SSI_0), ++ PINMUX_IPSR_MSEL(IP14_7_4, SSI_WS2_A, SEL_SSI2_0), + PINMUX_IPSR_MSEL(IP14_7_4, STP_OPWM_0_D, SEL_SSP1_0_3), + PINMUX_IPSR_GPSR(IP14_7_4, AUDIO_CLKOUT_D), + PINMUX_IPSR_MSEL(IP14_7_4, SPEEDIN_B, SEL_SPEED_PULSE_1), +@@ -1292,10 +1292,10 @@ static const u16 pinmux_data[] = { + PINMUX_IPSR_MSEL(IP14_31_28, MSIOF1_SS2_F, SEL_MSIOF1_5), + + /* IPSR15 */ +- PINMUX_IPSR_MSEL(IP15_3_0, SSI_SDATA1_A, SEL_SSI_0), ++ PINMUX_IPSR_MSEL(IP15_3_0, SSI_SDATA1_A, SEL_SSI1_0), + +- PINMUX_IPSR_MSEL(IP15_7_4, SSI_SDATA2_A, SEL_SSI_0), +- PINMUX_IPSR_MSEL(IP15_7_4, SSI_SCK1_B, SEL_SSI_1), ++ PINMUX_IPSR_MSEL(IP15_7_4, SSI_SDATA2_A, SEL_SSI2_0), ++ PINMUX_IPSR_MSEL(IP15_7_4, SSI_SCK1_B, SEL_SSI1_1), + + PINMUX_IPSR_GPSR(IP15_11_8, SSI_SCK34), + PINMUX_IPSR_MSEL(IP15_11_8, MSIOF1_SS1_A, SEL_MSIOF1_0), +@@ -1381,11 +1381,11 @@ static const u16 pinmux_data[] = { + PINMUX_IPSR_MSEL(IP16_27_24, RIF1_D1_A, SEL_DRIF1_0), + PINMUX_IPSR_MSEL(IP16_27_24, RIF3_D1_A, SEL_DRIF3_0), + +- PINMUX_IPSR_MSEL(IP16_31_28, SSI_SDATA9_A, SEL_SSI_0), ++ PINMUX_IPSR_MSEL(IP16_31_28, SSI_SDATA9_A, SEL_SSI9_0), + PINMUX_IPSR_MSEL(IP16_31_28, HSCK2_B, SEL_HSCIF2_1), + PINMUX_IPSR_MSEL(IP16_31_28, MSIOF1_SS1_C, SEL_MSIOF1_2), + PINMUX_IPSR_MSEL(IP16_31_28, HSCK1_A, SEL_HSCIF1_0), +- PINMUX_IPSR_MSEL(IP16_31_28, SSI_WS1_B, SEL_SSI_1), ++ PINMUX_IPSR_MSEL(IP16_31_28, SSI_WS1_B, SEL_SSI1_1), + PINMUX_IPSR_GPSR(IP16_31_28, SCK1), + PINMUX_IPSR_MSEL(IP16_31_28, STP_IVCXO27_1_A, SEL_SSP1_1_0), + PINMUX_IPSR_GPSR(IP16_31_28, SCK5_A), +@@ -1417,7 +1417,7 @@ static const u16 pinmux_data[] = { + + PINMUX_IPSR_GPSR(IP17_19_16, USB1_PWEN), + PINMUX_IPSR_MSEL(IP17_19_16, SIM0_CLK_C, SEL_SIMCARD_2), +- PINMUX_IPSR_MSEL(IP17_19_16, SSI_SCK1_A, SEL_SSI_0), ++ PINMUX_IPSR_MSEL(IP17_19_16, SSI_SCK1_A, SEL_SSI1_0), + PINMUX_IPSR_MSEL(IP17_19_16, TS_SCK0_E, SEL_TSIF0_4), + PINMUX_IPSR_MSEL(IP17_19_16, STP_ISCLK_0_E, SEL_SSP1_0_4), + PINMUX_IPSR_MSEL(IP17_19_16, FMCLK_B, SEL_FM_1), +@@ -1427,7 +1427,7 @@ static const u16 pinmux_data[] = { + + PINMUX_IPSR_GPSR(IP17_23_20, USB1_OVC), + PINMUX_IPSR_MSEL(IP17_23_20, MSIOF1_SS2_C, SEL_MSIOF1_2), +- PINMUX_IPSR_MSEL(IP17_23_20, SSI_WS1_A, SEL_SSI_0), ++ PINMUX_IPSR_MSEL(IP17_23_20, SSI_WS1_A, SEL_SSI1_0), + PINMUX_IPSR_MSEL(IP17_23_20, TS_SDAT0_E, SEL_TSIF0_4), + PINMUX_IPSR_MSEL(IP17_23_20, STP_ISD_0_E, SEL_SSP1_0_4), + PINMUX_IPSR_MSEL(IP17_23_20, FMIN_B, SEL_FM_1), +@@ -1437,7 +1437,7 @@ static const u16 pinmux_data[] = { + + PINMUX_IPSR_GPSR(IP17_27_24, USB30_PWEN), + PINMUX_IPSR_GPSR(IP17_27_24, AUDIO_CLKOUT_B), +- PINMUX_IPSR_MSEL(IP17_27_24, SSI_SCK2_B, SEL_SSI_1), ++ PINMUX_IPSR_MSEL(IP17_27_24, SSI_SCK2_B, SEL_SSI2_1), + PINMUX_IPSR_MSEL(IP17_27_24, TS_SDEN1_D, SEL_TSIF1_3), + PINMUX_IPSR_MSEL(IP17_27_24, STP_ISEN_1_D, SEL_SSP1_1_2), + PINMUX_IPSR_MSEL(IP17_27_24, STP_OPWM_0_E, SEL_SSP1_0_4), +@@ -1449,7 +1449,7 @@ static const u16 pinmux_data[] = { + + PINMUX_IPSR_GPSR(IP17_31_28, USB30_OVC), + PINMUX_IPSR_GPSR(IP17_31_28, AUDIO_CLKOUT1_B), +- PINMUX_IPSR_MSEL(IP17_31_28, SSI_WS2_B, SEL_SSI_1), ++ PINMUX_IPSR_MSEL(IP17_31_28, SSI_WS2_B, SEL_SSI2_1), + PINMUX_IPSR_MSEL(IP17_31_28, TS_SPSYNC1_D, SEL_TSIF1_3), + PINMUX_IPSR_MSEL(IP17_31_28, STP_ISSYNC_1_D, SEL_SSP1_1_3), + PINMUX_IPSR_MSEL(IP17_31_28, STP_IVCXO27_0_E, SEL_SSP1_0_4), +@@ -1460,7 +1460,7 @@ static const u16 pinmux_data[] = { + /* IPSR18 */ + PINMUX_IPSR_GPSR(IP18_3_0, GP6_30), + PINMUX_IPSR_GPSR(IP18_3_0, AUDIO_CLKOUT2_B), +- PINMUX_IPSR_MSEL(IP18_3_0, SSI_SCK9_B, SEL_SSI_1), ++ PINMUX_IPSR_MSEL(IP18_3_0, SSI_SCK9_B, SEL_SSI9_1), + PINMUX_IPSR_MSEL(IP18_3_0, TS_SDEN0_E, SEL_TSIF0_4), + PINMUX_IPSR_MSEL(IP18_3_0, STP_ISEN_0_E, SEL_SSP1_0_4), + PINMUX_IPSR_MSEL(IP18_3_0, RIF2_D0_B, SEL_DRIF2_1), +@@ -1471,7 +1471,7 @@ static const u16 pinmux_data[] = { + + PINMUX_IPSR_GPSR(IP18_7_4, GP6_31), + PINMUX_IPSR_GPSR(IP18_7_4, AUDIO_CLKOUT3_B), +- PINMUX_IPSR_MSEL(IP18_7_4, SSI_WS9_B, SEL_SSI_1), ++ PINMUX_IPSR_MSEL(IP18_7_4, SSI_WS9_B, SEL_SSI9_1), + PINMUX_IPSR_MSEL(IP18_7_4, TS_SPSYNC0_E, SEL_TSIF0_4), + PINMUX_IPSR_MSEL(IP18_7_4, STP_ISSYNC_0_E, SEL_SSP1_0_4), + PINMUX_IPSR_MSEL(IP18_7_4, RIF2_D1_B, SEL_DRIF2_1), +diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c +index 83e89e5d4752..b73a2376d913 100644 +--- a/drivers/regulator/gpio-regulator.c ++++ b/drivers/regulator/gpio-regulator.c +@@ -268,8 +268,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) + drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); + if (drvdata->desc.name == NULL) { + dev_err(&pdev->dev, "Failed to allocate supply name\n"); +- ret = -ENOMEM; +- goto err; ++ return -ENOMEM; + } + + if (config->nr_gpios != 0) { +@@ -289,7 +288,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) + dev_err(&pdev->dev, + "Could not obtain regulator setting GPIOs: %d\n", + ret); +- goto err_memstate; ++ goto err_memgpio; + } + } + +@@ -300,7 +299,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) + if (drvdata->states == NULL) { + dev_err(&pdev->dev, "Failed to allocate state data\n"); + ret = -ENOMEM; +- goto err_memgpio; ++ goto err_stategpio; + } + drvdata->nr_states = config->nr_states; + +@@ -321,7 +320,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) + default: + dev_err(&pdev->dev, "No regulator type set\n"); + ret = -EINVAL; +- goto err_memgpio; ++ goto err_memstate; + } + + /* build initial state from gpio init data. */ +@@ -358,22 +357,21 @@ static int gpio_regulator_probe(struct platform_device *pdev) + if (IS_ERR(drvdata->dev)) { + ret = PTR_ERR(drvdata->dev); + dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); +- goto err_stategpio; ++ goto err_memstate; + } + + platform_set_drvdata(pdev, drvdata); + + return 0; + +-err_stategpio: +- gpio_free_array(drvdata->gpios, drvdata->nr_gpios); + err_memstate: + kfree(drvdata->states); ++err_stategpio: ++ gpio_free_array(drvdata->gpios, drvdata->nr_gpios); + err_memgpio: + kfree(drvdata->gpios); + err_name: + kfree(drvdata->desc.name); +-err: + return ret; + } + +diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c +index 4f613ec99500..037675bb36b6 100644 +--- a/drivers/regulator/of_regulator.c ++++ b/drivers/regulator/of_regulator.c +@@ -282,6 +282,7 @@ int of_regulator_match(struct device *dev, struct device_node *node, + dev_err(dev, + "failed to parse DT for regulator %s\n", + child->name); ++ of_node_put(child); + return -EINVAL; + } + match->of_node = of_node_get(child); +diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c +index 8327d47e08b6..c46e31e0a6d9 100644 +--- a/drivers/s390/cio/device_fsm.c ++++ b/drivers/s390/cio/device_fsm.c +@@ -822,6 +822,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) + + ccw_device_set_timeout(cdev, 0); + cdev->private->iretry = 255; ++ cdev->private->async_kill_io_rc = -ETIMEDOUT; + ret = ccw_device_cancel_halt_clear(cdev); + if (ret == -EBUSY) { + ccw_device_set_timeout(cdev, 3*HZ); +@@ -898,7 +899,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) + /* OK, i/o is dead now. Call interrupt handler. */ + if (cdev->handler) + cdev->handler(cdev, cdev->private->intparm, +- ERR_PTR(-EIO)); ++ ERR_PTR(cdev->private->async_kill_io_rc)); + } + + static void +@@ -915,14 +916,16 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) + ccw_device_online_verify(cdev, 0); + if (cdev->handler) + cdev->handler(cdev, cdev->private->intparm, +- ERR_PTR(-EIO)); ++ ERR_PTR(cdev->private->async_kill_io_rc)); + } + + void ccw_device_kill_io(struct ccw_device *cdev) + { + int ret; + ++ ccw_device_set_timeout(cdev, 0); + cdev->private->iretry = 255; ++ cdev->private->async_kill_io_rc = -EIO; + ret = ccw_device_cancel_halt_clear(cdev); + if (ret == -EBUSY) { + ccw_device_set_timeout(cdev, 3*HZ); +diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c +index 877d9f601e63..85b289638133 100644 +--- a/drivers/s390/cio/device_ops.c ++++ b/drivers/s390/cio/device_ops.c +@@ -158,7 +158,7 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) + } + + /** +- * ccw_device_start_key() - start a s390 channel program with key ++ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to +@@ -169,10 +169,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. ++ * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). ++ * This function notifies the device driver if the channel program has not ++ * completed during the time specified by @expires. If a timeout occurs, the ++ * channel program is terminated via xsch, hsch or csch, and the device's ++ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; +@@ -181,9 +186,9 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) + * Context: + * Interrupts disabled, ccw device lock held + */ +-int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, +- unsigned long intparm, __u8 lpm, __u8 key, +- unsigned long flags) ++int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, ++ unsigned long intparm, __u8 lpm, __u8 key, ++ unsigned long flags, int expires) + { + struct subchannel *sch; + int ret; +@@ -223,6 +228,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + switch (ret) { + case 0: + cdev->private->intparm = intparm; ++ if (expires) ++ ccw_device_set_timeout(cdev, expires); + break; + case -EACCES: + case -ENODEV: +@@ -233,7 +240,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + } + + /** +- * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key ++ * ccw_device_start_key() - start a s390 channel program with key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to +@@ -244,15 +251,10 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. +- * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). +- * This function notifies the device driver if the channel program has not +- * completed during the time specified by @expires. If a timeout occurs, the +- * channel program is terminated via xsch, hsch or csch, and the device's +- * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; +@@ -261,19 +263,12 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + * Context: + * Interrupts disabled, ccw device lock held + */ +-int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, +- unsigned long intparm, __u8 lpm, __u8 key, +- unsigned long flags, int expires) ++int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, ++ unsigned long intparm, __u8 lpm, __u8 key, ++ unsigned long flags) + { +- int ret; +- +- if (!cdev) +- return -ENODEV; +- ccw_device_set_timeout(cdev, expires); +- ret = ccw_device_start_key(cdev, cpa, intparm, lpm, key, flags); +- if (ret != 0) +- ccw_device_set_timeout(cdev, 0); +- return ret; ++ return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, key, ++ flags, 0); + } + + /** +@@ -488,18 +483,20 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) + EXPORT_SYMBOL(ccw_device_get_id); + + /** +- * ccw_device_tm_start_key() - perform start function ++ * ccw_device_tm_start_timeout_key() - perform start function + * @cdev: ccw device on which to perform the start function + * @tcw: transport-command word to be started + * @intparm: user defined parameter to be passed to the interrupt handler + * @lpm: mask of paths to use + * @key: storage key to use for storage access ++ * @expires: time span in jiffies after which to abort request + * + * Start the tcw on the given ccw device. Return zero on success, non-zero + * otherwise. + */ +-int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, +- unsigned long intparm, u8 lpm, u8 key) ++int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, ++ unsigned long intparm, u8 lpm, u8 key, ++ int expires) + { + struct subchannel *sch; + int rc; +@@ -526,37 +523,32 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, + return -EACCES; + } + rc = cio_tm_start_key(sch, tcw, lpm, key); +- if (rc == 0) ++ if (rc == 0) { + cdev->private->intparm = intparm; ++ if (expires) ++ ccw_device_set_timeout(cdev, expires); ++ } + return rc; + } +-EXPORT_SYMBOL(ccw_device_tm_start_key); ++EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); + + /** +- * ccw_device_tm_start_timeout_key() - perform start function ++ * ccw_device_tm_start_key() - perform start function + * @cdev: ccw device on which to perform the start function + * @tcw: transport-command word to be started + * @intparm: user defined parameter to be passed to the interrupt handler + * @lpm: mask of paths to use + * @key: storage key to use for storage access +- * @expires: time span in jiffies after which to abort request + * + * Start the tcw on the given ccw device. Return zero on success, non-zero + * otherwise. + */ +-int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, +- unsigned long intparm, u8 lpm, u8 key, +- int expires) ++int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, ++ unsigned long intparm, u8 lpm, u8 key) + { +- int ret; +- +- ccw_device_set_timeout(cdev, expires); +- ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key); +- if (ret != 0) +- ccw_device_set_timeout(cdev, 0); +- return ret; ++ return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm, key, 0); + } +-EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); ++EXPORT_SYMBOL(ccw_device_tm_start_key); + + /** + * ccw_device_tm_start() - perform start function +diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h +index 220f49145b2f..1d984342eb53 100644 +--- a/drivers/s390/cio/io_sch.h ++++ b/drivers/s390/cio/io_sch.h +@@ -154,6 +154,7 @@ struct ccw_device_private { + unsigned long intparm; /* user interruption parameter */ + struct qdio_irq *qdio_data; + struct irb irb; /* device status */ ++ int async_kill_io_rc; + struct senseid senseid; /* SenseID info */ + struct pgid pgid[8]; /* path group IDs per chpid*/ + struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index e63597342c96..01699845c42c 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -522,6 +522,8 @@ static int sr_block_open(struct block_device *bdev, fmode_t mode) + struct scsi_cd *cd; + int ret = -ENXIO; + ++ check_disk_change(bdev); ++ + mutex_lock(&sr_mutex); + cd = scsi_cd_get(bdev->bd_disk); + if (cd) { +@@ -582,18 +584,28 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, + static unsigned int sr_block_check_events(struct gendisk *disk, + unsigned int clearing) + { +- struct scsi_cd *cd = scsi_cd(disk); ++ unsigned int ret = 0; ++ struct scsi_cd *cd; + +- if (atomic_read(&cd->device->disk_events_disable_depth)) ++ cd = scsi_cd_get(disk); ++ if (!cd) + return 0; + +- return cdrom_check_events(&cd->cdi, clearing); ++ if (!atomic_read(&cd->device->disk_events_disable_depth)) ++ ret = cdrom_check_events(&cd->cdi, clearing); ++ ++ scsi_cd_put(cd); ++ return ret; + } + + static int sr_block_revalidate_disk(struct gendisk *disk) + { +- struct scsi_cd *cd = scsi_cd(disk); + struct scsi_sense_hdr sshdr; ++ struct scsi_cd *cd; ++ ++ cd = scsi_cd_get(disk); ++ if (!cd) ++ return -ENXIO; + + /* if the unit is not ready, nothing more to do */ + if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) +@@ -602,6 +614,7 @@ static int sr_block_revalidate_disk(struct gendisk *disk) + sr_cd_check(&cd->cdi); + get_sectorsize(cd); + out: ++ scsi_cd_put(cd); + return 0; + } + +diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c +index 520aedd29965..78d3dbac872a 100644 +--- a/drivers/soc/qcom/wcnss_ctrl.c ++++ b/drivers/soc/qcom/wcnss_ctrl.c +@@ -247,7 +247,7 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) + /* Increment for next fragment */ + req->seq++; + +- data += req->hdr.len; ++ data += NV_FRAGMENT_SIZE; + left -= NV_FRAGMENT_SIZE; + } while (left > 0); + +diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c +index adc3f56d4773..63231760facc 100644 +--- a/drivers/spi/spi-bcm-qspi.c ++++ b/drivers/spi/spi-bcm-qspi.c +@@ -1220,7 +1220,7 @@ int bcm_qspi_probe(struct platform_device *pdev, + qspi->base[MSPI] = devm_ioremap_resource(dev, res); + if (IS_ERR(qspi->base[MSPI])) { + ret = PTR_ERR(qspi->base[MSPI]); +- goto qspi_probe_err; ++ goto qspi_resource_err; + } + } else { + goto qspi_resource_err; +@@ -1231,7 +1231,7 @@ int bcm_qspi_probe(struct platform_device *pdev, + qspi->base[BSPI] = devm_ioremap_resource(dev, res); + if (IS_ERR(qspi->base[BSPI])) { + ret = PTR_ERR(qspi->base[BSPI]); +- goto qspi_probe_err; ++ goto qspi_resource_err; + } + qspi->bspi_mode = true; + } else { +diff --git a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +index eaeb3c51e14b..cb95c3e940f1 100644 +--- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c ++++ b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +@@ -75,6 +75,8 @@ int __init its_fsl_mc_msi_init(void) + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { ++ if (!of_device_is_available(np)) ++ continue; + if (!of_property_read_bool(np, "msi-controller")) + continue; + +diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c +index a350209ffbd3..31c301d6be62 100644 +--- a/drivers/video/fbdev/sbuslib.c ++++ b/drivers/video/fbdev/sbuslib.c +@@ -121,7 +121,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + unsigned char __user *ured; + unsigned char __user *ugreen; + unsigned char __user *ublue; +- int index, count, i; ++ unsigned int index, count, i; + + if (get_user(index, &c->index) || + __get_user(count, &c->count) || +@@ -160,7 +160,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + unsigned char __user *ugreen; + unsigned char __user *ublue; + struct fb_cmap *cmap = &info->cmap; +- int index, count, i; ++ unsigned int index, count, i; + u8 red, green, blue; + + if (get_user(index, &c->index) || +diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c +index e682bf046e50..88cd2a52d8d3 100644 +--- a/drivers/watchdog/f71808e_wdt.c ++++ b/drivers/watchdog/f71808e_wdt.c +@@ -566,7 +566,8 @@ static ssize_t watchdog_write(struct file *file, const char __user *buf, + char c; + if (get_user(c, buf + i)) + return -EFAULT; +- expect_close = (c == 'V'); ++ if (c == 'V') ++ expect_close = true; + } + + /* Properly order writes across fork()ed processes */ +diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c +index ce0c38bd0f00..37523f139ccd 100644 +--- a/drivers/watchdog/sbsa_gwdt.c ++++ b/drivers/watchdog/sbsa_gwdt.c +@@ -50,6 +50,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -159,7 +160,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd) + !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0)) + timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR); + +- timeleft += readq(gwdt->control_base + SBSA_GWDT_WCV) - ++ timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) - + arch_counter_get_cntvct(); + + do_div(timeleft, gwdt->clk); +diff --git a/drivers/watchdog/sp5100_tco.h b/drivers/watchdog/sp5100_tco.h +index 2b28c00da0df..dfe20b81ced5 100644 +--- a/drivers/watchdog/sp5100_tco.h ++++ b/drivers/watchdog/sp5100_tco.h +@@ -54,7 +54,7 @@ + #define SB800_PM_WATCHDOG_CONFIG 0x4C + + #define SB800_PCI_WATCHDOG_DECODE_EN (1 << 0) +-#define SB800_PM_WATCHDOG_DISABLE (1 << 2) ++#define SB800_PM_WATCHDOG_DISABLE (1 << 1) + #define SB800_PM_WATCHDOG_SECOND_RES (3 << 0) + #define SB800_ACPI_MMIO_DECODE_EN (1 << 0) + #define SB800_ACPI_MMIO_SEL (1 << 1) +diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c +index d5dbdb9d24d8..6d3b32ccc2c4 100644 +--- a/drivers/xen/events/events_base.c ++++ b/drivers/xen/events/events_base.c +@@ -764,8 +764,8 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, + mutex_unlock(&irq_mapping_update_lock); + return irq; + error_irq: +- for (; i >= 0; i--) +- __unbind_from_irq(irq + i); ++ while (nvec--) ++ __unbind_from_irq(irq + nvec); + mutex_unlock(&irq_mapping_update_lock); + return ret; + } +diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c +index bb36b1e1dbcc..775d4195966c 100644 +--- a/drivers/xen/grant-table.c ++++ b/drivers/xen/grant-table.c +@@ -327,7 +327,7 @@ static void gnttab_handle_deferred(unsigned long unused) + if (entry->page) { + pr_debug("freeing g.e. %#x (pfn %#lx)\n", + entry->ref, page_to_pfn(entry->page)); +- __free_page(entry->page); ++ put_page(entry->page); + } else + pr_info("freeing g.e. %#x\n", entry->ref); + kfree(entry); +@@ -383,7 +383,7 @@ void gnttab_end_foreign_access(grant_ref_t ref, int readonly, + if (gnttab_end_foreign_access_ref(ref, readonly)) { + put_free_entry(ref); + if (page != 0) +- free_page(page); ++ put_page(virt_to_page(page)); + } else + gnttab_add_deferred(ref, readonly, + page ? virt_to_page(page) : NULL); +diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c +index b68ced5a6331..2fe7353ab720 100644 +--- a/drivers/xen/swiotlb-xen.c ++++ b/drivers/xen/swiotlb-xen.c +@@ -359,7 +359,7 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, + * physical address */ + phys = xen_bus_to_phys(dev_addr); + +- if (((dev_addr + size - 1 > dma_mask)) || ++ if (((dev_addr + size - 1 <= dma_mask)) || + range_straddles_page_boundary(phys, size)) + xen_destroy_contiguous_region(phys, order); + +diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c +index 4b857463a2b4..7ff9d25f714e 100644 +--- a/drivers/xen/xen-acpi-processor.c ++++ b/drivers/xen/xen-acpi-processor.c +@@ -362,9 +362,9 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv) + } + /* There are more ACPI Processor objects than in x2APIC or MADT. + * This can happen with incorrect ACPI SSDT declerations. */ +- if (acpi_id > nr_acpi_bits) { +- pr_debug("We only have %u, trying to set %u\n", +- nr_acpi_bits, acpi_id); ++ if (acpi_id >= nr_acpi_bits) { ++ pr_debug("max acpi id %u, trying to set %u\n", ++ nr_acpi_bits - 1, acpi_id); + return AE_OK; + } + /* OK, There is a ACPI Processor object */ +diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c +index 33a31cfef55d..c2d447687e33 100644 +--- a/drivers/xen/xenbus/xenbus_probe.c ++++ b/drivers/xen/xenbus/xenbus_probe.c +@@ -470,8 +470,11 @@ int xenbus_probe_node(struct xen_bus_type *bus, + + /* Register with generic device framework. */ + err = device_register(&xendev->dev); +- if (err) ++ if (err) { ++ put_device(&xendev->dev); ++ xendev = NULL; + goto fail; ++ } + + return 0; + fail: +diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c +index d295d9878dff..8ec79385d3cc 100644 +--- a/drivers/zorro/zorro.c ++++ b/drivers/zorro/zorro.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -185,6 +186,17 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) + z->dev.parent = &bus->dev; + z->dev.bus = &zorro_bus_type; + z->dev.id = i; ++ switch (z->rom.er_Type & ERT_TYPEMASK) { ++ case ERT_ZORROIII: ++ z->dev.coherent_dma_mask = DMA_BIT_MASK(32); ++ break; ++ ++ case ERT_ZORROII: ++ default: ++ z->dev.coherent_dma_mask = DMA_BIT_MASK(24); ++ break; ++ } ++ z->dev.dma_mask = &z->dev.coherent_dma_mask; + } + + /* ... then register them */ +diff --git a/fs/affs/namei.c b/fs/affs/namei.c +index 29186d29a3b6..2d4d4952e951 100644 +--- a/fs/affs/namei.c ++++ b/fs/affs/namei.c +@@ -224,9 +224,10 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) + + affs_lock_dir(dir); + bh = affs_find_entry(dir, dentry); +- affs_unlock_dir(dir); +- if (IS_ERR(bh)) ++ if (IS_ERR(bh)) { ++ affs_unlock_dir(dir); + return ERR_CAST(bh); ++ } + if (bh) { + u32 ino = bh->b_blocknr; + +@@ -240,10 +241,13 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) + } + affs_brelse(bh); + inode = affs_iget(sb, ino); +- if (IS_ERR(inode)) ++ if (IS_ERR(inode)) { ++ affs_unlock_dir(dir); + return ERR_CAST(inode); ++ } + } + d_add(dentry, inode); ++ affs_unlock_dir(dir); + return NULL; + } + +diff --git a/fs/aio.c b/fs/aio.c +index 0606f033cd9b..42d8c09311d1 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -1074,8 +1074,8 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id) + + ctx = rcu_dereference(table->table[id]); + if (ctx && ctx->user_id == ctx_id) { +- percpu_ref_get(&ctx->users); +- ret = ctx; ++ if (percpu_ref_tryget_live(&ctx->users)) ++ ret = ctx; + } + out: + rcu_read_unlock(); +diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c +index 409b12392474..c94d3390cbfc 100644 +--- a/fs/btrfs/ctree.c ++++ b/fs/btrfs/ctree.c +@@ -2760,6 +2760,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root + * contention with the cow code + */ + if (cow) { ++ bool last_level = (level == (BTRFS_MAX_LEVEL - 1)); ++ + /* + * if we don't really need to cow this block + * then we don't want to set the path blocking, +@@ -2784,9 +2786,13 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root + } + + btrfs_set_path_blocking(p); +- err = btrfs_cow_block(trans, root, b, +- p->nodes[level + 1], +- p->slots[level + 1], &b); ++ if (last_level) ++ err = btrfs_cow_block(trans, root, b, NULL, 0, ++ &b); ++ else ++ err = btrfs_cow_block(trans, root, b, ++ p->nodes[level + 1], ++ p->slots[level + 1], &b); + if (err) { + ret = err; + goto done; +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 1cd325765aaa..c5eafcdb3664 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -1281,7 +1281,7 @@ static struct btrfs_subvolume_writers *btrfs_alloc_subvolume_writers(void) + if (!writers) + return ERR_PTR(-ENOMEM); + +- ret = percpu_counter_init(&writers->counter, 0, GFP_KERNEL); ++ ret = percpu_counter_init(&writers->counter, 0, GFP_NOFS); + if (ret < 0) { + kfree(writers); + return ERR_PTR(ret); +@@ -4142,9 +4142,11 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, + btrfs_err(fs_info, "no valid FS found"); + ret = -EINVAL; + } +- if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP) +- btrfs_warn(fs_info, "unrecognized super flag: %llu", ++ if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP) { ++ btrfs_err(fs_info, "unrecognized or unsupported super flag: %llu", + btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP); ++ ret = -EINVAL; ++ } + if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) { + btrfs_err(fs_info, "tree_root level too big: %d >= %d", + btrfs_super_root_level(sb), BTRFS_MAX_LEVEL); +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index a29730c44850..44a43851404a 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -4527,6 +4527,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, + if (wait_for_alloc) { + mutex_unlock(&fs_info->chunk_mutex); + wait_for_alloc = 0; ++ cond_resched(); + goto again; + } + +diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c +index c95ff096cd24..437544846e4e 100644 +--- a/fs/btrfs/file.c ++++ b/fs/btrfs/file.c +@@ -1912,10 +1912,19 @@ int btrfs_release_file(struct inode *inode, struct file *filp) + static int start_ordered_ops(struct inode *inode, loff_t start, loff_t end) + { + int ret; ++ struct blk_plug plug; + ++ /* ++ * This is only called in fsync, which would do synchronous writes, so ++ * a plug can merge adjacent IOs as much as possible. Esp. in case of ++ * multiple disks using raid profile, a large IO can be split to ++ * several segments of stripe length (currently 64K). ++ */ ++ blk_start_plug(&plug); + atomic_inc(&BTRFS_I(inode)->sync_writers); + ret = btrfs_fdatawrite_range(inode, start, end); + atomic_dec(&BTRFS_I(inode)->sync_writers); ++ blk_finish_plug(&plug); + + return ret; + } +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index ffd5831ca15c..f073de65e818 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -6491,8 +6491,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, + goto out_unlock_inode; + } else { + btrfs_update_inode(trans, root, inode); +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + } + + out_unlock: +@@ -6567,8 +6566,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, + goto out_unlock_inode; + + BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + + out_unlock: + btrfs_end_transaction(trans, root); +@@ -6711,12 +6709,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + if (err) + goto out_fail_inode; + +- d_instantiate(dentry, inode); +- /* +- * mkdir is special. We're unlocking after we call d_instantiate +- * to avoid a race with nfsd calling d_instantiate. +- */ +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + drop_on_err = 0; + + out_fail: +@@ -10354,8 +10347,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, + goto out_unlock_inode; + } + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + + out_unlock: + btrfs_end_transaction(trans, root); +diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c +index d016d4a79864..af6a776fa18c 100644 +--- a/fs/btrfs/raid56.c ++++ b/fs/btrfs/raid56.c +@@ -2161,11 +2161,21 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio, + } + + /* +- * reconstruct from the q stripe if they are +- * asking for mirror 3 ++ * Loop retry: ++ * for 'mirror == 2', reconstruct from all other stripes. ++ * for 'mirror_num > 2', select a stripe to fail on every retry. + */ +- if (mirror_num == 3) +- rbio->failb = rbio->real_stripes - 2; ++ if (mirror_num > 2) { ++ /* ++ * 'mirror == 3' is to fail the p stripe and ++ * reconstruct from the q stripe. 'mirror > 3' is to ++ * fail a data stripe and reconstruct from p+q stripe. ++ */ ++ rbio->failb = rbio->real_stripes - (mirror_num - 1); ++ ASSERT(rbio->failb > 0); ++ if (rbio->failb <= rbio->faila) ++ rbio->failb--; ++ } + + ret = lock_stripe_add(rbio); + +diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c +index d040afc966fe..c8d2eec6596b 100644 +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -4822,6 +4822,9 @@ static int send_hole(struct send_ctx *sctx, u64 end) + u64 len; + int ret = 0; + ++ if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) ++ return send_update_extent(sctx, offset, end - offset); ++ + p = fs_path_alloc(); + if (!p) + return -ENOMEM; +diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c +index ca7cb5e6d385..9c6666692341 100644 +--- a/fs/btrfs/tests/qgroup-tests.c ++++ b/fs/btrfs/tests/qgroup-tests.c +@@ -63,7 +63,7 @@ static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr, + btrfs_set_extent_generation(leaf, item, 1); + btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK); + block_info = (struct btrfs_tree_block_info *)(item + 1); +- btrfs_set_tree_block_level(leaf, block_info, 1); ++ btrfs_set_tree_block_level(leaf, block_info, 0); + iref = (struct btrfs_extent_inline_ref *)(block_info + 1); + if (parent > 0) { + btrfs_set_extent_inline_ref_type(leaf, iref, +diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c +index c65350e5119c..44d34923de9c 100644 +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -2241,8 +2241,10 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans, + nritems = btrfs_header_nritems(path->nodes[0]); + if (path->slots[0] >= nritems) { + ret = btrfs_next_leaf(root, path); +- if (ret) ++ if (ret == 1) + break; ++ else if (ret < 0) ++ goto out; + } + btrfs_item_key_to_cpu(path->nodes[0], &found_key, + path->slots[0]); +@@ -3397,8 +3399,11 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, + * from this directory and from this transaction + */ + ret = btrfs_next_leaf(root, path); +- if (ret == 1) { +- last_offset = (u64)-1; ++ if (ret) { ++ if (ret == 1) ++ last_offset = (u64)-1; ++ else ++ err = ret; + goto done; + } + btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]); +@@ -3849,6 +3854,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, + ASSERT(ret == 0); + src = src_path->nodes[0]; + i = 0; ++ need_find_last_extent = true; + } + + btrfs_item_key_to_cpu(src, &key, i); +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index c2495cde26f6..76017e1b3c0f 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -5186,7 +5186,14 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) + else if (map->type & BTRFS_BLOCK_GROUP_RAID5) + ret = 2; + else if (map->type & BTRFS_BLOCK_GROUP_RAID6) +- ret = 3; ++ /* ++ * There could be two corrupted data stripes, we need ++ * to loop retry in order to rebuild the correct data. ++ * ++ * Fail a stripe at a time on every retry except the ++ * stripe under reconstruction. ++ */ ++ ret = map->num_stripes; + else + ret = 1; + free_extent_map(em); +diff --git a/fs/ceph/super.c b/fs/ceph/super.c +index b382e5910eea..2a8903025853 100644 +--- a/fs/ceph/super.c ++++ b/fs/ceph/super.c +@@ -816,7 +816,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) + int err; + unsigned long started = jiffies; /* note the start time */ + struct dentry *root; +- int first = 0; /* first vfsmount for this super_block */ + + dout("mount start %p\n", fsc); + mutex_lock(&fsc->client->mount_mutex); +@@ -834,17 +833,17 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) + path = fsc->mount_options->server_path + 1; + dout("mount opening path %s\n", path); + } ++ ++ err = ceph_fs_debugfs_init(fsc); ++ if (err < 0) ++ goto out; ++ + root = open_root_dentry(fsc, path, started); + if (IS_ERR(root)) { + err = PTR_ERR(root); + goto out; + } + fsc->sb->s_root = dget(root); +- first = 1; +- +- err = ceph_fs_debugfs_init(fsc); +- if (err < 0) +- goto fail; + } else { + root = dget(fsc->sb->s_root); + } +@@ -854,11 +853,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) + mutex_unlock(&fsc->client->mount_mutex); + return root; + +-fail: +- if (first) { +- dput(fsc->sb->s_root); +- fsc->sb->s_root = NULL; +- } + out: + mutex_unlock(&fsc->client->mount_mutex); + return ERR_PTR(err); +diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c +index cc420d6b71f7..d57222894892 100644 +--- a/fs/cifs/cifssmb.c ++++ b/fs/cifs/cifssmb.c +@@ -6413,9 +6413,7 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_EA); + +- parm_data = +- (struct fealist *) (((char *) &pSMB->hdr.Protocol) + +- offset); ++ parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset; + pSMB->ParameterOffset = cpu_to_le16(param_offset); + pSMB->DataOffset = cpu_to_le16(offset); + pSMB->SetupCount = 1; +diff --git a/fs/dcache.c b/fs/dcache.c +index 2225b9855c5f..7a5e6f9717f5 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1859,6 +1859,28 @@ void d_instantiate(struct dentry *entry, struct inode * inode) + } + EXPORT_SYMBOL(d_instantiate); + ++/* ++ * This should be equivalent to d_instantiate() + unlock_new_inode(), ++ * with lockdep-related part of unlock_new_inode() done before ++ * anything else. Use that instead of open-coding d_instantiate()/ ++ * unlock_new_inode() combinations. ++ */ ++void d_instantiate_new(struct dentry *entry, struct inode *inode) ++{ ++ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); ++ BUG_ON(!inode); ++ lockdep_annotate_inode_mutex_key(inode); ++ security_d_instantiate(entry, inode); ++ spin_lock(&inode->i_lock); ++ __d_instantiate(entry, inode); ++ WARN_ON(!(inode->i_state & I_NEW)); ++ inode->i_state &= ~I_NEW; ++ smp_mb(); ++ wake_up_bit(&inode->i_state, __I_NEW); ++ spin_unlock(&inode->i_lock); ++} ++EXPORT_SYMBOL(d_instantiate_new); ++ + /** + * d_instantiate_no_diralias - instantiate a non-aliased dentry + * @entry: dentry to complete +@@ -2452,7 +2474,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent, + + retry: + rcu_read_lock(); +- seq = smp_load_acquire(&parent->d_inode->i_dir_seq) & ~1; ++ seq = smp_load_acquire(&parent->d_inode->i_dir_seq); + r_seq = read_seqbegin(&rename_lock); + dentry = __d_lookup_rcu(parent, name, &d_seq); + if (unlikely(dentry)) { +@@ -2473,8 +2495,14 @@ struct dentry *d_alloc_parallel(struct dentry *parent, + rcu_read_unlock(); + goto retry; + } ++ ++ if (unlikely(seq & 1)) { ++ rcu_read_unlock(); ++ goto retry; ++ } ++ + hlist_bl_lock(b); +- if (unlikely(parent->d_inode->i_dir_seq != seq)) { ++ if (unlikely(READ_ONCE(parent->d_inode->i_dir_seq) != seq)) { + hlist_bl_unlock(b); + rcu_read_unlock(); + goto retry; +diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c +index cf390dceddd2..5c5ff9f6fe07 100644 +--- a/fs/ecryptfs/inode.c ++++ b/fs/ecryptfs/inode.c +@@ -284,8 +284,7 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, + iget_failed(ecryptfs_inode); + goto out; + } +- unlock_new_inode(ecryptfs_inode); +- d_instantiate(ecryptfs_dentry, ecryptfs_inode); ++ d_instantiate_new(ecryptfs_dentry, ecryptfs_inode); + out: + return rc; + } +diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c +index 814e405a2da6..c8efc5ea1b9f 100644 +--- a/fs/ext2/namei.c ++++ b/fs/ext2/namei.c +@@ -40,8 +40,7 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) + { + int err = ext2_add_link(dentry, inode); + if (!err) { +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + return 0; + } + inode_dec_link_count(inode); +@@ -268,8 +267,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) + if (err) + goto out_fail; + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + out: + return err; + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index b1766a67d2eb..248c43b63f13 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -2442,8 +2442,7 @@ static int ext4_add_nondir(handle_t *handle, + int err = ext4_add_entry(handle, dentry, inode); + if (!err) { + ext4_mark_inode_dirty(handle, inode); +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + return 0; + } + drop_nlink(inode); +@@ -2682,8 +2681,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + err = ext4_mark_inode_dirty(handle, dir); + if (err) + goto out_clear_inode; +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + if (IS_DIRSYNC(dir)) + ext4_handle_sync(handle); + +diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c +index 63e519658d73..d7b8c8b5fc39 100644 +--- a/fs/f2fs/extent_cache.c ++++ b/fs/f2fs/extent_cache.c +@@ -647,6 +647,9 @@ void f2fs_drop_extent_tree(struct inode *inode) + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct extent_tree *et = F2FS_I(inode)->extent_tree; + ++ if (!f2fs_may_extent_tree(inode)) ++ return; ++ + set_inode_flag(inode, FI_NO_EXTENT); + + write_lock(&et->lock); +diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c +index 8556fe1ccb8a..ccb99d5cfd8b 100644 +--- a/fs/f2fs/namei.c ++++ b/fs/f2fs/namei.c +@@ -158,8 +158,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + + alloc_nid_done(sbi, ino); + +- d_instantiate(dentry, inode); +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + + if (IS_DIRSYNC(dir)) + f2fs_sync_fs(sbi->sb, 1); +@@ -464,8 +463,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, + err = page_symlink(inode, disk_link.name, disk_link.len); + + err_out: +- d_instantiate(dentry, inode); +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + + /* + * Let's flush symlink data in order to avoid broken symlink as much as +@@ -519,8 +517,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + + alloc_nid_done(sbi, inode->i_ino); + +- d_instantiate(dentry, inode); +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + + if (IS_DIRSYNC(dir)) + f2fs_sync_fs(sbi->sb, 1); +@@ -564,8 +561,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, + + alloc_nid_done(sbi, inode->i_ino); + +- d_instantiate(dentry, inode); +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + + if (IS_DIRSYNC(dir)) + f2fs_sync_fs(sbi->sb, 1); +diff --git a/fs/fscache/page.c b/fs/fscache/page.c +index c8c4f79c7ce1..8a7923a4f93c 100644 +--- a/fs/fscache/page.c ++++ b/fs/fscache/page.c +@@ -776,6 +776,7 @@ static void fscache_write_op(struct fscache_operation *_op) + + _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage)); + ++again: + spin_lock(&object->lock); + cookie = object->cookie; + +@@ -816,10 +817,6 @@ static void fscache_write_op(struct fscache_operation *_op) + goto superseded; + page = results[0]; + _debug("gang %d [%lx]", n, page->index); +- if (page->index >= op->store_limit) { +- fscache_stat(&fscache_n_store_pages_over_limit); +- goto superseded; +- } + + radix_tree_tag_set(&cookie->stores, page->index, + FSCACHE_COOKIE_STORING_TAG); +@@ -829,6 +826,9 @@ static void fscache_write_op(struct fscache_operation *_op) + spin_unlock(&cookie->stores_lock); + spin_unlock(&object->lock); + ++ if (page->index >= op->store_limit) ++ goto discard_page; ++ + fscache_stat(&fscache_n_store_pages); + fscache_stat(&fscache_n_cop_write_page); + ret = object->cache->ops->write_page(op, page); +@@ -844,6 +844,11 @@ static void fscache_write_op(struct fscache_operation *_op) + _leave(""); + return; + ++discard_page: ++ fscache_stat(&fscache_n_store_pages_over_limit); ++ fscache_end_page_write(object, page); ++ goto again; ++ + superseded: + /* this writer is going away and there aren't any more things to + * write */ +diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c +index 39c382f16272..ff93e96099d8 100644 +--- a/fs/gfs2/file.c ++++ b/fs/gfs2/file.c +@@ -801,7 +801,7 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_alloc_parms ap = { .aflags = 0, }; + unsigned int data_blocks = 0, ind_blocks = 0, rblocks; +- loff_t bytes, max_bytes, max_blks = UINT_MAX; ++ loff_t bytes, max_bytes, max_blks; + int error; + const loff_t pos = offset; + const loff_t count = len; +@@ -853,7 +853,8 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t + return error; + /* ap.allowed tells us how many blocks quota will allow + * us to write. Check if this reduces max_blks */ +- if (ap.allowed && ap.allowed < max_blks) ++ max_blks = UINT_MAX; ++ if (ap.allowed) + max_blks = ap.allowed; + + error = gfs2_inplace_reserve(ip, &ap); +diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h +index 5e47c935a515..836f29480be6 100644 +--- a/fs/gfs2/quota.h ++++ b/fs/gfs2/quota.h +@@ -45,6 +45,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip, + { + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + int ret; ++ ++ ap->allowed = UINT_MAX; /* Assume we are permitted a whole lot */ + if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) + return 0; + ret = gfs2_quota_lock(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE); +diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c +index 0a754f38462e..e5a6deb38e1e 100644 +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -209,8 +209,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, + __func__, inode->i_ino, inode->i_mode, inode->i_nlink, + f->inocache->pino_nlink, inode->i_mapping->nrpages); + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + return 0; + + fail: +@@ -430,8 +429,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char + mutex_unlock(&dir_f->sem); + jffs2_complete_reservation(c); + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + return 0; + + fail: +@@ -575,8 +573,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode + mutex_unlock(&dir_f->sem); + jffs2_complete_reservation(c); + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + return 0; + + fail: +@@ -747,8 +744,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode + mutex_unlock(&dir_f->sem); + jffs2_complete_reservation(c); + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + return 0; + + fail: +diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c +index 567653f7c0ce..c9c47d03a690 100644 +--- a/fs/jffs2/fs.c ++++ b/fs/jffs2/fs.c +@@ -361,7 +361,6 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) + ret = -EIO; + error: + mutex_unlock(&f->sem); +- jffs2_do_clear_inode(c, f); + iget_failed(inode); + return ERR_PTR(ret); + } +diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c +index b41596d71858..56c3fcbfe80e 100644 +--- a/fs/jfs/namei.c ++++ b/fs/jfs/namei.c +@@ -178,8 +178,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode, + unlock_new_inode(ip); + iput(ip); + } else { +- unlock_new_inode(ip); +- d_instantiate(dentry, ip); ++ d_instantiate_new(dentry, ip); + } + + out2: +@@ -313,8 +312,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) + unlock_new_inode(ip); + iput(ip); + } else { +- unlock_new_inode(ip); +- d_instantiate(dentry, ip); ++ d_instantiate_new(dentry, ip); + } + + out2: +@@ -1059,8 +1057,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, + unlock_new_inode(ip); + iput(ip); + } else { +- unlock_new_inode(ip); +- d_instantiate(dentry, ip); ++ d_instantiate_new(dentry, ip); + } + + out2: +@@ -1447,8 +1444,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, + unlock_new_inode(ip); + iput(ip); + } else { +- unlock_new_inode(ip); +- d_instantiate(dentry, ip); ++ d_instantiate_new(dentry, ip); + } + + out1: +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index 1b1b616a6171..91e017ca7072 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -1934,7 +1934,7 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta + return ret; + } + +-static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, int err) ++static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, struct file_lock *fl, int err) + { + switch (err) { + default: +@@ -1981,7 +1981,11 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct + return -EAGAIN; + case -ENOMEM: + case -NFS4ERR_DENIED: +- /* kill_proc(fl->fl_pid, SIGLOST, 1); */ ++ if (fl) { ++ struct nfs4_lock_state *lsp = fl->fl_u.nfs4_fl.owner; ++ if (lsp) ++ set_bit(NFS_LOCK_LOST, &lsp->ls_flags); ++ } + return 0; + } + return err; +@@ -2017,7 +2021,7 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, + err = nfs4_open_recover_helper(opendata, FMODE_READ); + } + nfs4_opendata_put(opendata); +- return nfs4_handle_delegation_recall_error(server, state, stateid, err); ++ return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err); + } + + static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata) +@@ -6499,7 +6503,7 @@ int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, + if (err != 0) + return err; + err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); +- return nfs4_handle_delegation_recall_error(server, state, stateid, err); ++ return nfs4_handle_delegation_recall_error(server, state, stateid, fl, err); + } + + struct nfs_release_lockowner_data { +diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c +index 0bb0e620cf42..353691366fca 100644 +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -1429,6 +1429,7 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ + struct inode *inode = state->inode; + struct nfs_inode *nfsi = NFS_I(inode); + struct file_lock *fl; ++ struct nfs4_lock_state *lsp; + int status = 0; + struct file_lock_context *flctx = inode->i_flctx; + struct list_head *list; +@@ -1469,7 +1470,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ + case -NFS4ERR_DENIED: + case -NFS4ERR_RECLAIM_BAD: + case -NFS4ERR_RECLAIM_CONFLICT: +- /* kill_proc(fl->fl_pid, SIGLOST, 1); */ ++ lsp = fl->fl_u.nfs4_fl.owner; ++ if (lsp) ++ set_bit(NFS_LOCK_LOST, &lsp->ls_flags); + status = 0; + } + spin_lock(&flctx->flc_lock); +diff --git a/fs/nfs/nfs4sysctl.c b/fs/nfs/nfs4sysctl.c +index 8693d77c45ea..76241aa8d853 100644 +--- a/fs/nfs/nfs4sysctl.c ++++ b/fs/nfs/nfs4sysctl.c +@@ -31,7 +31,7 @@ static struct ctl_table nfs4_cb_sysctls[] = { + .data = &nfs_idmap_cache_timeout, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec_jiffies, ++ .proc_handler = proc_dointvec, + }, + { } + }; +diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c +index 2b71c60fe982..163131809e36 100644 +--- a/fs/nilfs2/namei.c ++++ b/fs/nilfs2/namei.c +@@ -46,8 +46,7 @@ static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) + int err = nilfs_add_link(dentry, inode); + + if (!err) { +- d_instantiate(dentry, inode); +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + return 0; + } + inode_dec_link_count(inode); +@@ -243,8 +242,7 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + goto out_fail; + + nilfs_mark_inode_dirty(inode); +- d_instantiate(dentry, inode); +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + out: + if (!err) + err = nilfs_transaction_commit(dir->i_sb); +diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c +index bed1fcb63088..ee8dbbae78b6 100644 +--- a/fs/ocfs2/acl.c ++++ b/fs/ocfs2/acl.c +@@ -314,7 +314,9 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) + return ERR_PTR(ret); + } + ++ down_read(&OCFS2_I(inode)->ip_xattr_sem); + acl = ocfs2_get_acl_nolock(inode, type, di_bh); ++ up_read(&OCFS2_I(inode)->ip_xattr_sem); + + ocfs2_inode_unlock(inode, 0); + brelse(di_bh); +@@ -333,7 +335,9 @@ int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh) + if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) + return 0; + ++ down_read(&OCFS2_I(inode)->ip_xattr_sem); + acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh); ++ up_read(&OCFS2_I(inode)->ip_xattr_sem); + if (IS_ERR(acl) || !acl) + return PTR_ERR(acl); + ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); +@@ -364,8 +368,10 @@ int ocfs2_init_acl(handle_t *handle, + + if (!S_ISLNK(inode->i_mode)) { + if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { ++ down_read(&OCFS2_I(dir)->ip_xattr_sem); + acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, + dir_bh); ++ up_read(&OCFS2_I(dir)->ip_xattr_sem); + if (IS_ERR(acl)) + return PTR_ERR(acl); + } +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 733e4e79c8e2..73be0c6dba5d 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -675,20 +675,6 @@ static void dlm_leave_domain(struct dlm_ctxt *dlm) + spin_unlock(&dlm->spinlock); + } + +-int dlm_shutting_down(struct dlm_ctxt *dlm) +-{ +- int ret = 0; +- +- spin_lock(&dlm_domain_lock); +- +- if (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN) +- ret = 1; +- +- spin_unlock(&dlm_domain_lock); +- +- return ret; +-} +- + void dlm_unregister_domain(struct dlm_ctxt *dlm) + { + int leave = 0; +diff --git a/fs/ocfs2/dlm/dlmdomain.h b/fs/ocfs2/dlm/dlmdomain.h +index fd6122a38dbd..8a9281411c18 100644 +--- a/fs/ocfs2/dlm/dlmdomain.h ++++ b/fs/ocfs2/dlm/dlmdomain.h +@@ -28,7 +28,30 @@ + extern spinlock_t dlm_domain_lock; + extern struct list_head dlm_domains; + +-int dlm_shutting_down(struct dlm_ctxt *dlm); ++static inline int dlm_joined(struct dlm_ctxt *dlm) ++{ ++ int ret = 0; ++ ++ spin_lock(&dlm_domain_lock); ++ if (dlm->dlm_state == DLM_CTXT_JOINED) ++ ret = 1; ++ spin_unlock(&dlm_domain_lock); ++ ++ return ret; ++} ++ ++static inline int dlm_shutting_down(struct dlm_ctxt *dlm) ++{ ++ int ret = 0; ++ ++ spin_lock(&dlm_domain_lock); ++ if (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN) ++ ret = 1; ++ spin_unlock(&dlm_domain_lock); ++ ++ return ret; ++} ++ + void dlm_fire_domain_eviction_callbacks(struct dlm_ctxt *dlm, + int node_num); + +diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c +index eef324823311..844dc8da53fb 100644 +--- a/fs/ocfs2/dlm/dlmrecovery.c ++++ b/fs/ocfs2/dlm/dlmrecovery.c +@@ -1378,6 +1378,15 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data, + if (!dlm_grab(dlm)) + return -EINVAL; + ++ if (!dlm_joined(dlm)) { ++ mlog(ML_ERROR, "Domain %s not joined! " ++ "lockres %.*s, master %u\n", ++ dlm->name, mres->lockname_len, ++ mres->lockname, mres->master); ++ dlm_put(dlm); ++ return -EINVAL; ++ } ++ + BUG_ON(!(mres->flags & (DLM_MRES_RECOVERY|DLM_MRES_MIGRATION))); + + real_master = mres->master; +diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c +index a244f14c6b87..fa947d36ae1d 100644 +--- a/fs/ocfs2/journal.c ++++ b/fs/ocfs2/journal.c +@@ -666,23 +666,24 @@ static int __ocfs2_journal_access(handle_t *handle, + /* we can safely remove this assertion after testing. */ + if (!buffer_uptodate(bh)) { + mlog(ML_ERROR, "giving me a buffer that's not uptodate!\n"); +- mlog(ML_ERROR, "b_blocknr=%llu\n", +- (unsigned long long)bh->b_blocknr); ++ mlog(ML_ERROR, "b_blocknr=%llu, b_state=0x%lx\n", ++ (unsigned long long)bh->b_blocknr, bh->b_state); + + lock_buffer(bh); + /* +- * A previous attempt to write this buffer head failed. +- * Nothing we can do but to retry the write and hope for +- * the best. ++ * A previous transaction with a couple of buffer heads fail ++ * to checkpoint, so all the bhs are marked as BH_Write_EIO. ++ * For current transaction, the bh is just among those error ++ * bhs which previous transaction handle. We can't just clear ++ * its BH_Write_EIO and reuse directly, since other bhs are ++ * not written to disk yet and that will cause metadata ++ * inconsistency. So we should set fs read-only to avoid ++ * further damage. + */ + if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) { +- clear_buffer_write_io_error(bh); +- set_buffer_uptodate(bh); +- } +- +- if (!buffer_uptodate(bh)) { + unlock_buffer(bh); +- return -EIO; ++ return ocfs2_error(osb->sb, "A previous attempt to " ++ "write this buffer head failed\n"); + } + unlock_buffer(bh); + } +diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c +index f56fe39fab04..64dfbe5755da 100644 +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -473,9 +473,8 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb) + new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); + if (!new) { + ocfs2_release_system_inodes(osb); +- status = -EINVAL; ++ status = ocfs2_is_soft_readonly(osb) ? -EROFS : -EINVAL; + mlog_errno(status); +- /* FIXME: Should ERROR_RO_FS */ + mlog(ML_ERROR, "Unable to load system inode %d, " + "possibly corrupt fs?", i); + goto bail; +@@ -504,7 +503,7 @@ static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb) + new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); + if (!new) { + ocfs2_release_system_inodes(osb); +- status = -EINVAL; ++ status = ocfs2_is_soft_readonly(osb) ? -EROFS : -EINVAL; + mlog(ML_ERROR, "status=%d, sysfile=%d, slot=%d\n", + status, i, osb->slot_num); + goto bail; +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index cb157a34a656..03f6ff249edb 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -638,9 +638,11 @@ int ocfs2_calc_xattr_init(struct inode *dir, + si->value_len); + + if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { ++ down_read(&OCFS2_I(dir)->ip_xattr_sem); + acl_len = ocfs2_xattr_get_nolock(dir, dir_bh, + OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT, + "", NULL, 0); ++ up_read(&OCFS2_I(dir)->ip_xattr_sem); + if (acl_len > 0) { + a_size = ocfs2_xattr_entry_real_size(0, acl_len); + if (S_ISDIR(mode)) +diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c +index 7c315938e9c2..561497a7a247 100644 +--- a/fs/orangefs/namei.c ++++ b/fs/orangefs/namei.c +@@ -70,8 +70,7 @@ static int orangefs_create(struct inode *dir, + get_khandle_from_ino(inode), + dentry); + +- d_instantiate(dentry, inode); +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + orangefs_set_timeout(dentry); + ORANGEFS_I(inode)->getattr_time = jiffies - 1; + +@@ -318,8 +317,7 @@ static int orangefs_symlink(struct inode *dir, + "Assigned symlink inode new number of %pU\n", + get_khandle_from_ino(inode)); + +- d_instantiate(dentry, inode); +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + orangefs_set_timeout(dentry); + ORANGEFS_I(inode)->getattr_time = jiffies - 1; + +@@ -382,8 +380,7 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode + "Assigned dir inode new number of %pU\n", + get_khandle_from_ino(inode)); + +- d_instantiate(dentry, inode); +- unlock_new_inode(inode); ++ d_instantiate_new(dentry, inode); + orangefs_set_timeout(dentry); + ORANGEFS_I(inode)->getattr_time = jiffies - 1; + +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 3fec83ba75fa..591bf2b1ab66 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -94,6 +94,8 @@ + #include "internal.h" + #include "fd.h" + ++#include "../../lib/kstrtox.h" ++ + /* NOTE: + * Implementing inode permission operations in /proc is almost + * certainly an error. Permission checks need to happen during +@@ -1864,8 +1866,33 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx, + static int dname_to_vma_addr(struct dentry *dentry, + unsigned long *start, unsigned long *end) + { +- if (sscanf(dentry->d_name.name, "%lx-%lx", start, end) != 2) ++ const char *str = dentry->d_name.name; ++ unsigned long long sval, eval; ++ unsigned int len; ++ ++ len = _parse_integer(str, 16, &sval); ++ if (len & KSTRTOX_OVERFLOW) ++ return -EINVAL; ++ if (sval != (unsigned long)sval) + return -EINVAL; ++ str += len; ++ ++ if (*str != '-') ++ return -EINVAL; ++ str++; ++ ++ len = _parse_integer(str, 16, &eval); ++ if (len & KSTRTOX_OVERFLOW) ++ return -EINVAL; ++ if (eval != (unsigned long)eval) ++ return -EINVAL; ++ str += len; ++ ++ if (*str != '\0') ++ return -EINVAL; ++ ++ *start = sval; ++ *end = eval; + + return 0; + } +diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c +index df7e07986ead..7ed961c0124f 100644 +--- a/fs/proc/kcore.c ++++ b/fs/proc/kcore.c +@@ -505,6 +505,10 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos) + /* we have to zero-fill user buffer even if no read */ + if (copy_to_user(buffer, buf, tsz)) + return -EFAULT; ++ } else if (m->type == KCORE_USER) { ++ /* User page is handled prior to normal kernel page: */ ++ if (copy_to_user(buffer, (char *)start, tsz)) ++ return -EFAULT; + } else { + if (kern_addr_valid(start)) { + /* +diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c +index d4e37acd4821..847f23420b40 100644 +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -660,7 +660,10 @@ static bool proc_sys_link_fill_cache(struct file *file, + struct ctl_table *table) + { + bool ret = true; ++ + head = sysctl_head_grab(head); ++ if (IS_ERR(head)) ++ return false; + + if (S_ISLNK(table->mode)) { + /* It is not an error if we can not follow the link ignore it */ +diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c +index e6a2b406af36..1ec728cf82d1 100644 +--- a/fs/reiserfs/namei.c ++++ b/fs/reiserfs/namei.c +@@ -687,8 +687,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mod + reiserfs_update_inode_transaction(inode); + reiserfs_update_inode_transaction(dir); + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + retval = journal_end(&th); + + out_failed: +@@ -771,8 +770,7 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode + goto out_failed; + } + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + retval = journal_end(&th); + + out_failed: +@@ -871,8 +869,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode + /* the above add_entry did not update dir's stat data */ + reiserfs_update_sd(&th, dir); + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + retval = journal_end(&th); + out_failed: + reiserfs_write_unlock(dir->i_sb); +@@ -1187,8 +1184,7 @@ static int reiserfs_symlink(struct inode *parent_dir, + goto out_failed; + } + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + retval = journal_end(&th); + out_failed: + reiserfs_write_unlock(parent_dir->i_sb); +diff --git a/fs/udf/namei.c b/fs/udf/namei.c +index 2d65e280748b..348b922d1b6a 100644 +--- a/fs/udf/namei.c ++++ b/fs/udf/namei.c +@@ -621,8 +621,7 @@ static int udf_add_nondir(struct dentry *dentry, struct inode *inode) + if (fibh.sbh != fibh.ebh) + brelse(fibh.ebh); + brelse(fibh.sbh); +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + + return 0; + } +@@ -732,8 +731,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + inc_nlink(dir); + dir->i_ctime = dir->i_mtime = current_time(dir); + mark_inode_dirty(dir); +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + if (fibh.sbh != fibh.ebh) + brelse(fibh.ebh); + brelse(fibh.sbh); +diff --git a/fs/udf/super.c b/fs/udf/super.c +index 4b1f6d5372c3..12467ad608cd 100644 +--- a/fs/udf/super.c ++++ b/fs/udf/super.c +@@ -2094,8 +2094,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) + bool lvid_open = false; + + uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); +- uopt.uid = INVALID_UID; +- uopt.gid = INVALID_GID; ++ /* By default we'll use overflow[ug]id when UDF inode [ug]id == -1 */ ++ uopt.uid = make_kuid(current_user_ns(), overflowuid); ++ uopt.gid = make_kgid(current_user_ns(), overflowgid); + uopt.umask = 0; + uopt.fmode = UDF_INVALID_MODE; + uopt.dmode = UDF_INVALID_MODE; +diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c +index 8eca4eda8450..2109c071718b 100644 +--- a/fs/ufs/namei.c ++++ b/fs/ufs/namei.c +@@ -38,8 +38,7 @@ static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode) + { + int err = ufs_add_link(dentry, inode); + if (!err) { +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + return 0; + } + inode_dec_link_count(inode); +@@ -192,8 +191,7 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) + if (err) + goto out_fail; + +- unlock_new_inode(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + return 0; + + out_fail: +diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c +index 4ff499aa7338..b2ab123e561d 100644 +--- a/fs/xfs/xfs_discard.c ++++ b/fs/xfs/xfs_discard.c +@@ -50,19 +50,19 @@ xfs_trim_extents( + + pag = xfs_perag_get(mp, agno); + +- error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); +- if (error || !agbp) +- goto out_put_perag; +- +- cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT); +- + /* + * Force out the log. This means any transactions that might have freed +- * space before we took the AGF buffer lock are now on disk, and the ++ * space before we take the AGF buffer lock are now on disk, and the + * volatile disk cache is flushed. + */ + xfs_log_force(mp, XFS_LOG_SYNC); + ++ error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); ++ if (error || !agbp) ++ goto out_put_perag; ++ ++ cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT); ++ + /* + * Look up the longest btree in the AGF and start with it. + */ +diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h +index f6ea0f3c03f8..4e8551c8ef18 100644 +--- a/include/asm-generic/pgtable.h ++++ b/include/asm-generic/pgtable.h +@@ -234,6 +234,21 @@ extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, + extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); + #endif + ++#ifdef CONFIG_TRANSPARENT_HUGEPAGE ++/* ++ * This is an implementation of pmdp_establish() that is only suitable for an ++ * architecture that doesn't have hardware dirty/accessed bits. In this case we ++ * can't race with CPU which sets these bits and non-atomic aproach is fine. ++ */ ++static inline pmd_t generic_pmdp_establish(struct vm_area_struct *vma, ++ unsigned long address, pmd_t *pmdp, pmd_t pmd) ++{ ++ pmd_t old_pmd = *pmdp; ++ set_pmd_at(vma->vm_mm, address, pmdp, pmd); ++ return old_pmd; ++} ++#endif ++ + #ifndef __HAVE_ARCH_PMDP_INVALIDATE + extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, + pmd_t *pmdp); +diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h +index 18ba29ff1449..203ad564dc60 100644 +--- a/include/linux/cpumask.h ++++ b/include/linux/cpumask.h +@@ -164,6 +164,8 @@ static inline unsigned int cpumask_local_spread(unsigned int i, int node) + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) + #define for_each_cpu_not(cpu, mask) \ + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) ++#define for_each_cpu_wrap(cpu, mask, start) \ ++ for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)(start)) + #define for_each_cpu_and(cpu, mask, and) \ + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and) + #else +diff --git a/include/linux/dcache.h b/include/linux/dcache.h +index ff295e166b2c..b757ee42bc63 100644 +--- a/include/linux/dcache.h ++++ b/include/linux/dcache.h +@@ -219,6 +219,7 @@ extern seqlock_t rename_lock; + * These are the low-level FS interfaces to the dcache.. + */ + extern void d_instantiate(struct dentry *, struct inode *); ++extern void d_instantiate_new(struct dentry *, struct inode *); + extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *); + extern int d_instantiate_no_diralias(struct dentry *, struct inode *); + extern void __d_drop(struct dentry *dentry); +diff --git a/include/linux/kcore.h b/include/linux/kcore.h +index d92762286645..3ffade4f2798 100644 +--- a/include/linux/kcore.h ++++ b/include/linux/kcore.h +@@ -9,6 +9,7 @@ enum kcore_type { + KCORE_VMALLOC, + KCORE_RAM, + KCORE_VMEMMAP, ++ KCORE_USER, + KCORE_OTHER, + }; + +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index 8c58db2c09c6..eb55374b73f3 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -1070,7 +1070,6 @@ static inline void kvm_irq_routing_update(struct kvm *kvm) + { + } + #endif +-void kvm_arch_irq_routing_update(struct kvm *kvm); + + static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) + { +@@ -1079,6 +1078,8 @@ static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) + + #endif /* CONFIG_HAVE_KVM_EVENTFD */ + ++void kvm_arch_irq_routing_update(struct kvm *kvm); ++ + static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu) + { + /* +diff --git a/include/linux/property.h b/include/linux/property.h +index 338f9b76914b..459337fb44d0 100644 +--- a/include/linux/property.h ++++ b/include/linux/property.h +@@ -187,7 +187,7 @@ struct property_entry { + */ + + #define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \ +-{ \ ++(struct property_entry) { \ + .name = _name_, \ + .length = ARRAY_SIZE(_val_) * sizeof(_type_), \ + .is_array = true, \ +@@ -205,7 +205,7 @@ struct property_entry { + PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_) + + #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ +-{ \ ++(struct property_entry) { \ + .name = _name_, \ + .length = ARRAY_SIZE(_val_) * sizeof(const char *), \ + .is_array = true, \ +@@ -214,7 +214,7 @@ struct property_entry { + } + + #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \ +-{ \ ++(struct property_entry) { \ + .name = _name_, \ + .length = sizeof(_type_), \ + .is_string = false, \ +@@ -231,7 +231,7 @@ struct property_entry { + PROPERTY_ENTRY_INTEGER(_name_, u64, _val_) + + #define PROPERTY_ENTRY_STRING(_name_, _val_) \ +-{ \ ++(struct property_entry) { \ + .name = _name_, \ + .length = sizeof(_val_), \ + .is_string = true, \ +@@ -239,7 +239,7 @@ struct property_entry { + } + + #define PROPERTY_ENTRY_BOOL(_name_) \ +-{ \ ++(struct property_entry) { \ + .name = _name_, \ + } + +diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h +index 05c6d20c2a7a..ac377a23265f 100644 +--- a/include/linux/ptr_ring.h ++++ b/include/linux/ptr_ring.h +@@ -351,7 +351,7 @@ static inline void *ptr_ring_consume_bh(struct ptr_ring *r) + + static inline void **__ptr_ring_init_queue_alloc(unsigned int size, gfp_t gfp) + { +- if (size * sizeof(void *) > KMALLOC_MAX_SIZE) ++ if (size > KMALLOC_MAX_SIZE / sizeof(void *)) + return NULL; + return kcalloc(size, sizeof(void *), gfp); + } +diff --git a/include/linux/suspend.h b/include/linux/suspend.h +index d9718378a8be..249dafce2788 100644 +--- a/include/linux/suspend.h ++++ b/include/linux/suspend.h +@@ -378,6 +378,8 @@ extern int swsusp_page_is_forbidden(struct page *); + extern void swsusp_set_page_free(struct page *); + extern void swsusp_unset_page_free(struct page *); + extern unsigned long get_safe_page(gfp_t gfp_mask); ++extern asmlinkage int swsusp_arch_suspend(void); ++extern asmlinkage int swsusp_arch_resume(void); + + extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); + extern int hibernate(void); +diff --git a/include/net/ip.h b/include/net/ip.h +index 0e3dcd5a134d..bc9b4deeb60e 100644 +--- a/include/net/ip.h ++++ b/include/net/ip.h +@@ -304,6 +304,13 @@ int ip_decrease_ttl(struct iphdr *iph) + return --iph->ttl; + } + ++static inline int ip_mtu_locked(const struct dst_entry *dst) ++{ ++ const struct rtable *rt = (const struct rtable *)dst; ++ ++ return rt->rt_mtu_locked || dst_metric_locked(dst, RTAX_MTU); ++} ++ + static inline + int ip_dont_fragment(const struct sock *sk, const struct dst_entry *dst) + { +@@ -311,7 +318,7 @@ int ip_dont_fragment(const struct sock *sk, const struct dst_entry *dst) + + return pmtudisc == IP_PMTUDISC_DO || + (pmtudisc == IP_PMTUDISC_WANT && +- !(dst_metric_locked(dst, RTAX_MTU))); ++ !ip_mtu_locked(dst)); + } + + static inline bool ip_sk_accept_pmtu(const struct sock *sk) +@@ -337,7 +344,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst, + struct net *net = dev_net(dst->dev); + + if (net->ipv4.sysctl_ip_fwd_use_pmtu || +- dst_metric_locked(dst, RTAX_MTU) || ++ ip_mtu_locked(dst) || + !forwarding) + return dst_mtu(dst); + +diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h +index aa758280d8a8..978387d6c3e6 100644 +--- a/include/net/ip_fib.h ++++ b/include/net/ip_fib.h +@@ -57,6 +57,7 @@ struct fib_nh_exception { + int fnhe_genid; + __be32 fnhe_daddr; + u32 fnhe_pmtu; ++ bool fnhe_mtu_locked; + __be32 fnhe_gw; + unsigned long fnhe_expires; + struct rtable __rcu *fnhe_rth_input; +diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h +index ea985aa7a6c5..df528a623548 100644 +--- a/include/net/llc_conn.h ++++ b/include/net/llc_conn.h +@@ -104,7 +104,7 @@ void llc_sk_reset(struct sock *sk); + + /* Access to a connection */ + int llc_conn_state_process(struct sock *sk, struct sk_buff *skb); +-void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb); ++int llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb); + void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb); + void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit); + void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit); +diff --git a/include/net/mac80211.h b/include/net/mac80211.h +index 8fd61bc50383..920a771c710f 100644 +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -4091,7 +4091,7 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid); + * The TX headroom reserved by mac80211 for its own tx_status functions. + * This is enough for the radiotap header. + */ +-#define IEEE80211_TX_STATUS_HEADROOM 14 ++#define IEEE80211_TX_STATUS_HEADROOM ALIGN(14, 4) + + /** + * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames +diff --git a/include/net/regulatory.h b/include/net/regulatory.h +index ebc5a2ed8631..f83cacce3308 100644 +--- a/include/net/regulatory.h ++++ b/include/net/regulatory.h +@@ -78,7 +78,7 @@ struct regulatory_request { + int wiphy_idx; + enum nl80211_reg_initiator initiator; + enum nl80211_user_reg_hint_type user_reg_hint_type; +- char alpha2[2]; ++ char alpha2[3]; + enum nl80211_dfs_regions dfs_region; + bool intersect; + bool processed; +diff --git a/include/net/route.h b/include/net/route.h +index 0429d47cad25..b8488efef920 100644 +--- a/include/net/route.h ++++ b/include/net/route.h +@@ -63,7 +63,8 @@ struct rtable { + __be32 rt_gateway; + + /* Miscellaneous cached information */ +- u32 rt_pmtu; ++ u32 rt_mtu_locked:1, ++ rt_pmtu:31; + + u32 rt_table_id; + +diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h +index 28c5da6fdfac..3411da79407d 100644 +--- a/include/trace/events/timer.h ++++ b/include/trace/events/timer.h +@@ -125,6 +125,20 @@ DEFINE_EVENT(timer_class, timer_cancel, + TP_ARGS(timer) + ); + ++#define decode_clockid(type) \ ++ __print_symbolic(type, \ ++ { CLOCK_REALTIME, "CLOCK_REALTIME" }, \ ++ { CLOCK_MONOTONIC, "CLOCK_MONOTONIC" }, \ ++ { CLOCK_BOOTTIME, "CLOCK_BOOTTIME" }, \ ++ { CLOCK_TAI, "CLOCK_TAI" }) ++ ++#define decode_hrtimer_mode(mode) \ ++ __print_symbolic(mode, \ ++ { HRTIMER_MODE_ABS, "ABS" }, \ ++ { HRTIMER_MODE_REL, "REL" }, \ ++ { HRTIMER_MODE_ABS_PINNED, "ABS|PINNED" }, \ ++ { HRTIMER_MODE_REL_PINNED, "REL|PINNED" }) ++ + /** + * hrtimer_init - called when the hrtimer is initialized + * @hrtimer: pointer to struct hrtimer +@@ -151,10 +165,8 @@ TRACE_EVENT(hrtimer_init, + ), + + TP_printk("hrtimer=%p clockid=%s mode=%s", __entry->hrtimer, +- __entry->clockid == CLOCK_REALTIME ? +- "CLOCK_REALTIME" : "CLOCK_MONOTONIC", +- __entry->mode == HRTIMER_MODE_ABS ? +- "HRTIMER_MODE_ABS" : "HRTIMER_MODE_REL") ++ decode_clockid(__entry->clockid), ++ decode_hrtimer_mode(__entry->mode)) + ); + + /** +diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h +index 91a31ffed828..9a781f0611df 100644 +--- a/include/uapi/drm/virtgpu_drm.h ++++ b/include/uapi/drm/virtgpu_drm.h +@@ -63,6 +63,7 @@ struct drm_virtgpu_execbuffer { + }; + + #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */ ++#define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */ + + struct drm_virtgpu_getparam { + __u64 param; +diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h +index 117d02e0fc31..659b1634de61 100644 +--- a/include/uapi/linux/if_ether.h ++++ b/include/uapi/linux/if_ether.h +@@ -29,6 +29,7 @@ + */ + + #define ETH_ALEN 6 /* Octets in one ethernet addr */ ++#define ETH_TLEN 2 /* Octets in ethernet type field */ + #define ETH_HLEN 14 /* Total octets in header. */ + #define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ + #define ETH_DATA_LEN 1500 /* Max. octets in payload */ +diff --git a/ipc/shm.c b/ipc/shm.c +index b626745e771c..9c687cda9b0a 100644 +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -1127,14 +1127,17 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, + goto out; + else if ((addr = (ulong)shmaddr)) { + if (addr & (shmlba - 1)) { +- /* +- * Round down to the nearest multiple of shmlba. +- * For sane do_mmap_pgoff() parameters, avoid +- * round downs that trigger nil-page and MAP_FIXED. +- */ +- if ((shmflg & SHM_RND) && addr >= shmlba) +- addr &= ~(shmlba - 1); +- else ++ if (shmflg & SHM_RND) { ++ addr &= ~(shmlba - 1); /* round down */ ++ ++ /* ++ * Ensure that the round-down is non-nil ++ * when remapping. This can happen for ++ * cases when addr < shmlba. ++ */ ++ if (!addr && (shmflg & SHM_REMAP)) ++ goto out; ++ } else + #ifndef __ARCH_FORCE_SHMLBA + if (addr & ~PAGE_MASK) + #endif +diff --git a/kernel/audit.c b/kernel/audit.c +index da4e7c0e36f7..3461a3d874fe 100644 +--- a/kernel/audit.c ++++ b/kernel/audit.c +@@ -742,6 +742,8 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature + return; + + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE); ++ if (!ab) ++ return; + audit_log_task_info(ab, current); + audit_log_format(ab, " feature=%s old=%u new=%u old_lock=%u new_lock=%u res=%d", + audit_feature_names[which], !!old_feature, !!new_feature, +diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c +index 2a20c0dfdafc..5a58421d7e2d 100644 +--- a/kernel/debug/kdb/kdb_main.c ++++ b/kernel/debug/kdb/kdb_main.c +@@ -1564,6 +1564,7 @@ static int kdb_md(int argc, const char **argv) + int symbolic = 0; + int valid = 0; + int phys = 0; ++ int raw = 0; + + kdbgetintenv("MDCOUNT", &mdcount); + kdbgetintenv("RADIX", &radix); +@@ -1573,9 +1574,10 @@ static int kdb_md(int argc, const char **argv) + repeat = mdcount * 16 / bytesperword; + + if (strcmp(argv[0], "mdr") == 0) { +- if (argc != 2) ++ if (argc == 2 || (argc == 0 && last_addr != 0)) ++ valid = raw = 1; ++ else + return KDB_ARGCOUNT; +- valid = 1; + } else if (isdigit(argv[0][2])) { + bytesperword = (int)(argv[0][2] - '0'); + if (bytesperword == 0) { +@@ -1611,7 +1613,10 @@ static int kdb_md(int argc, const char **argv) + radix = last_radix; + bytesperword = last_bytesperword; + repeat = last_repeat; +- mdcount = ((repeat * bytesperword) + 15) / 16; ++ if (raw) ++ mdcount = repeat; ++ else ++ mdcount = ((repeat * bytesperword) + 15) / 16; + } + + if (argc) { +@@ -1628,7 +1633,10 @@ static int kdb_md(int argc, const char **argv) + diag = kdbgetularg(argv[nextarg], &val); + if (!diag) { + mdcount = (int) val; +- repeat = mdcount * 16 / bytesperword; ++ if (raw) ++ repeat = mdcount; ++ else ++ repeat = mdcount * 16 / bytesperword; + } + } + if (argc >= nextarg+1) { +@@ -1638,8 +1646,15 @@ static int kdb_md(int argc, const char **argv) + } + } + +- if (strcmp(argv[0], "mdr") == 0) +- return kdb_mdr(addr, mdcount); ++ if (strcmp(argv[0], "mdr") == 0) { ++ int ret; ++ last_addr = addr; ++ ret = kdb_mdr(addr, mdcount); ++ last_addr += mdcount; ++ last_repeat = mdcount; ++ last_bytesperword = bytesperword; // to make REPEAT happy ++ return ret; ++ } + + switch (radix) { + case 10: +diff --git a/kernel/events/core.c b/kernel/events/core.c +index cbc51826cb94..6e6ec229c780 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -634,9 +634,15 @@ static inline void __update_cgrp_time(struct perf_cgroup *cgrp) + + static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx) + { +- struct perf_cgroup *cgrp_out = cpuctx->cgrp; +- if (cgrp_out) +- __update_cgrp_time(cgrp_out); ++ struct perf_cgroup *cgrp = cpuctx->cgrp; ++ struct cgroup_subsys_state *css; ++ ++ if (cgrp) { ++ for (css = &cgrp->css; css; css = css->parent) { ++ cgrp = container_of(css, struct perf_cgroup, css); ++ __update_cgrp_time(cgrp); ++ } ++ } + } + + static inline void update_cgrp_time_from_event(struct perf_event *event) +@@ -664,6 +670,7 @@ perf_cgroup_set_timestamp(struct task_struct *task, + { + struct perf_cgroup *cgrp; + struct perf_cgroup_info *info; ++ struct cgroup_subsys_state *css; + + /* + * ctx->lock held by caller +@@ -674,8 +681,12 @@ perf_cgroup_set_timestamp(struct task_struct *task, + return; + + cgrp = perf_cgroup_from_task(task, ctx); +- info = this_cpu_ptr(cgrp->info); +- info->timestamp = ctx->timestamp; ++ ++ for (css = &cgrp->css; css; css = css->parent) { ++ cgrp = container_of(css, struct perf_cgroup, css); ++ info = this_cpu_ptr(cgrp->info); ++ info->timestamp = ctx->timestamp; ++ } + } + + #define PERF_CGROUP_SWOUT 0x1 /* cgroup switch out every event */ +@@ -5689,7 +5700,8 @@ static void perf_output_read_group(struct perf_output_handle *handle, + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + values[n++] = running; + +- if (leader != event) ++ if ((leader != event) && ++ (leader->state == PERF_EVENT_STATE_ACTIVE)) + leader->pmu->read(leader); + + values[n++] = perf_event_count(leader); +diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c +index b2caec7315af..a72f5df643f8 100644 +--- a/kernel/locking/qspinlock.c ++++ b/kernel/locking/qspinlock.c +@@ -495,6 +495,14 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) + tail = encode_tail(smp_processor_id(), idx); + + node += idx; ++ ++ /* ++ * Ensure that we increment the head node->count before initialising ++ * the actual node. If the compiler is kind enough to reorder these ++ * stores, then an IRQ could overwrite our assignments. ++ */ ++ barrier(); ++ + node->locked = 0; + node->next = NULL; + pv_init_node(node); +diff --git a/kernel/power/power.h b/kernel/power/power.h +index 56d1d0dedf76..ccba4d820078 100644 +--- a/kernel/power/power.h ++++ b/kernel/power/power.h +@@ -103,9 +103,6 @@ extern int in_suspend; + extern dev_t swsusp_resume_device; + extern sector_t swsusp_resume_block; + +-extern asmlinkage int swsusp_arch_suspend(void); +-extern asmlinkage int swsusp_arch_resume(void); +- + extern int create_basic_memory_bitmaps(void); + extern void free_basic_memory_bitmaps(void); + extern int hibernate_preallocate_memory(void); +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index e3944c4b072d..554ea54e8d61 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -521,8 +521,14 @@ static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp) + } + t = list_entry(rnp->gp_tasks->prev, + struct task_struct, rcu_node_entry); +- list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) ++ list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) { ++ /* ++ * We could be printing a lot while holding a spinlock. ++ * Avoid triggering hard lockup. ++ */ ++ touch_nmi_watchdog(); + sched_show_task(t); ++ } + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + } + +@@ -1629,6 +1635,12 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu) + char *ticks_title; + unsigned long ticks_value; + ++ /* ++ * We could be printing a lot while holding a spinlock. Avoid ++ * triggering hard lockup. ++ */ ++ touch_nmi_watchdog(); ++ + if (rsp->gpnum == rdp->gpnum) { + ticks_title = "ticks this GP"; + ticks_value = rdp->ticks_this_gp; +diff --git a/kernel/relay.c b/kernel/relay.c +index 2603e04f55f9..91e8fbf8aff3 100644 +--- a/kernel/relay.c ++++ b/kernel/relay.c +@@ -163,7 +163,7 @@ static struct rchan_buf *relay_create_buf(struct rchan *chan) + { + struct rchan_buf *buf; + +- if (chan->n_subbufs > UINT_MAX / sizeof(size_t *)) ++ if (chan->n_subbufs > KMALLOC_MAX_SIZE / sizeof(size_t *)) + return NULL; + + buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL); +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index c7b0d2e7a9aa..9ab4d73e9cc9 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -830,6 +830,8 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun) + struct rq *rq = rq_of_rt_rq(rt_rq); + + raw_spin_lock(&rq->lock); ++ update_rq_clock(rq); ++ + if (rt_rq->rt_time) { + u64 runtime; + +diff --git a/kernel/signal.c b/kernel/signal.c +index 17428fec19b0..4364e57e6038 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -1392,6 +1392,10 @@ static int kill_something_info(int sig, struct siginfo *info, pid_t pid) + return ret; + } + ++ /* -INT_MIN is undefined. Exclude this case to avoid a UBSAN warning */ ++ if (pid == INT_MIN) ++ return -ESRCH; ++ + read_lock(&tasklist_lock); + if (pid != -1) { + ret = __kill_pgrp_info(sig, info, +diff --git a/kernel/sys.c b/kernel/sys.c +index 143cd63f1d47..b13b530b5e0f 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -1313,6 +1313,7 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, + if (resource >= RLIM_NLIMITS) + return -EINVAL; + ++ resource = array_index_nospec(resource, RLIM_NLIMITS); + task_lock(current->group_leader); + x = current->signal->rlim[resource]; + task_unlock(current->group_leader); +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 664aebc50fe3..1961dd408bc5 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -5272,7 +5272,7 @@ int workqueue_sysfs_register(struct workqueue_struct *wq) + + ret = device_register(&wq_dev->dev); + if (ret) { +- kfree(wq_dev); ++ put_device(&wq_dev->dev); + wq->wq_dev = NULL; + return ret; + } +diff --git a/lib/test_bpf.c b/lib/test_bpf.c +index 98da7520a6aa..1586dfdea809 100644 +--- a/lib/test_bpf.c ++++ b/lib/test_bpf.c +@@ -83,6 +83,7 @@ struct bpf_test { + __u32 result; + } test[MAX_SUBTESTS]; + int (*fill_helper)(struct bpf_test *self); ++ int expected_errcode; /* used when FLAG_EXPECTED_FAIL is set in the aux */ + __u8 frag_data[MAX_DATA]; + }; + +@@ -1900,7 +1901,9 @@ static struct bpf_test tests[] = { + }, + CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, + { }, +- { } ++ { }, ++ .fill_helper = NULL, ++ .expected_errcode = -EINVAL, + }, + { + "check: div_k_0", +@@ -1910,7 +1913,9 @@ static struct bpf_test tests[] = { + }, + CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, + { }, +- { } ++ { }, ++ .fill_helper = NULL, ++ .expected_errcode = -EINVAL, + }, + { + "check: unknown insn", +@@ -1921,7 +1926,9 @@ static struct bpf_test tests[] = { + }, + CLASSIC | FLAG_EXPECTED_FAIL, + { }, +- { } ++ { }, ++ .fill_helper = NULL, ++ .expected_errcode = -EINVAL, + }, + { + "check: out of range spill/fill", +@@ -1931,7 +1938,9 @@ static struct bpf_test tests[] = { + }, + CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, + { }, +- { } ++ { }, ++ .fill_helper = NULL, ++ .expected_errcode = -EINVAL, + }, + { + "JUMPS + HOLES", +@@ -2023,6 +2032,8 @@ static struct bpf_test tests[] = { + CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, + { }, + { }, ++ .fill_helper = NULL, ++ .expected_errcode = -EINVAL, + }, + { + "check: LDX + RET X", +@@ -2033,6 +2044,8 @@ static struct bpf_test tests[] = { + CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, + { }, + { }, ++ .fill_helper = NULL, ++ .expected_errcode = -EINVAL, + }, + { /* Mainly checking JIT here. */ + "M[]: alt STX + LDX", +@@ -2207,6 +2220,8 @@ static struct bpf_test tests[] = { + CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, + { }, + { }, ++ .fill_helper = NULL, ++ .expected_errcode = -EINVAL, + }, + { /* Passes checker but fails during runtime. */ + "LD [SKF_AD_OFF-1]", +@@ -4803,6 +4818,7 @@ static struct bpf_test tests[] = { + { }, + { }, + .fill_helper = bpf_fill_maxinsns4, ++ .expected_errcode = -EINVAL, + }, + { /* Mainly checking JIT here. */ + "BPF_MAXINSNS: Very long jump", +@@ -4858,10 +4874,15 @@ static struct bpf_test tests[] = { + { + "BPF_MAXINSNS: Jump, gap, jump, ...", + { }, ++#ifdef CONFIG_BPF_JIT_ALWAYS_ON ++ CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, ++#else + CLASSIC | FLAG_NO_DATA, ++#endif + { }, + { { 0, 0xababcbac } }, + .fill_helper = bpf_fill_maxinsns11, ++ .expected_errcode = -ENOTSUPP, + }, + { + "BPF_MAXINSNS: ld_abs+get_processor_id", +@@ -5632,7 +5653,7 @@ static struct bpf_prog *generate_filter(int which, int *err) + + *err = bpf_prog_create(&fp, &fprog); + if (tests[which].aux & FLAG_EXPECTED_FAIL) { +- if (*err == -EINVAL) { ++ if (*err == tests[which].expected_errcode) { + pr_cont("PASS\n"); + /* Verifier rejected filter as expected. */ + *err = 0; +diff --git a/mm/fadvise.c b/mm/fadvise.c +index 6c707bfe02fd..27fc9ad267ac 100644 +--- a/mm/fadvise.c ++++ b/mm/fadvise.c +@@ -126,7 +126,15 @@ SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice) + */ + start_index = (offset+(PAGE_SIZE-1)) >> PAGE_SHIFT; + end_index = (endbyte >> PAGE_SHIFT); +- if ((endbyte & ~PAGE_MASK) != ~PAGE_MASK) { ++ /* ++ * The page at end_index will be inclusively discarded according ++ * by invalidate_mapping_pages(), so subtracting 1 from ++ * end_index means we will skip the last page. But if endbyte ++ * is page aligned or is at the end of file, we should not skip ++ * that page - discarding the last page is safe enough. ++ */ ++ if ((endbyte & ~PAGE_MASK) != ~PAGE_MASK && ++ endbyte != inode->i_size - 1) { + /* First page is tricky as 0 - 1 = -1, but pgoff_t + * is unsigned, so the end_index >= start_index + * check below would be true and we'll discard the whole +diff --git a/mm/huge_memory.c b/mm/huge_memory.c +index e2982ea26090..724372866e67 100644 +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -542,7 +542,8 @@ static int __do_huge_pmd_anonymous_page(struct fault_env *fe, struct page *page, + + VM_BUG_ON_PAGE(!PageCompound(page), page); + +- if (mem_cgroup_try_charge(page, vma->vm_mm, gfp, &memcg, true)) { ++ if (mem_cgroup_try_charge(page, vma->vm_mm, gfp | __GFP_NORETRY, &memcg, ++ true)) { + put_page(page); + count_vm_event(THP_FAULT_FALLBACK); + return VM_FAULT_FALLBACK; +@@ -1060,7 +1061,7 @@ int do_huge_pmd_wp_page(struct fault_env *fe, pmd_t orig_pmd) + } + + if (unlikely(mem_cgroup_try_charge(new_page, vma->vm_mm, +- huge_gfp, &memcg, true))) { ++ huge_gfp | __GFP_NORETRY, &memcg, true))) { + put_page(new_page); + split_huge_pmd(vma, fe->pmd, fe->address); + if (page) +diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c +index 0e9505f66ec1..73c258129257 100644 +--- a/mm/kasan/kasan.c ++++ b/mm/kasan/kasan.c +@@ -800,5 +800,5 @@ static int __init kasan_memhotplug_init(void) + return 0; + } + +-module_init(kasan_memhotplug_init); ++core_initcall(kasan_memhotplug_init); + #endif +diff --git a/mm/khugepaged.c b/mm/khugepaged.c +index 898eb26f5dc8..1df37ee996d5 100644 +--- a/mm/khugepaged.c ++++ b/mm/khugepaged.c +@@ -963,7 +963,9 @@ static void collapse_huge_page(struct mm_struct *mm, + goto out_nolock; + } + +- if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) { ++ /* Do not oom kill for khugepaged charges */ ++ if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp | __GFP_NORETRY, ++ &memcg, true))) { + result = SCAN_CGROUP_CHARGE_FAIL; + goto out_nolock; + } +@@ -1323,7 +1325,9 @@ static void collapse_shmem(struct mm_struct *mm, + goto out; + } + +- if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) { ++ /* Do not oom kill for khugepaged charges */ ++ if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp | __GFP_NORETRY, ++ &memcg, true))) { + result = SCAN_CGROUP_CHARGE_FAIL; + goto out; + } +@@ -1678,10 +1682,14 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, + spin_unlock(&khugepaged_mm_lock); + + mm = mm_slot->mm; +- down_read(&mm->mmap_sem); +- if (unlikely(khugepaged_test_exit(mm))) +- vma = NULL; +- else ++ /* ++ * Don't wait for semaphore (to avoid long wait times). Just move to ++ * the next mm on the list. ++ */ ++ vma = NULL; ++ if (unlikely(!down_read_trylock(&mm->mmap_sem))) ++ goto breakouterloop_mmap_sem; ++ if (likely(!khugepaged_test_exit(mm))) + vma = find_vma(mm, khugepaged_scan.address); + + progress++; +diff --git a/mm/kmemleak.c b/mm/kmemleak.c +index 20cf3be9a5e8..9e66449ed91f 100644 +--- a/mm/kmemleak.c ++++ b/mm/kmemleak.c +@@ -1577,8 +1577,7 @@ static void start_scan_thread(void) + } + + /* +- * Stop the automatic memory scanning thread. This function must be called +- * with the scan_mutex held. ++ * Stop the automatic memory scanning thread. + */ + static void stop_scan_thread(void) + { +@@ -1841,12 +1840,15 @@ static void kmemleak_do_cleanup(struct work_struct *work) + { + stop_scan_thread(); + ++ mutex_lock(&scan_mutex); + /* +- * Once the scan thread has stopped, it is safe to no longer track +- * object freeing. Ordering of the scan thread stopping and the memory +- * accesses below is guaranteed by the kthread_stop() function. ++ * Once it is made sure that kmemleak_scan has stopped, it is safe to no ++ * longer track object freeing. Ordering of the scan thread stopping and ++ * the memory accesses below is guaranteed by the kthread_stop() ++ * function. + */ + kmemleak_free_enabled = 0; ++ mutex_unlock(&scan_mutex); + + if (!kmemleak_found_leaks) + __kmemleak_do_cleanup(); +diff --git a/mm/ksm.c b/mm/ksm.c +index caa54a55a357..614b2cce9ad7 100644 +--- a/mm/ksm.c ++++ b/mm/ksm.c +@@ -1469,8 +1469,22 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item) + tree_rmap_item = + unstable_tree_search_insert(rmap_item, page, &tree_page); + if (tree_rmap_item) { ++ bool split; ++ + kpage = try_to_merge_two_pages(rmap_item, page, + tree_rmap_item, tree_page); ++ /* ++ * If both pages we tried to merge belong to the same compound ++ * page, then we actually ended up increasing the reference ++ * count of the same compound page twice, and split_huge_page ++ * failed. ++ * Here we set a flag if that happened, and we use it later to ++ * try split_huge_page again. Since we call put_page right ++ * afterwards, the reference count will be correct and ++ * split_huge_page should succeed. ++ */ ++ split = PageTransCompound(page) ++ && compound_head(page) == compound_head(tree_page); + put_page(tree_page); + if (kpage) { + /* +@@ -1495,6 +1509,20 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item) + break_cow(tree_rmap_item); + break_cow(rmap_item); + } ++ } else if (split) { ++ /* ++ * We are here if we tried to merge two pages and ++ * failed because they both belonged to the same ++ * compound page. We will split the page now, but no ++ * merging will take place. ++ * We do not want to add the cost of a full lock; if ++ * the page is locked, it is better to skip it and ++ * perhaps try again later. ++ */ ++ if (!trylock_page(page)) ++ return; ++ split_huge_page(page); ++ unlock_page(page); + } + } + } +diff --git a/mm/mempolicy.c b/mm/mempolicy.c +index a8ab5e73dc61..69c4a0c92ebb 100644 +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -1264,6 +1264,7 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask, + unsigned long maxnode) + { + unsigned long k; ++ unsigned long t; + unsigned long nlongs; + unsigned long endmask; + +@@ -1280,13 +1281,19 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask, + else + endmask = (1UL << (maxnode % BITS_PER_LONG)) - 1; + +- /* When the user specified more nodes than supported just check +- if the non supported part is all zero. */ ++ /* ++ * When the user specified more nodes than supported just check ++ * if the non supported part is all zero. ++ * ++ * If maxnode have more longs than MAX_NUMNODES, check ++ * the bits in that area first. And then go through to ++ * check the rest bits which equal or bigger than MAX_NUMNODES. ++ * Otherwise, just check bits [MAX_NUMNODES, maxnode). ++ */ + if (nlongs > BITS_TO_LONGS(MAX_NUMNODES)) { + if (nlongs > PAGE_SIZE/sizeof(long)) + return -EINVAL; + for (k = BITS_TO_LONGS(MAX_NUMNODES); k < nlongs; k++) { +- unsigned long t; + if (get_user(t, nmask + k)) + return -EFAULT; + if (k == nlongs - 1) { +@@ -1299,6 +1306,16 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask, + endmask = ~0UL; + } + ++ if (maxnode > MAX_NUMNODES && MAX_NUMNODES % BITS_PER_LONG != 0) { ++ unsigned long valid_mask = endmask; ++ ++ valid_mask &= ~((1UL << (MAX_NUMNODES % BITS_PER_LONG)) - 1); ++ if (get_user(t, nmask + nlongs - 1)) ++ return -EFAULT; ++ if (t & valid_mask) ++ return -EINVAL; ++ } ++ + if (copy_from_user(nodes_addr(*nodes), nmask, nlongs*sizeof(unsigned long))) + return -EFAULT; + nodes_addr(*nodes)[nlongs-1] &= endmask; +@@ -1425,10 +1442,14 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode, + goto out_put; + } + +- if (!nodes_subset(*new, node_states[N_MEMORY])) { +- err = -EINVAL; ++ task_nodes = cpuset_mems_allowed(current); ++ nodes_and(*new, *new, task_nodes); ++ if (nodes_empty(*new)) ++ goto out_put; ++ ++ nodes_and(*new, *new, node_states[N_MEMORY]); ++ if (nodes_empty(*new)) + goto out_put; +- } + + err = security_task_movememory(task); + if (err) +@@ -2138,6 +2159,9 @@ bool __mpol_equal(struct mempolicy *a, struct mempolicy *b) + case MPOL_INTERLEAVE: + return !!nodes_equal(a->v.nodes, b->v.nodes); + case MPOL_PREFERRED: ++ /* a's ->flags is the same as b's */ ++ if (a->flags & MPOL_F_LOCAL) ++ return true; + return a->v.preferred_node == b->v.preferred_node; + default: + BUG(); +diff --git a/mm/swapfile.c b/mm/swapfile.c +index d76b2a18f044..79c03ecd31c8 100644 +--- a/mm/swapfile.c ++++ b/mm/swapfile.c +@@ -2271,6 +2271,10 @@ static unsigned long read_swap_header(struct swap_info_struct *p, + maxpages = swp_offset(pte_to_swp_entry( + swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1; + last_page = swap_header->info.last_page; ++ if (!last_page) { ++ pr_warn("Empty swap-file\n"); ++ return 0; ++ } + if (last_page > maxpages) { + pr_warn("Truncating oversized swap area, only using %luk out of %luk\n", + maxpages << (PAGE_SHIFT - 10), +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 557ad1367595..2d4b6478237b 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -1374,6 +1374,7 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode) + + if (PageDirty(page)) { + struct address_space *mapping; ++ bool migrate_dirty; + + /* ISOLATE_CLEAN means only clean pages */ + if (mode & ISOLATE_CLEAN) +@@ -1382,10 +1383,19 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode) + /* + * Only pages without mappings or that have a + * ->migratepage callback are possible to migrate +- * without blocking ++ * without blocking. However, we can be racing with ++ * truncation so it's necessary to lock the page ++ * to stabilise the mapping as truncation holds ++ * the page lock until after the page is removed ++ * from the page cache. + */ ++ if (!trylock_page(page)) ++ return ret; ++ + mapping = page_mapping(page); +- if (mapping && !mapping->a_ops->migratepage) ++ migrate_dirty = mapping && mapping->a_ops->migratepage; ++ unlock_page(page); ++ if (!migrate_dirty) + return ret; + } + } +@@ -3847,7 +3857,13 @@ int node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order) + */ + int page_evictable(struct page *page) + { +- return !mapping_unevictable(page_mapping(page)) && !PageMlocked(page); ++ int ret; ++ ++ /* Prevent address_space of inode and swap cache from being freed */ ++ rcu_read_lock(); ++ ret = !mapping_unevictable(page_mapping(page)) && !PageMlocked(page); ++ rcu_read_unlock(); ++ return ret; + } + + #ifdef CONFIG_SHMEM +diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c +index e2d18d0b1f06..946f1c269b1f 100644 +--- a/net/batman-adv/bat_iv_ogm.c ++++ b/net/batman-adv/bat_iv_ogm.c +@@ -2705,7 +2705,7 @@ static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_node *router; + struct batadv_gw_node *curr_gw; +- int ret = -EINVAL; ++ int ret = 0; + void *hdr; + + router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); +diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c +index e79f6f01182e..ed4ddf2059a6 100644 +--- a/net/batman-adv/bat_v.c ++++ b/net/batman-adv/bat_v.c +@@ -920,7 +920,7 @@ static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_node *router; + struct batadv_gw_node *curr_gw; +- int ret = -EINVAL; ++ int ret = 0; + void *hdr; + + router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); +diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c +index 5419b1214abd..582e27698bf0 100644 +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -2149,22 +2149,25 @@ batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + { + struct batadv_bla_claim *claim; + int idx = 0; ++ int ret = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(claim, head, hash_entry) { + if (idx++ < *idx_skip) + continue; +- if (batadv_bla_claim_dump_entry(msg, portid, seq, +- primary_if, claim)) { ++ ++ ret = batadv_bla_claim_dump_entry(msg, portid, seq, ++ primary_if, claim); ++ if (ret) { + *idx_skip = idx - 1; + goto unlock; + } + } + +- *idx_skip = idx; ++ *idx_skip = 0; + unlock: + rcu_read_unlock(); +- return 0; ++ return ret; + } + + /** +@@ -2379,22 +2382,25 @@ batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + { + struct batadv_bla_backbone_gw *backbone_gw; + int idx = 0; ++ int ret = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { + if (idx++ < *idx_skip) + continue; +- if (batadv_bla_backbone_dump_entry(msg, portid, seq, +- primary_if, backbone_gw)) { ++ ++ ret = batadv_bla_backbone_dump_entry(msg, portid, seq, ++ primary_if, backbone_gw); ++ if (ret) { + *idx_skip = idx - 1; + goto unlock; + } + } + +- *idx_skip = idx; ++ *idx_skip = 0; + unlock: + rcu_read_unlock(); +- return 0; ++ return ret; + } + + /** +diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c +index e257efdc5d03..df7c6a080188 100644 +--- a/net/batman-adv/distributed-arp-table.c ++++ b/net/batman-adv/distributed-arp-table.c +@@ -391,7 +391,7 @@ static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb, + batadv_arp_hw_src(skb, hdr_size), &ip_src, + batadv_arp_hw_dst(skb, hdr_size), &ip_dst); + +- if (hdr_size == 0) ++ if (hdr_size < sizeof(struct batadv_unicast_packet)) + return; + + unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data; +diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c +index 0934730fb7ff..57215e3fd1a0 100644 +--- a/net/batman-adv/fragmentation.c ++++ b/net/batman-adv/fragmentation.c +@@ -276,7 +276,8 @@ batadv_frag_merge_packets(struct hlist_head *chain) + /* Move the existing MAC header to just before the payload. (Override + * the fragment header.) + */ +- skb_pull_rcsum(skb_out, hdr_size); ++ skb_pull(skb_out, hdr_size); ++ skb_out->ip_summed = CHECKSUM_NONE; + memmove(skb_out->data - ETH_HLEN, skb_mac_header(skb_out), ETH_HLEN); + skb_set_mac_header(skb_out, -ETH_HLEN); + skb_reset_network_header(skb_out); +diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c +index de055d64debe..ed9aaf30fbcf 100644 +--- a/net/batman-adv/gateway_client.c ++++ b/net/batman-adv/gateway_client.c +@@ -715,6 +715,9 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, + + vid = batadv_get_vid(skb, 0); + ++ if (is_multicast_ether_addr(ethhdr->h_dest)) ++ goto out; ++ + orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, + ethhdr->h_dest, vid); + if (!orig_dst_node) +diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c +index 13661f43386f..5a2aac17805b 100644 +--- a/net/batman-adv/multicast.c ++++ b/net/batman-adv/multicast.c +@@ -527,8 +527,8 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) + bat_priv->mcast.enabled = true; + } + +- return !(mcast_data.flags & +- (BATADV_MCAST_WANT_ALL_IPV4 | BATADV_MCAST_WANT_ALL_IPV6)); ++ return !(mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV4 && ++ mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV6); + } + + /** +@@ -769,8 +769,8 @@ static struct batadv_orig_node * + batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv, + struct ethhdr *ethhdr) + { +- return batadv_transtable_search(bat_priv, ethhdr->h_source, +- ethhdr->h_dest, BATADV_NO_FLAGS); ++ return batadv_transtable_search(bat_priv, NULL, ethhdr->h_dest, ++ BATADV_NO_FLAGS); + } + + /** +diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c +index 7e8dc648b95a..8b98609ebc1e 100644 +--- a/net/batman-adv/routing.c ++++ b/net/batman-adv/routing.c +@@ -724,6 +724,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, + /** + * batadv_reroute_unicast_packet - update the unicast header for re-routing + * @bat_priv: the bat priv with all the soft interface information ++ * @skb: unicast packet to process + * @unicast_packet: the unicast header to be updated + * @dst_addr: the payload destination + * @vid: VLAN identifier +@@ -735,7 +736,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, + * Return: true if the packet header has been updated, false otherwise + */ + static bool +-batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, ++batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, + struct batadv_unicast_packet *unicast_packet, + u8 *dst_addr, unsigned short vid) + { +@@ -764,8 +765,10 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, + } + + /* update the packet header */ ++ skb_postpull_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); + ether_addr_copy(unicast_packet->dest, orig_addr); + unicast_packet->ttvn = orig_ttvn; ++ skb_postpush_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); + + ret = true; + out: +@@ -806,7 +809,7 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, + * the packet to + */ + if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { +- if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, ++ if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet, + ethhdr->h_dest, vid)) + batadv_dbg_ratelimited(BATADV_DBG_TT, + bat_priv, +@@ -852,7 +855,7 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, + * destination can possibly be updated and forwarded towards the new + * target host + */ +- if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, ++ if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet, + ethhdr->h_dest, vid)) { + batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv, + "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", +@@ -875,12 +878,14 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, + if (!primary_if) + return false; + ++ /* update the packet header */ ++ skb_postpull_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); + ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr); ++ unicast_packet->ttvn = curr_ttvn; ++ skb_postpush_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); + + batadv_hardif_put(primary_if); + +- unicast_packet->ttvn = curr_ttvn; +- + return true; + } + +diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c +index 49e16b6e0ba3..84c1b388d9ed 100644 +--- a/net/batman-adv/soft-interface.c ++++ b/net/batman-adv/soft-interface.c +@@ -448,13 +448,7 @@ void batadv_interface_rx(struct net_device *soft_iface, + + /* skb->dev & skb->pkt_type are set here */ + skb->protocol = eth_type_trans(skb, soft_iface); +- +- /* should not be necessary anymore as we use skb_pull_rcsum() +- * TODO: please verify this and remove this TODO +- * -- Dec 21st 2009, Simon Wunderlich +- */ +- +- /* skb->ip_summed = CHECKSUM_UNNECESSARY; */ ++ skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); + + batadv_inc_counter(bat_priv, BATADV_CNT_RX); + batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES, +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 5a89a4ac86ef..0a9222ef904c 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1625,7 +1625,8 @@ static int compat_match_to_user(struct ebt_entry_match *m, void __user **dstptr, + int off = ebt_compat_match_offset(match, m->match_size); + compat_uint_t msize = m->match_size - off; + +- BUG_ON(off >= m->match_size); ++ if (WARN_ON(off >= m->match_size)) ++ return -EINVAL; + + if (copy_to_user(cm->u.name, match->name, + strlen(match->name) + 1) || put_user(msize, &cm->match_size)) +@@ -1652,7 +1653,8 @@ static int compat_target_to_user(struct ebt_entry_target *t, + int off = xt_compat_target_offset(target); + compat_uint_t tsize = t->target_size - off; + +- BUG_ON(off >= t->target_size); ++ if (WARN_ON(off >= t->target_size)) ++ return -EINVAL; + + if (copy_to_user(cm->u.name, target->name, + strlen(target->name) + 1) || put_user(tsize, &cm->match_size)) +@@ -1880,7 +1882,8 @@ static int ebt_buf_add(struct ebt_entries_buf_state *state, + if (state->buf_kern_start == NULL) + goto count_only; + +- BUG_ON(state->buf_kern_offset + sz > state->buf_kern_len); ++ if (WARN_ON(state->buf_kern_offset + sz > state->buf_kern_len)) ++ return -EINVAL; + + memcpy(state->buf_kern_start + state->buf_kern_offset, data, sz); + +@@ -1893,7 +1896,8 @@ static int ebt_buf_add_pad(struct ebt_entries_buf_state *state, unsigned int sz) + { + char *b = state->buf_kern_start; + +- BUG_ON(b && state->buf_kern_offset > state->buf_kern_len); ++ if (WARN_ON(b && state->buf_kern_offset > state->buf_kern_len)) ++ return -EINVAL; + + if (b != NULL && sz > 0) + memset(b + state->buf_kern_offset, 0, sz); +@@ -1970,8 +1974,10 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, + pad = XT_ALIGN(size_kern) - size_kern; + + if (pad > 0 && dst) { +- BUG_ON(state->buf_kern_len <= pad); +- BUG_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad); ++ if (WARN_ON(state->buf_kern_len <= pad)) ++ return -EINVAL; ++ if (WARN_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad)) ++ return -EINVAL; + memset(dst + size_kern, 0, pad); + } + return off + match_size; +@@ -2021,7 +2027,8 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, + if (ret < 0) + return ret; + +- BUG_ON(ret < match32->match_size); ++ if (WARN_ON(ret < match32->match_size)) ++ return -EINVAL; + growth += ret - match32->match_size; + growth += ebt_compat_entry_padsize(); + +@@ -2090,8 +2097,12 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, + * offsets are relative to beginning of struct ebt_entry (i.e., 0). + */ + for (i = 0; i < 4 ; ++i) { +- if (offsets[i] >= *total) ++ if (offsets[i] > *total) ++ return -EINVAL; ++ ++ if (i < 3 && offsets[i] == *total) + return -EINVAL; ++ + if (i == 0) + continue; + if (offsets[i-1] > offsets[i]) +@@ -2130,7 +2141,8 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, + + startoff = state->buf_user_offset - startoff; + +- BUG_ON(*total < startoff); ++ if (WARN_ON(*total < startoff)) ++ return -EINVAL; + *total -= startoff; + return 0; + } +@@ -2257,7 +2269,8 @@ static int compat_do_replace(struct net *net, void __user *user, + state.buf_kern_len = size64; + + ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); +- BUG_ON(ret < 0); /* parses same data again */ ++ if (WARN_ON(ret < 0)) ++ goto out_unlock; + + vfree(entries_tmp); + tmp.entries_size = size64; +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index a40ccc184b83..9f697b00158d 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -4475,13 +4475,18 @@ EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); + + static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) + { ++ int mac_len; ++ + if (skb_cow(skb, skb_headroom(skb)) < 0) { + kfree_skb(skb); + return NULL; + } + +- memmove(skb->data - ETH_HLEN, skb->data - skb->mac_len - VLAN_HLEN, +- 2 * ETH_ALEN); ++ mac_len = skb->data - skb_mac_header(skb); ++ if (likely(mac_len > VLAN_HLEN + ETH_TLEN)) { ++ memmove(skb_mac_header(skb) + VLAN_HLEN, skb_mac_header(skb), ++ mac_len - VLAN_HLEN - ETH_TLEN); ++ } + skb->mac_header += VLAN_HLEN; + return skb; + } +diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c +index b120b9b11402..1ac55b116d5a 100644 +--- a/net/ipv4/ip_vti.c ++++ b/net/ipv4/ip_vti.c +@@ -396,8 +396,6 @@ static int vti_tunnel_init(struct net_device *dev) + memcpy(dev->dev_addr, &iph->saddr, 4); + memcpy(dev->broadcast, &iph->daddr, 4); + +- dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); +- dev->mtu = ETH_DATA_LEN; + dev->flags = IFF_NOARP; + dev->addr_len = 4; + dev->features |= NETIF_F_LLTX; +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 4c9fbf4f5905..890141d32ab9 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -618,6 +618,7 @@ static inline u32 fnhe_hashfun(__be32 daddr) + static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe) + { + rt->rt_pmtu = fnhe->fnhe_pmtu; ++ rt->rt_mtu_locked = fnhe->fnhe_mtu_locked; + rt->dst.expires = fnhe->fnhe_expires; + + if (fnhe->fnhe_gw) { +@@ -628,7 +629,7 @@ static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnh + } + + static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, +- u32 pmtu, unsigned long expires) ++ u32 pmtu, bool lock, unsigned long expires) + { + struct fnhe_hash_bucket *hash; + struct fib_nh_exception *fnhe; +@@ -665,8 +666,10 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, + fnhe->fnhe_genid = genid; + if (gw) + fnhe->fnhe_gw = gw; +- if (pmtu) ++ if (pmtu) { + fnhe->fnhe_pmtu = pmtu; ++ fnhe->fnhe_mtu_locked = lock; ++ } + fnhe->fnhe_expires = max(1UL, expires); + /* Update all cached dsts too */ + rt = rcu_dereference(fnhe->fnhe_rth_input); +@@ -690,6 +693,7 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, + fnhe->fnhe_daddr = daddr; + fnhe->fnhe_gw = gw; + fnhe->fnhe_pmtu = pmtu; ++ fnhe->fnhe_mtu_locked = lock; + fnhe->fnhe_expires = expires; + + /* Exception created; mark the cached routes for the nexthop +@@ -771,7 +775,8 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow + struct fib_nh *nh = &FIB_RES_NH(res); + + update_or_create_fnhe(nh, fl4->daddr, new_gw, +- 0, jiffies + ip_rt_gc_timeout); ++ 0, false, ++ jiffies + ip_rt_gc_timeout); + } + if (kill_route) + rt->dst.obsolete = DST_OBSOLETE_KILL; +@@ -983,15 +988,18 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) + { + struct dst_entry *dst = &rt->dst; + struct fib_result res; ++ bool lock = false; + +- if (dst_metric_locked(dst, RTAX_MTU)) ++ if (ip_mtu_locked(dst)) + return; + + if (ipv4_mtu(dst) < mtu) + return; + +- if (mtu < ip_rt_min_pmtu) ++ if (mtu < ip_rt_min_pmtu) { ++ lock = true; + mtu = ip_rt_min_pmtu; ++ } + + if (rt->rt_pmtu == mtu && + time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2)) +@@ -1001,7 +1009,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) + if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) { + struct fib_nh *nh = &FIB_RES_NH(res); + +- update_or_create_fnhe(nh, fl4->daddr, 0, mtu, ++ update_or_create_fnhe(nh, fl4->daddr, 0, mtu, lock, + jiffies + ip_rt_mtu_expires); + } + rcu_read_unlock(); +@@ -1256,7 +1264,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst) + + mtu = READ_ONCE(dst->dev->mtu); + +- if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { ++ if (unlikely(ip_mtu_locked(dst))) { + if (rt->rt_uses_gateway && mtu > 576) + mtu = 576; + } +@@ -1481,6 +1489,7 @@ struct rtable *rt_dst_alloc(struct net_device *dev, + rt->rt_is_input = 0; + rt->rt_iif = 0; + rt->rt_pmtu = 0; ++ rt->rt_mtu_locked = 0; + rt->rt_gateway = 0; + rt->rt_uses_gateway = 0; + rt->rt_table_id = 0; +@@ -2403,6 +2412,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or + rt->rt_is_input = ort->rt_is_input; + rt->rt_iif = ort->rt_iif; + rt->rt_pmtu = ort->rt_pmtu; ++ rt->rt_mtu_locked = ort->rt_mtu_locked; + + rt->rt_genid = rt_genid_ipv4(net); + rt->rt_flags = ort->rt_flags; +@@ -2505,6 +2515,8 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 table_id, + memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics)); + if (rt->rt_pmtu && expires) + metrics[RTAX_MTU - 1] = rt->rt_pmtu; ++ if (rt->rt_mtu_locked && expires) ++ metrics[RTAX_LOCK - 1] |= BIT(RTAX_MTU); + if (rtnetlink_put_metrics(skb, metrics) < 0) + goto nla_put_failure; + +diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c +index c8e6d86be114..95ca88731ff5 100644 +--- a/net/ipv4/tcp_illinois.c ++++ b/net/ipv4/tcp_illinois.c +@@ -6,7 +6,7 @@ + * The algorithm is described in: + * "TCP-Illinois: A Loss and Delay-Based Congestion Control Algorithm + * for High-Speed Networks" +- * http://www.ifp.illinois.edu/~srikant/Papers/liubassri06perf.pdf ++ * http://tamerbasar.csl.illinois.edu/LiuBasarSrikantPerfEvalArtJun2008.pdf + * + * Implemented from description in paper and ns-2 simulation. + * Copyright (C) 2007 Stephen Hemminger +diff --git a/net/ipv4/tcp_nv.c b/net/ipv4/tcp_nv.c +index e45e2c41c7bd..37a3cb999859 100644 +--- a/net/ipv4/tcp_nv.c ++++ b/net/ipv4/tcp_nv.c +@@ -338,7 +338,7 @@ static void tcpnv_acked(struct sock *sk, const struct ack_sample *sample) + */ + cwnd_by_slope = (u32) + div64_u64(((u64)ca->nv_rtt_max_rate) * ca->nv_min_rtt, +- (u64)(80000 * tp->mss_cache)); ++ 80000ULL * tp->mss_cache); + max_win = cwnd_by_slope + nv_pad; + + /* If cwnd > max_win, decrease cwnd +diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c +index 6a7ff6957535..622e158a6fc4 100644 +--- a/net/ipv4/xfrm4_policy.c ++++ b/net/ipv4/xfrm4_policy.c +@@ -97,6 +97,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, + xdst->u.rt.rt_gateway = rt->rt_gateway; + xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway; + xdst->u.rt.rt_pmtu = rt->rt_pmtu; ++ xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked; + xdst->u.rt.rt_table_id = rt->rt_table_id; + INIT_LIST_HEAD(&xdst->u.rt.rt_uncached); + +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index 417af5ea2509..c7b202c1720d 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -1972,14 +1972,14 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, + { + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); +- struct ip6_tnl *nt, *t; + struct ip_tunnel_encap ipencap; ++ struct ip6_tnl *nt, *t; ++ int err; + + nt = netdev_priv(dev); + + if (ip6_tnl_netlink_encap_parms(data, &ipencap)) { +- int err = ip6_tnl_encap_setup(nt, &ipencap); +- ++ err = ip6_tnl_encap_setup(nt, &ipencap); + if (err < 0) + return err; + } +@@ -1995,7 +1995,11 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, + return -EEXIST; + } + +- return ip6_tnl_create2(dev); ++ err = ip6_tnl_create2(dev); ++ if (!err && tb[IFLA_MTU]) ++ ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU])); ++ ++ return err; + } + + static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], +diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c +index b263bf3a19f7..64ec23388450 100644 +--- a/net/ipv6/netfilter/nf_conntrack_reasm.c ++++ b/net/ipv6/netfilter/nf_conntrack_reasm.c +@@ -230,7 +230,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, + + if ((unsigned int)end > IPV6_MAXPLEN) { + pr_debug("offset is too large.\n"); +- return -1; ++ return -EINVAL; + } + + ecn = ip6_frag_ecn(ipv6_hdr(skb)); +@@ -263,7 +263,8 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, + * this case. -DaveM + */ + pr_debug("end of fragment not rounded to 8 bytes.\n"); +- return -1; ++ inet_frag_kill(&fq->q, &nf_frags); ++ return -EPROTO; + } + if (end > fq->q.len) { + /* Some bits beyond end -> corruption. */ +@@ -357,7 +358,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, + discard_fq: + inet_frag_kill(&fq->q, &nf_frags); + err: +- return -1; ++ return -EINVAL; + } + + /* +@@ -566,6 +567,7 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff) + + int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user) + { ++ u16 savethdr = skb->transport_header; + struct net_device *dev = skb->dev; + int fhoff, nhoff, ret; + struct frag_hdr *fhdr; +@@ -599,8 +601,12 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user) + + spin_lock_bh(&fq->q.lock); + +- if (nf_ct_frag6_queue(fq, skb, fhdr, nhoff) < 0) { +- ret = -EINVAL; ++ ret = nf_ct_frag6_queue(fq, skb, fhdr, nhoff); ++ if (ret < 0) { ++ if (ret == -EPROTO) { ++ skb->transport_header = savethdr; ++ ret = 0; ++ } + goto out_unlock; + } + +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index dcb292134c21..ae0485d776f4 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -1572,6 +1572,13 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev, + if (err < 0) + return err; + ++ if (tb[IFLA_MTU]) { ++ u32 mtu = nla_get_u32(tb[IFLA_MTU]); ++ ++ if (mtu >= IPV6_MIN_MTU && mtu <= 0xFFF8 - dev->hard_header_len) ++ dev->mtu = mtu; ++ } ++ + #ifdef CONFIG_IPV6_SIT_6RD + if (ipip6_netlink_6rd_parms(data, &ip6rd)) + err = ipip6_tunnel_update_6rd(nt, &ip6rd); +diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c +index f8d4ab8ca1a5..4b60f68cb492 100644 +--- a/net/llc/llc_c_ac.c ++++ b/net/llc/llc_c_ac.c +@@ -389,7 +389,7 @@ static int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb) + llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR); + rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); + if (likely(!rc)) { +- llc_conn_send_pdu(sk, skb); ++ rc = llc_conn_send_pdu(sk, skb); + llc_conn_ac_inc_vs_by_1(sk, skb); + } + return rc; +@@ -916,7 +916,7 @@ static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk, + llc_pdu_init_as_i_cmd(skb, llc->ack_pf, llc->vS, llc->vR); + rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); + if (likely(!rc)) { +- llc_conn_send_pdu(sk, skb); ++ rc = llc_conn_send_pdu(sk, skb); + llc_conn_ac_inc_vs_by_1(sk, skb); + } + return rc; +@@ -935,14 +935,17 @@ static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk, + int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb) + { + struct llc_sock *llc = llc_sk(sk); ++ int ret; + + if (llc->ack_must_be_send) { +- llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb); ++ ret = llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb); + llc->ack_must_be_send = 0 ; + llc->ack_pf = 0; +- } else +- llc_conn_ac_send_i_cmd_p_set_0(sk, skb); +- return 0; ++ } else { ++ ret = llc_conn_ac_send_i_cmd_p_set_0(sk, skb); ++ } ++ ++ return ret; + } + + /** +diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c +index d861b74ad068..79c346fd859b 100644 +--- a/net/llc/llc_conn.c ++++ b/net/llc/llc_conn.c +@@ -30,7 +30,7 @@ + #endif + + static int llc_find_offset(int state, int ev_type); +-static void llc_conn_send_pdus(struct sock *sk); ++static int llc_conn_send_pdus(struct sock *sk, struct sk_buff *skb); + static int llc_conn_service(struct sock *sk, struct sk_buff *skb); + static int llc_exec_conn_trans_actions(struct sock *sk, + struct llc_conn_state_trans *trans, +@@ -193,11 +193,11 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) + return rc; + } + +-void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) ++int llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) + { + /* queue PDU to send to MAC layer */ + skb_queue_tail(&sk->sk_write_queue, skb); +- llc_conn_send_pdus(sk); ++ return llc_conn_send_pdus(sk, skb); + } + + /** +@@ -255,7 +255,7 @@ void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit) + if (howmany_resend > 0) + llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO; + /* any PDUs to re-send are queued up; start sending to MAC */ +- llc_conn_send_pdus(sk); ++ llc_conn_send_pdus(sk, NULL); + out:; + } + +@@ -296,7 +296,7 @@ void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit) + if (howmany_resend > 0) + llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO; + /* any PDUs to re-send are queued up; start sending to MAC */ +- llc_conn_send_pdus(sk); ++ llc_conn_send_pdus(sk, NULL); + out:; + } + +@@ -340,12 +340,16 @@ int llc_conn_remove_acked_pdus(struct sock *sk, u8 nr, u16 *how_many_unacked) + /** + * llc_conn_send_pdus - Sends queued PDUs + * @sk: active connection ++ * @hold_skb: the skb held by caller, or NULL if does not care + * +- * Sends queued pdus to MAC layer for transmission. ++ * Sends queued pdus to MAC layer for transmission. When @hold_skb is ++ * NULL, always return 0. Otherwise, return 0 if @hold_skb is sent ++ * successfully, or 1 for failure. + */ +-static void llc_conn_send_pdus(struct sock *sk) ++static int llc_conn_send_pdus(struct sock *sk, struct sk_buff *hold_skb) + { + struct sk_buff *skb; ++ int ret = 0; + + while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) { + struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); +@@ -357,10 +361,20 @@ static void llc_conn_send_pdus(struct sock *sk) + skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb); + if (!skb2) + break; +- skb = skb2; ++ dev_queue_xmit(skb2); ++ } else { ++ bool is_target = skb == hold_skb; ++ int rc; ++ ++ if (is_target) ++ skb_get(skb); ++ rc = dev_queue_xmit(skb); ++ if (is_target) ++ ret = rc; + } +- dev_queue_xmit(skb); + } ++ ++ return ret; + } + + /** +diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c +index 404284a14d75..474655a2aeae 100644 +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -3907,7 +3907,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, + if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS | + IEEE80211_FCTL_TODS)) != + fast_rx->expected_ds_bits) +- goto drop; ++ return false; + + /* assign the key to drop unencrypted frames (later) + * and strip the IV/MIC if necessary +diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c +index 97f4c9d6b54c..9249712765d7 100644 +--- a/net/mac80211/spectmgmt.c ++++ b/net/mac80211/spectmgmt.c +@@ -8,6 +8,7 @@ + * Copyright 2007, Michael Wu + * Copyright 2007-2008, Intel Corporation + * Copyright 2008, Johannes Berg ++ * Copyright (C) 2018 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -27,7 +28,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, + u32 sta_flags, u8 *bssid, + struct ieee80211_csa_ie *csa_ie) + { +- enum nl80211_band new_band; ++ enum nl80211_band new_band = current_band; + int new_freq; + u8 new_chan_no; + struct ieee80211_channel *new_chan; +@@ -53,15 +54,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, + elems->ext_chansw_ie->new_operating_class, + &new_band)) { + sdata_info(sdata, +- "cannot understand ECSA IE operating class %d, disconnecting\n", ++ "cannot understand ECSA IE operating class, %d, ignoring\n", + elems->ext_chansw_ie->new_operating_class); +- return -EINVAL; + } + new_chan_no = elems->ext_chansw_ie->new_ch_num; + csa_ie->count = elems->ext_chansw_ie->count; + csa_ie->mode = elems->ext_chansw_ie->mode; + } else if (elems->ch_switch_ie) { +- new_band = current_band; + new_chan_no = elems->ch_switch_ie->new_ch_num; + csa_ie->count = elems->ch_switch_ie->count; + csa_ie->mode = elems->ch_switch_ie->mode; +diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c +index 1ecf3d07d1f5..892c392ff8fc 100644 +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -313,7 +313,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, + + if (ieee80211_hw_check(hw, USES_RSS)) { + sta->pcpu_rx_stats = +- alloc_percpu(struct ieee80211_sta_rx_stats); ++ alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp); + if (!sta->pcpu_rx_stats) + goto free; + } +@@ -433,6 +433,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, + if (sta->sta.txq[0]) + kfree(to_txq_info(sta->sta.txq[0])); + free: ++ free_percpu(sta->pcpu_rx_stats); + #ifdef CONFIG_MAC80211_MESH + kfree(sta->mesh); + #endif +diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c +index 4528cff9138b..a123d0dc1ef9 100644 +--- a/net/netlabel/netlabel_unlabeled.c ++++ b/net/netlabel/netlabel_unlabeled.c +@@ -1469,6 +1469,16 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, + iface = rcu_dereference(netlbl_unlhsh_def); + if (iface == NULL || !iface->valid) + goto unlabel_getattr_nolabel; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ /* When resolving a fallback label, check the sk_buff version as ++ * it is possible (e.g. SCTP) to have family = PF_INET6 while ++ * receiving ip_hdr(skb)->version = 4. ++ */ ++ if (family == PF_INET6 && ip_hdr(skb)->version == 4) ++ family = PF_INET; ++#endif /* IPv6 */ ++ + switch (family) { + case PF_INET: { + struct iphdr *hdr4; +diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c +index c5959ce503e6..3f266115294f 100644 +--- a/net/nfc/llcp_commands.c ++++ b/net/nfc/llcp_commands.c +@@ -149,6 +149,10 @@ struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri, + + pr_debug("uri: %s, len: %zu\n", uri, uri_len); + ++ /* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */ ++ if (WARN_ON_ONCE(uri_len > U8_MAX - 4)) ++ return NULL; ++ + sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL); + if (sdreq == NULL) + return NULL; +diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c +index 102c681c48b5..dbf74afe82fb 100644 +--- a/net/nfc/netlink.c ++++ b/net/nfc/netlink.c +@@ -68,7 +68,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { + }; + + static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { +- [NFC_SDP_ATTR_URI] = { .type = NLA_STRING }, ++ [NFC_SDP_ATTR_URI] = { .type = NLA_STRING, ++ .len = U8_MAX - 4 }, + [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 }, + }; + +diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c +index 466393936db9..f135814c34ad 100644 +--- a/net/openvswitch/conntrack.c ++++ b/net/openvswitch/conntrack.c +@@ -906,6 +906,36 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, + return 0; + } + ++/* Trim the skb to the length specified by the IP/IPv6 header, ++ * removing any trailing lower-layer padding. This prepares the skb ++ * for higher-layer processing that assumes skb->len excludes padding ++ * (such as nf_ip_checksum). The caller needs to pull the skb to the ++ * network header, and ensure ip_hdr/ipv6_hdr points to valid data. ++ */ ++static int ovs_skb_network_trim(struct sk_buff *skb) ++{ ++ unsigned int len; ++ int err; ++ ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ len = ntohs(ip_hdr(skb)->tot_len); ++ break; ++ case htons(ETH_P_IPV6): ++ len = sizeof(struct ipv6hdr) ++ + ntohs(ipv6_hdr(skb)->payload_len); ++ break; ++ default: ++ len = skb->len; ++ } ++ ++ err = pskb_trim_rcsum(skb, len); ++ if (err) ++ kfree_skb(skb); ++ ++ return err; ++} ++ + /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero + * value if 'skb' is freed. + */ +@@ -920,6 +950,10 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, + nh_ofs = skb_network_offset(skb); + skb_pull_rcsum(skb, nh_ofs); + ++ err = ovs_skb_network_trim(skb); ++ if (err) ++ return err; ++ + if (key->ip.frag != OVS_FRAG_TYPE_NONE) { + err = handle_fragments(net, key, info->zone.id, skb); + if (err) +diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c +index 0d11132b3370..ff0112bc247f 100644 +--- a/net/qrtr/smd.c ++++ b/net/qrtr/smd.c +@@ -116,5 +116,6 @@ static struct qcom_smd_driver qcom_smd_qrtr_driver = { + + module_qcom_smd_driver(qcom_smd_qrtr_driver); + ++MODULE_ALIAS("rpmsg:IPCRTR"); + MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver"); + MODULE_LICENSE("GPL v2"); +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 5680d90b0b77..0efb3d2b338d 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -336,7 +336,8 @@ static int rds_ib_laddr_check(struct net *net, __be32 addr) + /* Create a CMA ID and try to bind it. This catches both + * IB and iWARP capable NICs. + */ +- cm_id = rdma_create_id(&init_net, NULL, NULL, RDMA_PS_TCP, IB_QPT_RC); ++ cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler, ++ NULL, RDMA_PS_TCP, IB_QPT_RC); + if (IS_ERR(cm_id)) + return PTR_ERR(cm_id); + +diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c +index 1060d14d4e6a..f3ac85a285a2 100644 +--- a/net/rxrpc/input.c ++++ b/net/rxrpc/input.c +@@ -1166,16 +1166,19 @@ void rxrpc_data_ready(struct sock *udp_sk) + goto discard_unlock; + + if (sp->hdr.callNumber == chan->last_call) { +- /* For the previous service call, if completed successfully, we +- * discard all further packets. ++ if (chan->call || ++ sp->hdr.type == RXRPC_PACKET_TYPE_ABORT) ++ goto discard_unlock; ++ ++ /* For the previous service call, if completed ++ * successfully, we discard all further packets. + */ + if (rxrpc_conn_is_service(conn) && +- (chan->last_type == RXRPC_PACKET_TYPE_ACK || +- sp->hdr.type == RXRPC_PACKET_TYPE_ABORT)) ++ chan->last_type == RXRPC_PACKET_TYPE_ACK) + goto discard_unlock; + +- /* But otherwise we need to retransmit the final packet from +- * data cached in the connection record. ++ /* But otherwise we need to retransmit the final packet ++ * from data cached in the connection record. + */ + rxrpc_post_packet_to_conn(conn, skb); + goto out_unlock; +diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c +index c29362d50a92..3e52b7fdc35d 100644 +--- a/net/rxrpc/recvmsg.c ++++ b/net/rxrpc/recvmsg.c +@@ -493,9 +493,10 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, + sizeof(unsigned int), &id32); + } else { ++ unsigned long idl = call->user_call_ID; ++ + ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, +- sizeof(unsigned long), +- &call->user_call_ID); ++ sizeof(unsigned long), &idl); + } + if (ret < 0) + goto error; +diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c +index b214a4d4a641..1de27c39564b 100644 +--- a/net/rxrpc/sendmsg.c ++++ b/net/rxrpc/sendmsg.c +@@ -78,7 +78,9 @@ static inline void rxrpc_instant_resend(struct rxrpc_call *call, int ix) + spin_lock_bh(&call->lock); + + if (call->state < RXRPC_CALL_COMPLETE) { +- call->rxtx_annotations[ix] = RXRPC_TX_ANNO_RETRANS; ++ call->rxtx_annotations[ix] = ++ (call->rxtx_annotations[ix] & RXRPC_TX_ANNO_LAST) | ++ RXRPC_TX_ANNO_RETRANS; + if (!test_and_set_bit(RXRPC_CALL_EV_RESEND, &call->events)) + rxrpc_queue_call(call); + } +diff --git a/scripts/adjust_autoksyms.sh b/scripts/adjust_autoksyms.sh +index 8dc1918b6783..564db3542ec2 100755 +--- a/scripts/adjust_autoksyms.sh ++++ b/scripts/adjust_autoksyms.sh +@@ -83,6 +83,13 @@ while read sympath; do + depfile="include/config/ksym/${sympath}.h" + mkdir -p "$(dirname "$depfile")" + touch "$depfile" ++ # Filesystems with coarse time precision may create timestamps ++ # equal to the one from a file that was very recently built and that ++ # needs to be rebuild. Let's guard against that by making sure our ++ # dep files are always newer than the first file we created here. ++ while [ ! "$depfile" -nt "$new_ksyms_file" ]; do ++ touch "$depfile" ++ done + echo $((count += 1)) + done | tail -1 ) + changed=${changed:-0} +diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c +index cbf4996dd9c1..ed29bad1f03a 100644 +--- a/scripts/kconfig/expr.c ++++ b/scripts/kconfig/expr.c +@@ -113,7 +113,7 @@ void expr_free(struct expr *e) + break; + case E_NOT: + expr_free(e->left.expr); +- return; ++ break; + case E_EQUAL: + case E_GEQ: + case E_GTH: +diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c +index aed678e8a777..4a61636158dd 100644 +--- a/scripts/kconfig/menu.c ++++ b/scripts/kconfig/menu.c +@@ -364,6 +364,7 @@ void menu_finalize(struct menu *parent) + menu->parent = parent; + last_menu = menu; + } ++ expr_free(basedep); + if (last_menu) { + parent->list = parent->next; + parent->next = last_menu->next; +diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y +index 71bf8bff696a..5122ed2d839a 100644 +--- a/scripts/kconfig/zconf.y ++++ b/scripts/kconfig/zconf.y +@@ -107,7 +107,27 @@ static struct menu *current_menu, *current_entry; + %% + input: nl start | start; + +-start: mainmenu_stmt stmt_list | stmt_list; ++start: mainmenu_stmt stmt_list | no_mainmenu_stmt stmt_list; ++ ++/* mainmenu entry */ ++ ++mainmenu_stmt: T_MAINMENU prompt nl ++{ ++ menu_add_prompt(P_MENU, $2, NULL); ++}; ++ ++/* Default main menu, if there's no mainmenu entry */ ++ ++no_mainmenu_stmt: /* empty */ ++{ ++ /* ++ * Hack: Keep the main menu title on the heap so we can safely free it ++ * later regardless of whether it comes from the 'prompt' in ++ * mainmenu_stmt or here ++ */ ++ menu_add_prompt(P_MENU, strdup("Linux Kernel Configuration"), NULL); ++}; ++ + + stmt_list: + /* empty */ +@@ -344,13 +364,6 @@ if_block: + | if_block choice_stmt + ; + +-/* mainmenu entry */ +- +-mainmenu_stmt: T_MAINMENU prompt nl +-{ +- menu_add_prompt(P_MENU, $2, NULL); +-}; +- + /* menu entry */ + + menu: T_MENU prompt T_EOL +@@ -495,6 +508,7 @@ word_opt: /* empty */ { $$ = NULL; } + + void conf_parse(const char *name) + { ++ const char *tmp; + struct symbol *sym; + int i; + +@@ -502,7 +516,6 @@ void conf_parse(const char *name) + + sym_init(); + _menu_init(); +- rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; +@@ -512,8 +525,10 @@ void conf_parse(const char *name) + if (!modules_sym) + modules_sym = sym_find( "n" ); + ++ tmp = rootmenu.prompt->text; + rootmenu.prompt->text = _(rootmenu.prompt->text); + rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); ++ free((char*)tmp); + + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { +diff --git a/scripts/package/builddeb b/scripts/package/builddeb +index 3c575cd07888..0a2a7372538c 100755 +--- a/scripts/package/builddeb ++++ b/scripts/package/builddeb +@@ -325,7 +325,7 @@ fi + + # Build kernel header package + (cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles" +-(cd $srctree; find arch/*/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles" ++(cd $srctree; find arch/*/include include scripts -type f -o -type l) >> "$objtree/debian/hdrsrcfiles" + (cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles" + (cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles" + if grep -q '^CONFIG_STACK_VALIDATION=y' $KCONFIG_CONFIG ; then +diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c +index 4304372b323f..95433acde1c1 100644 +--- a/security/integrity/digsig.c ++++ b/security/integrity/digsig.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index 38f2ed830dd6..93f09173cc49 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -78,6 +78,8 @@ int __init ima_init_crypto(void) + hash_algo_name[ima_hash_algo], rc); + return rc; + } ++ pr_info("Allocated hash algorithm: %s\n", ++ hash_algo_name[ima_hash_algo]); + return 0; + } + +diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c +index 2b3def14b4fb..a71f906b4f7a 100644 +--- a/security/integrity/ima/ima_main.c ++++ b/security/integrity/ima/ima_main.c +@@ -16,6 +16,9 @@ + * implements the IMA hooks: ima_bprm_check, ima_file_mmap, + * and ima_file_check. + */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ + #include + #include + #include +@@ -426,6 +429,16 @@ static int __init init_ima(void) + + hash_setup(CONFIG_IMA_DEFAULT_HASH); + error = ima_init(); ++ ++ if (error && strcmp(hash_algo_name[ima_hash_algo], ++ CONFIG_IMA_DEFAULT_HASH) != 0) { ++ pr_info("Allocating %s failed, going to use default hash algorithm %s\n", ++ hash_algo_name[ima_hash_algo], CONFIG_IMA_DEFAULT_HASH); ++ hash_setup_done = 0; ++ hash_setup(CONFIG_IMA_DEFAULT_HASH); ++ error = ima_init(); ++ } ++ + if (!error) { + ima_initialized = 1; + ima_update_policy_flag(); +diff --git a/sound/core/timer.c b/sound/core/timer.c +index e5ddc475dca4..152254193c69 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -547,7 +547,7 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop) + else + timeri->flags |= SNDRV_TIMER_IFLG_PAUSED; + snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : +- SNDRV_TIMER_EVENT_CONTINUE); ++ SNDRV_TIMER_EVENT_PAUSE); + unlock: + spin_unlock_irqrestore(&timer->lock, flags); + return result; +@@ -569,7 +569,7 @@ static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop) + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); + snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : +- SNDRV_TIMER_EVENT_CONTINUE); ++ SNDRV_TIMER_EVENT_PAUSE); + spin_unlock(&timeri->timer->lock); + } + spin_unlock_irqrestore(&slave_active_lock, flags); +diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c +index 6c58e6f73a01..7c6ef879c520 100644 +--- a/sound/core/vmaster.c ++++ b/sound/core/vmaster.c +@@ -68,10 +68,13 @@ static int slave_update(struct link_slave *slave) + return -ENOMEM; + uctl->id = slave->slave.id; + err = slave->slave.get(&slave->slave, uctl); ++ if (err < 0) ++ goto error; + for (ch = 0; ch < slave->info.count; ch++) + slave->vals[ch] = uctl->value.integer.value[ch]; ++ error: + kfree(uctl); +- return 0; ++ return err < 0 ? err : 0; + } + + /* get the slave ctl info and save the initial values */ +diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig +index 7f3b5ed81995..f7a492c382d9 100644 +--- a/sound/pci/hda/Kconfig ++++ b/sound/pci/hda/Kconfig +@@ -88,7 +88,6 @@ config SND_HDA_PATCH_LOADER + config SND_HDA_CODEC_REALTEK + tristate "Build Realtek HD-audio codec support" + select SND_HDA_GENERIC +- select INPUT + help + Say Y or M here to include Realtek HD-audio codec support in + snd-hda-intel driver, such as ALC880. +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 7ece1ab57eef..39cd35f6a6df 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -3495,6 +3495,7 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec, + } + } + ++#if IS_REACHABLE(INPUT) + static void gpio2_mic_hotkey_event(struct hda_codec *codec, + struct hda_jack_callback *event) + { +@@ -3627,6 +3628,10 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, + spec->kb_dev = NULL; + } + } ++#else /* INPUT */ ++#define alc280_fixup_hp_gpio2_mic_hotkey NULL ++#define alc233_fixup_lenovo_line2_mic_hotkey NULL ++#endif /* INPUT */ + + static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index b699aea9a025..7788cfb7cd7e 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -590,6 +590,24 @@ bpf_object__init_maps_name(struct bpf_object *obj) + return 0; + } + ++static bool section_have_execinstr(struct bpf_object *obj, int idx) ++{ ++ Elf_Scn *scn; ++ GElf_Shdr sh; ++ ++ scn = elf_getscn(obj->efile.elf, idx); ++ if (!scn) ++ return false; ++ ++ if (gelf_getshdr(scn, &sh) != &sh) ++ return false; ++ ++ if (sh.sh_flags & SHF_EXECINSTR) ++ return true; ++ ++ return false; ++} ++ + static int bpf_object__elf_collect(struct bpf_object *obj) + { + Elf *elf = obj->efile.elf; +@@ -673,6 +691,14 @@ static int bpf_object__elf_collect(struct bpf_object *obj) + } else if (sh.sh_type == SHT_REL) { + void *reloc = obj->efile.reloc; + int nr_reloc = obj->efile.nr_reloc + 1; ++ int sec = sh.sh_info; /* points to other section */ ++ ++ /* Only do relo for section with exec instructions */ ++ if (!section_have_execinstr(obj, sec)) { ++ pr_debug("skip relo %s(%d) for section(%d)\n", ++ name, idx, sec); ++ continue; ++ } + + reloc = realloc(reloc, + sizeof(*obj->efile.reloc) * nr_reloc); +diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c +index 664c90c8e22b..669475300ba8 100644 +--- a/tools/lib/traceevent/event-parse.c ++++ b/tools/lib/traceevent/event-parse.c +@@ -4927,21 +4927,22 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event + else + ls = 2; + +- if (*(ptr+1) == 'F' || *(ptr+1) == 'f' || +- *(ptr+1) == 'S' || *(ptr+1) == 's') { ++ if (isalnum(ptr[1])) + ptr++; ++ ++ if (*ptr == 'F' || *ptr == 'f' || ++ *ptr == 'S' || *ptr == 's') { + show_func = *ptr; +- } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { +- print_mac_arg(s, *(ptr+1), data, size, event, arg); +- ptr++; ++ } else if (*ptr == 'M' || *ptr == 'm') { ++ print_mac_arg(s, *ptr, data, size, event, arg); + arg = arg->next; + break; +- } else if (*(ptr+1) == 'I' || *(ptr+1) == 'i') { ++ } else if (*ptr == 'I' || *ptr == 'i') { + int n; + +- n = print_ip_arg(s, ptr+1, data, size, event, arg); ++ n = print_ip_arg(s, ptr, data, size, event, arg); + if (n > 0) { +- ptr += n; ++ ptr += n - 1; + arg = arg->next; + break; + } +diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c +index 7c214ceb9386..5e10ba796a6f 100644 +--- a/tools/lib/traceevent/parse-filter.c ++++ b/tools/lib/traceevent/parse-filter.c +@@ -1879,17 +1879,25 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r + struct pevent *pevent; + unsigned long long addr; + const char *val = NULL; ++ unsigned int size; + char hex[64]; + + /* If the field is not a string convert it */ + if (arg->str.field->flags & FIELD_IS_STRING) { + val = record->data + arg->str.field->offset; ++ size = arg->str.field->size; ++ ++ if (arg->str.field->flags & FIELD_IS_DYNAMIC) { ++ addr = *(unsigned int *)val; ++ val = record->data + (addr & 0xffff); ++ size = addr >> 16; ++ } + + /* + * We need to copy the data since we can't be sure the field + * is null terminated. + */ +- if (*(val + arg->str.field->size - 1)) { ++ if (*(val + size - 1)) { + /* copy it */ + memcpy(arg->str.buffer, val, arg->str.field->size); + /* the buffer is already NULL terminated */ +diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c +index a74a48db26f5..2eb11543e2e9 100644 +--- a/tools/perf/arch/x86/util/header.c ++++ b/tools/perf/arch/x86/util/header.c +@@ -69,7 +69,7 @@ get_cpuid_str(void) + { + char *buf = malloc(128); + +- if (__get_cpuid(buf, 128, "%s-%u-%X$") < 0) { ++ if (buf && __get_cpuid(buf, 128, "%s-%u-%X$") < 0) { + free(buf); + return NULL; + } +diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c +index 68861e81f06c..43d5f35e9074 100644 +--- a/tools/perf/builtin-stat.c ++++ b/tools/perf/builtin-stat.c +@@ -2042,11 +2042,16 @@ static int add_default_attributes(void) + return 0; + + if (transaction_run) { ++ struct parse_events_error errinfo; ++ + if (pmu_have_event("cpu", "cycles-ct") && + pmu_have_event("cpu", "el-start")) +- err = parse_events(evsel_list, transaction_attrs, NULL); ++ err = parse_events(evsel_list, transaction_attrs, ++ &errinfo); + else +- err = parse_events(evsel_list, transaction_limited_attrs, NULL); ++ err = parse_events(evsel_list, ++ transaction_limited_attrs, ++ &errinfo); + if (err) { + fprintf(stderr, "Cannot set up transaction events\n"); + return -1; +diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c +index c61e012e9771..e68c866ae798 100644 +--- a/tools/perf/builtin-top.c ++++ b/tools/perf/builtin-top.c +@@ -1061,8 +1061,10 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) + + static int perf_top_config(const char *var, const char *value, void *cb __maybe_unused) + { +- if (!strcmp(var, "top.call-graph")) +- var = "call-graph.record-mode"; /* fall-through */ ++ if (!strcmp(var, "top.call-graph")) { ++ var = "call-graph.record-mode"; ++ return perf_default_config(var, value, cb); ++ } + if (!strcmp(var, "top.children")) { + symbol_conf.cumulate_callchain = perf_config_bool(var, value); + return 0; +diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c +index a5082331f246..2aabf0ae7c0d 100644 +--- a/tools/perf/tests/vmlinux-kallsyms.c ++++ b/tools/perf/tests/vmlinux-kallsyms.c +@@ -123,7 +123,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) + + if (pair && UM(pair->start) == mem_start) { + next_pair: +- if (strcmp(sym->name, pair->name) == 0) { ++ if (arch__compare_symbol_names(sym->name, pair->name) == 0) { + /* + * kallsyms don't have the symbol end, so we + * set that by using the next symbol start - 1, +diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c +index bce80f866dd0..f55d10854565 100644 +--- a/tools/perf/util/evsel.c ++++ b/tools/perf/util/evsel.c +@@ -681,14 +681,14 @@ static void apply_config_terms(struct perf_evsel *evsel, + struct perf_evsel_config_term *term; + struct list_head *config_terms = &evsel->config_terms; + struct perf_event_attr *attr = &evsel->attr; +- struct callchain_param param; ++ /* callgraph default */ ++ struct callchain_param param = { ++ .record_mode = callchain_param.record_mode, ++ }; + u32 dump_size = 0; + int max_stack = 0; + const char *callgraph_buf = NULL; + +- /* callgraph default */ +- param.record_mode = callchain_param.record_mode; +- + list_for_each_entry(term, config_terms, list) { + switch (term->type) { + case PERF_EVSEL__CONFIG_TERM_PERIOD: +diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c +index 10849a079026..ad613ea51434 100644 +--- a/tools/perf/util/hist.c ++++ b/tools/perf/util/hist.c +@@ -865,7 +865,7 @@ iter_prepare_cumulative_entry(struct hist_entry_iter *iter, + * cumulated only one time to prevent entries more than 100% + * overhead. + */ +- he_cache = malloc(sizeof(*he_cache) * (iter->max_stack + 1)); ++ he_cache = malloc(sizeof(*he_cache) * (callchain_cursor.nr + 1)); + if (he_cache == NULL) + return -ENOMEM; + +@@ -1030,8 +1030,6 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, + if (err) + return err; + +- iter->max_stack = max_stack_depth; +- + err = iter->ops->prepare_entry(iter, al); + if (err) + goto out; +diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h +index a440a04a29ff..159d616e170b 100644 +--- a/tools/perf/util/hist.h ++++ b/tools/perf/util/hist.h +@@ -102,7 +102,6 @@ struct hist_entry_iter { + int curr; + + bool hide_unresolved; +- int max_stack; + + struct perf_evsel *evsel; + struct perf_sample *sample; +diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile +index a899ef81c705..76faf5bf0b32 100644 +--- a/tools/testing/selftests/Makefile ++++ b/tools/testing/selftests/Makefile +@@ -94,6 +94,7 @@ ifdef INSTALL_PATH + for TARGET in $(TARGETS); do \ + echo "echo ; echo Running tests in $$TARGET" >> $(ALL_SCRIPT); \ + echo "echo ========================================" >> $(ALL_SCRIPT); \ ++ echo "[ -w /dev/kmsg ] && echo \"kselftest: Running tests in $$TARGET\" >> /dev/kmsg" >> $(ALL_SCRIPT); \ + echo "cd $$TARGET" >> $(ALL_SCRIPT); \ + make -s --no-print-directory -C $$TARGET emit_tests >> $(ALL_SCRIPT); \ + echo "cd \$$ROOT" >> $(ALL_SCRIPT); \ +diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc +new file mode 100644 +index 000000000000..5ba73035e1d9 +--- /dev/null ++++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc +@@ -0,0 +1,46 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# description: Kprobe event string type argument ++ ++[ -f kprobe_events ] || exit_unsupported # this is configurable ++ ++echo 0 > events/enable ++echo > kprobe_events ++ ++case `uname -m` in ++x86_64) ++ ARG2=%si ++ OFFS=8 ++;; ++i[3456]86) ++ ARG2=%cx ++ OFFS=4 ++;; ++aarch64) ++ ARG2=%x1 ++ OFFS=8 ++;; ++arm*) ++ ARG2=%r1 ++ OFFS=4 ++;; ++*) ++ echo "Please implement other architecture here" ++ exit_untested ++esac ++ ++: "Test get argument (1)" ++echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string" > kprobe_events ++echo 1 > events/kprobes/testprobe/enable ++! echo test >> kprobe_events ++tail -n 1 trace | grep -qe "testprobe.* arg1=\"test\"" ++ ++echo 0 > events/kprobes/testprobe/enable ++: "Test get argument (2)" ++echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string arg2=+0(+${OFFS}(${ARG2})):string" > kprobe_events ++echo 1 > events/kprobes/testprobe/enable ++! echo test1 test2 >> kprobe_events ++tail -n 1 trace | grep -qe "testprobe.* arg1=\"test1\" arg2=\"test2\"" ++ ++echo 0 > events/enable ++echo > kprobe_events +diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc +new file mode 100644 +index 000000000000..231bcd2c4eb5 +--- /dev/null ++++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc +@@ -0,0 +1,97 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# description: Kprobe event argument syntax ++ ++[ -f kprobe_events ] || exit_unsupported # this is configurable ++ ++grep "x8/16/32/64" README > /dev/null || exit_unsupported # version issue ++ ++echo 0 > events/enable ++echo > kprobe_events ++ ++PROBEFUNC="vfs_read" ++GOODREG= ++BADREG= ++GOODSYM="_sdata" ++if ! grep -qw ${GOODSYM} /proc/kallsyms ; then ++ GOODSYM=$PROBEFUNC ++fi ++BADSYM="deaqswdefr" ++SYMADDR=0x`grep -w ${GOODSYM} /proc/kallsyms | cut -f 1 -d " "` ++GOODTYPE="x16" ++BADTYPE="y16" ++ ++case `uname -m` in ++x86_64|i[3456]86) ++ GOODREG=%ax ++ BADREG=%ex ++;; ++aarch64) ++ GOODREG=%x0 ++ BADREG=%ax ++;; ++arm*) ++ GOODREG=%r0 ++ BADREG=%ax ++;; ++esac ++ ++test_goodarg() # Good-args ++{ ++ while [ "$1" ]; do ++ echo "p ${PROBEFUNC} $1" > kprobe_events ++ shift 1 ++ done; ++} ++ ++test_badarg() # Bad-args ++{ ++ while [ "$1" ]; do ++ ! echo "p ${PROBEFUNC} $1" > kprobe_events ++ shift 1 ++ done; ++} ++ ++echo > kprobe_events ++ ++: "Register access" ++test_goodarg ${GOODREG} ++test_badarg ${BADREG} ++ ++: "Symbol access" ++test_goodarg "@${GOODSYM}" "@${SYMADDR}" "@${GOODSYM}+10" "@${GOODSYM}-10" ++test_badarg "@" "@${BADSYM}" "@${GOODSYM}*10" "@${GOODSYM}/10" \ ++ "@${GOODSYM}%10" "@${GOODSYM}&10" "@${GOODSYM}|10" ++ ++: "Stack access" ++test_goodarg "\$stack" "\$stack0" "\$stack1" ++test_badarg "\$stackp" "\$stack0+10" "\$stack1-10" ++ ++: "Retval access" ++echo "r ${PROBEFUNC} \$retval" > kprobe_events ++! echo "p ${PROBEFUNC} \$retval" > kprobe_events ++ ++: "Comm access" ++test_goodarg "\$comm" ++ ++: "Indirect memory access" ++test_goodarg "+0(${GOODREG})" "-0(${GOODREG})" "+10(\$stack)" \ ++ "+0(\$stack1)" "+10(@${GOODSYM}-10)" "+0(+10(+20(\$stack)))" ++test_badarg "+(${GOODREG})" "(${GOODREG}+10)" "-(${GOODREG})" "(${GOODREG})" \ ++ "+10(\$comm)" "+0(${GOODREG})+10" ++ ++: "Name assignment" ++test_goodarg "varname=${GOODREG}" ++test_badarg "varname=varname2=${GOODREG}" ++ ++: "Type syntax" ++test_goodarg "${GOODREG}:${GOODTYPE}" ++test_badarg "${GOODREG}::${GOODTYPE}" "${GOODREG}:${BADTYPE}" \ ++ "${GOODTYPE}:${GOODREG}" ++ ++: "Combination check" ++ ++test_goodarg "\$comm:string" "+0(\$stack):string" ++test_badarg "\$comm:x64" "\$stack:string" "${GOODREG}:string" ++ ++echo > kprobe_events +diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc +new file mode 100644 +index 000000000000..4fda01a08da4 +--- /dev/null ++++ b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc +@@ -0,0 +1,43 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++# description: Kprobe events - probe points ++ ++[ -f kprobe_events ] || exit_unsupported # this is configurable ++ ++TARGET_FUNC=create_trace_kprobe ++ ++dec_addr() { # hexaddr ++ printf "%d" "0x"`echo $1 | tail -c 8` ++} ++ ++set_offs() { # prev target next ++ A1=`dec_addr $1` ++ A2=`dec_addr $2` ++ A3=`dec_addr $3` ++ TARGET="0x$2" # an address ++ PREV=`expr $A1 - $A2` # offset to previous symbol ++ NEXT=+`expr $A3 - $A2` # offset to next symbol ++ OVERFLOW=+`printf "0x%x" ${PREV}` # overflow offset to previous symbol ++} ++ ++# We have to decode symbol addresses to get correct offsets. ++# If the offset is not an instruction boundary, it cause -EILSEQ. ++set_offs `grep -A1 -B1 ${TARGET_FUNC} /proc/kallsyms | cut -f 1 -d " " | xargs` ++ ++UINT_TEST=no ++# printf "%x" -1 returns (unsigned long)-1. ++if [ `printf "%x" -1 | wc -c` != 9 ]; then ++ UINT_TEST=yes ++fi ++ ++echo 0 > events/enable ++echo > kprobe_events ++echo "p:testprobe ${TARGET_FUNC}" > kprobe_events ++echo "p:testprobe ${TARGET}" > kprobe_events ++echo "p:testprobe ${TARGET_FUNC}${NEXT}" > kprobe_events ++! echo "p:testprobe ${TARGET_FUNC}${PREV}" > kprobe_events ++if [ "${UINT_TEST}" = yes ]; then ++! echo "p:testprobe ${TARGET_FUNC}${OVERFLOW}" > kprobe_events ++fi ++echo > kprobe_events ++clear_trace +diff --git a/tools/testing/selftests/memfd/config b/tools/testing/selftests/memfd/config +new file mode 100644 +index 000000000000..835c7f4dadcd +--- /dev/null ++++ b/tools/testing/selftests/memfd/config +@@ -0,0 +1 @@ ++CONFIG_FUSE_FS=m +diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c +index 412459369686..9b654a070e7d 100644 +--- a/tools/testing/selftests/net/psock_fanout.c ++++ b/tools/testing/selftests/net/psock_fanout.c +@@ -97,6 +97,8 @@ static int sock_fanout_open(uint16_t typeflags, int num_packets) + + static void sock_fanout_set_ebpf(int fd) + { ++ static char log_buf[65536]; ++ + const int len_off = __builtin_offsetof(struct __sk_buff, len); + struct bpf_insn prog[] = { + { BPF_ALU64 | BPF_MOV | BPF_X, 6, 1, 0, 0 }, +@@ -109,7 +111,6 @@ static void sock_fanout_set_ebpf(int fd) + { BPF_ALU | BPF_MOV | BPF_K, 0, 0, 0, 0 }, + { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 } + }; +- char log_buf[512]; + union bpf_attr attr; + int pfd; + +diff --git a/tools/testing/selftests/net/reuseport_bpf.c b/tools/testing/selftests/net/reuseport_bpf.c +index 4a8217448f20..cad14cd0ea92 100644 +--- a/tools/testing/selftests/net/reuseport_bpf.c ++++ b/tools/testing/selftests/net/reuseport_bpf.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + #ifndef ARRAY_SIZE +@@ -190,11 +191,14 @@ static void send_from(struct test_params p, uint16_t sport, char *buf, + struct sockaddr * const saddr = new_any_sockaddr(p.send_family, sport); + struct sockaddr * const daddr = + new_loopback_sockaddr(p.send_family, p.recv_port); +- const int fd = socket(p.send_family, p.protocol, 0); ++ const int fd = socket(p.send_family, p.protocol, 0), one = 1; + + if (fd < 0) + error(1, errno, "failed to create send socket"); + ++ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) ++ error(1, errno, "failed to set reuseaddr"); ++ + if (bind(fd, saddr, sockaddr_size())) + error(1, errno, "failed to bind send socket"); + +@@ -433,6 +437,21 @@ void enable_fastopen(void) + } + } + ++static struct rlimit rlim_old, rlim_new; ++ ++static __attribute__((constructor)) void main_ctor(void) ++{ ++ getrlimit(RLIMIT_MEMLOCK, &rlim_old); ++ rlim_new.rlim_cur = rlim_old.rlim_cur + (1UL << 20); ++ rlim_new.rlim_max = rlim_old.rlim_max + (1UL << 20); ++ setrlimit(RLIMIT_MEMLOCK, &rlim_new); ++} ++ ++static __attribute__((destructor)) void main_dtor(void) ++{ ++ setrlimit(RLIMIT_MEMLOCK, &rlim_old); ++} ++ + int main(void) + { + fprintf(stderr, "---- IPv4 UDP ----\n"); +diff --git a/tools/testing/selftests/powerpc/mm/subpage_prot.c b/tools/testing/selftests/powerpc/mm/subpage_prot.c +index 35ade7406dcd..3ae77ba93208 100644 +--- a/tools/testing/selftests/powerpc/mm/subpage_prot.c ++++ b/tools/testing/selftests/powerpc/mm/subpage_prot.c +@@ -135,6 +135,16 @@ static int run_test(void *addr, unsigned long size) + return 0; + } + ++static int syscall_available(void) ++{ ++ int rc; ++ ++ errno = 0; ++ rc = syscall(__NR_subpage_prot, 0, 0, 0); ++ ++ return rc == 0 || (errno != ENOENT && errno != ENOSYS); ++} ++ + int test_anon(void) + { + unsigned long align; +@@ -145,6 +155,8 @@ int test_anon(void) + void *mallocblock; + unsigned long mallocsize; + ++ SKIP_IF(!syscall_available()); ++ + if (getpagesize() != 0x10000) { + fprintf(stderr, "Kernel page size must be 64K!\n"); + return 1; +@@ -180,6 +192,8 @@ int test_file(void) + off_t filesize; + int fd; + ++ SKIP_IF(!syscall_available()); ++ + fd = open(file_name, O_RDWR); + if (fd == -1) { + perror("failed to open file"); +diff --git a/tools/testing/selftests/pstore/config b/tools/testing/selftests/pstore/config +index 6a8e5a9bfc10..d148f9f89fb6 100644 +--- a/tools/testing/selftests/pstore/config ++++ b/tools/testing/selftests/pstore/config +@@ -2,3 +2,4 @@ CONFIG_MISC_FILESYSTEMS=y + CONFIG_PSTORE=y + CONFIG_PSTORE_PMSG=y + CONFIG_PSTORE_CONSOLE=y ++CONFIG_PSTORE_RAM=m +diff --git a/tools/thermal/tmon/sysfs.c b/tools/thermal/tmon/sysfs.c +index 1c12536f2081..18f523557983 100644 +--- a/tools/thermal/tmon/sysfs.c ++++ b/tools/thermal/tmon/sysfs.c +@@ -486,6 +486,7 @@ int zone_instance_to_index(int zone_inst) + int update_thermal_data() + { + int i; ++ int next_thermal_record = cur_thermal_record + 1; + char tz_name[256]; + static unsigned long samples; + +@@ -495,9 +496,9 @@ int update_thermal_data() + } + + /* circular buffer for keeping historic data */ +- if (cur_thermal_record >= NR_THERMAL_RECORDS) +- cur_thermal_record = 0; +- gettimeofday(&trec[cur_thermal_record].tv, NULL); ++ if (next_thermal_record >= NR_THERMAL_RECORDS) ++ next_thermal_record = 0; ++ gettimeofday(&trec[next_thermal_record].tv, NULL); + if (tmon_log) { + fprintf(tmon_log, "%lu ", ++samples); + fprintf(tmon_log, "%3.1f ", p_param.t_target); +@@ -507,11 +508,12 @@ int update_thermal_data() + snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, + ptdata.tzi[i].instance); + sysfs_get_ulong(tz_name, "temp", +- &trec[cur_thermal_record].temp[i]); ++ &trec[next_thermal_record].temp[i]); + if (tmon_log) + fprintf(tmon_log, "%lu ", +- trec[cur_thermal_record].temp[i]/1000); ++ trec[next_thermal_record].temp[i] / 1000); + } ++ cur_thermal_record = next_thermal_record; + for (i = 0; i < ptdata.nr_cooling_dev; i++) { + char cdev_name[256]; + unsigned long val; +diff --git a/tools/thermal/tmon/tmon.c b/tools/thermal/tmon/tmon.c +index 9aa19652e8e8..b43138f8b862 100644 +--- a/tools/thermal/tmon/tmon.c ++++ b/tools/thermal/tmon/tmon.c +@@ -336,7 +336,6 @@ int main(int argc, char **argv) + show_data_w(); + show_cooling_device(); + } +- cur_thermal_record++; + time_elapsed += ticktime; + controller_handler(trec[0].temp[target_tz_index] / 1000, + &yk); +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index eaae7252f60c..4f2a2df85b1f 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -1466,7 +1466,8 @@ static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault) + + static int hva_to_pfn_remapped(struct vm_area_struct *vma, + unsigned long addr, bool *async, +- bool write_fault, kvm_pfn_t *p_pfn) ++ bool write_fault, bool *writable, ++ kvm_pfn_t *p_pfn) + { + unsigned long pfn; + int r; +@@ -1492,6 +1493,8 @@ static int hva_to_pfn_remapped(struct vm_area_struct *vma, + + } + ++ if (writable) ++ *writable = true; + + /* + * Get a reference here because callers of *hva_to_pfn* and +@@ -1557,7 +1560,7 @@ static kvm_pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, + if (vma == NULL) + pfn = KVM_PFN_ERR_FAULT; + else if (vma->vm_flags & (VM_IO | VM_PFNMAP)) { +- r = hva_to_pfn_remapped(vma, addr, async, write_fault, &pfn); ++ r = hva_to_pfn_remapped(vma, addr, async, write_fault, writable, &pfn); + if (r == -EAGAIN) + goto retry; + if (r < 0) diff --git a/patch/kernel/odroidxu4-next/0004-patch-4.9.104-105.patch b/patch/kernel/odroidxu4-next/0004-patch-4.9.104-105.patch new file mode 100644 index 0000000000..7831777d80 --- /dev/null +++ b/patch/kernel/odroidxu4-next/0004-patch-4.9.104-105.patch @@ -0,0 +1,24 @@ +diff --git a/Makefile b/Makefile +index 780dcc8033b2..7d06dba3fde8 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 4 + PATCHLEVEL = 9 +-SUBLEVEL = 104 ++SUBLEVEL = 105 + EXTRAVERSION = + NAME = Roaring Lionus + +diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c +index 1ac55b116d5a..cbff0d6ff1ac 100644 +--- a/net/ipv4/ip_vti.c ++++ b/net/ipv4/ip_vti.c +@@ -396,6 +396,7 @@ static int vti_tunnel_init(struct net_device *dev) + memcpy(dev->dev_addr, &iph->saddr, 4); + memcpy(dev->broadcast, &iph->daddr, 4); + ++ dev->mtu = ETH_DATA_LEN; + dev->flags = IFF_NOARP; + dev->addr_len = 4; + dev->features |= NETIF_F_LLTX; diff --git a/patch/kernel/odroidxu4-next/0004-patch-4.9.105-106.patch b/patch/kernel/odroidxu4-next/0004-patch-4.9.105-106.patch new file mode 100644 index 0000000000..ccb7913552 --- /dev/null +++ b/patch/kernel/odroidxu4-next/0004-patch-4.9.105-106.patch @@ -0,0 +1,13260 @@ +diff --git a/Makefile b/Makefile +index 7d06dba3fde8..48d87e3a36c1 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 4 + PATCHLEVEL = 9 +-SUBLEVEL = 105 ++SUBLEVEL = 106 + EXTRAVERSION = + NAME = Roaring Lionus + +diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile +index 34b3fa2889d1..9e32d40d71bd 100644 +--- a/arch/x86/crypto/Makefile ++++ b/arch/x86/crypto/Makefile +@@ -2,6 +2,8 @@ + # Arch-specific CryptoAPI modules. + # + ++OBJECT_FILES_NON_STANDARD := y ++ + avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no) + avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ + $(comma)4)$(comma)%ymm2,yes,no) +diff --git a/arch/x86/crypto/sha1-mb/Makefile b/arch/x86/crypto/sha1-mb/Makefile +index 2f8756375df5..2e14acc3da25 100644 +--- a/arch/x86/crypto/sha1-mb/Makefile ++++ b/arch/x86/crypto/sha1-mb/Makefile +@@ -2,6 +2,8 @@ + # Arch-specific CryptoAPI modules. + # + ++OBJECT_FILES_NON_STANDARD := y ++ + avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ + $(comma)4)$(comma)%ymm2,yes,no) + ifeq ($(avx2_supported),yes) +diff --git a/arch/x86/crypto/sha256-mb/Makefile b/arch/x86/crypto/sha256-mb/Makefile +index 41089e7c400c..45b4fca6c4a8 100644 +--- a/arch/x86/crypto/sha256-mb/Makefile ++++ b/arch/x86/crypto/sha256-mb/Makefile +@@ -2,6 +2,8 @@ + # Arch-specific CryptoAPI modules. + # + ++OBJECT_FILES_NON_STANDARD := y ++ + avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ + $(comma)4)$(comma)%ymm2,yes,no) + ifeq ($(avx2_supported),yes) +diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h +new file mode 100644 +index 000000000000..7dc777a6cb40 +--- /dev/null ++++ b/arch/x86/include/asm/orc_types.h +@@ -0,0 +1,107 @@ ++/* ++ * Copyright (C) 2017 Josh Poimboeuf ++ * ++ * 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, see . ++ */ ++ ++#ifndef _ORC_TYPES_H ++#define _ORC_TYPES_H ++ ++#include ++#include ++ ++/* ++ * The ORC_REG_* registers are base registers which are used to find other ++ * registers on the stack. ++ * ++ * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the ++ * address of the previous frame: the caller's SP before it called the current ++ * function. ++ * ++ * ORC_REG_UNDEFINED means the corresponding register's value didn't change in ++ * the current frame. ++ * ++ * The most commonly used base registers are SP and BP -- which the previous SP ++ * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is ++ * usually based on. ++ * ++ * The rest of the base registers are needed for special cases like entry code ++ * and GCC realigned stacks. ++ */ ++#define ORC_REG_UNDEFINED 0 ++#define ORC_REG_PREV_SP 1 ++#define ORC_REG_DX 2 ++#define ORC_REG_DI 3 ++#define ORC_REG_BP 4 ++#define ORC_REG_SP 5 ++#define ORC_REG_R10 6 ++#define ORC_REG_R13 7 ++#define ORC_REG_BP_INDIRECT 8 ++#define ORC_REG_SP_INDIRECT 9 ++#define ORC_REG_MAX 15 ++ ++/* ++ * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the ++ * caller's SP right before it made the call). Used for all callable ++ * functions, i.e. all C code and all callable asm functions. ++ * ++ * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points ++ * to a fully populated pt_regs from a syscall, interrupt, or exception. ++ * ++ * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset ++ * points to the iret return frame. ++ * ++ * The UNWIND_HINT macros are used only for the unwind_hint struct. They ++ * aren't used in struct orc_entry due to size and complexity constraints. ++ * Objtool converts them to real types when it converts the hints to orc ++ * entries. ++ */ ++#define ORC_TYPE_CALL 0 ++#define ORC_TYPE_REGS 1 ++#define ORC_TYPE_REGS_IRET 2 ++#define UNWIND_HINT_TYPE_SAVE 3 ++#define UNWIND_HINT_TYPE_RESTORE 4 ++ ++#ifndef __ASSEMBLY__ ++/* ++ * This struct is more or less a vastly simplified version of the DWARF Call ++ * Frame Information standard. It contains only the necessary parts of DWARF ++ * CFI, simplified for ease of access by the in-kernel unwinder. It tells the ++ * unwinder how to find the previous SP and BP (and sometimes entry regs) on ++ * the stack for a given code address. Each instance of the struct corresponds ++ * to one or more code locations. ++ */ ++struct orc_entry { ++ s16 sp_offset; ++ s16 bp_offset; ++ unsigned sp_reg:4; ++ unsigned bp_reg:4; ++ unsigned type:2; ++}; ++ ++/* ++ * This struct is used by asm and inline asm code to manually annotate the ++ * location of registers on the stack for the ORC unwinder. ++ * ++ * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. ++ */ ++struct unwind_hint { ++ u32 ip; ++ s16 sp_offset; ++ u8 sp_reg; ++ u8 type; ++}; ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* _ORC_TYPES_H */ +diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h +new file mode 100644 +index 000000000000..5e02b11c9b86 +--- /dev/null ++++ b/arch/x86/include/asm/unwind_hints.h +@@ -0,0 +1,103 @@ ++#ifndef _ASM_X86_UNWIND_HINTS_H ++#define _ASM_X86_UNWIND_HINTS_H ++ ++#include "orc_types.h" ++ ++#ifdef __ASSEMBLY__ ++ ++/* ++ * In asm, there are two kinds of code: normal C-type callable functions and ++ * the rest. The normal callable functions can be called by other code, and ++ * don't do anything unusual with the stack. Such normal callable functions ++ * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this ++ * category. In this case, no special debugging annotations are needed because ++ * objtool can automatically generate the ORC data for the ORC unwinder to read ++ * at runtime. ++ * ++ * Anything which doesn't fall into the above category, such as syscall and ++ * interrupt handlers, tends to not be called directly by other functions, and ++ * often does unusual non-C-function-type things with the stack pointer. Such ++ * code needs to be annotated such that objtool can understand it. The ++ * following CFI hint macros are for this type of code. ++ * ++ * These macros provide hints to objtool about the state of the stack at each ++ * instruction. Objtool starts from the hints and follows the code flow, ++ * making automatic CFI adjustments when it sees pushes and pops, filling out ++ * the debuginfo as necessary. It will also warn if it sees any ++ * inconsistencies. ++ */ ++.macro UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=0 type=ORC_TYPE_CALL ++#ifdef CONFIG_STACK_VALIDATION ++.Lunwind_hint_ip_\@: ++ .pushsection .discard.unwind_hints ++ /* struct unwind_hint */ ++ .long .Lunwind_hint_ip_\@ - . ++ .short \sp_offset ++ .byte \sp_reg ++ .byte \type ++ .popsection ++#endif ++.endm ++ ++.macro UNWIND_HINT_EMPTY ++ UNWIND_HINT sp_reg=ORC_REG_UNDEFINED ++.endm ++ ++.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 iret=0 ++ .if \base == %rsp && \indirect ++ .set sp_reg, ORC_REG_SP_INDIRECT ++ .elseif \base == %rsp ++ .set sp_reg, ORC_REG_SP ++ .elseif \base == %rbp ++ .set sp_reg, ORC_REG_BP ++ .elseif \base == %rdi ++ .set sp_reg, ORC_REG_DI ++ .elseif \base == %rdx ++ .set sp_reg, ORC_REG_DX ++ .elseif \base == %r10 ++ .set sp_reg, ORC_REG_R10 ++ .else ++ .error "UNWIND_HINT_REGS: bad base register" ++ .endif ++ ++ .set sp_offset, \offset ++ ++ .if \iret ++ .set type, ORC_TYPE_REGS_IRET ++ .elseif \extra == 0 ++ .set type, ORC_TYPE_REGS_IRET ++ .set sp_offset, \offset + (16*8) ++ .else ++ .set type, ORC_TYPE_REGS ++ .endif ++ ++ UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type ++.endm ++ ++.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 ++ UNWIND_HINT_REGS base=\base offset=\offset iret=1 ++.endm ++ ++.macro UNWIND_HINT_FUNC sp_offset=8 ++ UNWIND_HINT sp_offset=\sp_offset ++.endm ++ ++#else /* !__ASSEMBLY__ */ ++ ++#define UNWIND_HINT(sp_reg, sp_offset, type) \ ++ "987: \n\t" \ ++ ".pushsection .discard.unwind_hints\n\t" \ ++ /* struct unwind_hint */ \ ++ ".long 987b - .\n\t" \ ++ ".short " __stringify(sp_offset) "\n\t" \ ++ ".byte " __stringify(sp_reg) "\n\t" \ ++ ".byte " __stringify(type) "\n\t" \ ++ ".popsection\n\t" ++ ++#define UNWIND_HINT_SAVE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_SAVE) ++ ++#define UNWIND_HINT_RESTORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_RESTORE) ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* _ASM_X86_UNWIND_HINTS_H */ +diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile +index 79076d75bdbf..4c9c61517613 100644 +--- a/arch/x86/kernel/Makefile ++++ b/arch/x86/kernel/Makefile +@@ -29,6 +29,7 @@ OBJECT_FILES_NON_STANDARD_head_$(BITS).o := y + OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y + OBJECT_FILES_NON_STANDARD_mcount_$(BITS).o := y + OBJECT_FILES_NON_STANDARD_test_nx.o := y ++OBJECT_FILES_NON_STANDARD_paravirt_patch_$(BITS).o := y + + # If instrumentation of this dir is enabled, boot hangs during first second. + # Probably could be more selective here, but note that files related to irqs, +diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile +index 26b78d86f25a..85a9e17e0dbc 100644 +--- a/arch/x86/kernel/acpi/Makefile ++++ b/arch/x86/kernel/acpi/Makefile +@@ -1,3 +1,5 @@ ++OBJECT_FILES_NON_STANDARD_wakeup_$(BITS).o := y ++ + obj-$(CONFIG_ACPI) += boot.o + obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o + obj-$(CONFIG_ACPI_APEI) += apei.o +diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c +index fa671b90c374..1808a9cc7701 100644 +--- a/arch/x86/kernel/kprobes/opt.c ++++ b/arch/x86/kernel/kprobes/opt.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -91,6 +92,7 @@ static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val) + } + + asm ( ++ "optprobe_template_func:\n" + ".global optprobe_template_entry\n" + "optprobe_template_entry:\n" + #ifdef CONFIG_X86_64 +@@ -128,7 +130,12 @@ asm ( + " popf\n" + #endif + ".global optprobe_template_end\n" +- "optprobe_template_end:\n"); ++ "optprobe_template_end:\n" ++ ".type optprobe_template_func, @function\n" ++ ".size optprobe_template_func, .-optprobe_template_func\n"); ++ ++void optprobe_template_func(void); ++STACK_FRAME_NON_STANDARD(optprobe_template_func); + + #define TMPL_MOVE_IDX \ + ((long)&optprobe_template_val - (long)&optprobe_template_entry) +diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c +index 03f21dbfaa9d..4a12362a194a 100644 +--- a/arch/x86/kernel/reboot.c ++++ b/arch/x86/kernel/reboot.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -127,6 +128,7 @@ void __noreturn machine_real_restart(unsigned int type) + #ifdef CONFIG_APM_MODULE + EXPORT_SYMBOL(machine_real_restart); + #endif ++STACK_FRAME_NON_STANDARD(machine_real_restart); + + /* + * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index c7194e97c3d4..4ef267fb635a 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -353,6 +353,7 @@ SECTIONS + /DISCARD/ : { + *(.eh_frame) + *(__func_stack_frame_non_standard) ++ *(__unreachable) + } + } + +diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c +index a27f9e442ffc..c4cd1280ac3e 100644 +--- a/arch/x86/kvm/svm.c ++++ b/arch/x86/kvm/svm.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -5111,6 +5112,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) + + mark_all_clean(svm->vmcb); + } ++STACK_FRAME_NON_STANDARD(svm_vcpu_run); + + static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) + { +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index 2827a9622d97..4a66a620fc17 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include "kvm_cache_regs.h" + #include "x86.h" +@@ -8698,6 +8699,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu) + ); + } + } ++STACK_FRAME_NON_STANDARD(vmx_handle_external_intr); + + static bool vmx_has_emulated_msr(int index) + { +@@ -9138,6 +9140,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) + vmx_recover_nmi_blocking(vmx); + vmx_complete_interrupts(vmx); + } ++STACK_FRAME_NON_STANDARD(vmx_vcpu_run); + + static void vmx_load_vmcs01(struct kvm_vcpu *vcpu) + { +diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S +index c81556409bbb..10ffa7e8519f 100644 +--- a/arch/x86/lib/msr-reg.S ++++ b/arch/x86/lib/msr-reg.S +@@ -13,14 +13,14 @@ + .macro op_safe_regs op + ENTRY(\op\()_safe_regs) + pushq %rbx +- pushq %rbp ++ pushq %r12 + movq %rdi, %r10 /* Save pointer */ + xorl %r11d, %r11d /* Return value */ + movl (%rdi), %eax + movl 4(%rdi), %ecx + movl 8(%rdi), %edx + movl 12(%rdi), %ebx +- movl 20(%rdi), %ebp ++ movl 20(%rdi), %r12d + movl 24(%rdi), %esi + movl 28(%rdi), %edi + 1: \op +@@ -29,10 +29,10 @@ ENTRY(\op\()_safe_regs) + movl %ecx, 4(%r10) + movl %edx, 8(%r10) + movl %ebx, 12(%r10) +- movl %ebp, 20(%r10) ++ movl %r12d, 20(%r10) + movl %esi, 24(%r10) + movl %edi, 28(%r10) +- popq %rbp ++ popq %r12 + popq %rbx + ret + 3: +diff --git a/arch/x86/net/Makefile b/arch/x86/net/Makefile +index 90568c33ddb0..fefb4b619598 100644 +--- a/arch/x86/net/Makefile ++++ b/arch/x86/net/Makefile +@@ -1,4 +1,6 @@ + # + # Arch-specific network modules + # ++OBJECT_FILES_NON_STANDARD_bpf_jit.o += y ++ + obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o +diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile +index 066619b0700c..7a255022933e 100644 +--- a/arch/x86/platform/efi/Makefile ++++ b/arch/x86/platform/efi/Makefile +@@ -1,4 +1,5 @@ + OBJECT_FILES_NON_STANDARD_efi_thunk_$(BITS).o := y ++OBJECT_FILES_NON_STANDARD_efi_stub_$(BITS).o := y + + obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o + obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o +diff --git a/arch/x86/power/Makefile b/arch/x86/power/Makefile +index a6a198c33623..05041871ac90 100644 +--- a/arch/x86/power/Makefile ++++ b/arch/x86/power/Makefile +@@ -1,3 +1,5 @@ ++OBJECT_FILES_NON_STANDARD_hibernate_asm_$(BITS).o := y ++ + # __restore_processor_state() restores %gs after S3 resume and so should not + # itself be stack-protected + nostackp := $(call cc-option, -fno-stack-protector) +diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile +index e47e52787d32..4a54059f42ba 100644 +--- a/arch/x86/xen/Makefile ++++ b/arch/x86/xen/Makefile +@@ -1,3 +1,6 @@ ++OBJECT_FILES_NON_STANDARD_xen-asm_$(BITS).o := y ++OBJECT_FILES_NON_STANDARD_xen-pvh.o := y ++ + ifdef CONFIG_FUNCTION_TRACER + # Do not profile debug and lowlevel utilities + CFLAGS_REMOVE_spinlock.o = -pg +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 081437b5f381..e3a3f5a64884 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -75,6 +75,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_ACPI + #include +@@ -1452,10 +1453,12 @@ static void __ref xen_setup_gdt(int cpu) + * GDT. The new GDT has __KERNEL_CS with CS.L = 1 + * and we are jumping to reload it. + */ +- asm volatile ("pushq %0\n" ++ asm volatile (UNWIND_HINT_SAVE ++ "pushq %0\n" + "leaq 1f(%%rip),%0\n" + "pushq %0\n" + "lretq\n" ++ UNWIND_HINT_RESTORE + "1:\n" + : "=&r" (dummy) : "0" (__KERNEL_CS)); + +diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h +index a1b1de17455c..2214b2f9c73c 100644 +--- a/include/linux/compiler-gcc.h ++++ b/include/linux/compiler-gcc.h +@@ -203,6 +203,17 @@ + #endif + #endif + ++#ifdef CONFIG_STACK_VALIDATION ++#define annotate_unreachable() ({ \ ++ asm("1:\t\n" \ ++ ".pushsection __unreachable, \"a\"\t\n" \ ++ ".long 1b\t\n" \ ++ ".popsection\t\n"); \ ++}) ++#else ++#define annotate_unreachable() ++#endif ++ + /* + * Mark a position in code as unreachable. This can be used to + * suppress control flow warnings after asm blocks that transfer +@@ -212,7 +223,8 @@ + * this in the preprocessor, but we can live with this because they're + * unreleased. Really, we need to have autoconf for the kernel. + */ +-#define unreachable() __builtin_unreachable() ++#define unreachable() \ ++ do { annotate_unreachable(); __builtin_unreachable(); } while (0) + + /* Mark a function definition as prohibited from being cloned. */ + #define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) +diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c +index 561675589511..f5ab72ebda11 100644 +--- a/kernel/kexec_core.c ++++ b/kernel/kexec_core.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -878,7 +879,7 @@ int kexec_load_disabled; + * only when panic_cpu holds the current CPU number; this is the only CPU + * which processes crash_kexec routines. + */ +-void __crash_kexec(struct pt_regs *regs) ++void __noclone __crash_kexec(struct pt_regs *regs) + { + /* Take the kexec_mutex here to prevent sys_kexec_load + * running on one cpu from replacing the crash kernel +@@ -900,6 +901,7 @@ void __crash_kexec(struct pt_regs *regs) + mutex_unlock(&kexec_mutex); + } + } ++STACK_FRAME_NON_STANDARD(__crash_kexec); + + void crash_kexec(struct pt_regs *regs) + { +diff --git a/tools/arch/arm/include/uapi/asm/kvm.h b/tools/arch/arm/include/uapi/asm/kvm.h +index a2b3eb313a25..0b8cf31d8416 100644 +--- a/tools/arch/arm/include/uapi/asm/kvm.h ++++ b/tools/arch/arm/include/uapi/asm/kvm.h +@@ -84,6 +84,13 @@ struct kvm_regs { + #define KVM_VGIC_V2_DIST_SIZE 0x1000 + #define KVM_VGIC_V2_CPU_SIZE 0x2000 + ++/* Supported VGICv3 address types */ ++#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 ++#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 ++ ++#define KVM_VGIC_V3_DIST_SIZE SZ_64K ++#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) ++ + #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ + #define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */ + +@@ -166,6 +173,12 @@ struct kvm_arch_memory_slot { + #define KVM_REG_ARM_VFP_FPINST 0x1009 + #define KVM_REG_ARM_VFP_FPINST2 0x100A + ++/* KVM-as-firmware specific pseudo-registers */ ++#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) ++#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \ ++ KVM_REG_ARM_FW | ((r) & 0xffff)) ++#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) ++ + /* Device Control API: ARM VGIC */ + #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 + #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h +index 3051f86a9b5f..702de7a2b024 100644 +--- a/tools/arch/arm64/include/uapi/asm/kvm.h ++++ b/tools/arch/arm64/include/uapi/asm/kvm.h +@@ -195,6 +195,12 @@ struct kvm_arch_memory_slot { + #define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) + #define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) + ++/* KVM-as-firmware specific pseudo-registers */ ++#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) ++#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ ++ KVM_REG_ARM_FW | ((r) & 0xffff)) ++#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) ++ + /* Device Control API: ARM VGIC */ + #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 + #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h +index c93cf35ce379..0fb1326c3ea2 100644 +--- a/tools/arch/powerpc/include/uapi/asm/kvm.h ++++ b/tools/arch/powerpc/include/uapi/asm/kvm.h +@@ -596,6 +596,7 @@ struct kvm_get_htab_header { + #define KVM_REG_PPC_TM_VSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U32 | 0x67) + #define KVM_REG_PPC_TM_DSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x68) + #define KVM_REG_PPC_TM_TAR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x69) ++#define KVM_REG_PPC_TM_XER (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x6a) + + /* PPC64 eXternal Interrupt Controller Specification */ + #define KVM_DEV_XICS_GRP_SOURCES 1 /* 64-bit source attributes */ +diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h +index a2ffec4139ad..81c02e198527 100644 +--- a/tools/arch/s390/include/uapi/asm/kvm.h ++++ b/tools/arch/s390/include/uapi/asm/kvm.h +@@ -197,6 +197,7 @@ struct kvm_guest_debug_arch { + #define KVM_SYNC_VRS (1UL << 6) + #define KVM_SYNC_RICCB (1UL << 7) + #define KVM_SYNC_FPRS (1UL << 8) ++#define KVM_SYNC_BPBC (1UL << 10) + /* definition of registers in kvm_run */ + struct kvm_sync_regs { + __u64 prefix; /* prefix register */ +@@ -217,7 +218,9 @@ struct kvm_sync_regs { + }; + __u8 reserved[512]; /* for future vector expansion */ + __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ +- __u8 padding[52]; /* riccb needs to be 64byte aligned */ ++ __u8 bpbc : 1; /* bp mode */ ++ __u8 reserved2 : 7; ++ __u8 padding1[51]; /* riccb needs to be 64byte aligned */ + __u8 riccb[64]; /* runtime instrumentation controls block */ + }; + +diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h +index f79669a38c0c..c278f276c9b3 100644 +--- a/tools/arch/x86/include/asm/cpufeatures.h ++++ b/tools/arch/x86/include/asm/cpufeatures.h +@@ -12,7 +12,7 @@ + /* + * Defines x86 CPU feature bits + */ +-#define NCAPINTS 18 /* N 32-bit words worth of info */ ++#define NCAPINTS 19 /* N 32-bit words worth of info */ + #define NBUGINTS 1 /* N 32-bit bug flags */ + + /* +@@ -189,17 +189,32 @@ + + #define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */ + #define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */ ++#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 4) /* Effectively INVPCID && CR4.PCIDE=1 */ + + #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ + #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ + +-#define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ +-#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */ +-#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */ ++#define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */ ++#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */ ++ ++#define X86_FEATURE_MSR_SPEC_CTRL ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */ ++#define X86_FEATURE_SSBD ( 7*32+17) /* Speculative Store Bypass Disable */ ++ ++#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */ + + /* Because the ALTERNATIVE scheme is for members of the X86_FEATURE club... */ + #define X86_FEATURE_KAISER ( 7*32+31) /* CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */ + ++#define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ ++#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ ++#define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ ++#define X86_FEATURE_LS_CFG_SSBD ( 7*32+24) /* "" AMD SSBD implementation */ ++#define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */ ++#define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ ++#define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ ++#define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */ ++ ++ + /* Virtualization flags: Linux defined, word 8 */ + #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ + #define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ +@@ -231,6 +246,7 @@ + #define X86_FEATURE_SMAP ( 9*32+20) /* Supervisor Mode Access Prevention */ + #define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */ + #define X86_FEATURE_CLWB ( 9*32+24) /* CLWB instruction */ ++#define X86_FEATURE_INTEL_PT ( 9*32+25) /* Intel Processor Trace */ + #define X86_FEATURE_AVX512PF ( 9*32+26) /* AVX-512 Prefetch */ + #define X86_FEATURE_AVX512ER ( 9*32+27) /* AVX-512 Exponential and Reciprocal */ + #define X86_FEATURE_AVX512CD ( 9*32+28) /* AVX-512 Conflict Detection */ +@@ -255,6 +271,10 @@ + /* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */ + #define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */ + #define X86_FEATURE_IRPERF (13*32+1) /* Instructions Retired Count */ ++#define X86_FEATURE_AMD_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */ ++#define X86_FEATURE_AMD_IBRS (13*32+14) /* Indirect Branch Restricted Speculation */ ++#define X86_FEATURE_AMD_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */ ++#define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */ + + /* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */ + #define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ +@@ -290,6 +310,16 @@ + #define X86_FEATURE_SUCCOR (17*32+1) /* Uncorrectable error containment and recovery */ + #define X86_FEATURE_SMCA (17*32+3) /* Scalable MCA */ + ++ ++/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ ++#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ ++#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ ++#define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ ++#define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ ++#define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ ++#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ ++#define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* "" Speculative Store Bypass Disable */ ++ + /* + * BUG word(s) + */ +@@ -314,4 +344,10 @@ + #define X86_BUG_NULL_SEG X86_BUG(10) /* Nulling a selector preserves the base */ + #define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */ + #define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */ ++#define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */ ++#define X86_BUG_CPU_MELTDOWN X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */ ++#define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */ ++#define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */ ++#define X86_BUG_SPEC_STORE_BYPASS X86_BUG(17) /* CPU is affected by speculative store bypass attack */ ++ + #endif /* _ASM_X86_CPUFEATURES_H */ +diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h +index 85599ad4d024..1f8cca459c6c 100644 +--- a/tools/arch/x86/include/asm/disabled-features.h ++++ b/tools/arch/x86/include/asm/disabled-features.h +@@ -21,11 +21,13 @@ + # define DISABLE_K6_MTRR (1<<(X86_FEATURE_K6_MTRR & 31)) + # define DISABLE_CYRIX_ARR (1<<(X86_FEATURE_CYRIX_ARR & 31)) + # define DISABLE_CENTAUR_MCR (1<<(X86_FEATURE_CENTAUR_MCR & 31)) ++# define DISABLE_PCID 0 + #else + # define DISABLE_VME 0 + # define DISABLE_K6_MTRR 0 + # define DISABLE_CYRIX_ARR 0 + # define DISABLE_CENTAUR_MCR 0 ++# define DISABLE_PCID (1<<(X86_FEATURE_PCID & 31)) + #endif /* CONFIG_X86_64 */ + + #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +@@ -43,7 +45,7 @@ + #define DISABLED_MASK1 0 + #define DISABLED_MASK2 0 + #define DISABLED_MASK3 (DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR) +-#define DISABLED_MASK4 0 ++#define DISABLED_MASK4 (DISABLE_PCID) + #define DISABLED_MASK5 0 + #define DISABLED_MASK6 0 + #define DISABLED_MASK7 0 +@@ -57,6 +59,7 @@ + #define DISABLED_MASK15 0 + #define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE) + #define DISABLED_MASK17 0 +-#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) ++#define DISABLED_MASK18 0 ++#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) + + #endif /* _ASM_X86_DISABLED_FEATURES_H */ +diff --git a/tools/arch/x86/include/asm/required-features.h b/tools/arch/x86/include/asm/required-features.h +index fac9a5c0abe9..6847d85400a8 100644 +--- a/tools/arch/x86/include/asm/required-features.h ++++ b/tools/arch/x86/include/asm/required-features.h +@@ -100,6 +100,7 @@ + #define REQUIRED_MASK15 0 + #define REQUIRED_MASK16 0 + #define REQUIRED_MASK17 0 +-#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) ++#define REQUIRED_MASK18 0 ++#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) + + #endif /* _ASM_X86_REQUIRED_FEATURES_H */ +diff --git a/tools/include/asm-generic/bitops.h b/tools/include/asm-generic/bitops.h +index 653d1bad77de..0304600121da 100644 +--- a/tools/include/asm-generic/bitops.h ++++ b/tools/include/asm-generic/bitops.h +@@ -13,6 +13,7 @@ + */ + + #include ++#include + #include + #include + #include +diff --git a/tools/include/asm-generic/bitops/__ffz.h b/tools/include/asm-generic/bitops/__ffz.h +new file mode 100644 +index 000000000000..6744bd4cdf46 +--- /dev/null ++++ b/tools/include/asm-generic/bitops/__ffz.h +@@ -0,0 +1,12 @@ ++#ifndef _ASM_GENERIC_BITOPS_FFZ_H_ ++#define _ASM_GENERIC_BITOPS_FFZ_H_ ++ ++/* ++ * ffz - find first zero in word. ++ * @word: The word to search ++ * ++ * Undefined if no zero exists, so code should check against ~0UL first. ++ */ ++#define ffz(x) __ffs(~(x)) ++ ++#endif /* _ASM_GENERIC_BITOPS_FFZ_H_ */ +diff --git a/tools/include/asm-generic/bitops/find.h b/tools/include/asm-generic/bitops/find.h +index 31f51547fcd4..5538ecdc964a 100644 +--- a/tools/include/asm-generic/bitops/find.h ++++ b/tools/include/asm-generic/bitops/find.h +@@ -15,6 +15,21 @@ extern unsigned long find_next_bit(const unsigned long *addr, unsigned long + size, unsigned long offset); + #endif + ++#ifndef find_next_zero_bit ++ ++/** ++ * find_next_zero_bit - find the next cleared bit in a memory region ++ * @addr: The address to base the search on ++ * @offset: The bitnumber to start searching at ++ * @size: The bitmap size in bits ++ * ++ * Returns the bit number of the next zero bit ++ * If no bits are zero, returns @size. ++ */ ++unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, ++ unsigned long offset); ++#endif ++ + #ifndef find_first_bit + + /** +@@ -30,4 +45,17 @@ extern unsigned long find_first_bit(const unsigned long *addr, + + #endif /* find_first_bit */ + ++#ifndef find_first_zero_bit ++ ++/** ++ * find_first_zero_bit - find the first cleared bit in a memory region ++ * @addr: The address to start the search at ++ * @size: The maximum number of bits to search ++ * ++ * Returns the bit number of the first cleared bit. ++ * If no bits are zero, returns @size. ++ */ ++unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size); ++#endif ++ + #endif /*_TOOLS_LINUX_ASM_GENERIC_BITOPS_FIND_H_ */ +diff --git a/tools/include/linux/atomic.h b/tools/include/linux/atomic.h +index 4e3d3d18ebab..9f21fc2b092b 100644 +--- a/tools/include/linux/atomic.h ++++ b/tools/include/linux/atomic.h +@@ -3,4 +3,10 @@ + + #include + ++/* atomic_cmpxchg_relaxed */ ++#ifndef atomic_cmpxchg_relaxed ++#define atomic_cmpxchg_relaxed atomic_cmpxchg ++#define atomic_cmpxchg_release atomic_cmpxchg ++#endif /* atomic_cmpxchg_relaxed */ ++ + #endif /* __TOOLS_LINUX_ATOMIC_H */ +diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h +index 43c1c5021e4b..eef41d500e9e 100644 +--- a/tools/include/linux/bitmap.h ++++ b/tools/include/linux/bitmap.h +@@ -35,6 +35,32 @@ static inline void bitmap_zero(unsigned long *dst, int nbits) + } + } + ++static inline void bitmap_fill(unsigned long *dst, unsigned int nbits) ++{ ++ unsigned int nlongs = BITS_TO_LONGS(nbits); ++ if (!small_const_nbits(nbits)) { ++ unsigned int len = (nlongs - 1) * sizeof(unsigned long); ++ memset(dst, 0xff, len); ++ } ++ dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); ++} ++ ++static inline int bitmap_empty(const unsigned long *src, unsigned nbits) ++{ ++ if (small_const_nbits(nbits)) ++ return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); ++ ++ return find_first_bit(src, nbits) == nbits; ++} ++ ++static inline int bitmap_full(const unsigned long *src, unsigned int nbits) ++{ ++ if (small_const_nbits(nbits)) ++ return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); ++ ++ return find_first_zero_bit(src, nbits) == nbits; ++} ++ + static inline int bitmap_weight(const unsigned long *src, int nbits) + { + if (small_const_nbits(nbits)) +diff --git a/tools/include/linux/bitops.h b/tools/include/linux/bitops.h +index 49c929a104ee..fc446343ff41 100644 +--- a/tools/include/linux/bitops.h ++++ b/tools/include/linux/bitops.h +@@ -39,6 +39,11 @@ extern unsigned long __sw_hweight64(__u64 w); + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + ++#define for_each_clear_bit(bit, addr, size) \ ++ for ((bit) = find_first_zero_bit((addr), (size)); \ ++ (bit) < (size); \ ++ (bit) = find_next_zero_bit((addr), (size), (bit) + 1)) ++ + /* same as for_each_set_bit() but use bit as value to start with */ + #define for_each_set_bit_from(bit, addr, size) \ + for ((bit) = find_next_bit((addr), (size), (bit)); \ +diff --git a/tools/include/linux/bug.h b/tools/include/linux/bug.h +new file mode 100644 +index 000000000000..8e4a4f49135d +--- /dev/null ++++ b/tools/include/linux/bug.h +@@ -0,0 +1,10 @@ ++#ifndef _TOOLS_PERF_LINUX_BUG_H ++#define _TOOLS_PERF_LINUX_BUG_H ++ ++/* Force a compilation error if condition is true, but also produce a ++ result (of value 0 and type size_t), so the expression can be used ++ e.g. in a structure initializer (or where-ever else comma expressions ++ aren't permitted). */ ++#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) ++ ++#endif /* _TOOLS_PERF_LINUX_BUG_H */ +diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h +new file mode 100644 +index 000000000000..825d44f89a29 +--- /dev/null ++++ b/tools/include/linux/compiler-gcc.h +@@ -0,0 +1,21 @@ ++#ifndef _TOOLS_LINUX_COMPILER_H_ ++#error "Please don't include directly, include instead." ++#endif ++ ++/* ++ * Common definitions for all gcc versions go here. ++ */ ++#define GCC_VERSION (__GNUC__ * 10000 \ ++ + __GNUC_MINOR__ * 100 \ ++ + __GNUC_PATCHLEVEL__) ++ ++#if GCC_VERSION >= 70000 && !defined(__CHECKER__) ++# define __fallthrough __attribute__ ((fallthrough)) ++#endif ++ ++#if GCC_VERSION >= 40300 ++# define __compiletime_error(message) __attribute__((error(message))) ++#endif /* GCC_VERSION >= 40300 */ ++ ++/* &a[0] degrades to a pointer: a different type from an array */ ++#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) +diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h +index d94179f94caa..23299d7e7160 100644 +--- a/tools/include/linux/compiler.h ++++ b/tools/include/linux/compiler.h +@@ -1,6 +1,14 @@ + #ifndef _TOOLS_LINUX_COMPILER_H_ + #define _TOOLS_LINUX_COMPILER_H_ + ++#ifdef __GNUC__ ++#include ++#endif ++ ++#ifndef __compiletime_error ++# define __compiletime_error(message) ++#endif ++ + /* Optimization barrier */ + /* The "volatile" is due to gcc bugs */ + #define barrier() __asm__ __volatile__("": : :"memory") +@@ -9,6 +17,11 @@ + # define __always_inline inline __attribute__((always_inline)) + #endif + ++/* Are two types/vars the same type (ignoring qualifiers)? */ ++#ifndef __same_type ++# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) ++#endif ++ + #ifdef __ANDROID__ + /* + * FIXME: Big hammer to get rid of tons of: +@@ -21,6 +34,8 @@ + #endif + + #define __user ++#define __rcu ++#define __read_mostly + + #ifndef __attribute_const__ + # define __attribute_const__ +@@ -50,6 +65,8 @@ + # define unlikely(x) __builtin_expect(!!(x), 0) + #endif + ++#define uninitialized_var(x) x = *(&(x)) ++ + #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) + + #include +@@ -128,11 +145,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s + + + #ifndef __fallthrough +-# if defined(__GNUC__) && __GNUC__ >= 7 +-# define __fallthrough __attribute__ ((fallthrough)) +-# else +-# define __fallthrough +-# endif ++# define __fallthrough + #endif + + #endif /* _TOOLS_LINUX_COMPILER_H */ +diff --git a/tools/include/linux/hashtable.h b/tools/include/linux/hashtable.h +index c65cc0aa2659..251eabf2a05e 100644 +--- a/tools/include/linux/hashtable.h ++++ b/tools/include/linux/hashtable.h +@@ -13,10 +13,6 @@ + #include + #include + +-#ifndef ARRAY_SIZE +-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +-#endif +- + #define DEFINE_HASHTABLE(name, bits) \ + struct hlist_head name[1 << (bits)] = \ + { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } +diff --git a/tools/include/linux/kernel.h b/tools/include/linux/kernel.h +index 28607db02bd3..73ccc48126bb 100644 +--- a/tools/include/linux/kernel.h ++++ b/tools/include/linux/kernel.h +@@ -4,6 +4,11 @@ + #include + #include + #include ++#include ++ ++#ifndef UINT_MAX ++#define UINT_MAX (~0U) ++#endif + + #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) + +@@ -72,6 +77,8 @@ + int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); + int scnprintf(char * buf, size_t size, const char * fmt, ...); + ++#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) ++ + /* + * This looks more complex than it should be. But we need to + * get the type for the ~ right in round_down (it needs to be +diff --git a/tools/include/linux/log2.h b/tools/include/linux/log2.h +index d5677d39c1e4..0325cefc2220 100644 +--- a/tools/include/linux/log2.h ++++ b/tools/include/linux/log2.h +@@ -12,6 +12,9 @@ + #ifndef _TOOLS_LINUX_LOG2_H + #define _TOOLS_LINUX_LOG2_H + ++#include ++#include ++ + /* + * non-constant log of base 2 calculators + * - the arch may override these in asm/bitops.h if they can be implemented +diff --git a/tools/include/linux/refcount.h b/tools/include/linux/refcount.h +new file mode 100644 +index 000000000000..a0177c1f55b1 +--- /dev/null ++++ b/tools/include/linux/refcount.h +@@ -0,0 +1,151 @@ ++#ifndef _TOOLS_LINUX_REFCOUNT_H ++#define _TOOLS_LINUX_REFCOUNT_H ++ ++/* ++ * Variant of atomic_t specialized for reference counts. ++ * ++ * The interface matches the atomic_t interface (to aid in porting) but only ++ * provides the few functions one should use for reference counting. ++ * ++ * It differs in that the counter saturates at UINT_MAX and will not move once ++ * there. This avoids wrapping the counter and causing 'spurious' ++ * use-after-free issues. ++ * ++ * Memory ordering rules are slightly relaxed wrt regular atomic_t functions ++ * and provide only what is strictly required for refcounts. ++ * ++ * The increments are fully relaxed; these will not provide ordering. The ++ * rationale is that whatever is used to obtain the object we're increasing the ++ * reference count on will provide the ordering. For locked data structures, ++ * its the lock acquire, for RCU/lockless data structures its the dependent ++ * load. ++ * ++ * Do note that inc_not_zero() provides a control dependency which will order ++ * future stores against the inc, this ensures we'll never modify the object ++ * if we did not in fact acquire a reference. ++ * ++ * The decrements will provide release order, such that all the prior loads and ++ * stores will be issued before, it also provides a control dependency, which ++ * will order us against the subsequent free(). ++ * ++ * The control dependency is against the load of the cmpxchg (ll/sc) that ++ * succeeded. This means the stores aren't fully ordered, but this is fine ++ * because the 1->0 transition indicates no concurrency. ++ * ++ * Note that the allocator is responsible for ordering things between free() ++ * and alloc(). ++ * ++ */ ++ ++#include ++#include ++ ++#ifdef NDEBUG ++#define REFCOUNT_WARN(cond, str) (void)(cond) ++#define __refcount_check ++#else ++#define REFCOUNT_WARN(cond, str) BUG_ON(cond) ++#define __refcount_check __must_check ++#endif ++ ++typedef struct refcount_struct { ++ atomic_t refs; ++} refcount_t; ++ ++#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), } ++ ++static inline void refcount_set(refcount_t *r, unsigned int n) ++{ ++ atomic_set(&r->refs, n); ++} ++ ++static inline unsigned int refcount_read(const refcount_t *r) ++{ ++ return atomic_read(&r->refs); ++} ++ ++/* ++ * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN. ++ * ++ * Provides no memory ordering, it is assumed the caller has guaranteed the ++ * object memory to be stable (RCU, etc.). It does provide a control dependency ++ * and thereby orders future stores. See the comment on top. ++ */ ++static inline __refcount_check ++bool refcount_inc_not_zero(refcount_t *r) ++{ ++ unsigned int old, new, val = atomic_read(&r->refs); ++ ++ for (;;) { ++ new = val + 1; ++ ++ if (!val) ++ return false; ++ ++ if (unlikely(!new)) ++ return true; ++ ++ old = atomic_cmpxchg_relaxed(&r->refs, val, new); ++ if (old == val) ++ break; ++ ++ val = old; ++ } ++ ++ REFCOUNT_WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); ++ ++ return true; ++} ++ ++/* ++ * Similar to atomic_inc(), will saturate at UINT_MAX and WARN. ++ * ++ * Provides no memory ordering, it is assumed the caller already has a ++ * reference on the object, will WARN when this is not so. ++ */ ++static inline void refcount_inc(refcount_t *r) ++{ ++ REFCOUNT_WARN(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); ++} ++ ++/* ++ * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to ++ * decrement when saturated at UINT_MAX. ++ * ++ * Provides release memory ordering, such that prior loads and stores are done ++ * before, and provides a control dependency such that free() must come after. ++ * See the comment on top. ++ */ ++static inline __refcount_check ++bool refcount_sub_and_test(unsigned int i, refcount_t *r) ++{ ++ unsigned int old, new, val = atomic_read(&r->refs); ++ ++ for (;;) { ++ if (unlikely(val == UINT_MAX)) ++ return false; ++ ++ new = val - i; ++ if (new > val) { ++ REFCOUNT_WARN(new > val, "refcount_t: underflow; use-after-free.\n"); ++ return false; ++ } ++ ++ old = atomic_cmpxchg_release(&r->refs, val, new); ++ if (old == val) ++ break; ++ ++ val = old; ++ } ++ ++ return !new; ++} ++ ++static inline __refcount_check ++bool refcount_dec_and_test(refcount_t *r) ++{ ++ return refcount_sub_and_test(1, r); ++} ++ ++ ++#endif /* _ATOMIC_LINUX_REFCOUNT_H */ +diff --git a/tools/include/linux/spinlock.h b/tools/include/linux/spinlock.h +new file mode 100644 +index 000000000000..58397dcb19d6 +--- /dev/null ++++ b/tools/include/linux/spinlock.h +@@ -0,0 +1,5 @@ ++#define spinlock_t pthread_mutex_t ++#define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; ++ ++#define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) ++#define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) +diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h +index 8ebf6278b2ef..77a28a26a670 100644 +--- a/tools/include/linux/types.h ++++ b/tools/include/linux/types.h +@@ -7,6 +7,7 @@ + + #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ + #include ++#include + + struct page; + struct kmem_cache; +@@ -42,11 +43,7 @@ typedef __s8 s8; + #else + #define __bitwise__ + #endif +-#ifdef __CHECK_ENDIAN__ + #define __bitwise __bitwise__ +-#else +-#define __bitwise +-#endif + + #define __force + #define __user +diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h +index 58274382a616..8c27db0c5c08 100644 +--- a/tools/include/uapi/asm-generic/mman-common.h ++++ b/tools/include/uapi/asm-generic/mman-common.h +@@ -72,4 +72,9 @@ + #define MAP_HUGE_SHIFT 26 + #define MAP_HUGE_MASK 0x3f + ++#define PKEY_DISABLE_ACCESS 0x1 ++#define PKEY_DISABLE_WRITE 0x2 ++#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\ ++ PKEY_DISABLE_WRITE) ++ + #endif /* __ASM_GENERIC_MMAN_COMMON_H */ +diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h +index 9e5fc168c8a3..f09c70b97eca 100644 +--- a/tools/include/uapi/linux/bpf.h ++++ b/tools/include/uapi/linux/bpf.h +@@ -95,6 +95,7 @@ enum bpf_prog_type { + BPF_PROG_TYPE_SCHED_ACT, + BPF_PROG_TYPE_TRACEPOINT, + BPF_PROG_TYPE_XDP, ++ BPF_PROG_TYPE_PERF_EVENT, + }; + + #define BPF_PSEUDO_MAP_FD 1 +@@ -375,6 +376,56 @@ enum bpf_func_id { + */ + BPF_FUNC_probe_write_user, + ++ /** ++ * bpf_current_task_under_cgroup(map, index) - Check cgroup2 membership of current task ++ * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type ++ * @index: index of the cgroup in the bpf_map ++ * Return: ++ * == 0 current failed the cgroup2 descendant test ++ * == 1 current succeeded the cgroup2 descendant test ++ * < 0 error ++ */ ++ BPF_FUNC_current_task_under_cgroup, ++ ++ /** ++ * bpf_skb_change_tail(skb, len, flags) ++ * The helper will resize the skb to the given new size, ++ * to be used f.e. with control messages. ++ * @skb: pointer to skb ++ * @len: new skb length ++ * @flags: reserved ++ * Return: 0 on success or negative error ++ */ ++ BPF_FUNC_skb_change_tail, ++ ++ /** ++ * bpf_skb_pull_data(skb, len) ++ * The helper will pull in non-linear data in case the ++ * skb is non-linear and not all of len are part of the ++ * linear section. Only needed for read/write with direct ++ * packet access. ++ * @skb: pointer to skb ++ * @len: len to make read/writeable ++ * Return: 0 on success or negative error ++ */ ++ BPF_FUNC_skb_pull_data, ++ ++ /** ++ * bpf_csum_update(skb, csum) ++ * Adds csum into skb->csum in case of CHECKSUM_COMPLETE. ++ * @skb: pointer to skb ++ * @csum: csum to add ++ * Return: csum on success or negative error ++ */ ++ BPF_FUNC_csum_update, ++ ++ /** ++ * bpf_set_hash_invalid(skb) ++ * Invalidate current skb>hash. ++ * @skb: pointer to skb ++ */ ++ BPF_FUNC_set_hash_invalid, ++ + __BPF_FUNC_MAX_ID, + }; + +diff --git a/tools/include/uapi/linux/fcntl.h b/tools/include/uapi/linux/fcntl.h +new file mode 100644 +index 000000000000..beed138bd359 +--- /dev/null ++++ b/tools/include/uapi/linux/fcntl.h +@@ -0,0 +1,67 @@ ++#ifndef _UAPI_LINUX_FCNTL_H ++#define _UAPI_LINUX_FCNTL_H ++ ++#include ++ ++#define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0) ++#define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1) ++ ++/* ++ * Cancel a blocking posix lock; internal use only until we expose an ++ * asynchronous lock api to userspace: ++ */ ++#define F_CANCELLK (F_LINUX_SPECIFIC_BASE + 5) ++ ++/* Create a file descriptor with FD_CLOEXEC set. */ ++#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) ++ ++/* ++ * Request nofications on a directory. ++ * See below for events that may be notified. ++ */ ++#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2) ++ ++/* ++ * Set and get of pipe page size array ++ */ ++#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) ++#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) ++ ++/* ++ * Set/Get seals ++ */ ++#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) ++#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) ++ ++/* ++ * Types of seals ++ */ ++#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ ++#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ ++#define F_SEAL_GROW 0x0004 /* prevent file from growing */ ++#define F_SEAL_WRITE 0x0008 /* prevent writes */ ++/* (1U << 31) is reserved for signed error codes */ ++ ++/* ++ * Types of directory notifications that may be requested. ++ */ ++#define DN_ACCESS 0x00000001 /* File accessed */ ++#define DN_MODIFY 0x00000002 /* File modified */ ++#define DN_CREATE 0x00000004 /* File created */ ++#define DN_DELETE 0x00000008 /* File removed */ ++#define DN_RENAME 0x00000010 /* File renamed */ ++#define DN_ATTRIB 0x00000020 /* File changed attibutes */ ++#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ ++ ++#define AT_FDCWD -100 /* Special value used to indicate ++ openat should use the current ++ working directory. */ ++#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ ++#define AT_REMOVEDIR 0x200 /* Remove directory instead of ++ unlinking file. */ ++#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ ++#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ ++#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ ++ ++ ++#endif /* _UAPI_LINUX_FCNTL_H */ +diff --git a/tools/include/uapi/linux/stat.h b/tools/include/uapi/linux/stat.h +new file mode 100644 +index 000000000000..7fec7e36d921 +--- /dev/null ++++ b/tools/include/uapi/linux/stat.h +@@ -0,0 +1,45 @@ ++#ifndef _UAPI_LINUX_STAT_H ++#define _UAPI_LINUX_STAT_H ++ ++ ++#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) ++ ++#define S_IFMT 00170000 ++#define S_IFSOCK 0140000 ++#define S_IFLNK 0120000 ++#define S_IFREG 0100000 ++#define S_IFBLK 0060000 ++#define S_IFDIR 0040000 ++#define S_IFCHR 0020000 ++#define S_IFIFO 0010000 ++#define S_ISUID 0004000 ++#define S_ISGID 0002000 ++#define S_ISVTX 0001000 ++ ++#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) ++#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) ++#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) ++#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) ++#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) ++#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) ++#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) ++ ++#define S_IRWXU 00700 ++#define S_IRUSR 00400 ++#define S_IWUSR 00200 ++#define S_IXUSR 00100 ++ ++#define S_IRWXG 00070 ++#define S_IRGRP 00040 ++#define S_IWGRP 00020 ++#define S_IXGRP 00010 ++ ++#define S_IRWXO 00007 ++#define S_IROTH 00004 ++#define S_IWOTH 00002 ++#define S_IXOTH 00001 ++ ++#endif ++ ++ ++#endif /* _UAPI_LINUX_STAT_H */ +diff --git a/tools/lib/find_bit.c b/tools/lib/find_bit.c +index 9122a9e80046..6d8b8f22cf55 100644 +--- a/tools/lib/find_bit.c ++++ b/tools/lib/find_bit.c +@@ -82,3 +82,28 @@ unsigned long find_first_bit(const unsigned long *addr, unsigned long size) + return size; + } + #endif ++ ++#ifndef find_first_zero_bit ++/* ++ * Find the first cleared bit in a memory region. ++ */ ++unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) ++{ ++ unsigned long idx; ++ ++ for (idx = 0; idx * BITS_PER_LONG < size; idx++) { ++ if (addr[idx] != ~0UL) ++ return min(idx * BITS_PER_LONG + ffz(addr[idx]), size); ++ } ++ ++ return size; ++} ++#endif ++ ++#ifndef find_next_zero_bit ++unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, ++ unsigned long offset) ++{ ++ return _find_next_bit(addr, size, offset, ~0UL); ++} ++#endif +diff --git a/tools/objtool/Build b/tools/objtool/Build +index d6cdece5e58b..749becdf5b90 100644 +--- a/tools/objtool/Build ++++ b/tools/objtool/Build +@@ -1,5 +1,9 @@ + objtool-y += arch/$(SRCARCH)/ + objtool-y += builtin-check.o ++objtool-y += builtin-orc.o ++objtool-y += check.o ++objtool-y += orc_gen.o ++objtool-y += orc_dump.o + objtool-y += elf.o + objtool-y += special.o + objtool-y += objtool.o +diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt +index 55a60d331f47..3995735a878f 100644 +--- a/tools/objtool/Documentation/stack-validation.txt ++++ b/tools/objtool/Documentation/stack-validation.txt +@@ -11,9 +11,6 @@ analyzes every .o file and ensures the validity of its stack metadata. + It enforces a set of rules on asm code and C inline assembly code so + that stack traces can be reliable. + +-Currently it only checks frame pointer usage, but there are plans to add +-CFI validation for C files and CFI generation for asm files. +- + For each function, it recursively follows all possible code paths and + validates the correct frame pointer state at each instruction. + +@@ -23,6 +20,10 @@ alternative execution paths to a given instruction (or set of + instructions). Similarly, it knows how to follow switch statements, for + which gcc sometimes uses jump tables. + ++(Objtool also has an 'orc generate' subcommand which generates debuginfo ++for the ORC unwinder. See Documentation/x86/orc-unwinder.txt in the ++kernel tree for more details.) ++ + + Why do we need stack metadata validation? + ----------------------------------------- +@@ -93,62 +94,24 @@ a) More reliable stack traces for frame pointer enabled kernels + or at the very end of the function after the stack frame has been + destroyed. This is an inherent limitation of frame pointers. + +-b) 100% reliable stack traces for DWARF enabled kernels +- +- (NOTE: This is not yet implemented) +- +- As an alternative to frame pointers, DWARF Call Frame Information +- (CFI) metadata can be used to walk the stack. Unlike frame pointers, +- CFI metadata is out of band. So it doesn't affect runtime +- performance and it can be reliable even when interrupts or exceptions +- are involved. +- +- For C code, gcc automatically generates DWARF CFI metadata. But for +- asm code, generating CFI is a tedious manual approach which requires +- manually placed .cfi assembler macros to be scattered throughout the +- code. It's clumsy and very easy to get wrong, and it makes the real +- code harder to read. +- +- Stacktool will improve this situation in several ways. For code +- which already has CFI annotations, it will validate them. For code +- which doesn't have CFI annotations, it will generate them. So an +- architecture can opt to strip out all the manual .cfi annotations +- from their asm code and have objtool generate them instead. ++b) ORC (Oops Rewind Capability) unwind table generation + +- We might also add a runtime stack validation debug option where we +- periodically walk the stack from schedule() and/or an NMI to ensure +- that the stack metadata is sane and that we reach the bottom of the +- stack. ++ An alternative to frame pointers and DWARF, ORC unwind data can be ++ used to walk the stack. Unlike frame pointers, ORC data is out of ++ band. So it doesn't affect runtime performance and it can be ++ reliable even when interrupts or exceptions are involved. + +- So the benefit of objtool here will be that external tooling should +- always show perfect stack traces. And the same will be true for +- kernel warning/oops traces if the architecture has a runtime DWARF +- unwinder. ++ For more details, see Documentation/x86/orc-unwinder.txt. + + c) Higher live patching compatibility rate + +- (NOTE: This is not yet implemented) +- +- Currently with CONFIG_LIVEPATCH there's a basic live patching +- framework which is safe for roughly 85-90% of "security" fixes. But +- patches can't have complex features like function dependency or +- prototype changes, or data structure changes. +- +- There's a strong need to support patches which have the more complex +- features so that the patch compatibility rate for security fixes can +- eventually approach something resembling 100%. To achieve that, a +- "consistency model" is needed, which allows tasks to be safely +- transitioned from an unpatched state to a patched state. +- +- One of the key requirements of the currently proposed livepatch +- consistency model [*] is that it needs to walk the stack of each +- sleeping task to determine if it can be transitioned to the patched +- state. If objtool can ensure that stack traces are reliable, this +- consistency model can be used and the live patching compatibility +- rate can be improved significantly. +- +- [*] https://lkml.kernel.org/r/cover.1423499826.git.jpoimboe@redhat.com ++ Livepatch has an optional "consistency model", which is needed for ++ more complex patches. In order for the consistency model to work, ++ stack traces need to be reliable (or an unreliable condition needs to ++ be detectable). Objtool makes that possible. + ++ For more details, see the livepatch documentation in the Linux kernel ++ source tree at Documentation/livepatch/livepatch.txt. + + Rules + ----- +@@ -201,80 +164,84 @@ To achieve the validation, objtool enforces the following rules: + return normally. + + +-Errors in .S files +------------------- ++Objtool warnings ++---------------- ++ ++For asm files, if you're getting an error which doesn't make sense, ++first make sure that the affected code follows the above rules. + +-If you're getting an error in a compiled .S file which you don't +-understand, first make sure that the affected code follows the above +-rules. ++For C files, the common culprits are inline asm statements and calls to ++"noreturn" functions. See below for more details. ++ ++Another possible cause for errors in C code is if the Makefile removes ++-fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. + + Here are some examples of common warnings reported by objtool, what + they mean, and suggestions for how to fix them. + + +-1. asm_file.o: warning: objtool: func()+0x128: call without frame pointer save/setup ++1. file.o: warning: objtool: func()+0x128: call without frame pointer save/setup + + The func() function made a function call without first saving and/or +- updating the frame pointer. +- +- If func() is indeed a callable function, add proper frame pointer +- logic using the FRAME_BEGIN and FRAME_END macros. Otherwise, remove +- its ELF function annotation by changing ENDPROC to END. +- +- If you're getting this error in a .c file, see the "Errors in .c +- files" section. ++ updating the frame pointer, and CONFIG_FRAME_POINTER is enabled. + ++ If the error is for an asm file, and func() is indeed a callable ++ function, add proper frame pointer logic using the FRAME_BEGIN and ++ FRAME_END macros. Otherwise, if it's not a callable function, remove ++ its ELF function annotation by changing ENDPROC to END, and instead ++ use the manual unwind hint macros in asm/unwind_hints.h. + +-2. asm_file.o: warning: objtool: .text+0x53: return instruction outside of a callable function ++ If it's a GCC-compiled .c file, the error may be because the function ++ uses an inline asm() statement which has a "call" instruction. An ++ asm() statement with a call instruction must declare the use of the ++ stack pointer in its output operand. On x86_64, this means adding ++ the ASM_CALL_CONSTRAINT as an output constraint: + +- A return instruction was detected, but objtool couldn't find a way +- for a callable function to reach the instruction. ++ asm volatile("call func" : ASM_CALL_CONSTRAINT); + +- If the return instruction is inside (or reachable from) a callable +- function, the function needs to be annotated with the ENTRY/ENDPROC +- macros. ++ Otherwise the stack frame may not get created before the call. + +- If you _really_ need a return instruction outside of a function, and +- are 100% sure that it won't affect stack traces, you can tell +- objtool to ignore it. See the "Adding exceptions" section below. + ++2. file.o: warning: objtool: .text+0x53: unreachable instruction + +-3. asm_file.o: warning: objtool: func()+0x9: function has unreachable instruction ++ Objtool couldn't find a code path to reach the instruction. + +- The instruction lives inside of a callable function, but there's no +- possible control flow path from the beginning of the function to the +- instruction. ++ If the error is for an asm file, and the instruction is inside (or ++ reachable from) a callable function, the function should be annotated ++ with the ENTRY/ENDPROC macros (ENDPROC is the important one). ++ Otherwise, the code should probably be annotated with the unwind hint ++ macros in asm/unwind_hints.h so objtool and the unwinder can know the ++ stack state associated with the code. + +- If the instruction is actually needed, and it's actually in a +- callable function, ensure that its function is properly annotated +- with ENTRY/ENDPROC. ++ If you're 100% sure the code won't affect stack traces, or if you're ++ a just a bad person, you can tell objtool to ignore it. See the ++ "Adding exceptions" section below. + + If it's not actually in a callable function (e.g. kernel entry code), + change ENDPROC to END. + + +-4. asm_file.o: warning: objtool: func(): can't find starting instruction ++4. file.o: warning: objtool: func(): can't find starting instruction + or +- asm_file.o: warning: objtool: func()+0x11dd: can't decode instruction ++ file.o: warning: objtool: func()+0x11dd: can't decode instruction + +- Did you put data in a text section? If so, that can confuse ++ Does the file have data in a text section? If so, that can confuse + objtool's instruction decoder. Move the data to a more appropriate + section like .data or .rodata. + + +-5. asm_file.o: warning: objtool: func()+0x6: kernel entry/exit from callable instruction +- +- This is a kernel entry/exit instruction like sysenter or sysret. +- Such instructions aren't allowed in a callable function, and are most +- likely part of the kernel entry code. ++5. file.o: warning: objtool: func()+0x6: unsupported instruction in callable function + +- If the instruction isn't actually in a callable function, change +- ENDPROC to END. ++ This is a kernel entry/exit instruction like sysenter or iret. Such ++ instructions aren't allowed in a callable function, and are most ++ likely part of the kernel entry code. They should usually not have ++ the callable function annotation (ENDPROC) and should always be ++ annotated with the unwind hint macros in asm/unwind_hints.h. + + +-6. asm_file.o: warning: objtool: func()+0x26: sibling call from callable instruction with changed frame pointer ++6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame + +- This is a dynamic jump or a jump to an undefined symbol. Stacktool ++ This is a dynamic jump or a jump to an undefined symbol. Objtool + assumed it's a sibling call and detected that the frame pointer + wasn't first restored to its original state. + +@@ -282,24 +249,28 @@ they mean, and suggestions for how to fix them. + destination code to the local file. + + If the instruction is not actually in a callable function (e.g. +- kernel entry code), change ENDPROC to END. ++ kernel entry code), change ENDPROC to END and annotate manually with ++ the unwind hint macros in asm/unwind_hints.h. + + +-7. asm_file: warning: objtool: func()+0x5c: frame pointer state mismatch ++7. file: warning: objtool: func()+0x5c: stack state mismatch + + The instruction's frame pointer state is inconsistent, depending on + which execution path was taken to reach the instruction. + +- Make sure the function pushes and sets up the frame pointer (for +- x86_64, this means rbp) at the beginning of the function and pops it +- at the end of the function. Also make sure that no other code in the +- function touches the frame pointer. ++ Make sure that, when CONFIG_FRAME_POINTER is enabled, the function ++ pushes and sets up the frame pointer (for x86_64, this means rbp) at ++ the beginning of the function and pops it at the end of the function. ++ Also make sure that no other code in the function touches the frame ++ pointer. + ++ Another possibility is that the code has some asm or inline asm which ++ does some unusual things to the stack or the frame pointer. In such ++ cases it's probably appropriate to use the unwind hint macros in ++ asm/unwind_hints.h. + +-Errors in .c files +------------------- + +-1. c_file.o: warning: objtool: funcA() falls through to next function funcB() ++8. file.o: warning: objtool: funcA() falls through to next function funcB() + + This means that funcA() doesn't end with a return instruction or an + unconditional jump, and that objtool has determined that the function +@@ -318,22 +289,6 @@ Errors in .c files + might be corrupt due to a gcc bug. For more details, see: + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 + +-2. If you're getting any other objtool error in a compiled .c file, it +- may be because the file uses an asm() statement which has a "call" +- instruction. An asm() statement with a call instruction must declare +- the use of the stack pointer in its output operand. For example, on +- x86_64: +- +- register void *__sp asm("rsp"); +- asm volatile("call func" : "+r" (__sp)); +- +- Otherwise the stack frame may not get created before the call. +- +-3. Another possible cause for errors in C code is if the Makefile removes +- -fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. +- +-Also see the above section for .S file errors for more information what +-the individual error messages mean. + + If the error doesn't seem to make sense, it could be a bug in objtool. + Feel free to ask the objtool maintainer for help. +diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile +index 041b493ad3ab..e6acc281dd37 100644 +--- a/tools/objtool/Makefile ++++ b/tools/objtool/Makefile +@@ -1,3 +1,4 @@ ++# SPDX-License-Identifier: GPL-2.0 + include ../scripts/Makefile.include + include ../scripts/Makefile.arch + +@@ -6,17 +7,19 @@ ARCH := x86 + endif + + # always use the host compiler +-CC = gcc +-LD = ld +-AR = ar ++HOSTCC ?= gcc ++HOSTLD ?= ld ++CC = $(HOSTCC) ++LD = $(HOSTLD) ++AR = ar + + ifeq ($(srctree),) +-srctree := $(patsubst %/,%,$(dir $(shell pwd))) ++srctree := $(patsubst %/,%,$(dir $(CURDIR))) + srctree := $(patsubst %/,%,$(dir $(srctree))) + endif + + SUBCMD_SRCDIR = $(srctree)/tools/lib/subcmd/ +-LIBSUBCMD_OUTPUT = $(if $(OUTPUT),$(OUTPUT),$(PWD)/) ++LIBSUBCMD_OUTPUT = $(if $(OUTPUT),$(OUTPUT),$(CURDIR)/) + LIBSUBCMD = $(LIBSUBCMD_OUTPUT)libsubcmd.a + + OBJTOOL := $(OUTPUT)objtool +@@ -24,8 +27,11 @@ OBJTOOL_IN := $(OBJTOOL)-in.o + + all: $(OBJTOOL) + +-INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi +-CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) ++INCLUDES := -I$(srctree)/tools/include \ ++ -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ ++ -I$(srctree)/tools/objtool/arch/$(ARCH)/include ++WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed ++CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) + LDFLAGS += -lelf $(LIBSUBCMD) + + # Allow old libelf to be used: +@@ -39,19 +45,8 @@ include $(srctree)/tools/build/Makefile.include + $(OBJTOOL_IN): fixdep FORCE + @$(MAKE) $(build)=objtool + +-# Busybox's diff doesn't have -I, avoid warning in that case +-# + $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) +- @(diff -I 2>&1 | grep -q 'option requires an argument' && \ +- test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ +- diff -I'^#include' arch/x86/insn/insn.c ../../arch/x86/lib/insn.c >/dev/null && \ +- diff -I'^#include' arch/x86/insn/inat.c ../../arch/x86/lib/inat.c >/dev/null && \ +- diff arch/x86/insn/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null && \ +- diff arch/x86/insn/gen-insn-attr-x86.awk ../../arch/x86/tools/gen-insn-attr-x86.awk >/dev/null && \ +- diff -I'^#include' arch/x86/insn/insn.h ../../arch/x86/include/asm/insn.h >/dev/null && \ +- diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ +- diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ +- || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true ++ @$(CONFIG_SHELL) ./sync-check.sh + $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ + + +@@ -61,7 +56,7 @@ $(LIBSUBCMD): fixdep FORCE + clean: + $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) + $(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete +- $(Q)$(RM) $(OUTPUT)arch/x86/insn/inat-tables.c $(OUTPUT)fixdep ++ $(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep + + FORCE: + +diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h +index f7350fcedc70..b0d7dc3d71b5 100644 +--- a/tools/objtool/arch.h ++++ b/tools/objtool/arch.h +@@ -19,26 +19,64 @@ + #define _ARCH_H + + #include ++#include + #include "elf.h" ++#include "cfi.h" + +-#define INSN_FP_SAVE 1 +-#define INSN_FP_SETUP 2 +-#define INSN_FP_RESTORE 3 +-#define INSN_JUMP_CONDITIONAL 4 +-#define INSN_JUMP_UNCONDITIONAL 5 +-#define INSN_JUMP_DYNAMIC 6 +-#define INSN_CALL 7 +-#define INSN_CALL_DYNAMIC 8 +-#define INSN_RETURN 9 +-#define INSN_CONTEXT_SWITCH 10 +-#define INSN_BUG 11 +-#define INSN_NOP 12 +-#define INSN_OTHER 13 ++#define INSN_JUMP_CONDITIONAL 1 ++#define INSN_JUMP_UNCONDITIONAL 2 ++#define INSN_JUMP_DYNAMIC 3 ++#define INSN_CALL 4 ++#define INSN_CALL_DYNAMIC 5 ++#define INSN_RETURN 6 ++#define INSN_CONTEXT_SWITCH 7 ++#define INSN_STACK 8 ++#define INSN_BUG 9 ++#define INSN_NOP 10 ++#define INSN_OTHER 11 + #define INSN_LAST INSN_OTHER + ++enum op_dest_type { ++ OP_DEST_REG, ++ OP_DEST_REG_INDIRECT, ++ OP_DEST_MEM, ++ OP_DEST_PUSH, ++ OP_DEST_LEAVE, ++}; ++ ++struct op_dest { ++ enum op_dest_type type; ++ unsigned char reg; ++ int offset; ++}; ++ ++enum op_src_type { ++ OP_SRC_REG, ++ OP_SRC_REG_INDIRECT, ++ OP_SRC_CONST, ++ OP_SRC_POP, ++ OP_SRC_ADD, ++ OP_SRC_AND, ++}; ++ ++struct op_src { ++ enum op_src_type type; ++ unsigned char reg; ++ int offset; ++}; ++ ++struct stack_op { ++ struct op_dest dest; ++ struct op_src src; ++}; ++ ++void arch_initial_func_cfi_state(struct cfi_state *state); ++ + int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, + unsigned int *len, unsigned char *type, +- unsigned long *displacement); ++ unsigned long *immediate, struct stack_op *op); ++ ++bool arch_callee_saved_reg(unsigned char reg); + + #endif /* _ARCH_H */ +diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build +index debbdb0b5c43..b998412c017d 100644 +--- a/tools/objtool/arch/x86/Build ++++ b/tools/objtool/arch/x86/Build +@@ -1,12 +1,12 @@ + objtool-y += decode.o + +-inat_tables_script = arch/x86/insn/gen-insn-attr-x86.awk +-inat_tables_maps = arch/x86/insn/x86-opcode-map.txt ++inat_tables_script = arch/x86/tools/gen-insn-attr-x86.awk ++inat_tables_maps = arch/x86/lib/x86-opcode-map.txt + +-$(OUTPUT)arch/x86/insn/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) ++$(OUTPUT)arch/x86/lib/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) + $(call rule_mkdir) + $(Q)$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ + +-$(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/insn/inat-tables.c ++$(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/lib/inat-tables.c + +-CFLAGS_decode.o += -I$(OUTPUT)arch/x86/insn ++CFLAGS_decode.o += -I$(OUTPUT)arch/x86/lib +diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c +index 039636ffb6c8..540a209b78ab 100644 +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -19,14 +19,25 @@ + #include + + #define unlikely(cond) (cond) +-#include "insn/insn.h" +-#include "insn/inat.c" +-#include "insn/insn.c" ++#include ++#include "lib/inat.c" ++#include "lib/insn.c" + + #include "../../elf.h" + #include "../../arch.h" + #include "../../warn.h" + ++static unsigned char op_to_cfi_reg[][2] = { ++ {CFI_AX, CFI_R8}, ++ {CFI_CX, CFI_R9}, ++ {CFI_DX, CFI_R10}, ++ {CFI_BX, CFI_R11}, ++ {CFI_SP, CFI_R12}, ++ {CFI_BP, CFI_R13}, ++ {CFI_SI, CFI_R14}, ++ {CFI_DI, CFI_R15}, ++}; ++ + static int is_x86_64(struct elf *elf) + { + switch (elf->ehdr.e_machine) { +@@ -40,24 +51,50 @@ static int is_x86_64(struct elf *elf) + } + } + ++bool arch_callee_saved_reg(unsigned char reg) ++{ ++ switch (reg) { ++ case CFI_BP: ++ case CFI_BX: ++ case CFI_R12: ++ case CFI_R13: ++ case CFI_R14: ++ case CFI_R15: ++ return true; ++ ++ case CFI_AX: ++ case CFI_CX: ++ case CFI_DX: ++ case CFI_SI: ++ case CFI_DI: ++ case CFI_SP: ++ case CFI_R8: ++ case CFI_R9: ++ case CFI_R10: ++ case CFI_R11: ++ case CFI_RA: ++ default: ++ return false; ++ } ++} ++ + int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, + unsigned int *len, unsigned char *type, +- unsigned long *immediate) ++ unsigned long *immediate, struct stack_op *op) + { + struct insn insn; +- int x86_64; +- unsigned char op1, op2, ext; ++ int x86_64, sign; ++ unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, ++ rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, ++ modrm_reg = 0, sib = 0; + + x86_64 = is_x86_64(elf); + if (x86_64 == -1) + return -1; + +- insn_init(&insn, (void *)(sec->data + offset), maxlen, x86_64); ++ insn_init(&insn, sec->data->d_buf + offset, maxlen, x86_64); + insn_get_length(&insn); +- insn_get_opcode(&insn); +- insn_get_modrm(&insn); +- insn_get_immediate(&insn); + + if (!insn_complete(&insn)) { + WARN_FUNC("can't decode instruction", sec, offset); +@@ -73,70 +110,317 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, + op1 = insn.opcode.bytes[0]; + op2 = insn.opcode.bytes[1]; + ++ if (insn.rex_prefix.nbytes) { ++ rex = insn.rex_prefix.bytes[0]; ++ rex_w = X86_REX_W(rex) >> 3; ++ rex_r = X86_REX_R(rex) >> 2; ++ rex_x = X86_REX_X(rex) >> 1; ++ rex_b = X86_REX_B(rex); ++ } ++ ++ if (insn.modrm.nbytes) { ++ modrm = insn.modrm.bytes[0]; ++ modrm_mod = X86_MODRM_MOD(modrm); ++ modrm_reg = X86_MODRM_REG(modrm); ++ modrm_rm = X86_MODRM_RM(modrm); ++ } ++ ++ if (insn.sib.nbytes) ++ sib = insn.sib.bytes[0]; ++ + switch (op1) { +- case 0x55: +- if (!insn.rex_prefix.nbytes) +- /* push rbp */ +- *type = INSN_FP_SAVE; ++ ++ case 0x1: ++ case 0x29: ++ if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { ++ ++ /* add/sub reg, %rsp */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ } ++ break; ++ ++ case 0x50 ... 0x57: ++ ++ /* push reg */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_REG; ++ op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; ++ op->dest.type = OP_DEST_PUSH; ++ ++ break; ++ ++ case 0x58 ... 0x5f: ++ ++ /* pop reg */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_POP; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; ++ + break; + +- case 0x5d: +- if (!insn.rex_prefix.nbytes) +- /* pop rbp */ +- *type = INSN_FP_RESTORE; ++ case 0x68: ++ case 0x6a: ++ /* push immediate */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_CONST; ++ op->dest.type = OP_DEST_PUSH; + break; + + case 0x70 ... 0x7f: + *type = INSN_JUMP_CONDITIONAL; + break; + ++ case 0x81: ++ case 0x83: ++ if (rex != 0x48) ++ break; ++ ++ if (modrm == 0xe4) { ++ /* and imm, %rsp */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_AND; ++ op->src.reg = CFI_SP; ++ op->src.offset = insn.immediate.value; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ break; ++ } ++ ++ if (modrm == 0xc4) ++ sign = 1; ++ else if (modrm == 0xec) ++ sign = -1; ++ else ++ break; ++ ++ /* add/sub imm, %rsp */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = CFI_SP; ++ op->src.offset = insn.immediate.value * sign; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ break; ++ + case 0x89: +- if (insn.rex_prefix.nbytes == 1 && +- insn.rex_prefix.bytes[0] == 0x48 && +- insn.modrm.nbytes && insn.modrm.bytes[0] == 0xe5) +- /* mov rsp, rbp */ +- *type = INSN_FP_SETUP; ++ if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) { ++ ++ /* mov %rsp, reg */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_REG; ++ op->src.reg = CFI_SP; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; ++ break; ++ } ++ ++ if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { ++ ++ /* mov reg, %rsp */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_REG; ++ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ break; ++ } ++ ++ /* fallthrough */ ++ case 0x88: ++ if (!rex_b && ++ (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) { ++ ++ /* mov reg, disp(%rbp) */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_REG; ++ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ op->dest.type = OP_DEST_REG_INDIRECT; ++ op->dest.reg = CFI_BP; ++ op->dest.offset = insn.displacement.value; ++ ++ } else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) { ++ ++ /* mov reg, disp(%rsp) */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_REG; ++ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ op->dest.type = OP_DEST_REG_INDIRECT; ++ op->dest.reg = CFI_SP; ++ op->dest.offset = insn.displacement.value; ++ } ++ ++ break; ++ ++ case 0x8b: ++ if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) { ++ ++ /* mov disp(%rbp), reg */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_REG_INDIRECT; ++ op->src.reg = CFI_BP; ++ op->src.offset = insn.displacement.value; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ ++ } else if (rex_w && !rex_b && sib == 0x24 && ++ modrm_mod != 3 && modrm_rm == 4) { ++ ++ /* mov disp(%rsp), reg */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_REG_INDIRECT; ++ op->src.reg = CFI_SP; ++ op->src.offset = insn.displacement.value; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ } ++ + break; + + case 0x8d: +- if (insn.rex_prefix.nbytes && +- insn.rex_prefix.bytes[0] == 0x48 && +- insn.modrm.nbytes && insn.modrm.bytes[0] == 0x2c && +- insn.sib.nbytes && insn.sib.bytes[0] == 0x24) +- /* lea %(rsp), %rbp */ +- *type = INSN_FP_SETUP; ++ if (sib == 0x24 && rex_w && !rex_b && !rex_x) { ++ ++ *type = INSN_STACK; ++ if (!insn.displacement.value) { ++ /* lea (%rsp), reg */ ++ op->src.type = OP_SRC_REG; ++ } else { ++ /* lea disp(%rsp), reg */ ++ op->src.type = OP_SRC_ADD; ++ op->src.offset = insn.displacement.value; ++ } ++ op->src.reg = CFI_SP; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ ++ } else if (rex == 0x48 && modrm == 0x65) { ++ ++ /* lea disp(%rbp), %rsp */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = CFI_BP; ++ op->src.offset = insn.displacement.value; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ ++ } else if (rex == 0x49 && modrm == 0x62 && ++ insn.displacement.value == -8) { ++ ++ /* ++ * lea -0x8(%r10), %rsp ++ * ++ * Restoring rsp back to its original value after a ++ * stack realignment. ++ */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = CFI_R10; ++ op->src.offset = -8; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ ++ } else if (rex == 0x49 && modrm == 0x65 && ++ insn.displacement.value == -16) { ++ ++ /* ++ * lea -0x10(%r13), %rsp ++ * ++ * Restoring rsp back to its original value after a ++ * stack realignment. ++ */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = CFI_R13; ++ op->src.offset = -16; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ } ++ ++ break; ++ ++ case 0x8f: ++ /* pop to mem */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_POP; ++ op->dest.type = OP_DEST_MEM; + break; + + case 0x90: + *type = INSN_NOP; + break; + ++ case 0x9c: ++ /* pushf */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_CONST; ++ op->dest.type = OP_DEST_PUSH; ++ break; ++ ++ case 0x9d: ++ /* popf */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_POP; ++ op->dest.type = OP_DEST_MEM; ++ break; ++ + case 0x0f: +- if (op2 >= 0x80 && op2 <= 0x8f) ++ ++ if (op2 >= 0x80 && op2 <= 0x8f) { ++ + *type = INSN_JUMP_CONDITIONAL; +- else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || +- op2 == 0x35) ++ ++ } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || ++ op2 == 0x35) { ++ + /* sysenter, sysret */ + *type = INSN_CONTEXT_SWITCH; +- else if (op2 == 0x0b || op2 == 0xb9) ++ ++ } else if (op2 == 0x0b || op2 == 0xb9) { ++ + /* ud2 */ + *type = INSN_BUG; +- else if (op2 == 0x0d || op2 == 0x1f) ++ ++ } else if (op2 == 0x0d || op2 == 0x1f) { ++ + /* nopl/nopw */ + *type = INSN_NOP; +- else if (op2 == 0x01 && insn.modrm.nbytes && +- (insn.modrm.bytes[0] == 0xc2 || +- insn.modrm.bytes[0] == 0xd8)) +- /* vmlaunch, vmrun */ +- *type = INSN_CONTEXT_SWITCH; ++ ++ } else if (op2 == 0xa0 || op2 == 0xa8) { ++ ++ /* push fs/gs */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_CONST; ++ op->dest.type = OP_DEST_PUSH; ++ ++ } else if (op2 == 0xa1 || op2 == 0xa9) { ++ ++ /* pop fs/gs */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_POP; ++ op->dest.type = OP_DEST_MEM; ++ } + + break; + +- case 0xc9: /* leave */ +- *type = INSN_FP_RESTORE; ++ case 0xc9: ++ /* ++ * leave ++ * ++ * equivalent to: ++ * mov bp, sp ++ * pop bp ++ */ ++ *type = INSN_STACK; ++ op->dest.type = OP_DEST_LEAVE; ++ + break; + +- case 0xe3: /* jecxz/jrcxz */ ++ case 0xe3: ++ /* jecxz/jrcxz */ + *type = INSN_JUMP_CONDITIONAL; + break; + +@@ -161,14 +445,27 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, + break; + + case 0xff: +- ext = X86_MODRM_REG(insn.modrm.bytes[0]); +- if (ext == 2 || ext == 3) ++ if (modrm_reg == 2 || modrm_reg == 3) ++ + *type = INSN_CALL_DYNAMIC; +- else if (ext == 4) ++ ++ else if (modrm_reg == 4) ++ + *type = INSN_JUMP_DYNAMIC; +- else if (ext == 5) /*jmpf */ ++ ++ else if (modrm_reg == 5) ++ ++ /* jmpf */ + *type = INSN_CONTEXT_SWITCH; + ++ else if (modrm_reg == 6) { ++ ++ /* push from mem */ ++ *type = INSN_STACK; ++ op->src.type = OP_SRC_CONST; ++ op->dest.type = OP_DEST_PUSH; ++ } ++ + break; + + default: +@@ -179,3 +476,21 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, + + return 0; + } ++ ++void arch_initial_func_cfi_state(struct cfi_state *state) ++{ ++ int i; ++ ++ for (i = 0; i < CFI_NUM_REGS; i++) { ++ state->regs[i].base = CFI_UNDEFINED; ++ state->regs[i].offset = 0; ++ } ++ ++ /* initial CFA (call frame address) */ ++ state->cfa.base = CFI_SP; ++ state->cfa.offset = 8; ++ ++ /* initial RA (return address) */ ++ state->regs[16].base = CFI_CFA; ++ state->regs[16].offset = -8; ++} +diff --git a/tools/objtool/arch/x86/include/asm/inat.h b/tools/objtool/arch/x86/include/asm/inat.h +new file mode 100644 +index 000000000000..02aff0867211 +--- /dev/null ++++ b/tools/objtool/arch/x86/include/asm/inat.h +@@ -0,0 +1,234 @@ ++#ifndef _ASM_X86_INAT_H ++#define _ASM_X86_INAT_H ++/* ++ * x86 instruction attributes ++ * ++ * Written by Masami Hiramatsu ++ * ++ * 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. ++ * ++ */ ++#include ++ ++/* ++ * Internal bits. Don't use bitmasks directly, because these bits are ++ * unstable. You should use checking functions. ++ */ ++ ++#define INAT_OPCODE_TABLE_SIZE 256 ++#define INAT_GROUP_TABLE_SIZE 8 ++ ++/* Legacy last prefixes */ ++#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ ++#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ ++#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ ++/* Other Legacy prefixes */ ++#define INAT_PFX_LOCK 4 /* 0xF0 */ ++#define INAT_PFX_CS 5 /* 0x2E */ ++#define INAT_PFX_DS 6 /* 0x3E */ ++#define INAT_PFX_ES 7 /* 0x26 */ ++#define INAT_PFX_FS 8 /* 0x64 */ ++#define INAT_PFX_GS 9 /* 0x65 */ ++#define INAT_PFX_SS 10 /* 0x36 */ ++#define INAT_PFX_ADDRSZ 11 /* 0x67 */ ++/* x86-64 REX prefix */ ++#define INAT_PFX_REX 12 /* 0x4X */ ++/* AVX VEX prefixes */ ++#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ ++#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ ++#define INAT_PFX_EVEX 15 /* EVEX prefix */ ++ ++#define INAT_LSTPFX_MAX 3 ++#define INAT_LGCPFX_MAX 11 ++ ++/* Immediate size */ ++#define INAT_IMM_BYTE 1 ++#define INAT_IMM_WORD 2 ++#define INAT_IMM_DWORD 3 ++#define INAT_IMM_QWORD 4 ++#define INAT_IMM_PTR 5 ++#define INAT_IMM_VWORD32 6 ++#define INAT_IMM_VWORD 7 ++ ++/* Legacy prefix */ ++#define INAT_PFX_OFFS 0 ++#define INAT_PFX_BITS 4 ++#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) ++#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) ++/* Escape opcodes */ ++#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) ++#define INAT_ESC_BITS 2 ++#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) ++#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) ++/* Group opcodes (1-16) */ ++#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) ++#define INAT_GRP_BITS 5 ++#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) ++#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) ++/* Immediates */ ++#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) ++#define INAT_IMM_BITS 3 ++#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) ++/* Flags */ ++#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) ++#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) ++#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) ++#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) ++#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) ++#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) ++#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) ++#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) ++#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) ++/* Attribute making macros for attribute tables */ ++#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) ++#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) ++#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) ++#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) ++ ++/* Attribute search APIs */ ++extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); ++extern int inat_get_last_prefix_id(insn_byte_t last_pfx); ++extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, ++ int lpfx_id, ++ insn_attr_t esc_attr); ++extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, ++ int lpfx_id, ++ insn_attr_t esc_attr); ++extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, ++ insn_byte_t vex_m, ++ insn_byte_t vex_pp); ++ ++/* Attribute checking functions */ ++static inline int inat_is_legacy_prefix(insn_attr_t attr) ++{ ++ attr &= INAT_PFX_MASK; ++ return attr && attr <= INAT_LGCPFX_MAX; ++} ++ ++static inline int inat_is_address_size_prefix(insn_attr_t attr) ++{ ++ return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; ++} ++ ++static inline int inat_is_operand_size_prefix(insn_attr_t attr) ++{ ++ return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; ++} ++ ++static inline int inat_is_rex_prefix(insn_attr_t attr) ++{ ++ return (attr & INAT_PFX_MASK) == INAT_PFX_REX; ++} ++ ++static inline int inat_last_prefix_id(insn_attr_t attr) ++{ ++ if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) ++ return 0; ++ else ++ return attr & INAT_PFX_MASK; ++} ++ ++static inline int inat_is_vex_prefix(insn_attr_t attr) ++{ ++ attr &= INAT_PFX_MASK; ++ return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || ++ attr == INAT_PFX_EVEX; ++} ++ ++static inline int inat_is_evex_prefix(insn_attr_t attr) ++{ ++ return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; ++} ++ ++static inline int inat_is_vex3_prefix(insn_attr_t attr) ++{ ++ return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; ++} ++ ++static inline int inat_is_escape(insn_attr_t attr) ++{ ++ return attr & INAT_ESC_MASK; ++} ++ ++static inline int inat_escape_id(insn_attr_t attr) ++{ ++ return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; ++} ++ ++static inline int inat_is_group(insn_attr_t attr) ++{ ++ return attr & INAT_GRP_MASK; ++} ++ ++static inline int inat_group_id(insn_attr_t attr) ++{ ++ return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; ++} ++ ++static inline int inat_group_common_attribute(insn_attr_t attr) ++{ ++ return attr & ~INAT_GRP_MASK; ++} ++ ++static inline int inat_has_immediate(insn_attr_t attr) ++{ ++ return attr & INAT_IMM_MASK; ++} ++ ++static inline int inat_immediate_size(insn_attr_t attr) ++{ ++ return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; ++} ++ ++static inline int inat_has_modrm(insn_attr_t attr) ++{ ++ return attr & INAT_MODRM; ++} ++ ++static inline int inat_is_force64(insn_attr_t attr) ++{ ++ return attr & INAT_FORCE64; ++} ++ ++static inline int inat_has_second_immediate(insn_attr_t attr) ++{ ++ return attr & INAT_SCNDIMM; ++} ++ ++static inline int inat_has_moffset(insn_attr_t attr) ++{ ++ return attr & INAT_MOFFSET; ++} ++ ++static inline int inat_has_variant(insn_attr_t attr) ++{ ++ return attr & INAT_VARIANT; ++} ++ ++static inline int inat_accept_vex(insn_attr_t attr) ++{ ++ return attr & INAT_VEXOK; ++} ++ ++static inline int inat_must_vex(insn_attr_t attr) ++{ ++ return attr & (INAT_VEXONLY | INAT_EVEXONLY); ++} ++ ++static inline int inat_must_evex(insn_attr_t attr) ++{ ++ return attr & INAT_EVEXONLY; ++} ++#endif +diff --git a/tools/objtool/arch/x86/include/asm/inat_types.h b/tools/objtool/arch/x86/include/asm/inat_types.h +new file mode 100644 +index 000000000000..cb3c20ce39cf +--- /dev/null ++++ b/tools/objtool/arch/x86/include/asm/inat_types.h +@@ -0,0 +1,29 @@ ++#ifndef _ASM_X86_INAT_TYPES_H ++#define _ASM_X86_INAT_TYPES_H ++/* ++ * x86 instruction attributes ++ * ++ * Written by Masami Hiramatsu ++ * ++ * 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. ++ * ++ */ ++ ++/* Instruction attributes */ ++typedef unsigned int insn_attr_t; ++typedef unsigned char insn_byte_t; ++typedef signed int insn_value_t; ++ ++#endif +diff --git a/tools/objtool/arch/x86/include/asm/insn.h b/tools/objtool/arch/x86/include/asm/insn.h +new file mode 100644 +index 000000000000..b3e32b010ab1 +--- /dev/null ++++ b/tools/objtool/arch/x86/include/asm/insn.h +@@ -0,0 +1,211 @@ ++#ifndef _ASM_X86_INSN_H ++#define _ASM_X86_INSN_H ++/* ++ * x86 instruction analysis ++ * ++ * 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. ++ * ++ * Copyright (C) IBM Corporation, 2009 ++ */ ++ ++/* insn_attr_t is defined in inat.h */ ++#include ++ ++struct insn_field { ++ union { ++ insn_value_t value; ++ insn_byte_t bytes[4]; ++ }; ++ /* !0 if we've run insn_get_xxx() for this field */ ++ unsigned char got; ++ unsigned char nbytes; ++}; ++ ++struct insn { ++ struct insn_field prefixes; /* ++ * Prefixes ++ * prefixes.bytes[3]: last prefix ++ */ ++ struct insn_field rex_prefix; /* REX prefix */ ++ struct insn_field vex_prefix; /* VEX prefix */ ++ struct insn_field opcode; /* ++ * opcode.bytes[0]: opcode1 ++ * opcode.bytes[1]: opcode2 ++ * opcode.bytes[2]: opcode3 ++ */ ++ struct insn_field modrm; ++ struct insn_field sib; ++ struct insn_field displacement; ++ union { ++ struct insn_field immediate; ++ struct insn_field moffset1; /* for 64bit MOV */ ++ struct insn_field immediate1; /* for 64bit imm or off16/32 */ ++ }; ++ union { ++ struct insn_field moffset2; /* for 64bit MOV */ ++ struct insn_field immediate2; /* for 64bit imm or seg16 */ ++ }; ++ ++ insn_attr_t attr; ++ unsigned char opnd_bytes; ++ unsigned char addr_bytes; ++ unsigned char length; ++ unsigned char x86_64; ++ ++ const insn_byte_t *kaddr; /* kernel address of insn to analyze */ ++ const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ ++ const insn_byte_t *next_byte; ++}; ++ ++#define MAX_INSN_SIZE 15 ++ ++#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) ++#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) ++#define X86_MODRM_RM(modrm) ((modrm) & 0x07) ++ ++#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) ++#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) ++#define X86_SIB_BASE(sib) ((sib) & 0x07) ++ ++#define X86_REX_W(rex) ((rex) & 8) ++#define X86_REX_R(rex) ((rex) & 4) ++#define X86_REX_X(rex) ((rex) & 2) ++#define X86_REX_B(rex) ((rex) & 1) ++ ++/* VEX bit flags */ ++#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ ++#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ ++#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ ++#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ ++#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ ++/* VEX bit fields */ ++#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ ++#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ ++#define X86_VEX2_M 1 /* VEX2.M always 1 */ ++#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ ++#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ ++#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ ++ ++extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); ++extern void insn_get_prefixes(struct insn *insn); ++extern void insn_get_opcode(struct insn *insn); ++extern void insn_get_modrm(struct insn *insn); ++extern void insn_get_sib(struct insn *insn); ++extern void insn_get_displacement(struct insn *insn); ++extern void insn_get_immediate(struct insn *insn); ++extern void insn_get_length(struct insn *insn); ++ ++/* Attribute will be determined after getting ModRM (for opcode groups) */ ++static inline void insn_get_attribute(struct insn *insn) ++{ ++ insn_get_modrm(insn); ++} ++ ++/* Instruction uses RIP-relative addressing */ ++extern int insn_rip_relative(struct insn *insn); ++ ++/* Init insn for kernel text */ ++static inline void kernel_insn_init(struct insn *insn, ++ const void *kaddr, int buf_len) ++{ ++#ifdef CONFIG_X86_64 ++ insn_init(insn, kaddr, buf_len, 1); ++#else /* CONFIG_X86_32 */ ++ insn_init(insn, kaddr, buf_len, 0); ++#endif ++} ++ ++static inline int insn_is_avx(struct insn *insn) ++{ ++ if (!insn->prefixes.got) ++ insn_get_prefixes(insn); ++ return (insn->vex_prefix.value != 0); ++} ++ ++static inline int insn_is_evex(struct insn *insn) ++{ ++ if (!insn->prefixes.got) ++ insn_get_prefixes(insn); ++ return (insn->vex_prefix.nbytes == 4); ++} ++ ++/* Ensure this instruction is decoded completely */ ++static inline int insn_complete(struct insn *insn) ++{ ++ return insn->opcode.got && insn->modrm.got && insn->sib.got && ++ insn->displacement.got && insn->immediate.got; ++} ++ ++static inline insn_byte_t insn_vex_m_bits(struct insn *insn) ++{ ++ if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ ++ return X86_VEX2_M; ++ else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ ++ return X86_VEX3_M(insn->vex_prefix.bytes[1]); ++ else /* EVEX */ ++ return X86_EVEX_M(insn->vex_prefix.bytes[1]); ++} ++ ++static inline insn_byte_t insn_vex_p_bits(struct insn *insn) ++{ ++ if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ ++ return X86_VEX_P(insn->vex_prefix.bytes[1]); ++ else ++ return X86_VEX_P(insn->vex_prefix.bytes[2]); ++} ++ ++/* Get the last prefix id from last prefix or VEX prefix */ ++static inline int insn_last_prefix_id(struct insn *insn) ++{ ++ if (insn_is_avx(insn)) ++ return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ ++ ++ if (insn->prefixes.bytes[3]) ++ return inat_get_last_prefix_id(insn->prefixes.bytes[3]); ++ ++ return 0; ++} ++ ++/* Offset of each field from kaddr */ ++static inline int insn_offset_rex_prefix(struct insn *insn) ++{ ++ return insn->prefixes.nbytes; ++} ++static inline int insn_offset_vex_prefix(struct insn *insn) ++{ ++ return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; ++} ++static inline int insn_offset_opcode(struct insn *insn) ++{ ++ return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; ++} ++static inline int insn_offset_modrm(struct insn *insn) ++{ ++ return insn_offset_opcode(insn) + insn->opcode.nbytes; ++} ++static inline int insn_offset_sib(struct insn *insn) ++{ ++ return insn_offset_modrm(insn) + insn->modrm.nbytes; ++} ++static inline int insn_offset_displacement(struct insn *insn) ++{ ++ return insn_offset_sib(insn) + insn->sib.nbytes; ++} ++static inline int insn_offset_immediate(struct insn *insn) ++{ ++ return insn_offset_displacement(insn) + insn->displacement.nbytes; ++} ++ ++#endif /* _ASM_X86_INSN_H */ +diff --git a/tools/objtool/arch/x86/include/asm/orc_types.h b/tools/objtool/arch/x86/include/asm/orc_types.h +new file mode 100644 +index 000000000000..7dc777a6cb40 +--- /dev/null ++++ b/tools/objtool/arch/x86/include/asm/orc_types.h +@@ -0,0 +1,107 @@ ++/* ++ * Copyright (C) 2017 Josh Poimboeuf ++ * ++ * 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, see . ++ */ ++ ++#ifndef _ORC_TYPES_H ++#define _ORC_TYPES_H ++ ++#include ++#include ++ ++/* ++ * The ORC_REG_* registers are base registers which are used to find other ++ * registers on the stack. ++ * ++ * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the ++ * address of the previous frame: the caller's SP before it called the current ++ * function. ++ * ++ * ORC_REG_UNDEFINED means the corresponding register's value didn't change in ++ * the current frame. ++ * ++ * The most commonly used base registers are SP and BP -- which the previous SP ++ * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is ++ * usually based on. ++ * ++ * The rest of the base registers are needed for special cases like entry code ++ * and GCC realigned stacks. ++ */ ++#define ORC_REG_UNDEFINED 0 ++#define ORC_REG_PREV_SP 1 ++#define ORC_REG_DX 2 ++#define ORC_REG_DI 3 ++#define ORC_REG_BP 4 ++#define ORC_REG_SP 5 ++#define ORC_REG_R10 6 ++#define ORC_REG_R13 7 ++#define ORC_REG_BP_INDIRECT 8 ++#define ORC_REG_SP_INDIRECT 9 ++#define ORC_REG_MAX 15 ++ ++/* ++ * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the ++ * caller's SP right before it made the call). Used for all callable ++ * functions, i.e. all C code and all callable asm functions. ++ * ++ * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points ++ * to a fully populated pt_regs from a syscall, interrupt, or exception. ++ * ++ * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset ++ * points to the iret return frame. ++ * ++ * The UNWIND_HINT macros are used only for the unwind_hint struct. They ++ * aren't used in struct orc_entry due to size and complexity constraints. ++ * Objtool converts them to real types when it converts the hints to orc ++ * entries. ++ */ ++#define ORC_TYPE_CALL 0 ++#define ORC_TYPE_REGS 1 ++#define ORC_TYPE_REGS_IRET 2 ++#define UNWIND_HINT_TYPE_SAVE 3 ++#define UNWIND_HINT_TYPE_RESTORE 4 ++ ++#ifndef __ASSEMBLY__ ++/* ++ * This struct is more or less a vastly simplified version of the DWARF Call ++ * Frame Information standard. It contains only the necessary parts of DWARF ++ * CFI, simplified for ease of access by the in-kernel unwinder. It tells the ++ * unwinder how to find the previous SP and BP (and sometimes entry regs) on ++ * the stack for a given code address. Each instance of the struct corresponds ++ * to one or more code locations. ++ */ ++struct orc_entry { ++ s16 sp_offset; ++ s16 bp_offset; ++ unsigned sp_reg:4; ++ unsigned bp_reg:4; ++ unsigned type:2; ++}; ++ ++/* ++ * This struct is used by asm and inline asm code to manually annotate the ++ * location of registers on the stack for the ORC unwinder. ++ * ++ * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. ++ */ ++struct unwind_hint { ++ u32 ip; ++ s16 sp_offset; ++ u8 sp_reg; ++ u8 type; ++}; ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* _ORC_TYPES_H */ +diff --git a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk b/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk +deleted file mode 100644 +index a3d2c62fd805..000000000000 +--- a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk ++++ /dev/null +@@ -1,392 +0,0 @@ +-#!/bin/awk -f +-# gen-insn-attr-x86.awk: Instruction attribute table generator +-# Written by Masami Hiramatsu +-# +-# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c +- +-# Awk implementation sanity check +-function check_awk_implement() { +- if (sprintf("%x", 0) != "0") +- return "Your awk has a printf-format problem." +- return "" +-} +- +-# Clear working vars +-function clear_vars() { +- delete table +- delete lptable2 +- delete lptable1 +- delete lptable3 +- eid = -1 # escape id +- gid = -1 # group id +- aid = -1 # AVX id +- tname = "" +-} +- +-BEGIN { +- # Implementation error checking +- awkchecked = check_awk_implement() +- if (awkchecked != "") { +- print "Error: " awkchecked > "/dev/stderr" +- print "Please try to use gawk." > "/dev/stderr" +- exit 1 +- } +- +- # Setup generating tables +- print "/* x86 opcode map generated from x86-opcode-map.txt */" +- print "/* Do not change this code. */\n" +- ggid = 1 +- geid = 1 +- gaid = 0 +- delete etable +- delete gtable +- delete atable +- +- opnd_expr = "^[A-Za-z/]" +- ext_expr = "^\\(" +- sep_expr = "^\\|$" +- group_expr = "^Grp[0-9A-Za-z]+" +- +- imm_expr = "^[IJAOL][a-z]" +- imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" +- imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" +- imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" +- imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" +- imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" +- imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" +- imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" +- imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" +- imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" +- imm_flag["Ob"] = "INAT_MOFFSET" +- imm_flag["Ov"] = "INAT_MOFFSET" +- imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" +- +- modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" +- force64_expr = "\\([df]64\\)" +- rex_expr = "^REX(\\.[XRWB]+)*" +- fpu_expr = "^ESC" # TODO +- +- lprefix1_expr = "\\((66|!F3)\\)" +- lprefix2_expr = "\\(F3\\)" +- lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)" +- lprefix_expr = "\\((66|F2|F3)\\)" +- max_lprefix = 4 +- +- # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript +- # accepts VEX prefix +- vexok_opcode_expr = "^[vk].*" +- vexok_expr = "\\(v1\\)" +- # All opcodes with (v) superscript supports *only* VEX prefix +- vexonly_expr = "\\(v\\)" +- # All opcodes with (ev) superscript supports *only* EVEX prefix +- evexonly_expr = "\\(ev\\)" +- +- prefix_expr = "\\(Prefix\\)" +- prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" +- prefix_num["REPNE"] = "INAT_PFX_REPNE" +- prefix_num["REP/REPE"] = "INAT_PFX_REPE" +- prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" +- prefix_num["XRELEASE"] = "INAT_PFX_REPE" +- prefix_num["LOCK"] = "INAT_PFX_LOCK" +- prefix_num["SEG=CS"] = "INAT_PFX_CS" +- prefix_num["SEG=DS"] = "INAT_PFX_DS" +- prefix_num["SEG=ES"] = "INAT_PFX_ES" +- prefix_num["SEG=FS"] = "INAT_PFX_FS" +- prefix_num["SEG=GS"] = "INAT_PFX_GS" +- prefix_num["SEG=SS"] = "INAT_PFX_SS" +- prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" +- prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" +- prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" +- prefix_num["EVEX"] = "INAT_PFX_EVEX" +- +- clear_vars() +-} +- +-function semantic_error(msg) { +- print "Semantic error at " NR ": " msg > "/dev/stderr" +- exit 1 +-} +- +-function debug(msg) { +- print "DEBUG: " msg +-} +- +-function array_size(arr, i,c) { +- c = 0 +- for (i in arr) +- c++ +- return c +-} +- +-/^Table:/ { +- print "/* " $0 " */" +- if (tname != "") +- semantic_error("Hit Table: before EndTable:."); +-} +- +-/^Referrer:/ { +- if (NF != 1) { +- # escape opcode table +- ref = "" +- for (i = 2; i <= NF; i++) +- ref = ref $i +- eid = escape[ref] +- tname = sprintf("inat_escape_table_%d", eid) +- } +-} +- +-/^AVXcode:/ { +- if (NF != 1) { +- # AVX/escape opcode table +- aid = $2 +- if (gaid <= aid) +- gaid = aid + 1 +- if (tname == "") # AVX only opcode table +- tname = sprintf("inat_avx_table_%d", $2) +- } +- if (aid == -1 && eid == -1) # primary opcode table +- tname = "inat_primary_table" +-} +- +-/^GrpTable:/ { +- print "/* " $0 " */" +- if (!($2 in group)) +- semantic_error("No group: " $2 ) +- gid = group[$2] +- tname = "inat_group_table_" gid +-} +- +-function print_table(tbl,name,fmt,n) +-{ +- print "const insn_attr_t " name " = {" +- for (i = 0; i < n; i++) { +- id = sprintf(fmt, i) +- if (tbl[id]) +- print " [" id "] = " tbl[id] "," +- } +- print "};" +-} +- +-/^EndTable/ { +- if (gid != -1) { +- # print group tables +- if (array_size(table) != 0) { +- print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", +- "0x%x", 8) +- gtable[gid,0] = tname +- } +- if (array_size(lptable1) != 0) { +- print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", +- "0x%x", 8) +- gtable[gid,1] = tname "_1" +- } +- if (array_size(lptable2) != 0) { +- print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", +- "0x%x", 8) +- gtable[gid,2] = tname "_2" +- } +- if (array_size(lptable3) != 0) { +- print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", +- "0x%x", 8) +- gtable[gid,3] = tname "_3" +- } +- } else { +- # print primary/escaped tables +- if (array_size(table) != 0) { +- print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", +- "0x%02x", 256) +- etable[eid,0] = tname +- if (aid >= 0) +- atable[aid,0] = tname +- } +- if (array_size(lptable1) != 0) { +- print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", +- "0x%02x", 256) +- etable[eid,1] = tname "_1" +- if (aid >= 0) +- atable[aid,1] = tname "_1" +- } +- if (array_size(lptable2) != 0) { +- print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", +- "0x%02x", 256) +- etable[eid,2] = tname "_2" +- if (aid >= 0) +- atable[aid,2] = tname "_2" +- } +- if (array_size(lptable3) != 0) { +- print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", +- "0x%02x", 256) +- etable[eid,3] = tname "_3" +- if (aid >= 0) +- atable[aid,3] = tname "_3" +- } +- } +- print "" +- clear_vars() +-} +- +-function add_flags(old,new) { +- if (old && new) +- return old " | " new +- else if (old) +- return old +- else +- return new +-} +- +-# convert operands to flags. +-function convert_operands(count,opnd, i,j,imm,mod) +-{ +- imm = null +- mod = null +- for (j = 1; j <= count; j++) { +- i = opnd[j] +- if (match(i, imm_expr) == 1) { +- if (!imm_flag[i]) +- semantic_error("Unknown imm opnd: " i) +- if (imm) { +- if (i != "Ib") +- semantic_error("Second IMM error") +- imm = add_flags(imm, "INAT_SCNDIMM") +- } else +- imm = imm_flag[i] +- } else if (match(i, modrm_expr)) +- mod = "INAT_MODRM" +- } +- return add_flags(imm, mod) +-} +- +-/^[0-9a-f]+\:/ { +- if (NR == 1) +- next +- # get index +- idx = "0x" substr($1, 1, index($1,":") - 1) +- if (idx in table) +- semantic_error("Redefine " idx " in " tname) +- +- # check if escaped opcode +- if ("escape" == $2) { +- if ($3 != "#") +- semantic_error("No escaped name") +- ref = "" +- for (i = 4; i <= NF; i++) +- ref = ref $i +- if (ref in escape) +- semantic_error("Redefine escape (" ref ")") +- escape[ref] = geid +- geid++ +- table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" +- next +- } +- +- variant = null +- # converts +- i = 2 +- while (i <= NF) { +- opcode = $(i++) +- delete opnds +- ext = null +- flags = null +- opnd = null +- # parse one opcode +- if (match($i, opnd_expr)) { +- opnd = $i +- count = split($(i++), opnds, ",") +- flags = convert_operands(count, opnds) +- } +- if (match($i, ext_expr)) +- ext = $(i++) +- if (match($i, sep_expr)) +- i++ +- else if (i < NF) +- semantic_error($i " is not a separator") +- +- # check if group opcode +- if (match(opcode, group_expr)) { +- if (!(opcode in group)) { +- group[opcode] = ggid +- ggid++ +- } +- flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") +- } +- # check force(or default) 64bit +- if (match(ext, force64_expr)) +- flags = add_flags(flags, "INAT_FORCE64") +- +- # check REX prefix +- if (match(opcode, rex_expr)) +- flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") +- +- # check coprocessor escape : TODO +- if (match(opcode, fpu_expr)) +- flags = add_flags(flags, "INAT_MODRM") +- +- # check VEX codes +- if (match(ext, evexonly_expr)) +- flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") +- else if (match(ext, vexonly_expr)) +- flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") +- else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) +- flags = add_flags(flags, "INAT_VEXOK") +- +- # check prefixes +- if (match(ext, prefix_expr)) { +- if (!prefix_num[opcode]) +- semantic_error("Unknown prefix: " opcode) +- flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") +- } +- if (length(flags) == 0) +- continue +- # check if last prefix +- if (match(ext, lprefix1_expr)) { +- lptable1[idx] = add_flags(lptable1[idx],flags) +- variant = "INAT_VARIANT" +- } +- if (match(ext, lprefix2_expr)) { +- lptable2[idx] = add_flags(lptable2[idx],flags) +- variant = "INAT_VARIANT" +- } +- if (match(ext, lprefix3_expr)) { +- lptable3[idx] = add_flags(lptable3[idx],flags) +- variant = "INAT_VARIANT" +- } +- if (!match(ext, lprefix_expr)){ +- table[idx] = add_flags(table[idx],flags) +- } +- } +- if (variant) +- table[idx] = add_flags(table[idx],variant) +-} +- +-END { +- if (awkchecked != "") +- exit 1 +- # print escape opcode map's array +- print "/* Escape opcode map array */" +- print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ +- "[INAT_LSTPFX_MAX + 1] = {" +- for (i = 0; i < geid; i++) +- for (j = 0; j < max_lprefix; j++) +- if (etable[i,j]) +- print " ["i"]["j"] = "etable[i,j]"," +- print "};\n" +- # print group opcode map's array +- print "/* Group opcode map array */" +- print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ +- "[INAT_LSTPFX_MAX + 1] = {" +- for (i = 0; i < ggid; i++) +- for (j = 0; j < max_lprefix; j++) +- if (gtable[i,j]) +- print " ["i"]["j"] = "gtable[i,j]"," +- print "};\n" +- # print AVX opcode map's array +- print "/* AVX opcode map array */" +- print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ +- "[INAT_LSTPFX_MAX + 1] = {" +- for (i = 0; i < gaid; i++) +- for (j = 0; j < max_lprefix; j++) +- if (atable[i,j]) +- print " ["i"]["j"] = "atable[i,j]"," +- print "};" +-} +- +diff --git a/tools/objtool/arch/x86/insn/inat.c b/tools/objtool/arch/x86/insn/inat.c +deleted file mode 100644 +index e4bf28e6f4c7..000000000000 +--- a/tools/objtool/arch/x86/insn/inat.c ++++ /dev/null +@@ -1,97 +0,0 @@ +-/* +- * x86 instruction attribute tables +- * +- * Written by Masami Hiramatsu +- * +- * 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. +- * +- */ +-#include "insn.h" +- +-/* Attribute tables are generated from opcode map */ +-#include "inat-tables.c" +- +-/* Attribute search APIs */ +-insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) +-{ +- return inat_primary_table[opcode]; +-} +- +-int inat_get_last_prefix_id(insn_byte_t last_pfx) +-{ +- insn_attr_t lpfx_attr; +- +- lpfx_attr = inat_get_opcode_attribute(last_pfx); +- return inat_last_prefix_id(lpfx_attr); +-} +- +-insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, +- insn_attr_t esc_attr) +-{ +- const insn_attr_t *table; +- int n; +- +- n = inat_escape_id(esc_attr); +- +- table = inat_escape_tables[n][0]; +- if (!table) +- return 0; +- if (inat_has_variant(table[opcode]) && lpfx_id) { +- table = inat_escape_tables[n][lpfx_id]; +- if (!table) +- return 0; +- } +- return table[opcode]; +-} +- +-insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, +- insn_attr_t grp_attr) +-{ +- const insn_attr_t *table; +- int n; +- +- n = inat_group_id(grp_attr); +- +- table = inat_group_tables[n][0]; +- if (!table) +- return inat_group_common_attribute(grp_attr); +- if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { +- table = inat_group_tables[n][lpfx_id]; +- if (!table) +- return inat_group_common_attribute(grp_attr); +- } +- return table[X86_MODRM_REG(modrm)] | +- inat_group_common_attribute(grp_attr); +-} +- +-insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, +- insn_byte_t vex_p) +-{ +- const insn_attr_t *table; +- if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) +- return 0; +- /* At first, this checks the master table */ +- table = inat_avx_tables[vex_m][0]; +- if (!table) +- return 0; +- if (!inat_is_group(table[opcode]) && vex_p) { +- /* If this is not a group, get attribute directly */ +- table = inat_avx_tables[vex_m][vex_p]; +- if (!table) +- return 0; +- } +- return table[opcode]; +-} +- +diff --git a/tools/objtool/arch/x86/insn/inat.h b/tools/objtool/arch/x86/insn/inat.h +deleted file mode 100644 +index 125ecd2a300d..000000000000 +--- a/tools/objtool/arch/x86/insn/inat.h ++++ /dev/null +@@ -1,234 +0,0 @@ +-#ifndef _ASM_X86_INAT_H +-#define _ASM_X86_INAT_H +-/* +- * x86 instruction attributes +- * +- * Written by Masami Hiramatsu +- * +- * 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. +- * +- */ +-#include "inat_types.h" +- +-/* +- * Internal bits. Don't use bitmasks directly, because these bits are +- * unstable. You should use checking functions. +- */ +- +-#define INAT_OPCODE_TABLE_SIZE 256 +-#define INAT_GROUP_TABLE_SIZE 8 +- +-/* Legacy last prefixes */ +-#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ +-#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ +-#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ +-/* Other Legacy prefixes */ +-#define INAT_PFX_LOCK 4 /* 0xF0 */ +-#define INAT_PFX_CS 5 /* 0x2E */ +-#define INAT_PFX_DS 6 /* 0x3E */ +-#define INAT_PFX_ES 7 /* 0x26 */ +-#define INAT_PFX_FS 8 /* 0x64 */ +-#define INAT_PFX_GS 9 /* 0x65 */ +-#define INAT_PFX_SS 10 /* 0x36 */ +-#define INAT_PFX_ADDRSZ 11 /* 0x67 */ +-/* x86-64 REX prefix */ +-#define INAT_PFX_REX 12 /* 0x4X */ +-/* AVX VEX prefixes */ +-#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ +-#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ +-#define INAT_PFX_EVEX 15 /* EVEX prefix */ +- +-#define INAT_LSTPFX_MAX 3 +-#define INAT_LGCPFX_MAX 11 +- +-/* Immediate size */ +-#define INAT_IMM_BYTE 1 +-#define INAT_IMM_WORD 2 +-#define INAT_IMM_DWORD 3 +-#define INAT_IMM_QWORD 4 +-#define INAT_IMM_PTR 5 +-#define INAT_IMM_VWORD32 6 +-#define INAT_IMM_VWORD 7 +- +-/* Legacy prefix */ +-#define INAT_PFX_OFFS 0 +-#define INAT_PFX_BITS 4 +-#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) +-#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) +-/* Escape opcodes */ +-#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) +-#define INAT_ESC_BITS 2 +-#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) +-#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) +-/* Group opcodes (1-16) */ +-#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) +-#define INAT_GRP_BITS 5 +-#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) +-#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) +-/* Immediates */ +-#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) +-#define INAT_IMM_BITS 3 +-#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) +-/* Flags */ +-#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) +-#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) +-#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) +-#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) +-#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) +-#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) +-#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) +-#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) +-#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) +-/* Attribute making macros for attribute tables */ +-#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) +-#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) +-#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) +-#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) +- +-/* Attribute search APIs */ +-extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); +-extern int inat_get_last_prefix_id(insn_byte_t last_pfx); +-extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, +- int lpfx_id, +- insn_attr_t esc_attr); +-extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, +- int lpfx_id, +- insn_attr_t esc_attr); +-extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, +- insn_byte_t vex_m, +- insn_byte_t vex_pp); +- +-/* Attribute checking functions */ +-static inline int inat_is_legacy_prefix(insn_attr_t attr) +-{ +- attr &= INAT_PFX_MASK; +- return attr && attr <= INAT_LGCPFX_MAX; +-} +- +-static inline int inat_is_address_size_prefix(insn_attr_t attr) +-{ +- return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; +-} +- +-static inline int inat_is_operand_size_prefix(insn_attr_t attr) +-{ +- return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; +-} +- +-static inline int inat_is_rex_prefix(insn_attr_t attr) +-{ +- return (attr & INAT_PFX_MASK) == INAT_PFX_REX; +-} +- +-static inline int inat_last_prefix_id(insn_attr_t attr) +-{ +- if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) +- return 0; +- else +- return attr & INAT_PFX_MASK; +-} +- +-static inline int inat_is_vex_prefix(insn_attr_t attr) +-{ +- attr &= INAT_PFX_MASK; +- return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || +- attr == INAT_PFX_EVEX; +-} +- +-static inline int inat_is_evex_prefix(insn_attr_t attr) +-{ +- return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; +-} +- +-static inline int inat_is_vex3_prefix(insn_attr_t attr) +-{ +- return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; +-} +- +-static inline int inat_is_escape(insn_attr_t attr) +-{ +- return attr & INAT_ESC_MASK; +-} +- +-static inline int inat_escape_id(insn_attr_t attr) +-{ +- return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; +-} +- +-static inline int inat_is_group(insn_attr_t attr) +-{ +- return attr & INAT_GRP_MASK; +-} +- +-static inline int inat_group_id(insn_attr_t attr) +-{ +- return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; +-} +- +-static inline int inat_group_common_attribute(insn_attr_t attr) +-{ +- return attr & ~INAT_GRP_MASK; +-} +- +-static inline int inat_has_immediate(insn_attr_t attr) +-{ +- return attr & INAT_IMM_MASK; +-} +- +-static inline int inat_immediate_size(insn_attr_t attr) +-{ +- return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; +-} +- +-static inline int inat_has_modrm(insn_attr_t attr) +-{ +- return attr & INAT_MODRM; +-} +- +-static inline int inat_is_force64(insn_attr_t attr) +-{ +- return attr & INAT_FORCE64; +-} +- +-static inline int inat_has_second_immediate(insn_attr_t attr) +-{ +- return attr & INAT_SCNDIMM; +-} +- +-static inline int inat_has_moffset(insn_attr_t attr) +-{ +- return attr & INAT_MOFFSET; +-} +- +-static inline int inat_has_variant(insn_attr_t attr) +-{ +- return attr & INAT_VARIANT; +-} +- +-static inline int inat_accept_vex(insn_attr_t attr) +-{ +- return attr & INAT_VEXOK; +-} +- +-static inline int inat_must_vex(insn_attr_t attr) +-{ +- return attr & (INAT_VEXONLY | INAT_EVEXONLY); +-} +- +-static inline int inat_must_evex(insn_attr_t attr) +-{ +- return attr & INAT_EVEXONLY; +-} +-#endif +diff --git a/tools/objtool/arch/x86/insn/inat_types.h b/tools/objtool/arch/x86/insn/inat_types.h +deleted file mode 100644 +index cb3c20ce39cf..000000000000 +--- a/tools/objtool/arch/x86/insn/inat_types.h ++++ /dev/null +@@ -1,29 +0,0 @@ +-#ifndef _ASM_X86_INAT_TYPES_H +-#define _ASM_X86_INAT_TYPES_H +-/* +- * x86 instruction attributes +- * +- * Written by Masami Hiramatsu +- * +- * 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. +- * +- */ +- +-/* Instruction attributes */ +-typedef unsigned int insn_attr_t; +-typedef unsigned char insn_byte_t; +-typedef signed int insn_value_t; +- +-#endif +diff --git a/tools/objtool/arch/x86/insn/insn.c b/tools/objtool/arch/x86/insn/insn.c +deleted file mode 100644 +index ca983e2bea8b..000000000000 +--- a/tools/objtool/arch/x86/insn/insn.c ++++ /dev/null +@@ -1,606 +0,0 @@ +-/* +- * x86 instruction analysis +- * +- * 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. +- * +- * Copyright (C) IBM Corporation, 2002, 2004, 2009 +- */ +- +-#ifdef __KERNEL__ +-#include +-#else +-#include +-#endif +-#include "inat.h" +-#include "insn.h" +- +-/* Verify next sizeof(t) bytes can be on the same instruction */ +-#define validate_next(t, insn, n) \ +- ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) +- +-#define __get_next(t, insn) \ +- ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) +- +-#define __peek_nbyte_next(t, insn, n) \ +- ({ t r = *(t*)((insn)->next_byte + n); r; }) +- +-#define get_next(t, insn) \ +- ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) +- +-#define peek_nbyte_next(t, insn, n) \ +- ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) +- +-#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) +- +-/** +- * insn_init() - initialize struct insn +- * @insn: &struct insn to be initialized +- * @kaddr: address (in kernel memory) of instruction (or copy thereof) +- * @x86_64: !0 for 64-bit kernel or 64-bit app +- */ +-void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) +-{ +- /* +- * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid +- * even if the input buffer is long enough to hold them. +- */ +- if (buf_len > MAX_INSN_SIZE) +- buf_len = MAX_INSN_SIZE; +- +- memset(insn, 0, sizeof(*insn)); +- insn->kaddr = kaddr; +- insn->end_kaddr = kaddr + buf_len; +- insn->next_byte = kaddr; +- insn->x86_64 = x86_64 ? 1 : 0; +- insn->opnd_bytes = 4; +- if (x86_64) +- insn->addr_bytes = 8; +- else +- insn->addr_bytes = 4; +-} +- +-/** +- * insn_get_prefixes - scan x86 instruction prefix bytes +- * @insn: &struct insn containing instruction +- * +- * Populates the @insn->prefixes bitmap, and updates @insn->next_byte +- * to point to the (first) opcode. No effect if @insn->prefixes.got +- * is already set. +- */ +-void insn_get_prefixes(struct insn *insn) +-{ +- struct insn_field *prefixes = &insn->prefixes; +- insn_attr_t attr; +- insn_byte_t b, lb; +- int i, nb; +- +- if (prefixes->got) +- return; +- +- nb = 0; +- lb = 0; +- b = peek_next(insn_byte_t, insn); +- attr = inat_get_opcode_attribute(b); +- while (inat_is_legacy_prefix(attr)) { +- /* Skip if same prefix */ +- for (i = 0; i < nb; i++) +- if (prefixes->bytes[i] == b) +- goto found; +- if (nb == 4) +- /* Invalid instruction */ +- break; +- prefixes->bytes[nb++] = b; +- if (inat_is_address_size_prefix(attr)) { +- /* address size switches 2/4 or 4/8 */ +- if (insn->x86_64) +- insn->addr_bytes ^= 12; +- else +- insn->addr_bytes ^= 6; +- } else if (inat_is_operand_size_prefix(attr)) { +- /* oprand size switches 2/4 */ +- insn->opnd_bytes ^= 6; +- } +-found: +- prefixes->nbytes++; +- insn->next_byte++; +- lb = b; +- b = peek_next(insn_byte_t, insn); +- attr = inat_get_opcode_attribute(b); +- } +- /* Set the last prefix */ +- if (lb && lb != insn->prefixes.bytes[3]) { +- if (unlikely(insn->prefixes.bytes[3])) { +- /* Swap the last prefix */ +- b = insn->prefixes.bytes[3]; +- for (i = 0; i < nb; i++) +- if (prefixes->bytes[i] == lb) +- prefixes->bytes[i] = b; +- } +- insn->prefixes.bytes[3] = lb; +- } +- +- /* Decode REX prefix */ +- if (insn->x86_64) { +- b = peek_next(insn_byte_t, insn); +- attr = inat_get_opcode_attribute(b); +- if (inat_is_rex_prefix(attr)) { +- insn->rex_prefix.value = b; +- insn->rex_prefix.nbytes = 1; +- insn->next_byte++; +- if (X86_REX_W(b)) +- /* REX.W overrides opnd_size */ +- insn->opnd_bytes = 8; +- } +- } +- insn->rex_prefix.got = 1; +- +- /* Decode VEX prefix */ +- b = peek_next(insn_byte_t, insn); +- attr = inat_get_opcode_attribute(b); +- if (inat_is_vex_prefix(attr)) { +- insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); +- if (!insn->x86_64) { +- /* +- * In 32-bits mode, if the [7:6] bits (mod bits of +- * ModRM) on the second byte are not 11b, it is +- * LDS or LES or BOUND. +- */ +- if (X86_MODRM_MOD(b2) != 3) +- goto vex_end; +- } +- insn->vex_prefix.bytes[0] = b; +- insn->vex_prefix.bytes[1] = b2; +- if (inat_is_evex_prefix(attr)) { +- b2 = peek_nbyte_next(insn_byte_t, insn, 2); +- insn->vex_prefix.bytes[2] = b2; +- b2 = peek_nbyte_next(insn_byte_t, insn, 3); +- insn->vex_prefix.bytes[3] = b2; +- insn->vex_prefix.nbytes = 4; +- insn->next_byte += 4; +- if (insn->x86_64 && X86_VEX_W(b2)) +- /* VEX.W overrides opnd_size */ +- insn->opnd_bytes = 8; +- } else if (inat_is_vex3_prefix(attr)) { +- b2 = peek_nbyte_next(insn_byte_t, insn, 2); +- insn->vex_prefix.bytes[2] = b2; +- insn->vex_prefix.nbytes = 3; +- insn->next_byte += 3; +- if (insn->x86_64 && X86_VEX_W(b2)) +- /* VEX.W overrides opnd_size */ +- insn->opnd_bytes = 8; +- } else { +- /* +- * For VEX2, fake VEX3-like byte#2. +- * Makes it easier to decode vex.W, vex.vvvv, +- * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. +- */ +- insn->vex_prefix.bytes[2] = b2 & 0x7f; +- insn->vex_prefix.nbytes = 2; +- insn->next_byte += 2; +- } +- } +-vex_end: +- insn->vex_prefix.got = 1; +- +- prefixes->got = 1; +- +-err_out: +- return; +-} +- +-/** +- * insn_get_opcode - collect opcode(s) +- * @insn: &struct insn containing instruction +- * +- * Populates @insn->opcode, updates @insn->next_byte to point past the +- * opcode byte(s), and set @insn->attr (except for groups). +- * If necessary, first collects any preceding (prefix) bytes. +- * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got +- * is already 1. +- */ +-void insn_get_opcode(struct insn *insn) +-{ +- struct insn_field *opcode = &insn->opcode; +- insn_byte_t op; +- int pfx_id; +- if (opcode->got) +- return; +- if (!insn->prefixes.got) +- insn_get_prefixes(insn); +- +- /* Get first opcode */ +- op = get_next(insn_byte_t, insn); +- opcode->bytes[0] = op; +- opcode->nbytes = 1; +- +- /* Check if there is VEX prefix or not */ +- if (insn_is_avx(insn)) { +- insn_byte_t m, p; +- m = insn_vex_m_bits(insn); +- p = insn_vex_p_bits(insn); +- insn->attr = inat_get_avx_attribute(op, m, p); +- if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || +- (!inat_accept_vex(insn->attr) && +- !inat_is_group(insn->attr))) +- insn->attr = 0; /* This instruction is bad */ +- goto end; /* VEX has only 1 byte for opcode */ +- } +- +- insn->attr = inat_get_opcode_attribute(op); +- while (inat_is_escape(insn->attr)) { +- /* Get escaped opcode */ +- op = get_next(insn_byte_t, insn); +- opcode->bytes[opcode->nbytes++] = op; +- pfx_id = insn_last_prefix_id(insn); +- insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); +- } +- if (inat_must_vex(insn->attr)) +- insn->attr = 0; /* This instruction is bad */ +-end: +- opcode->got = 1; +- +-err_out: +- return; +-} +- +-/** +- * insn_get_modrm - collect ModRM byte, if any +- * @insn: &struct insn containing instruction +- * +- * Populates @insn->modrm and updates @insn->next_byte to point past the +- * ModRM byte, if any. If necessary, first collects the preceding bytes +- * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. +- */ +-void insn_get_modrm(struct insn *insn) +-{ +- struct insn_field *modrm = &insn->modrm; +- insn_byte_t pfx_id, mod; +- if (modrm->got) +- return; +- if (!insn->opcode.got) +- insn_get_opcode(insn); +- +- if (inat_has_modrm(insn->attr)) { +- mod = get_next(insn_byte_t, insn); +- modrm->value = mod; +- modrm->nbytes = 1; +- if (inat_is_group(insn->attr)) { +- pfx_id = insn_last_prefix_id(insn); +- insn->attr = inat_get_group_attribute(mod, pfx_id, +- insn->attr); +- if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) +- insn->attr = 0; /* This is bad */ +- } +- } +- +- if (insn->x86_64 && inat_is_force64(insn->attr)) +- insn->opnd_bytes = 8; +- modrm->got = 1; +- +-err_out: +- return; +-} +- +- +-/** +- * insn_rip_relative() - Does instruction use RIP-relative addressing mode? +- * @insn: &struct insn containing instruction +- * +- * If necessary, first collects the instruction up to and including the +- * ModRM byte. No effect if @insn->x86_64 is 0. +- */ +-int insn_rip_relative(struct insn *insn) +-{ +- struct insn_field *modrm = &insn->modrm; +- +- if (!insn->x86_64) +- return 0; +- if (!modrm->got) +- insn_get_modrm(insn); +- /* +- * For rip-relative instructions, the mod field (top 2 bits) +- * is zero and the r/m field (bottom 3 bits) is 0x5. +- */ +- return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); +-} +- +-/** +- * insn_get_sib() - Get the SIB byte of instruction +- * @insn: &struct insn containing instruction +- * +- * If necessary, first collects the instruction up to and including the +- * ModRM byte. +- */ +-void insn_get_sib(struct insn *insn) +-{ +- insn_byte_t modrm; +- +- if (insn->sib.got) +- return; +- if (!insn->modrm.got) +- insn_get_modrm(insn); +- if (insn->modrm.nbytes) { +- modrm = (insn_byte_t)insn->modrm.value; +- if (insn->addr_bytes != 2 && +- X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { +- insn->sib.value = get_next(insn_byte_t, insn); +- insn->sib.nbytes = 1; +- } +- } +- insn->sib.got = 1; +- +-err_out: +- return; +-} +- +- +-/** +- * insn_get_displacement() - Get the displacement of instruction +- * @insn: &struct insn containing instruction +- * +- * If necessary, first collects the instruction up to and including the +- * SIB byte. +- * Displacement value is sign-expanded. +- */ +-void insn_get_displacement(struct insn *insn) +-{ +- insn_byte_t mod, rm, base; +- +- if (insn->displacement.got) +- return; +- if (!insn->sib.got) +- insn_get_sib(insn); +- if (insn->modrm.nbytes) { +- /* +- * Interpreting the modrm byte: +- * mod = 00 - no displacement fields (exceptions below) +- * mod = 01 - 1-byte displacement field +- * mod = 10 - displacement field is 4 bytes, or 2 bytes if +- * address size = 2 (0x67 prefix in 32-bit mode) +- * mod = 11 - no memory operand +- * +- * If address size = 2... +- * mod = 00, r/m = 110 - displacement field is 2 bytes +- * +- * If address size != 2... +- * mod != 11, r/m = 100 - SIB byte exists +- * mod = 00, SIB base = 101 - displacement field is 4 bytes +- * mod = 00, r/m = 101 - rip-relative addressing, displacement +- * field is 4 bytes +- */ +- mod = X86_MODRM_MOD(insn->modrm.value); +- rm = X86_MODRM_RM(insn->modrm.value); +- base = X86_SIB_BASE(insn->sib.value); +- if (mod == 3) +- goto out; +- if (mod == 1) { +- insn->displacement.value = get_next(signed char, insn); +- insn->displacement.nbytes = 1; +- } else if (insn->addr_bytes == 2) { +- if ((mod == 0 && rm == 6) || mod == 2) { +- insn->displacement.value = +- get_next(short, insn); +- insn->displacement.nbytes = 2; +- } +- } else { +- if ((mod == 0 && rm == 5) || mod == 2 || +- (mod == 0 && base == 5)) { +- insn->displacement.value = get_next(int, insn); +- insn->displacement.nbytes = 4; +- } +- } +- } +-out: +- insn->displacement.got = 1; +- +-err_out: +- return; +-} +- +-/* Decode moffset16/32/64. Return 0 if failed */ +-static int __get_moffset(struct insn *insn) +-{ +- switch (insn->addr_bytes) { +- case 2: +- insn->moffset1.value = get_next(short, insn); +- insn->moffset1.nbytes = 2; +- break; +- case 4: +- insn->moffset1.value = get_next(int, insn); +- insn->moffset1.nbytes = 4; +- break; +- case 8: +- insn->moffset1.value = get_next(int, insn); +- insn->moffset1.nbytes = 4; +- insn->moffset2.value = get_next(int, insn); +- insn->moffset2.nbytes = 4; +- break; +- default: /* opnd_bytes must be modified manually */ +- goto err_out; +- } +- insn->moffset1.got = insn->moffset2.got = 1; +- +- return 1; +- +-err_out: +- return 0; +-} +- +-/* Decode imm v32(Iz). Return 0 if failed */ +-static int __get_immv32(struct insn *insn) +-{ +- switch (insn->opnd_bytes) { +- case 2: +- insn->immediate.value = get_next(short, insn); +- insn->immediate.nbytes = 2; +- break; +- case 4: +- case 8: +- insn->immediate.value = get_next(int, insn); +- insn->immediate.nbytes = 4; +- break; +- default: /* opnd_bytes must be modified manually */ +- goto err_out; +- } +- +- return 1; +- +-err_out: +- return 0; +-} +- +-/* Decode imm v64(Iv/Ov), Return 0 if failed */ +-static int __get_immv(struct insn *insn) +-{ +- switch (insn->opnd_bytes) { +- case 2: +- insn->immediate1.value = get_next(short, insn); +- insn->immediate1.nbytes = 2; +- break; +- case 4: +- insn->immediate1.value = get_next(int, insn); +- insn->immediate1.nbytes = 4; +- break; +- case 8: +- insn->immediate1.value = get_next(int, insn); +- insn->immediate1.nbytes = 4; +- insn->immediate2.value = get_next(int, insn); +- insn->immediate2.nbytes = 4; +- break; +- default: /* opnd_bytes must be modified manually */ +- goto err_out; +- } +- insn->immediate1.got = insn->immediate2.got = 1; +- +- return 1; +-err_out: +- return 0; +-} +- +-/* Decode ptr16:16/32(Ap) */ +-static int __get_immptr(struct insn *insn) +-{ +- switch (insn->opnd_bytes) { +- case 2: +- insn->immediate1.value = get_next(short, insn); +- insn->immediate1.nbytes = 2; +- break; +- case 4: +- insn->immediate1.value = get_next(int, insn); +- insn->immediate1.nbytes = 4; +- break; +- case 8: +- /* ptr16:64 is not exist (no segment) */ +- return 0; +- default: /* opnd_bytes must be modified manually */ +- goto err_out; +- } +- insn->immediate2.value = get_next(unsigned short, insn); +- insn->immediate2.nbytes = 2; +- insn->immediate1.got = insn->immediate2.got = 1; +- +- return 1; +-err_out: +- return 0; +-} +- +-/** +- * insn_get_immediate() - Get the immediates of instruction +- * @insn: &struct insn containing instruction +- * +- * If necessary, first collects the instruction up to and including the +- * displacement bytes. +- * Basically, most of immediates are sign-expanded. Unsigned-value can be +- * get by bit masking with ((1 << (nbytes * 8)) - 1) +- */ +-void insn_get_immediate(struct insn *insn) +-{ +- if (insn->immediate.got) +- return; +- if (!insn->displacement.got) +- insn_get_displacement(insn); +- +- if (inat_has_moffset(insn->attr)) { +- if (!__get_moffset(insn)) +- goto err_out; +- goto done; +- } +- +- if (!inat_has_immediate(insn->attr)) +- /* no immediates */ +- goto done; +- +- switch (inat_immediate_size(insn->attr)) { +- case INAT_IMM_BYTE: +- insn->immediate.value = get_next(signed char, insn); +- insn->immediate.nbytes = 1; +- break; +- case INAT_IMM_WORD: +- insn->immediate.value = get_next(short, insn); +- insn->immediate.nbytes = 2; +- break; +- case INAT_IMM_DWORD: +- insn->immediate.value = get_next(int, insn); +- insn->immediate.nbytes = 4; +- break; +- case INAT_IMM_QWORD: +- insn->immediate1.value = get_next(int, insn); +- insn->immediate1.nbytes = 4; +- insn->immediate2.value = get_next(int, insn); +- insn->immediate2.nbytes = 4; +- break; +- case INAT_IMM_PTR: +- if (!__get_immptr(insn)) +- goto err_out; +- break; +- case INAT_IMM_VWORD32: +- if (!__get_immv32(insn)) +- goto err_out; +- break; +- case INAT_IMM_VWORD: +- if (!__get_immv(insn)) +- goto err_out; +- break; +- default: +- /* Here, insn must have an immediate, but failed */ +- goto err_out; +- } +- if (inat_has_second_immediate(insn->attr)) { +- insn->immediate2.value = get_next(signed char, insn); +- insn->immediate2.nbytes = 1; +- } +-done: +- insn->immediate.got = 1; +- +-err_out: +- return; +-} +- +-/** +- * insn_get_length() - Get the length of instruction +- * @insn: &struct insn containing instruction +- * +- * If necessary, first collects the instruction up to and including the +- * immediates bytes. +- */ +-void insn_get_length(struct insn *insn) +-{ +- if (insn->length) +- return; +- if (!insn->immediate.got) +- insn_get_immediate(insn); +- insn->length = (unsigned char)((unsigned long)insn->next_byte +- - (unsigned long)insn->kaddr); +-} +diff --git a/tools/objtool/arch/x86/insn/insn.h b/tools/objtool/arch/x86/insn/insn.h +deleted file mode 100644 +index e23578c7b1be..000000000000 +--- a/tools/objtool/arch/x86/insn/insn.h ++++ /dev/null +@@ -1,211 +0,0 @@ +-#ifndef _ASM_X86_INSN_H +-#define _ASM_X86_INSN_H +-/* +- * x86 instruction analysis +- * +- * 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. +- * +- * Copyright (C) IBM Corporation, 2009 +- */ +- +-/* insn_attr_t is defined in inat.h */ +-#include "inat.h" +- +-struct insn_field { +- union { +- insn_value_t value; +- insn_byte_t bytes[4]; +- }; +- /* !0 if we've run insn_get_xxx() for this field */ +- unsigned char got; +- unsigned char nbytes; +-}; +- +-struct insn { +- struct insn_field prefixes; /* +- * Prefixes +- * prefixes.bytes[3]: last prefix +- */ +- struct insn_field rex_prefix; /* REX prefix */ +- struct insn_field vex_prefix; /* VEX prefix */ +- struct insn_field opcode; /* +- * opcode.bytes[0]: opcode1 +- * opcode.bytes[1]: opcode2 +- * opcode.bytes[2]: opcode3 +- */ +- struct insn_field modrm; +- struct insn_field sib; +- struct insn_field displacement; +- union { +- struct insn_field immediate; +- struct insn_field moffset1; /* for 64bit MOV */ +- struct insn_field immediate1; /* for 64bit imm or off16/32 */ +- }; +- union { +- struct insn_field moffset2; /* for 64bit MOV */ +- struct insn_field immediate2; /* for 64bit imm or seg16 */ +- }; +- +- insn_attr_t attr; +- unsigned char opnd_bytes; +- unsigned char addr_bytes; +- unsigned char length; +- unsigned char x86_64; +- +- const insn_byte_t *kaddr; /* kernel address of insn to analyze */ +- const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ +- const insn_byte_t *next_byte; +-}; +- +-#define MAX_INSN_SIZE 15 +- +-#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) +-#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) +-#define X86_MODRM_RM(modrm) ((modrm) & 0x07) +- +-#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) +-#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) +-#define X86_SIB_BASE(sib) ((sib) & 0x07) +- +-#define X86_REX_W(rex) ((rex) & 8) +-#define X86_REX_R(rex) ((rex) & 4) +-#define X86_REX_X(rex) ((rex) & 2) +-#define X86_REX_B(rex) ((rex) & 1) +- +-/* VEX bit flags */ +-#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ +-#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ +-#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ +-#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ +-#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ +-/* VEX bit fields */ +-#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ +-#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ +-#define X86_VEX2_M 1 /* VEX2.M always 1 */ +-#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ +-#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ +-#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ +- +-extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); +-extern void insn_get_prefixes(struct insn *insn); +-extern void insn_get_opcode(struct insn *insn); +-extern void insn_get_modrm(struct insn *insn); +-extern void insn_get_sib(struct insn *insn); +-extern void insn_get_displacement(struct insn *insn); +-extern void insn_get_immediate(struct insn *insn); +-extern void insn_get_length(struct insn *insn); +- +-/* Attribute will be determined after getting ModRM (for opcode groups) */ +-static inline void insn_get_attribute(struct insn *insn) +-{ +- insn_get_modrm(insn); +-} +- +-/* Instruction uses RIP-relative addressing */ +-extern int insn_rip_relative(struct insn *insn); +- +-/* Init insn for kernel text */ +-static inline void kernel_insn_init(struct insn *insn, +- const void *kaddr, int buf_len) +-{ +-#ifdef CONFIG_X86_64 +- insn_init(insn, kaddr, buf_len, 1); +-#else /* CONFIG_X86_32 */ +- insn_init(insn, kaddr, buf_len, 0); +-#endif +-} +- +-static inline int insn_is_avx(struct insn *insn) +-{ +- if (!insn->prefixes.got) +- insn_get_prefixes(insn); +- return (insn->vex_prefix.value != 0); +-} +- +-static inline int insn_is_evex(struct insn *insn) +-{ +- if (!insn->prefixes.got) +- insn_get_prefixes(insn); +- return (insn->vex_prefix.nbytes == 4); +-} +- +-/* Ensure this instruction is decoded completely */ +-static inline int insn_complete(struct insn *insn) +-{ +- return insn->opcode.got && insn->modrm.got && insn->sib.got && +- insn->displacement.got && insn->immediate.got; +-} +- +-static inline insn_byte_t insn_vex_m_bits(struct insn *insn) +-{ +- if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ +- return X86_VEX2_M; +- else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ +- return X86_VEX3_M(insn->vex_prefix.bytes[1]); +- else /* EVEX */ +- return X86_EVEX_M(insn->vex_prefix.bytes[1]); +-} +- +-static inline insn_byte_t insn_vex_p_bits(struct insn *insn) +-{ +- if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ +- return X86_VEX_P(insn->vex_prefix.bytes[1]); +- else +- return X86_VEX_P(insn->vex_prefix.bytes[2]); +-} +- +-/* Get the last prefix id from last prefix or VEX prefix */ +-static inline int insn_last_prefix_id(struct insn *insn) +-{ +- if (insn_is_avx(insn)) +- return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ +- +- if (insn->prefixes.bytes[3]) +- return inat_get_last_prefix_id(insn->prefixes.bytes[3]); +- +- return 0; +-} +- +-/* Offset of each field from kaddr */ +-static inline int insn_offset_rex_prefix(struct insn *insn) +-{ +- return insn->prefixes.nbytes; +-} +-static inline int insn_offset_vex_prefix(struct insn *insn) +-{ +- return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; +-} +-static inline int insn_offset_opcode(struct insn *insn) +-{ +- return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; +-} +-static inline int insn_offset_modrm(struct insn *insn) +-{ +- return insn_offset_opcode(insn) + insn->opcode.nbytes; +-} +-static inline int insn_offset_sib(struct insn *insn) +-{ +- return insn_offset_modrm(insn) + insn->modrm.nbytes; +-} +-static inline int insn_offset_displacement(struct insn *insn) +-{ +- return insn_offset_sib(insn) + insn->sib.nbytes; +-} +-static inline int insn_offset_immediate(struct insn *insn) +-{ +- return insn_offset_displacement(insn) + insn->displacement.nbytes; +-} +- +-#endif /* _ASM_X86_INSN_H */ +diff --git a/tools/objtool/arch/x86/insn/x86-opcode-map.txt b/tools/objtool/arch/x86/insn/x86-opcode-map.txt +deleted file mode 100644 +index 1754e094bc28..000000000000 +--- a/tools/objtool/arch/x86/insn/x86-opcode-map.txt ++++ /dev/null +@@ -1,1063 +0,0 @@ +-# x86 Opcode Maps +-# +-# This is (mostly) based on following documentations. +-# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C +-# (#326018-047US, June 2013) +-# +-# +-# Table: table-name +-# Referrer: escaped-name +-# AVXcode: avx-code +-# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] +-# (or) +-# opcode: escape # escaped-name +-# EndTable +-# +-# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix +-# mnemonics that begin with lowercase 'k' accept a VEX prefix +-# +-# +-# GrpTable: GrpXXX +-# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] +-# EndTable +-# +-# AVX Superscripts +-# (ev): this opcode requires EVEX prefix. +-# (evo): this opcode is changed by EVEX prefix (EVEX opcode) +-# (v): this opcode requires VEX prefix. +-# (v1): this opcode only supports 128bit VEX. +-# +-# Last Prefix Superscripts +-# - (66): the last prefix is 0x66 +-# - (F3): the last prefix is 0xF3 +-# - (F2): the last prefix is 0xF2 +-# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) +-# - (66&F2): Both 0x66 and 0xF2 prefixes are specified. +- +-Table: one byte opcode +-Referrer: +-AVXcode: +-# 0x00 - 0x0f +-00: ADD Eb,Gb +-01: ADD Ev,Gv +-02: ADD Gb,Eb +-03: ADD Gv,Ev +-04: ADD AL,Ib +-05: ADD rAX,Iz +-06: PUSH ES (i64) +-07: POP ES (i64) +-08: OR Eb,Gb +-09: OR Ev,Gv +-0a: OR Gb,Eb +-0b: OR Gv,Ev +-0c: OR AL,Ib +-0d: OR rAX,Iz +-0e: PUSH CS (i64) +-0f: escape # 2-byte escape +-# 0x10 - 0x1f +-10: ADC Eb,Gb +-11: ADC Ev,Gv +-12: ADC Gb,Eb +-13: ADC Gv,Ev +-14: ADC AL,Ib +-15: ADC rAX,Iz +-16: PUSH SS (i64) +-17: POP SS (i64) +-18: SBB Eb,Gb +-19: SBB Ev,Gv +-1a: SBB Gb,Eb +-1b: SBB Gv,Ev +-1c: SBB AL,Ib +-1d: SBB rAX,Iz +-1e: PUSH DS (i64) +-1f: POP DS (i64) +-# 0x20 - 0x2f +-20: AND Eb,Gb +-21: AND Ev,Gv +-22: AND Gb,Eb +-23: AND Gv,Ev +-24: AND AL,Ib +-25: AND rAx,Iz +-26: SEG=ES (Prefix) +-27: DAA (i64) +-28: SUB Eb,Gb +-29: SUB Ev,Gv +-2a: SUB Gb,Eb +-2b: SUB Gv,Ev +-2c: SUB AL,Ib +-2d: SUB rAX,Iz +-2e: SEG=CS (Prefix) +-2f: DAS (i64) +-# 0x30 - 0x3f +-30: XOR Eb,Gb +-31: XOR Ev,Gv +-32: XOR Gb,Eb +-33: XOR Gv,Ev +-34: XOR AL,Ib +-35: XOR rAX,Iz +-36: SEG=SS (Prefix) +-37: AAA (i64) +-38: CMP Eb,Gb +-39: CMP Ev,Gv +-3a: CMP Gb,Eb +-3b: CMP Gv,Ev +-3c: CMP AL,Ib +-3d: CMP rAX,Iz +-3e: SEG=DS (Prefix) +-3f: AAS (i64) +-# 0x40 - 0x4f +-40: INC eAX (i64) | REX (o64) +-41: INC eCX (i64) | REX.B (o64) +-42: INC eDX (i64) | REX.X (o64) +-43: INC eBX (i64) | REX.XB (o64) +-44: INC eSP (i64) | REX.R (o64) +-45: INC eBP (i64) | REX.RB (o64) +-46: INC eSI (i64) | REX.RX (o64) +-47: INC eDI (i64) | REX.RXB (o64) +-48: DEC eAX (i64) | REX.W (o64) +-49: DEC eCX (i64) | REX.WB (o64) +-4a: DEC eDX (i64) | REX.WX (o64) +-4b: DEC eBX (i64) | REX.WXB (o64) +-4c: DEC eSP (i64) | REX.WR (o64) +-4d: DEC eBP (i64) | REX.WRB (o64) +-4e: DEC eSI (i64) | REX.WRX (o64) +-4f: DEC eDI (i64) | REX.WRXB (o64) +-# 0x50 - 0x5f +-50: PUSH rAX/r8 (d64) +-51: PUSH rCX/r9 (d64) +-52: PUSH rDX/r10 (d64) +-53: PUSH rBX/r11 (d64) +-54: PUSH rSP/r12 (d64) +-55: PUSH rBP/r13 (d64) +-56: PUSH rSI/r14 (d64) +-57: PUSH rDI/r15 (d64) +-58: POP rAX/r8 (d64) +-59: POP rCX/r9 (d64) +-5a: POP rDX/r10 (d64) +-5b: POP rBX/r11 (d64) +-5c: POP rSP/r12 (d64) +-5d: POP rBP/r13 (d64) +-5e: POP rSI/r14 (d64) +-5f: POP rDI/r15 (d64) +-# 0x60 - 0x6f +-60: PUSHA/PUSHAD (i64) +-61: POPA/POPAD (i64) +-62: BOUND Gv,Ma (i64) | EVEX (Prefix) +-63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) +-64: SEG=FS (Prefix) +-65: SEG=GS (Prefix) +-66: Operand-Size (Prefix) +-67: Address-Size (Prefix) +-68: PUSH Iz (d64) +-69: IMUL Gv,Ev,Iz +-6a: PUSH Ib (d64) +-6b: IMUL Gv,Ev,Ib +-6c: INS/INSB Yb,DX +-6d: INS/INSW/INSD Yz,DX +-6e: OUTS/OUTSB DX,Xb +-6f: OUTS/OUTSW/OUTSD DX,Xz +-# 0x70 - 0x7f +-70: JO Jb +-71: JNO Jb +-72: JB/JNAE/JC Jb +-73: JNB/JAE/JNC Jb +-74: JZ/JE Jb +-75: JNZ/JNE Jb +-76: JBE/JNA Jb +-77: JNBE/JA Jb +-78: JS Jb +-79: JNS Jb +-7a: JP/JPE Jb +-7b: JNP/JPO Jb +-7c: JL/JNGE Jb +-7d: JNL/JGE Jb +-7e: JLE/JNG Jb +-7f: JNLE/JG Jb +-# 0x80 - 0x8f +-80: Grp1 Eb,Ib (1A) +-81: Grp1 Ev,Iz (1A) +-82: Grp1 Eb,Ib (1A),(i64) +-83: Grp1 Ev,Ib (1A) +-84: TEST Eb,Gb +-85: TEST Ev,Gv +-86: XCHG Eb,Gb +-87: XCHG Ev,Gv +-88: MOV Eb,Gb +-89: MOV Ev,Gv +-8a: MOV Gb,Eb +-8b: MOV Gv,Ev +-8c: MOV Ev,Sw +-8d: LEA Gv,M +-8e: MOV Sw,Ew +-8f: Grp1A (1A) | POP Ev (d64) +-# 0x90 - 0x9f +-90: NOP | PAUSE (F3) | XCHG r8,rAX +-91: XCHG rCX/r9,rAX +-92: XCHG rDX/r10,rAX +-93: XCHG rBX/r11,rAX +-94: XCHG rSP/r12,rAX +-95: XCHG rBP/r13,rAX +-96: XCHG rSI/r14,rAX +-97: XCHG rDI/r15,rAX +-98: CBW/CWDE/CDQE +-99: CWD/CDQ/CQO +-9a: CALLF Ap (i64) +-9b: FWAIT/WAIT +-9c: PUSHF/D/Q Fv (d64) +-9d: POPF/D/Q Fv (d64) +-9e: SAHF +-9f: LAHF +-# 0xa0 - 0xaf +-a0: MOV AL,Ob +-a1: MOV rAX,Ov +-a2: MOV Ob,AL +-a3: MOV Ov,rAX +-a4: MOVS/B Yb,Xb +-a5: MOVS/W/D/Q Yv,Xv +-a6: CMPS/B Xb,Yb +-a7: CMPS/W/D Xv,Yv +-a8: TEST AL,Ib +-a9: TEST rAX,Iz +-aa: STOS/B Yb,AL +-ab: STOS/W/D/Q Yv,rAX +-ac: LODS/B AL,Xb +-ad: LODS/W/D/Q rAX,Xv +-ae: SCAS/B AL,Yb +-# Note: The May 2011 Intel manual shows Xv for the second parameter of the +-# next instruction but Yv is correct +-af: SCAS/W/D/Q rAX,Yv +-# 0xb0 - 0xbf +-b0: MOV AL/R8L,Ib +-b1: MOV CL/R9L,Ib +-b2: MOV DL/R10L,Ib +-b3: MOV BL/R11L,Ib +-b4: MOV AH/R12L,Ib +-b5: MOV CH/R13L,Ib +-b6: MOV DH/R14L,Ib +-b7: MOV BH/R15L,Ib +-b8: MOV rAX/r8,Iv +-b9: MOV rCX/r9,Iv +-ba: MOV rDX/r10,Iv +-bb: MOV rBX/r11,Iv +-bc: MOV rSP/r12,Iv +-bd: MOV rBP/r13,Iv +-be: MOV rSI/r14,Iv +-bf: MOV rDI/r15,Iv +-# 0xc0 - 0xcf +-c0: Grp2 Eb,Ib (1A) +-c1: Grp2 Ev,Ib (1A) +-c2: RETN Iw (f64) +-c3: RETN +-c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) +-c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) +-c6: Grp11A Eb,Ib (1A) +-c7: Grp11B Ev,Iz (1A) +-c8: ENTER Iw,Ib +-c9: LEAVE (d64) +-ca: RETF Iw +-cb: RETF +-cc: INT3 +-cd: INT Ib +-ce: INTO (i64) +-cf: IRET/D/Q +-# 0xd0 - 0xdf +-d0: Grp2 Eb,1 (1A) +-d1: Grp2 Ev,1 (1A) +-d2: Grp2 Eb,CL (1A) +-d3: Grp2 Ev,CL (1A) +-d4: AAM Ib (i64) +-d5: AAD Ib (i64) +-d6: +-d7: XLAT/XLATB +-d8: ESC +-d9: ESC +-da: ESC +-db: ESC +-dc: ESC +-dd: ESC +-de: ESC +-df: ESC +-# 0xe0 - 0xef +-# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix +-# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation +-# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD. +-e0: LOOPNE/LOOPNZ Jb (f64) +-e1: LOOPE/LOOPZ Jb (f64) +-e2: LOOP Jb (f64) +-e3: JrCXZ Jb (f64) +-e4: IN AL,Ib +-e5: IN eAX,Ib +-e6: OUT Ib,AL +-e7: OUT Ib,eAX +-# With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset +-# in "near" jumps and calls is 16-bit. For CALL, +-# push of return address is 16-bit wide, RSP is decremented by 2 +-# but is not truncated to 16 bits, unlike RIP. +-e8: CALL Jz (f64) +-e9: JMP-near Jz (f64) +-ea: JMP-far Ap (i64) +-eb: JMP-short Jb (f64) +-ec: IN AL,DX +-ed: IN eAX,DX +-ee: OUT DX,AL +-ef: OUT DX,eAX +-# 0xf0 - 0xff +-f0: LOCK (Prefix) +-f1: +-f2: REPNE (Prefix) | XACQUIRE (Prefix) +-f3: REP/REPE (Prefix) | XRELEASE (Prefix) +-f4: HLT +-f5: CMC +-f6: Grp3_1 Eb (1A) +-f7: Grp3_2 Ev (1A) +-f8: CLC +-f9: STC +-fa: CLI +-fb: STI +-fc: CLD +-fd: STD +-fe: Grp4 (1A) +-ff: Grp5 (1A) +-EndTable +- +-Table: 2-byte opcode (0x0f) +-Referrer: 2-byte escape +-AVXcode: 1 +-# 0x0f 0x00-0x0f +-00: Grp6 (1A) +-01: Grp7 (1A) +-02: LAR Gv,Ew +-03: LSL Gv,Ew +-04: +-05: SYSCALL (o64) +-06: CLTS +-07: SYSRET (o64) +-08: INVD +-09: WBINVD +-0a: +-0b: UD2 (1B) +-0c: +-# AMD's prefetch group. Intel supports prefetchw(/1) only. +-0d: GrpP +-0e: FEMMS +-# 3DNow! uses the last imm byte as opcode extension. +-0f: 3DNow! Pq,Qq,Ib +-# 0x0f 0x10-0x1f +-# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands +-# but it actually has operands. And also, vmovss and vmovsd only accept 128bit. +-# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. +-# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming +-# Reference A.1 +-10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) +-11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) +-12: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2) +-13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) +-14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) +-15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) +-16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) +-17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) +-18: Grp16 (1A) +-19: +-# Intel SDM opcode map does not list MPX instructions. For now using Gv for +-# bnd registers and Ev for everything else is OK because the instruction +-# decoder does not use the information except as an indication that there is +-# a ModR/M byte. +-1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev +-1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv +-1c: +-1d: +-1e: +-1f: NOP Ev +-# 0x0f 0x20-0x2f +-20: MOV Rd,Cd +-21: MOV Rd,Dd +-22: MOV Cd,Rd +-23: MOV Dd,Rd +-24: +-25: +-26: +-27: +-28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) +-29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) +-2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) +-2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) +-2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) +-2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) +-2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) +-2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) +-# 0x0f 0x30-0x3f +-30: WRMSR +-31: RDTSC +-32: RDMSR +-33: RDPMC +-34: SYSENTER +-35: SYSEXIT +-36: +-37: GETSEC +-38: escape # 3-byte escape 1 +-39: +-3a: escape # 3-byte escape 2 +-3b: +-3c: +-3d: +-3e: +-3f: +-# 0x0f 0x40-0x4f +-40: CMOVO Gv,Ev +-41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) +-42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) +-43: CMOVAE/NB/NC Gv,Ev +-44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) +-45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) +-46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) +-47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) +-48: CMOVS Gv,Ev +-49: CMOVNS Gv,Ev +-4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) +-4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk +-4c: CMOVL/NGE Gv,Ev +-4d: CMOVNL/GE Gv,Ev +-4e: CMOVLE/NG Gv,Ev +-4f: CMOVNLE/G Gv,Ev +-# 0x0f 0x50-0x5f +-50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) +-51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) +-52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) +-53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) +-54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) +-55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) +-56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) +-57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) +-58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) +-59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) +-5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) +-5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) +-5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) +-5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) +-5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) +-5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) +-# 0x0f 0x60-0x6f +-60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) +-61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) +-62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) +-63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) +-64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) +-65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) +-66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) +-67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) +-68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) +-69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) +-6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) +-6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) +-6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) +-6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) +-6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) +-6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqa32/64 Vx,Wx (66),(evo) | vmovdqu Vx,Wx (F3) | vmovdqu32/64 Vx,Wx (F3),(evo) | vmovdqu8/16 Vx,Wx (F2),(ev) +-# 0x0f 0x70-0x7f +-70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) +-71: Grp12 (1A) +-72: Grp13 (1A) +-73: Grp14 (1A) +-74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) +-75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) +-76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) +-# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. +-77: emms | vzeroupper | vzeroall +-78: VMREAD Ey,Gy | vcvttps2udq/pd2udq Vx,Wpd (evo) | vcvttsd2usi Gv,Wx (F2),(ev) | vcvttss2usi Gv,Wx (F3),(ev) | vcvttps2uqq/pd2uqq Vx,Wx (66),(ev) +-79: VMWRITE Gy,Ey | vcvtps2udq/pd2udq Vx,Wpd (evo) | vcvtsd2usi Gv,Wx (F2),(ev) | vcvtss2usi Gv,Wx (F3),(ev) | vcvtps2uqq/pd2uqq Vx,Wx (66),(ev) +-7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) +-7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) +-7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) +-7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) +-7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) +-7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev) +-# 0x0f 0x80-0x8f +-# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). +-80: JO Jz (f64) +-81: JNO Jz (f64) +-82: JB/JC/JNAE Jz (f64) +-83: JAE/JNB/JNC Jz (f64) +-84: JE/JZ Jz (f64) +-85: JNE/JNZ Jz (f64) +-86: JBE/JNA Jz (f64) +-87: JA/JNBE Jz (f64) +-88: JS Jz (f64) +-89: JNS Jz (f64) +-8a: JP/JPE Jz (f64) +-8b: JNP/JPO Jz (f64) +-8c: JL/JNGE Jz (f64) +-8d: JNL/JGE Jz (f64) +-8e: JLE/JNG Jz (f64) +-8f: JNLE/JG Jz (f64) +-# 0x0f 0x90-0x9f +-90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) +-91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) +-92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) +-93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) +-94: SETE/Z Eb +-95: SETNE/NZ Eb +-96: SETBE/NA Eb +-97: SETA/NBE Eb +-98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) +-99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) +-9a: SETP/PE Eb +-9b: SETNP/PO Eb +-9c: SETL/NGE Eb +-9d: SETNL/GE Eb +-9e: SETLE/NG Eb +-9f: SETNLE/G Eb +-# 0x0f 0xa0-0xaf +-a0: PUSH FS (d64) +-a1: POP FS (d64) +-a2: CPUID +-a3: BT Ev,Gv +-a4: SHLD Ev,Gv,Ib +-a5: SHLD Ev,Gv,CL +-a6: GrpPDLK +-a7: GrpRNG +-a8: PUSH GS (d64) +-a9: POP GS (d64) +-aa: RSM +-ab: BTS Ev,Gv +-ac: SHRD Ev,Gv,Ib +-ad: SHRD Ev,Gv,CL +-ae: Grp15 (1A),(1C) +-af: IMUL Gv,Ev +-# 0x0f 0xb0-0xbf +-b0: CMPXCHG Eb,Gb +-b1: CMPXCHG Ev,Gv +-b2: LSS Gv,Mp +-b3: BTR Ev,Gv +-b4: LFS Gv,Mp +-b5: LGS Gv,Mp +-b6: MOVZX Gv,Eb +-b7: MOVZX Gv,Ew +-b8: JMPE (!F3) | POPCNT Gv,Ev (F3) +-b9: Grp10 (1A) +-ba: Grp8 Ev,Ib (1A) +-bb: BTC Ev,Gv +-bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) +-bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) +-be: MOVSX Gv,Eb +-bf: MOVSX Gv,Ew +-# 0x0f 0xc0-0xcf +-c0: XADD Eb,Gb +-c1: XADD Ev,Gv +-c2: vcmpps Vps,Hps,Wps,Ib | vcmppd Vpd,Hpd,Wpd,Ib (66) | vcmpss Vss,Hss,Wss,Ib (F3),(v1) | vcmpsd Vsd,Hsd,Wsd,Ib (F2),(v1) +-c3: movnti My,Gy +-c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) +-c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) +-c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) +-c7: Grp9 (1A) +-c8: BSWAP RAX/EAX/R8/R8D +-c9: BSWAP RCX/ECX/R9/R9D +-ca: BSWAP RDX/EDX/R10/R10D +-cb: BSWAP RBX/EBX/R11/R11D +-cc: BSWAP RSP/ESP/R12/R12D +-cd: BSWAP RBP/EBP/R13/R13D +-ce: BSWAP RSI/ESI/R14/R14D +-cf: BSWAP RDI/EDI/R15/R15D +-# 0x0f 0xd0-0xdf +-d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) +-d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) +-d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) +-d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) +-d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) +-d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) +-d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) +-d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) +-d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) +-d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) +-da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) +-db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) +-dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) +-dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) +-de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) +-df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) +-# 0x0f 0xe0-0xef +-e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) +-e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) +-e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) +-e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) +-e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) +-e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) +-e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) +-e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) +-e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) +-e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) +-ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) +-eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) +-ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) +-ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) +-ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) +-ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) +-# 0x0f 0xf0-0xff +-f0: vlddqu Vx,Mx (F2) +-f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) +-f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) +-f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) +-f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) +-f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) +-f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) +-f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) +-f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) +-f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) +-fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) +-fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) +-fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) +-fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) +-fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) +-ff: +-EndTable +- +-Table: 3-byte opcode 1 (0x0f 0x38) +-Referrer: 3-byte escape 1 +-AVXcode: 2 +-# 0x0f 0x38 0x00-0x0f +-00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) +-01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) +-02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) +-03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) +-04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) +-05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) +-06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) +-07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) +-08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) +-09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) +-0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) +-0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) +-0c: vpermilps Vx,Hx,Wx (66),(v) +-0d: vpermilpd Vx,Hx,Wx (66),(v) +-0e: vtestps Vx,Wx (66),(v) +-0f: vtestpd Vx,Wx (66),(v) +-# 0x0f 0x38 0x10-0x1f +-10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) +-11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) +-12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) +-13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) +-14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) +-15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) +-16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) +-17: vptest Vx,Wx (66) +-18: vbroadcastss Vx,Wd (66),(v) +-19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) +-1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) +-1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) +-1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) +-1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) +-1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) +-1f: vpabsq Vx,Wx (66),(ev) +-# 0x0f 0x38 0x20-0x2f +-20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) +-21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) +-22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) +-23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) +-24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) +-25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) +-26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) +-27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) +-28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) +-29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) +-2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) +-2b: vpackusdw Vx,Hx,Wx (66),(v1) +-2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) +-2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) +-2e: vmaskmovps Mx,Hx,Vx (66),(v) +-2f: vmaskmovpd Mx,Hx,Vx (66),(v) +-# 0x0f 0x38 0x30-0x3f +-30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) +-31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) +-32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) +-33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) +-34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) +-35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) +-36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) +-37: vpcmpgtq Vx,Hx,Wx (66),(v1) +-38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) +-39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) +-3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) +-3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) +-3c: vpmaxsb Vx,Hx,Wx (66),(v1) +-3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) +-3e: vpmaxuw Vx,Hx,Wx (66),(v1) +-3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) +-# 0x0f 0x38 0x40-0x8f +-40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) +-41: vphminposuw Vdq,Wdq (66),(v1) +-42: vgetexpps/d Vx,Wx (66),(ev) +-43: vgetexpss/d Vx,Hx,Wx (66),(ev) +-44: vplzcntd/q Vx,Wx (66),(ev) +-45: vpsrlvd/q Vx,Hx,Wx (66),(v) +-46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) +-47: vpsllvd/q Vx,Hx,Wx (66),(v) +-# Skip 0x48-0x4b +-4c: vrcp14ps/d Vpd,Wpd (66),(ev) +-4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) +-4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) +-4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) +-# Skip 0x50-0x57 +-58: vpbroadcastd Vx,Wx (66),(v) +-59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) +-5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) +-5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) +-# Skip 0x5c-0x63 +-64: vpblendmd/q Vx,Hx,Wx (66),(ev) +-65: vblendmps/d Vx,Hx,Wx (66),(ev) +-66: vpblendmb/w Vx,Hx,Wx (66),(ev) +-# Skip 0x67-0x74 +-75: vpermi2b/w Vx,Hx,Wx (66),(ev) +-76: vpermi2d/q Vx,Hx,Wx (66),(ev) +-77: vpermi2ps/d Vx,Hx,Wx (66),(ev) +-78: vpbroadcastb Vx,Wx (66),(v) +-79: vpbroadcastw Vx,Wx (66),(v) +-7a: vpbroadcastb Vx,Rv (66),(ev) +-7b: vpbroadcastw Vx,Rv (66),(ev) +-7c: vpbroadcastd/q Vx,Rv (66),(ev) +-7d: vpermt2b/w Vx,Hx,Wx (66),(ev) +-7e: vpermt2d/q Vx,Hx,Wx (66),(ev) +-7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) +-80: INVEPT Gy,Mdq (66) +-81: INVPID Gy,Mdq (66) +-82: INVPCID Gy,Mdq (66) +-83: vpmultishiftqb Vx,Hx,Wx (66),(ev) +-88: vexpandps/d Vpd,Wpd (66),(ev) +-89: vpexpandd/q Vx,Wx (66),(ev) +-8a: vcompressps/d Wx,Vx (66),(ev) +-8b: vpcompressd/q Wx,Vx (66),(ev) +-8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) +-8d: vpermb/w Vx,Hx,Wx (66),(ev) +-8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) +-# 0x0f 0x38 0x90-0xbf (FMA) +-90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) +-91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) +-92: vgatherdps/d Vx,Hx,Wx (66),(v) +-93: vgatherqps/d Vx,Hx,Wx (66),(v) +-94: +-95: +-96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) +-97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) +-98: vfmadd132ps/d Vx,Hx,Wx (66),(v) +-99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) +-9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) +-9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) +-9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) +-9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) +-9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) +-9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) +-a0: vpscatterdd/q Wx,Vx (66),(ev) +-a1: vpscatterqd/q Wx,Vx (66),(ev) +-a2: vscatterdps/d Wx,Vx (66),(ev) +-a3: vscatterqps/d Wx,Vx (66),(ev) +-a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) +-a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) +-a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) +-a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) +-aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) +-ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) +-ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) +-ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) +-ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) +-af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) +-b4: vpmadd52luq Vx,Hx,Wx (66),(ev) +-b5: vpmadd52huq Vx,Hx,Wx (66),(ev) +-b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) +-b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) +-b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) +-b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) +-ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) +-bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) +-bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) +-bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) +-be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) +-bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) +-# 0x0f 0x38 0xc0-0xff +-c4: vpconflictd/q Vx,Wx (66),(ev) +-c6: Grp18 (1A) +-c7: Grp19 (1A) +-c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) +-c9: sha1msg1 Vdq,Wdq +-ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) +-cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) +-cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) +-cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) +-db: VAESIMC Vdq,Wdq (66),(v1) +-dc: VAESENC Vdq,Hdq,Wdq (66),(v1) +-dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) +-de: VAESDEC Vdq,Hdq,Wdq (66),(v1) +-df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) +-f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) +-f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) +-f2: ANDN Gy,By,Ey (v) +-f3: Grp17 (1A) +-f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) +-f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) +-f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) +-EndTable +- +-Table: 3-byte opcode 2 (0x0f 0x3a) +-Referrer: 3-byte escape 2 +-AVXcode: 3 +-# 0x0f 0x3a 0x00-0xff +-00: vpermq Vqq,Wqq,Ib (66),(v) +-01: vpermpd Vqq,Wqq,Ib (66),(v) +-02: vpblendd Vx,Hx,Wx,Ib (66),(v) +-03: valignd/q Vx,Hx,Wx,Ib (66),(ev) +-04: vpermilps Vx,Wx,Ib (66),(v) +-05: vpermilpd Vx,Wx,Ib (66),(v) +-06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) +-07: +-08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) +-09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) +-0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) +-0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) +-0c: vblendps Vx,Hx,Wx,Ib (66) +-0d: vblendpd Vx,Hx,Wx,Ib (66) +-0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) +-0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) +-14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) +-15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) +-16: vpextrd/q Ey,Vdq,Ib (66),(v1) +-17: vextractps Ed,Vdq,Ib (66),(v1) +-18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) +-19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) +-1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) +-1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) +-1d: vcvtps2ph Wx,Vx,Ib (66),(v) +-1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) +-1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) +-20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) +-21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) +-22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) +-23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) +-25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) +-26: vgetmantps/d Vx,Wx,Ib (66),(ev) +-27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) +-30: kshiftrb/w Vk,Uk,Ib (66),(v) +-31: kshiftrd/q Vk,Uk,Ib (66),(v) +-32: kshiftlb/w Vk,Uk,Ib (66),(v) +-33: kshiftld/q Vk,Uk,Ib (66),(v) +-38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) +-39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) +-3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) +-3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) +-3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) +-3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) +-40: vdpps Vx,Hx,Wx,Ib (66) +-41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) +-42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) +-43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) +-44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) +-46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) +-4a: vblendvps Vx,Hx,Wx,Lx (66),(v) +-4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) +-4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) +-50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) +-51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) +-54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) +-55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) +-56: vreduceps/d Vx,Wx,Ib (66),(ev) +-57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) +-60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) +-61: vpcmpestri Vdq,Wdq,Ib (66),(v1) +-62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) +-63: vpcmpistri Vdq,Wdq,Ib (66),(v1) +-66: vfpclassps/d Vk,Wx,Ib (66),(ev) +-67: vfpclassss/d Vk,Wx,Ib (66),(ev) +-cc: sha1rnds4 Vdq,Wdq,Ib +-df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) +-f0: RORX Gy,Ey,Ib (F2),(v) +-EndTable +- +-GrpTable: Grp1 +-0: ADD +-1: OR +-2: ADC +-3: SBB +-4: AND +-5: SUB +-6: XOR +-7: CMP +-EndTable +- +-GrpTable: Grp1A +-0: POP +-EndTable +- +-GrpTable: Grp2 +-0: ROL +-1: ROR +-2: RCL +-3: RCR +-4: SHL/SAL +-5: SHR +-6: +-7: SAR +-EndTable +- +-GrpTable: Grp3_1 +-0: TEST Eb,Ib +-1: TEST Eb,Ib +-2: NOT Eb +-3: NEG Eb +-4: MUL AL,Eb +-5: IMUL AL,Eb +-6: DIV AL,Eb +-7: IDIV AL,Eb +-EndTable +- +-GrpTable: Grp3_2 +-0: TEST Ev,Iz +-1: +-2: NOT Ev +-3: NEG Ev +-4: MUL rAX,Ev +-5: IMUL rAX,Ev +-6: DIV rAX,Ev +-7: IDIV rAX,Ev +-EndTable +- +-GrpTable: Grp4 +-0: INC Eb +-1: DEC Eb +-EndTable +- +-GrpTable: Grp5 +-0: INC Ev +-1: DEC Ev +-# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). +-2: CALLN Ev (f64) +-3: CALLF Ep +-4: JMPN Ev (f64) +-5: JMPF Mp +-6: PUSH Ev (d64) +-7: +-EndTable +- +-GrpTable: Grp6 +-0: SLDT Rv/Mw +-1: STR Rv/Mw +-2: LLDT Ew +-3: LTR Ew +-4: VERR Ew +-5: VERW Ew +-EndTable +- +-GrpTable: Grp7 +-0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) +-1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) +-2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) +-3: LIDT Ms +-4: SMSW Mw/Rv +-5: rdpkru (110),(11B) | wrpkru (111),(11B) +-6: LMSW Ew +-7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) +-EndTable +- +-GrpTable: Grp8 +-4: BT +-5: BTS +-6: BTR +-7: BTC +-EndTable +- +-GrpTable: Grp9 +-1: CMPXCHG8B/16B Mq/Mdq +-3: xrstors +-4: xsavec +-5: xsaves +-6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) +-7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) +-EndTable +- +-GrpTable: Grp10 +-EndTable +- +-# Grp11A and Grp11B are expressed as Grp11 in Intel SDM +-GrpTable: Grp11A +-0: MOV Eb,Ib +-7: XABORT Ib (000),(11B) +-EndTable +- +-GrpTable: Grp11B +-0: MOV Eb,Iz +-7: XBEGIN Jz (000),(11B) +-EndTable +- +-GrpTable: Grp12 +-2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) +-4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) +-6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) +-EndTable +- +-GrpTable: Grp13 +-0: vprord/q Hx,Wx,Ib (66),(ev) +-1: vprold/q Hx,Wx,Ib (66),(ev) +-2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) +-4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) +-6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) +-EndTable +- +-GrpTable: Grp14 +-2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) +-3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) +-6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) +-7: vpslldq Hx,Ux,Ib (66),(11B),(v1) +-EndTable +- +-GrpTable: Grp15 +-0: fxsave | RDFSBASE Ry (F3),(11B) +-1: fxstor | RDGSBASE Ry (F3),(11B) +-2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) +-3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) +-4: XSAVE +-5: XRSTOR | lfence (11B) +-6: XSAVEOPT | clwb (66) | mfence (11B) +-7: clflush | clflushopt (66) | sfence (11B) +-EndTable +- +-GrpTable: Grp16 +-0: prefetch NTA +-1: prefetch T0 +-2: prefetch T1 +-3: prefetch T2 +-EndTable +- +-GrpTable: Grp17 +-1: BLSR By,Ey (v) +-2: BLSMSK By,Ey (v) +-3: BLSI By,Ey (v) +-EndTable +- +-GrpTable: Grp18 +-1: vgatherpf0dps/d Wx (66),(ev) +-2: vgatherpf1dps/d Wx (66),(ev) +-5: vscatterpf0dps/d Wx (66),(ev) +-6: vscatterpf1dps/d Wx (66),(ev) +-EndTable +- +-GrpTable: Grp19 +-1: vgatherpf0qps/d Wx (66),(ev) +-2: vgatherpf1qps/d Wx (66),(ev) +-5: vscatterpf0qps/d Wx (66),(ev) +-6: vscatterpf1qps/d Wx (66),(ev) +-EndTable +- +-# AMD's Prefetch Group +-GrpTable: GrpP +-0: PREFETCH +-1: PREFETCHW +-EndTable +- +-GrpTable: GrpPDLK +-0: MONTMUL +-1: XSHA1 +-2: XSHA2 +-EndTable +- +-GrpTable: GrpRNG +-0: xstore-rng +-1: xcrypt-ecb +-2: xcrypt-cbc +-4: xcrypt-cfb +-5: xcrypt-ofb +-EndTable +diff --git a/tools/objtool/arch/x86/lib/inat.c b/tools/objtool/arch/x86/lib/inat.c +new file mode 100644 +index 000000000000..c1f01a8e9f65 +--- /dev/null ++++ b/tools/objtool/arch/x86/lib/inat.c +@@ -0,0 +1,97 @@ ++/* ++ * x86 instruction attribute tables ++ * ++ * Written by Masami Hiramatsu ++ * ++ * 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. ++ * ++ */ ++#include ++ ++/* Attribute tables are generated from opcode map */ ++#include "inat-tables.c" ++ ++/* Attribute search APIs */ ++insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) ++{ ++ return inat_primary_table[opcode]; ++} ++ ++int inat_get_last_prefix_id(insn_byte_t last_pfx) ++{ ++ insn_attr_t lpfx_attr; ++ ++ lpfx_attr = inat_get_opcode_attribute(last_pfx); ++ return inat_last_prefix_id(lpfx_attr); ++} ++ ++insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, ++ insn_attr_t esc_attr) ++{ ++ const insn_attr_t *table; ++ int n; ++ ++ n = inat_escape_id(esc_attr); ++ ++ table = inat_escape_tables[n][0]; ++ if (!table) ++ return 0; ++ if (inat_has_variant(table[opcode]) && lpfx_id) { ++ table = inat_escape_tables[n][lpfx_id]; ++ if (!table) ++ return 0; ++ } ++ return table[opcode]; ++} ++ ++insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, ++ insn_attr_t grp_attr) ++{ ++ const insn_attr_t *table; ++ int n; ++ ++ n = inat_group_id(grp_attr); ++ ++ table = inat_group_tables[n][0]; ++ if (!table) ++ return inat_group_common_attribute(grp_attr); ++ if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { ++ table = inat_group_tables[n][lpfx_id]; ++ if (!table) ++ return inat_group_common_attribute(grp_attr); ++ } ++ return table[X86_MODRM_REG(modrm)] | ++ inat_group_common_attribute(grp_attr); ++} ++ ++insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, ++ insn_byte_t vex_p) ++{ ++ const insn_attr_t *table; ++ if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) ++ return 0; ++ /* At first, this checks the master table */ ++ table = inat_avx_tables[vex_m][0]; ++ if (!table) ++ return 0; ++ if (!inat_is_group(table[opcode]) && vex_p) { ++ /* If this is not a group, get attribute directly */ ++ table = inat_avx_tables[vex_m][vex_p]; ++ if (!table) ++ return 0; ++ } ++ return table[opcode]; ++} ++ +diff --git a/tools/objtool/arch/x86/lib/insn.c b/tools/objtool/arch/x86/lib/insn.c +new file mode 100644 +index 000000000000..1088eb8f3a5f +--- /dev/null ++++ b/tools/objtool/arch/x86/lib/insn.c +@@ -0,0 +1,606 @@ ++/* ++ * x86 instruction analysis ++ * ++ * 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. ++ * ++ * Copyright (C) IBM Corporation, 2002, 2004, 2009 ++ */ ++ ++#ifdef __KERNEL__ ++#include ++#else ++#include ++#endif ++#include ++#include ++ ++/* Verify next sizeof(t) bytes can be on the same instruction */ ++#define validate_next(t, insn, n) \ ++ ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) ++ ++#define __get_next(t, insn) \ ++ ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) ++ ++#define __peek_nbyte_next(t, insn, n) \ ++ ({ t r = *(t*)((insn)->next_byte + n); r; }) ++ ++#define get_next(t, insn) \ ++ ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) ++ ++#define peek_nbyte_next(t, insn, n) \ ++ ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) ++ ++#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) ++ ++/** ++ * insn_init() - initialize struct insn ++ * @insn: &struct insn to be initialized ++ * @kaddr: address (in kernel memory) of instruction (or copy thereof) ++ * @x86_64: !0 for 64-bit kernel or 64-bit app ++ */ ++void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) ++{ ++ /* ++ * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid ++ * even if the input buffer is long enough to hold them. ++ */ ++ if (buf_len > MAX_INSN_SIZE) ++ buf_len = MAX_INSN_SIZE; ++ ++ memset(insn, 0, sizeof(*insn)); ++ insn->kaddr = kaddr; ++ insn->end_kaddr = kaddr + buf_len; ++ insn->next_byte = kaddr; ++ insn->x86_64 = x86_64 ? 1 : 0; ++ insn->opnd_bytes = 4; ++ if (x86_64) ++ insn->addr_bytes = 8; ++ else ++ insn->addr_bytes = 4; ++} ++ ++/** ++ * insn_get_prefixes - scan x86 instruction prefix bytes ++ * @insn: &struct insn containing instruction ++ * ++ * Populates the @insn->prefixes bitmap, and updates @insn->next_byte ++ * to point to the (first) opcode. No effect if @insn->prefixes.got ++ * is already set. ++ */ ++void insn_get_prefixes(struct insn *insn) ++{ ++ struct insn_field *prefixes = &insn->prefixes; ++ insn_attr_t attr; ++ insn_byte_t b, lb; ++ int i, nb; ++ ++ if (prefixes->got) ++ return; ++ ++ nb = 0; ++ lb = 0; ++ b = peek_next(insn_byte_t, insn); ++ attr = inat_get_opcode_attribute(b); ++ while (inat_is_legacy_prefix(attr)) { ++ /* Skip if same prefix */ ++ for (i = 0; i < nb; i++) ++ if (prefixes->bytes[i] == b) ++ goto found; ++ if (nb == 4) ++ /* Invalid instruction */ ++ break; ++ prefixes->bytes[nb++] = b; ++ if (inat_is_address_size_prefix(attr)) { ++ /* address size switches 2/4 or 4/8 */ ++ if (insn->x86_64) ++ insn->addr_bytes ^= 12; ++ else ++ insn->addr_bytes ^= 6; ++ } else if (inat_is_operand_size_prefix(attr)) { ++ /* oprand size switches 2/4 */ ++ insn->opnd_bytes ^= 6; ++ } ++found: ++ prefixes->nbytes++; ++ insn->next_byte++; ++ lb = b; ++ b = peek_next(insn_byte_t, insn); ++ attr = inat_get_opcode_attribute(b); ++ } ++ /* Set the last prefix */ ++ if (lb && lb != insn->prefixes.bytes[3]) { ++ if (unlikely(insn->prefixes.bytes[3])) { ++ /* Swap the last prefix */ ++ b = insn->prefixes.bytes[3]; ++ for (i = 0; i < nb; i++) ++ if (prefixes->bytes[i] == lb) ++ prefixes->bytes[i] = b; ++ } ++ insn->prefixes.bytes[3] = lb; ++ } ++ ++ /* Decode REX prefix */ ++ if (insn->x86_64) { ++ b = peek_next(insn_byte_t, insn); ++ attr = inat_get_opcode_attribute(b); ++ if (inat_is_rex_prefix(attr)) { ++ insn->rex_prefix.value = b; ++ insn->rex_prefix.nbytes = 1; ++ insn->next_byte++; ++ if (X86_REX_W(b)) ++ /* REX.W overrides opnd_size */ ++ insn->opnd_bytes = 8; ++ } ++ } ++ insn->rex_prefix.got = 1; ++ ++ /* Decode VEX prefix */ ++ b = peek_next(insn_byte_t, insn); ++ attr = inat_get_opcode_attribute(b); ++ if (inat_is_vex_prefix(attr)) { ++ insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); ++ if (!insn->x86_64) { ++ /* ++ * In 32-bits mode, if the [7:6] bits (mod bits of ++ * ModRM) on the second byte are not 11b, it is ++ * LDS or LES or BOUND. ++ */ ++ if (X86_MODRM_MOD(b2) != 3) ++ goto vex_end; ++ } ++ insn->vex_prefix.bytes[0] = b; ++ insn->vex_prefix.bytes[1] = b2; ++ if (inat_is_evex_prefix(attr)) { ++ b2 = peek_nbyte_next(insn_byte_t, insn, 2); ++ insn->vex_prefix.bytes[2] = b2; ++ b2 = peek_nbyte_next(insn_byte_t, insn, 3); ++ insn->vex_prefix.bytes[3] = b2; ++ insn->vex_prefix.nbytes = 4; ++ insn->next_byte += 4; ++ if (insn->x86_64 && X86_VEX_W(b2)) ++ /* VEX.W overrides opnd_size */ ++ insn->opnd_bytes = 8; ++ } else if (inat_is_vex3_prefix(attr)) { ++ b2 = peek_nbyte_next(insn_byte_t, insn, 2); ++ insn->vex_prefix.bytes[2] = b2; ++ insn->vex_prefix.nbytes = 3; ++ insn->next_byte += 3; ++ if (insn->x86_64 && X86_VEX_W(b2)) ++ /* VEX.W overrides opnd_size */ ++ insn->opnd_bytes = 8; ++ } else { ++ /* ++ * For VEX2, fake VEX3-like byte#2. ++ * Makes it easier to decode vex.W, vex.vvvv, ++ * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. ++ */ ++ insn->vex_prefix.bytes[2] = b2 & 0x7f; ++ insn->vex_prefix.nbytes = 2; ++ insn->next_byte += 2; ++ } ++ } ++vex_end: ++ insn->vex_prefix.got = 1; ++ ++ prefixes->got = 1; ++ ++err_out: ++ return; ++} ++ ++/** ++ * insn_get_opcode - collect opcode(s) ++ * @insn: &struct insn containing instruction ++ * ++ * Populates @insn->opcode, updates @insn->next_byte to point past the ++ * opcode byte(s), and set @insn->attr (except for groups). ++ * If necessary, first collects any preceding (prefix) bytes. ++ * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got ++ * is already 1. ++ */ ++void insn_get_opcode(struct insn *insn) ++{ ++ struct insn_field *opcode = &insn->opcode; ++ insn_byte_t op; ++ int pfx_id; ++ if (opcode->got) ++ return; ++ if (!insn->prefixes.got) ++ insn_get_prefixes(insn); ++ ++ /* Get first opcode */ ++ op = get_next(insn_byte_t, insn); ++ opcode->bytes[0] = op; ++ opcode->nbytes = 1; ++ ++ /* Check if there is VEX prefix or not */ ++ if (insn_is_avx(insn)) { ++ insn_byte_t m, p; ++ m = insn_vex_m_bits(insn); ++ p = insn_vex_p_bits(insn); ++ insn->attr = inat_get_avx_attribute(op, m, p); ++ if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || ++ (!inat_accept_vex(insn->attr) && ++ !inat_is_group(insn->attr))) ++ insn->attr = 0; /* This instruction is bad */ ++ goto end; /* VEX has only 1 byte for opcode */ ++ } ++ ++ insn->attr = inat_get_opcode_attribute(op); ++ while (inat_is_escape(insn->attr)) { ++ /* Get escaped opcode */ ++ op = get_next(insn_byte_t, insn); ++ opcode->bytes[opcode->nbytes++] = op; ++ pfx_id = insn_last_prefix_id(insn); ++ insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); ++ } ++ if (inat_must_vex(insn->attr)) ++ insn->attr = 0; /* This instruction is bad */ ++end: ++ opcode->got = 1; ++ ++err_out: ++ return; ++} ++ ++/** ++ * insn_get_modrm - collect ModRM byte, if any ++ * @insn: &struct insn containing instruction ++ * ++ * Populates @insn->modrm and updates @insn->next_byte to point past the ++ * ModRM byte, if any. If necessary, first collects the preceding bytes ++ * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. ++ */ ++void insn_get_modrm(struct insn *insn) ++{ ++ struct insn_field *modrm = &insn->modrm; ++ insn_byte_t pfx_id, mod; ++ if (modrm->got) ++ return; ++ if (!insn->opcode.got) ++ insn_get_opcode(insn); ++ ++ if (inat_has_modrm(insn->attr)) { ++ mod = get_next(insn_byte_t, insn); ++ modrm->value = mod; ++ modrm->nbytes = 1; ++ if (inat_is_group(insn->attr)) { ++ pfx_id = insn_last_prefix_id(insn); ++ insn->attr = inat_get_group_attribute(mod, pfx_id, ++ insn->attr); ++ if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) ++ insn->attr = 0; /* This is bad */ ++ } ++ } ++ ++ if (insn->x86_64 && inat_is_force64(insn->attr)) ++ insn->opnd_bytes = 8; ++ modrm->got = 1; ++ ++err_out: ++ return; ++} ++ ++ ++/** ++ * insn_rip_relative() - Does instruction use RIP-relative addressing mode? ++ * @insn: &struct insn containing instruction ++ * ++ * If necessary, first collects the instruction up to and including the ++ * ModRM byte. No effect if @insn->x86_64 is 0. ++ */ ++int insn_rip_relative(struct insn *insn) ++{ ++ struct insn_field *modrm = &insn->modrm; ++ ++ if (!insn->x86_64) ++ return 0; ++ if (!modrm->got) ++ insn_get_modrm(insn); ++ /* ++ * For rip-relative instructions, the mod field (top 2 bits) ++ * is zero and the r/m field (bottom 3 bits) is 0x5. ++ */ ++ return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); ++} ++ ++/** ++ * insn_get_sib() - Get the SIB byte of instruction ++ * @insn: &struct insn containing instruction ++ * ++ * If necessary, first collects the instruction up to and including the ++ * ModRM byte. ++ */ ++void insn_get_sib(struct insn *insn) ++{ ++ insn_byte_t modrm; ++ ++ if (insn->sib.got) ++ return; ++ if (!insn->modrm.got) ++ insn_get_modrm(insn); ++ if (insn->modrm.nbytes) { ++ modrm = (insn_byte_t)insn->modrm.value; ++ if (insn->addr_bytes != 2 && ++ X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { ++ insn->sib.value = get_next(insn_byte_t, insn); ++ insn->sib.nbytes = 1; ++ } ++ } ++ insn->sib.got = 1; ++ ++err_out: ++ return; ++} ++ ++ ++/** ++ * insn_get_displacement() - Get the displacement of instruction ++ * @insn: &struct insn containing instruction ++ * ++ * If necessary, first collects the instruction up to and including the ++ * SIB byte. ++ * Displacement value is sign-expanded. ++ */ ++void insn_get_displacement(struct insn *insn) ++{ ++ insn_byte_t mod, rm, base; ++ ++ if (insn->displacement.got) ++ return; ++ if (!insn->sib.got) ++ insn_get_sib(insn); ++ if (insn->modrm.nbytes) { ++ /* ++ * Interpreting the modrm byte: ++ * mod = 00 - no displacement fields (exceptions below) ++ * mod = 01 - 1-byte displacement field ++ * mod = 10 - displacement field is 4 bytes, or 2 bytes if ++ * address size = 2 (0x67 prefix in 32-bit mode) ++ * mod = 11 - no memory operand ++ * ++ * If address size = 2... ++ * mod = 00, r/m = 110 - displacement field is 2 bytes ++ * ++ * If address size != 2... ++ * mod != 11, r/m = 100 - SIB byte exists ++ * mod = 00, SIB base = 101 - displacement field is 4 bytes ++ * mod = 00, r/m = 101 - rip-relative addressing, displacement ++ * field is 4 bytes ++ */ ++ mod = X86_MODRM_MOD(insn->modrm.value); ++ rm = X86_MODRM_RM(insn->modrm.value); ++ base = X86_SIB_BASE(insn->sib.value); ++ if (mod == 3) ++ goto out; ++ if (mod == 1) { ++ insn->displacement.value = get_next(signed char, insn); ++ insn->displacement.nbytes = 1; ++ } else if (insn->addr_bytes == 2) { ++ if ((mod == 0 && rm == 6) || mod == 2) { ++ insn->displacement.value = ++ get_next(short, insn); ++ insn->displacement.nbytes = 2; ++ } ++ } else { ++ if ((mod == 0 && rm == 5) || mod == 2 || ++ (mod == 0 && base == 5)) { ++ insn->displacement.value = get_next(int, insn); ++ insn->displacement.nbytes = 4; ++ } ++ } ++ } ++out: ++ insn->displacement.got = 1; ++ ++err_out: ++ return; ++} ++ ++/* Decode moffset16/32/64. Return 0 if failed */ ++static int __get_moffset(struct insn *insn) ++{ ++ switch (insn->addr_bytes) { ++ case 2: ++ insn->moffset1.value = get_next(short, insn); ++ insn->moffset1.nbytes = 2; ++ break; ++ case 4: ++ insn->moffset1.value = get_next(int, insn); ++ insn->moffset1.nbytes = 4; ++ break; ++ case 8: ++ insn->moffset1.value = get_next(int, insn); ++ insn->moffset1.nbytes = 4; ++ insn->moffset2.value = get_next(int, insn); ++ insn->moffset2.nbytes = 4; ++ break; ++ default: /* opnd_bytes must be modified manually */ ++ goto err_out; ++ } ++ insn->moffset1.got = insn->moffset2.got = 1; ++ ++ return 1; ++ ++err_out: ++ return 0; ++} ++ ++/* Decode imm v32(Iz). Return 0 if failed */ ++static int __get_immv32(struct insn *insn) ++{ ++ switch (insn->opnd_bytes) { ++ case 2: ++ insn->immediate.value = get_next(short, insn); ++ insn->immediate.nbytes = 2; ++ break; ++ case 4: ++ case 8: ++ insn->immediate.value = get_next(int, insn); ++ insn->immediate.nbytes = 4; ++ break; ++ default: /* opnd_bytes must be modified manually */ ++ goto err_out; ++ } ++ ++ return 1; ++ ++err_out: ++ return 0; ++} ++ ++/* Decode imm v64(Iv/Ov), Return 0 if failed */ ++static int __get_immv(struct insn *insn) ++{ ++ switch (insn->opnd_bytes) { ++ case 2: ++ insn->immediate1.value = get_next(short, insn); ++ insn->immediate1.nbytes = 2; ++ break; ++ case 4: ++ insn->immediate1.value = get_next(int, insn); ++ insn->immediate1.nbytes = 4; ++ break; ++ case 8: ++ insn->immediate1.value = get_next(int, insn); ++ insn->immediate1.nbytes = 4; ++ insn->immediate2.value = get_next(int, insn); ++ insn->immediate2.nbytes = 4; ++ break; ++ default: /* opnd_bytes must be modified manually */ ++ goto err_out; ++ } ++ insn->immediate1.got = insn->immediate2.got = 1; ++ ++ return 1; ++err_out: ++ return 0; ++} ++ ++/* Decode ptr16:16/32(Ap) */ ++static int __get_immptr(struct insn *insn) ++{ ++ switch (insn->opnd_bytes) { ++ case 2: ++ insn->immediate1.value = get_next(short, insn); ++ insn->immediate1.nbytes = 2; ++ break; ++ case 4: ++ insn->immediate1.value = get_next(int, insn); ++ insn->immediate1.nbytes = 4; ++ break; ++ case 8: ++ /* ptr16:64 is not exist (no segment) */ ++ return 0; ++ default: /* opnd_bytes must be modified manually */ ++ goto err_out; ++ } ++ insn->immediate2.value = get_next(unsigned short, insn); ++ insn->immediate2.nbytes = 2; ++ insn->immediate1.got = insn->immediate2.got = 1; ++ ++ return 1; ++err_out: ++ return 0; ++} ++ ++/** ++ * insn_get_immediate() - Get the immediates of instruction ++ * @insn: &struct insn containing instruction ++ * ++ * If necessary, first collects the instruction up to and including the ++ * displacement bytes. ++ * Basically, most of immediates are sign-expanded. Unsigned-value can be ++ * get by bit masking with ((1 << (nbytes * 8)) - 1) ++ */ ++void insn_get_immediate(struct insn *insn) ++{ ++ if (insn->immediate.got) ++ return; ++ if (!insn->displacement.got) ++ insn_get_displacement(insn); ++ ++ if (inat_has_moffset(insn->attr)) { ++ if (!__get_moffset(insn)) ++ goto err_out; ++ goto done; ++ } ++ ++ if (!inat_has_immediate(insn->attr)) ++ /* no immediates */ ++ goto done; ++ ++ switch (inat_immediate_size(insn->attr)) { ++ case INAT_IMM_BYTE: ++ insn->immediate.value = get_next(signed char, insn); ++ insn->immediate.nbytes = 1; ++ break; ++ case INAT_IMM_WORD: ++ insn->immediate.value = get_next(short, insn); ++ insn->immediate.nbytes = 2; ++ break; ++ case INAT_IMM_DWORD: ++ insn->immediate.value = get_next(int, insn); ++ insn->immediate.nbytes = 4; ++ break; ++ case INAT_IMM_QWORD: ++ insn->immediate1.value = get_next(int, insn); ++ insn->immediate1.nbytes = 4; ++ insn->immediate2.value = get_next(int, insn); ++ insn->immediate2.nbytes = 4; ++ break; ++ case INAT_IMM_PTR: ++ if (!__get_immptr(insn)) ++ goto err_out; ++ break; ++ case INAT_IMM_VWORD32: ++ if (!__get_immv32(insn)) ++ goto err_out; ++ break; ++ case INAT_IMM_VWORD: ++ if (!__get_immv(insn)) ++ goto err_out; ++ break; ++ default: ++ /* Here, insn must have an immediate, but failed */ ++ goto err_out; ++ } ++ if (inat_has_second_immediate(insn->attr)) { ++ insn->immediate2.value = get_next(signed char, insn); ++ insn->immediate2.nbytes = 1; ++ } ++done: ++ insn->immediate.got = 1; ++ ++err_out: ++ return; ++} ++ ++/** ++ * insn_get_length() - Get the length of instruction ++ * @insn: &struct insn containing instruction ++ * ++ * If necessary, first collects the instruction up to and including the ++ * immediates bytes. ++ */ ++void insn_get_length(struct insn *insn) ++{ ++ if (insn->length) ++ return; ++ if (!insn->immediate.got) ++ insn_get_immediate(insn); ++ insn->length = (unsigned char)((unsigned long)insn->next_byte ++ - (unsigned long)insn->kaddr); ++} +diff --git a/tools/objtool/arch/x86/lib/x86-opcode-map.txt b/tools/objtool/arch/x86/lib/x86-opcode-map.txt +new file mode 100644 +index 000000000000..1754e094bc28 +--- /dev/null ++++ b/tools/objtool/arch/x86/lib/x86-opcode-map.txt +@@ -0,0 +1,1063 @@ ++# x86 Opcode Maps ++# ++# This is (mostly) based on following documentations. ++# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C ++# (#326018-047US, June 2013) ++# ++# ++# Table: table-name ++# Referrer: escaped-name ++# AVXcode: avx-code ++# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] ++# (or) ++# opcode: escape # escaped-name ++# EndTable ++# ++# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix ++# mnemonics that begin with lowercase 'k' accept a VEX prefix ++# ++# ++# GrpTable: GrpXXX ++# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] ++# EndTable ++# ++# AVX Superscripts ++# (ev): this opcode requires EVEX prefix. ++# (evo): this opcode is changed by EVEX prefix (EVEX opcode) ++# (v): this opcode requires VEX prefix. ++# (v1): this opcode only supports 128bit VEX. ++# ++# Last Prefix Superscripts ++# - (66): the last prefix is 0x66 ++# - (F3): the last prefix is 0xF3 ++# - (F2): the last prefix is 0xF2 ++# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) ++# - (66&F2): Both 0x66 and 0xF2 prefixes are specified. ++ ++Table: one byte opcode ++Referrer: ++AVXcode: ++# 0x00 - 0x0f ++00: ADD Eb,Gb ++01: ADD Ev,Gv ++02: ADD Gb,Eb ++03: ADD Gv,Ev ++04: ADD AL,Ib ++05: ADD rAX,Iz ++06: PUSH ES (i64) ++07: POP ES (i64) ++08: OR Eb,Gb ++09: OR Ev,Gv ++0a: OR Gb,Eb ++0b: OR Gv,Ev ++0c: OR AL,Ib ++0d: OR rAX,Iz ++0e: PUSH CS (i64) ++0f: escape # 2-byte escape ++# 0x10 - 0x1f ++10: ADC Eb,Gb ++11: ADC Ev,Gv ++12: ADC Gb,Eb ++13: ADC Gv,Ev ++14: ADC AL,Ib ++15: ADC rAX,Iz ++16: PUSH SS (i64) ++17: POP SS (i64) ++18: SBB Eb,Gb ++19: SBB Ev,Gv ++1a: SBB Gb,Eb ++1b: SBB Gv,Ev ++1c: SBB AL,Ib ++1d: SBB rAX,Iz ++1e: PUSH DS (i64) ++1f: POP DS (i64) ++# 0x20 - 0x2f ++20: AND Eb,Gb ++21: AND Ev,Gv ++22: AND Gb,Eb ++23: AND Gv,Ev ++24: AND AL,Ib ++25: AND rAx,Iz ++26: SEG=ES (Prefix) ++27: DAA (i64) ++28: SUB Eb,Gb ++29: SUB Ev,Gv ++2a: SUB Gb,Eb ++2b: SUB Gv,Ev ++2c: SUB AL,Ib ++2d: SUB rAX,Iz ++2e: SEG=CS (Prefix) ++2f: DAS (i64) ++# 0x30 - 0x3f ++30: XOR Eb,Gb ++31: XOR Ev,Gv ++32: XOR Gb,Eb ++33: XOR Gv,Ev ++34: XOR AL,Ib ++35: XOR rAX,Iz ++36: SEG=SS (Prefix) ++37: AAA (i64) ++38: CMP Eb,Gb ++39: CMP Ev,Gv ++3a: CMP Gb,Eb ++3b: CMP Gv,Ev ++3c: CMP AL,Ib ++3d: CMP rAX,Iz ++3e: SEG=DS (Prefix) ++3f: AAS (i64) ++# 0x40 - 0x4f ++40: INC eAX (i64) | REX (o64) ++41: INC eCX (i64) | REX.B (o64) ++42: INC eDX (i64) | REX.X (o64) ++43: INC eBX (i64) | REX.XB (o64) ++44: INC eSP (i64) | REX.R (o64) ++45: INC eBP (i64) | REX.RB (o64) ++46: INC eSI (i64) | REX.RX (o64) ++47: INC eDI (i64) | REX.RXB (o64) ++48: DEC eAX (i64) | REX.W (o64) ++49: DEC eCX (i64) | REX.WB (o64) ++4a: DEC eDX (i64) | REX.WX (o64) ++4b: DEC eBX (i64) | REX.WXB (o64) ++4c: DEC eSP (i64) | REX.WR (o64) ++4d: DEC eBP (i64) | REX.WRB (o64) ++4e: DEC eSI (i64) | REX.WRX (o64) ++4f: DEC eDI (i64) | REX.WRXB (o64) ++# 0x50 - 0x5f ++50: PUSH rAX/r8 (d64) ++51: PUSH rCX/r9 (d64) ++52: PUSH rDX/r10 (d64) ++53: PUSH rBX/r11 (d64) ++54: PUSH rSP/r12 (d64) ++55: PUSH rBP/r13 (d64) ++56: PUSH rSI/r14 (d64) ++57: PUSH rDI/r15 (d64) ++58: POP rAX/r8 (d64) ++59: POP rCX/r9 (d64) ++5a: POP rDX/r10 (d64) ++5b: POP rBX/r11 (d64) ++5c: POP rSP/r12 (d64) ++5d: POP rBP/r13 (d64) ++5e: POP rSI/r14 (d64) ++5f: POP rDI/r15 (d64) ++# 0x60 - 0x6f ++60: PUSHA/PUSHAD (i64) ++61: POPA/POPAD (i64) ++62: BOUND Gv,Ma (i64) | EVEX (Prefix) ++63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) ++64: SEG=FS (Prefix) ++65: SEG=GS (Prefix) ++66: Operand-Size (Prefix) ++67: Address-Size (Prefix) ++68: PUSH Iz (d64) ++69: IMUL Gv,Ev,Iz ++6a: PUSH Ib (d64) ++6b: IMUL Gv,Ev,Ib ++6c: INS/INSB Yb,DX ++6d: INS/INSW/INSD Yz,DX ++6e: OUTS/OUTSB DX,Xb ++6f: OUTS/OUTSW/OUTSD DX,Xz ++# 0x70 - 0x7f ++70: JO Jb ++71: JNO Jb ++72: JB/JNAE/JC Jb ++73: JNB/JAE/JNC Jb ++74: JZ/JE Jb ++75: JNZ/JNE Jb ++76: JBE/JNA Jb ++77: JNBE/JA Jb ++78: JS Jb ++79: JNS Jb ++7a: JP/JPE Jb ++7b: JNP/JPO Jb ++7c: JL/JNGE Jb ++7d: JNL/JGE Jb ++7e: JLE/JNG Jb ++7f: JNLE/JG Jb ++# 0x80 - 0x8f ++80: Grp1 Eb,Ib (1A) ++81: Grp1 Ev,Iz (1A) ++82: Grp1 Eb,Ib (1A),(i64) ++83: Grp1 Ev,Ib (1A) ++84: TEST Eb,Gb ++85: TEST Ev,Gv ++86: XCHG Eb,Gb ++87: XCHG Ev,Gv ++88: MOV Eb,Gb ++89: MOV Ev,Gv ++8a: MOV Gb,Eb ++8b: MOV Gv,Ev ++8c: MOV Ev,Sw ++8d: LEA Gv,M ++8e: MOV Sw,Ew ++8f: Grp1A (1A) | POP Ev (d64) ++# 0x90 - 0x9f ++90: NOP | PAUSE (F3) | XCHG r8,rAX ++91: XCHG rCX/r9,rAX ++92: XCHG rDX/r10,rAX ++93: XCHG rBX/r11,rAX ++94: XCHG rSP/r12,rAX ++95: XCHG rBP/r13,rAX ++96: XCHG rSI/r14,rAX ++97: XCHG rDI/r15,rAX ++98: CBW/CWDE/CDQE ++99: CWD/CDQ/CQO ++9a: CALLF Ap (i64) ++9b: FWAIT/WAIT ++9c: PUSHF/D/Q Fv (d64) ++9d: POPF/D/Q Fv (d64) ++9e: SAHF ++9f: LAHF ++# 0xa0 - 0xaf ++a0: MOV AL,Ob ++a1: MOV rAX,Ov ++a2: MOV Ob,AL ++a3: MOV Ov,rAX ++a4: MOVS/B Yb,Xb ++a5: MOVS/W/D/Q Yv,Xv ++a6: CMPS/B Xb,Yb ++a7: CMPS/W/D Xv,Yv ++a8: TEST AL,Ib ++a9: TEST rAX,Iz ++aa: STOS/B Yb,AL ++ab: STOS/W/D/Q Yv,rAX ++ac: LODS/B AL,Xb ++ad: LODS/W/D/Q rAX,Xv ++ae: SCAS/B AL,Yb ++# Note: The May 2011 Intel manual shows Xv for the second parameter of the ++# next instruction but Yv is correct ++af: SCAS/W/D/Q rAX,Yv ++# 0xb0 - 0xbf ++b0: MOV AL/R8L,Ib ++b1: MOV CL/R9L,Ib ++b2: MOV DL/R10L,Ib ++b3: MOV BL/R11L,Ib ++b4: MOV AH/R12L,Ib ++b5: MOV CH/R13L,Ib ++b6: MOV DH/R14L,Ib ++b7: MOV BH/R15L,Ib ++b8: MOV rAX/r8,Iv ++b9: MOV rCX/r9,Iv ++ba: MOV rDX/r10,Iv ++bb: MOV rBX/r11,Iv ++bc: MOV rSP/r12,Iv ++bd: MOV rBP/r13,Iv ++be: MOV rSI/r14,Iv ++bf: MOV rDI/r15,Iv ++# 0xc0 - 0xcf ++c0: Grp2 Eb,Ib (1A) ++c1: Grp2 Ev,Ib (1A) ++c2: RETN Iw (f64) ++c3: RETN ++c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) ++c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) ++c6: Grp11A Eb,Ib (1A) ++c7: Grp11B Ev,Iz (1A) ++c8: ENTER Iw,Ib ++c9: LEAVE (d64) ++ca: RETF Iw ++cb: RETF ++cc: INT3 ++cd: INT Ib ++ce: INTO (i64) ++cf: IRET/D/Q ++# 0xd0 - 0xdf ++d0: Grp2 Eb,1 (1A) ++d1: Grp2 Ev,1 (1A) ++d2: Grp2 Eb,CL (1A) ++d3: Grp2 Ev,CL (1A) ++d4: AAM Ib (i64) ++d5: AAD Ib (i64) ++d6: ++d7: XLAT/XLATB ++d8: ESC ++d9: ESC ++da: ESC ++db: ESC ++dc: ESC ++dd: ESC ++de: ESC ++df: ESC ++# 0xe0 - 0xef ++# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix ++# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation ++# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD. ++e0: LOOPNE/LOOPNZ Jb (f64) ++e1: LOOPE/LOOPZ Jb (f64) ++e2: LOOP Jb (f64) ++e3: JrCXZ Jb (f64) ++e4: IN AL,Ib ++e5: IN eAX,Ib ++e6: OUT Ib,AL ++e7: OUT Ib,eAX ++# With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset ++# in "near" jumps and calls is 16-bit. For CALL, ++# push of return address is 16-bit wide, RSP is decremented by 2 ++# but is not truncated to 16 bits, unlike RIP. ++e8: CALL Jz (f64) ++e9: JMP-near Jz (f64) ++ea: JMP-far Ap (i64) ++eb: JMP-short Jb (f64) ++ec: IN AL,DX ++ed: IN eAX,DX ++ee: OUT DX,AL ++ef: OUT DX,eAX ++# 0xf0 - 0xff ++f0: LOCK (Prefix) ++f1: ++f2: REPNE (Prefix) | XACQUIRE (Prefix) ++f3: REP/REPE (Prefix) | XRELEASE (Prefix) ++f4: HLT ++f5: CMC ++f6: Grp3_1 Eb (1A) ++f7: Grp3_2 Ev (1A) ++f8: CLC ++f9: STC ++fa: CLI ++fb: STI ++fc: CLD ++fd: STD ++fe: Grp4 (1A) ++ff: Grp5 (1A) ++EndTable ++ ++Table: 2-byte opcode (0x0f) ++Referrer: 2-byte escape ++AVXcode: 1 ++# 0x0f 0x00-0x0f ++00: Grp6 (1A) ++01: Grp7 (1A) ++02: LAR Gv,Ew ++03: LSL Gv,Ew ++04: ++05: SYSCALL (o64) ++06: CLTS ++07: SYSRET (o64) ++08: INVD ++09: WBINVD ++0a: ++0b: UD2 (1B) ++0c: ++# AMD's prefetch group. Intel supports prefetchw(/1) only. ++0d: GrpP ++0e: FEMMS ++# 3DNow! uses the last imm byte as opcode extension. ++0f: 3DNow! Pq,Qq,Ib ++# 0x0f 0x10-0x1f ++# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands ++# but it actually has operands. And also, vmovss and vmovsd only accept 128bit. ++# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. ++# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming ++# Reference A.1 ++10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) ++11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) ++12: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2) ++13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) ++14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) ++15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) ++16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) ++17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) ++18: Grp16 (1A) ++19: ++# Intel SDM opcode map does not list MPX instructions. For now using Gv for ++# bnd registers and Ev for everything else is OK because the instruction ++# decoder does not use the information except as an indication that there is ++# a ModR/M byte. ++1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev ++1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv ++1c: ++1d: ++1e: ++1f: NOP Ev ++# 0x0f 0x20-0x2f ++20: MOV Rd,Cd ++21: MOV Rd,Dd ++22: MOV Cd,Rd ++23: MOV Dd,Rd ++24: ++25: ++26: ++27: ++28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) ++29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) ++2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) ++2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) ++2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) ++2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) ++2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) ++2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) ++# 0x0f 0x30-0x3f ++30: WRMSR ++31: RDTSC ++32: RDMSR ++33: RDPMC ++34: SYSENTER ++35: SYSEXIT ++36: ++37: GETSEC ++38: escape # 3-byte escape 1 ++39: ++3a: escape # 3-byte escape 2 ++3b: ++3c: ++3d: ++3e: ++3f: ++# 0x0f 0x40-0x4f ++40: CMOVO Gv,Ev ++41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) ++42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) ++43: CMOVAE/NB/NC Gv,Ev ++44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) ++45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) ++46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) ++47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) ++48: CMOVS Gv,Ev ++49: CMOVNS Gv,Ev ++4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) ++4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk ++4c: CMOVL/NGE Gv,Ev ++4d: CMOVNL/GE Gv,Ev ++4e: CMOVLE/NG Gv,Ev ++4f: CMOVNLE/G Gv,Ev ++# 0x0f 0x50-0x5f ++50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) ++51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) ++52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) ++53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) ++54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) ++55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) ++56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) ++57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) ++58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) ++59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) ++5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) ++5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) ++5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) ++5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) ++5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) ++5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) ++# 0x0f 0x60-0x6f ++60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) ++61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) ++62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) ++63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) ++64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) ++65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) ++66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) ++67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) ++68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) ++69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) ++6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) ++6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) ++6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) ++6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) ++6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) ++6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqa32/64 Vx,Wx (66),(evo) | vmovdqu Vx,Wx (F3) | vmovdqu32/64 Vx,Wx (F3),(evo) | vmovdqu8/16 Vx,Wx (F2),(ev) ++# 0x0f 0x70-0x7f ++70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) ++71: Grp12 (1A) ++72: Grp13 (1A) ++73: Grp14 (1A) ++74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) ++75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) ++76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) ++# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. ++77: emms | vzeroupper | vzeroall ++78: VMREAD Ey,Gy | vcvttps2udq/pd2udq Vx,Wpd (evo) | vcvttsd2usi Gv,Wx (F2),(ev) | vcvttss2usi Gv,Wx (F3),(ev) | vcvttps2uqq/pd2uqq Vx,Wx (66),(ev) ++79: VMWRITE Gy,Ey | vcvtps2udq/pd2udq Vx,Wpd (evo) | vcvtsd2usi Gv,Wx (F2),(ev) | vcvtss2usi Gv,Wx (F3),(ev) | vcvtps2uqq/pd2uqq Vx,Wx (66),(ev) ++7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) ++7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) ++7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) ++7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) ++7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) ++7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev) ++# 0x0f 0x80-0x8f ++# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). ++80: JO Jz (f64) ++81: JNO Jz (f64) ++82: JB/JC/JNAE Jz (f64) ++83: JAE/JNB/JNC Jz (f64) ++84: JE/JZ Jz (f64) ++85: JNE/JNZ Jz (f64) ++86: JBE/JNA Jz (f64) ++87: JA/JNBE Jz (f64) ++88: JS Jz (f64) ++89: JNS Jz (f64) ++8a: JP/JPE Jz (f64) ++8b: JNP/JPO Jz (f64) ++8c: JL/JNGE Jz (f64) ++8d: JNL/JGE Jz (f64) ++8e: JLE/JNG Jz (f64) ++8f: JNLE/JG Jz (f64) ++# 0x0f 0x90-0x9f ++90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) ++91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) ++92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) ++93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) ++94: SETE/Z Eb ++95: SETNE/NZ Eb ++96: SETBE/NA Eb ++97: SETA/NBE Eb ++98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) ++99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) ++9a: SETP/PE Eb ++9b: SETNP/PO Eb ++9c: SETL/NGE Eb ++9d: SETNL/GE Eb ++9e: SETLE/NG Eb ++9f: SETNLE/G Eb ++# 0x0f 0xa0-0xaf ++a0: PUSH FS (d64) ++a1: POP FS (d64) ++a2: CPUID ++a3: BT Ev,Gv ++a4: SHLD Ev,Gv,Ib ++a5: SHLD Ev,Gv,CL ++a6: GrpPDLK ++a7: GrpRNG ++a8: PUSH GS (d64) ++a9: POP GS (d64) ++aa: RSM ++ab: BTS Ev,Gv ++ac: SHRD Ev,Gv,Ib ++ad: SHRD Ev,Gv,CL ++ae: Grp15 (1A),(1C) ++af: IMUL Gv,Ev ++# 0x0f 0xb0-0xbf ++b0: CMPXCHG Eb,Gb ++b1: CMPXCHG Ev,Gv ++b2: LSS Gv,Mp ++b3: BTR Ev,Gv ++b4: LFS Gv,Mp ++b5: LGS Gv,Mp ++b6: MOVZX Gv,Eb ++b7: MOVZX Gv,Ew ++b8: JMPE (!F3) | POPCNT Gv,Ev (F3) ++b9: Grp10 (1A) ++ba: Grp8 Ev,Ib (1A) ++bb: BTC Ev,Gv ++bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) ++bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) ++be: MOVSX Gv,Eb ++bf: MOVSX Gv,Ew ++# 0x0f 0xc0-0xcf ++c0: XADD Eb,Gb ++c1: XADD Ev,Gv ++c2: vcmpps Vps,Hps,Wps,Ib | vcmppd Vpd,Hpd,Wpd,Ib (66) | vcmpss Vss,Hss,Wss,Ib (F3),(v1) | vcmpsd Vsd,Hsd,Wsd,Ib (F2),(v1) ++c3: movnti My,Gy ++c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) ++c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) ++c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) ++c7: Grp9 (1A) ++c8: BSWAP RAX/EAX/R8/R8D ++c9: BSWAP RCX/ECX/R9/R9D ++ca: BSWAP RDX/EDX/R10/R10D ++cb: BSWAP RBX/EBX/R11/R11D ++cc: BSWAP RSP/ESP/R12/R12D ++cd: BSWAP RBP/EBP/R13/R13D ++ce: BSWAP RSI/ESI/R14/R14D ++cf: BSWAP RDI/EDI/R15/R15D ++# 0x0f 0xd0-0xdf ++d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) ++d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) ++d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) ++d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) ++d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) ++d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) ++d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) ++d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) ++d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) ++d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) ++da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) ++db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) ++dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) ++dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) ++de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) ++df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) ++# 0x0f 0xe0-0xef ++e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) ++e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) ++e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) ++e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) ++e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) ++e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) ++e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) ++e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) ++e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) ++e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) ++ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) ++eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) ++ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) ++ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) ++ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) ++ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) ++# 0x0f 0xf0-0xff ++f0: vlddqu Vx,Mx (F2) ++f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) ++f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) ++f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) ++f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) ++f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) ++f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) ++f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) ++f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) ++f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) ++fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) ++fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) ++fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) ++fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) ++fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) ++ff: ++EndTable ++ ++Table: 3-byte opcode 1 (0x0f 0x38) ++Referrer: 3-byte escape 1 ++AVXcode: 2 ++# 0x0f 0x38 0x00-0x0f ++00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) ++01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) ++02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) ++03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) ++04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) ++05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) ++06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) ++07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) ++08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) ++09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) ++0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) ++0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) ++0c: vpermilps Vx,Hx,Wx (66),(v) ++0d: vpermilpd Vx,Hx,Wx (66),(v) ++0e: vtestps Vx,Wx (66),(v) ++0f: vtestpd Vx,Wx (66),(v) ++# 0x0f 0x38 0x10-0x1f ++10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) ++11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) ++12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) ++13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) ++14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) ++15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) ++16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) ++17: vptest Vx,Wx (66) ++18: vbroadcastss Vx,Wd (66),(v) ++19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) ++1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) ++1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) ++1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) ++1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) ++1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) ++1f: vpabsq Vx,Wx (66),(ev) ++# 0x0f 0x38 0x20-0x2f ++20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) ++21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) ++22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) ++23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) ++24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) ++25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) ++26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) ++27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) ++28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) ++29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) ++2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) ++2b: vpackusdw Vx,Hx,Wx (66),(v1) ++2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) ++2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) ++2e: vmaskmovps Mx,Hx,Vx (66),(v) ++2f: vmaskmovpd Mx,Hx,Vx (66),(v) ++# 0x0f 0x38 0x30-0x3f ++30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) ++31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) ++32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) ++33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) ++34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) ++35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) ++36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) ++37: vpcmpgtq Vx,Hx,Wx (66),(v1) ++38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) ++39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) ++3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) ++3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) ++3c: vpmaxsb Vx,Hx,Wx (66),(v1) ++3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) ++3e: vpmaxuw Vx,Hx,Wx (66),(v1) ++3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) ++# 0x0f 0x38 0x40-0x8f ++40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) ++41: vphminposuw Vdq,Wdq (66),(v1) ++42: vgetexpps/d Vx,Wx (66),(ev) ++43: vgetexpss/d Vx,Hx,Wx (66),(ev) ++44: vplzcntd/q Vx,Wx (66),(ev) ++45: vpsrlvd/q Vx,Hx,Wx (66),(v) ++46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) ++47: vpsllvd/q Vx,Hx,Wx (66),(v) ++# Skip 0x48-0x4b ++4c: vrcp14ps/d Vpd,Wpd (66),(ev) ++4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) ++4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) ++4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) ++# Skip 0x50-0x57 ++58: vpbroadcastd Vx,Wx (66),(v) ++59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) ++5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) ++5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) ++# Skip 0x5c-0x63 ++64: vpblendmd/q Vx,Hx,Wx (66),(ev) ++65: vblendmps/d Vx,Hx,Wx (66),(ev) ++66: vpblendmb/w Vx,Hx,Wx (66),(ev) ++# Skip 0x67-0x74 ++75: vpermi2b/w Vx,Hx,Wx (66),(ev) ++76: vpermi2d/q Vx,Hx,Wx (66),(ev) ++77: vpermi2ps/d Vx,Hx,Wx (66),(ev) ++78: vpbroadcastb Vx,Wx (66),(v) ++79: vpbroadcastw Vx,Wx (66),(v) ++7a: vpbroadcastb Vx,Rv (66),(ev) ++7b: vpbroadcastw Vx,Rv (66),(ev) ++7c: vpbroadcastd/q Vx,Rv (66),(ev) ++7d: vpermt2b/w Vx,Hx,Wx (66),(ev) ++7e: vpermt2d/q Vx,Hx,Wx (66),(ev) ++7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) ++80: INVEPT Gy,Mdq (66) ++81: INVPID Gy,Mdq (66) ++82: INVPCID Gy,Mdq (66) ++83: vpmultishiftqb Vx,Hx,Wx (66),(ev) ++88: vexpandps/d Vpd,Wpd (66),(ev) ++89: vpexpandd/q Vx,Wx (66),(ev) ++8a: vcompressps/d Wx,Vx (66),(ev) ++8b: vpcompressd/q Wx,Vx (66),(ev) ++8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) ++8d: vpermb/w Vx,Hx,Wx (66),(ev) ++8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) ++# 0x0f 0x38 0x90-0xbf (FMA) ++90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) ++91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) ++92: vgatherdps/d Vx,Hx,Wx (66),(v) ++93: vgatherqps/d Vx,Hx,Wx (66),(v) ++94: ++95: ++96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) ++97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) ++98: vfmadd132ps/d Vx,Hx,Wx (66),(v) ++99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) ++9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) ++9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) ++9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) ++9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) ++9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) ++9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) ++a0: vpscatterdd/q Wx,Vx (66),(ev) ++a1: vpscatterqd/q Wx,Vx (66),(ev) ++a2: vscatterdps/d Wx,Vx (66),(ev) ++a3: vscatterqps/d Wx,Vx (66),(ev) ++a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) ++a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) ++a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) ++a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) ++aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) ++ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) ++ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) ++ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) ++ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) ++af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) ++b4: vpmadd52luq Vx,Hx,Wx (66),(ev) ++b5: vpmadd52huq Vx,Hx,Wx (66),(ev) ++b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) ++b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) ++b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) ++b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) ++ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) ++bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) ++bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) ++bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) ++be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) ++bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) ++# 0x0f 0x38 0xc0-0xff ++c4: vpconflictd/q Vx,Wx (66),(ev) ++c6: Grp18 (1A) ++c7: Grp19 (1A) ++c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) ++c9: sha1msg1 Vdq,Wdq ++ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) ++cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) ++cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) ++cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) ++db: VAESIMC Vdq,Wdq (66),(v1) ++dc: VAESENC Vdq,Hdq,Wdq (66),(v1) ++dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) ++de: VAESDEC Vdq,Hdq,Wdq (66),(v1) ++df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) ++f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) ++f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) ++f2: ANDN Gy,By,Ey (v) ++f3: Grp17 (1A) ++f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) ++f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) ++f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) ++EndTable ++ ++Table: 3-byte opcode 2 (0x0f 0x3a) ++Referrer: 3-byte escape 2 ++AVXcode: 3 ++# 0x0f 0x3a 0x00-0xff ++00: vpermq Vqq,Wqq,Ib (66),(v) ++01: vpermpd Vqq,Wqq,Ib (66),(v) ++02: vpblendd Vx,Hx,Wx,Ib (66),(v) ++03: valignd/q Vx,Hx,Wx,Ib (66),(ev) ++04: vpermilps Vx,Wx,Ib (66),(v) ++05: vpermilpd Vx,Wx,Ib (66),(v) ++06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) ++07: ++08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) ++09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) ++0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) ++0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) ++0c: vblendps Vx,Hx,Wx,Ib (66) ++0d: vblendpd Vx,Hx,Wx,Ib (66) ++0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) ++0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) ++14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) ++15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) ++16: vpextrd/q Ey,Vdq,Ib (66),(v1) ++17: vextractps Ed,Vdq,Ib (66),(v1) ++18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) ++19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) ++1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) ++1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) ++1d: vcvtps2ph Wx,Vx,Ib (66),(v) ++1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) ++1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) ++20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) ++21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) ++22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) ++23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) ++25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) ++26: vgetmantps/d Vx,Wx,Ib (66),(ev) ++27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) ++30: kshiftrb/w Vk,Uk,Ib (66),(v) ++31: kshiftrd/q Vk,Uk,Ib (66),(v) ++32: kshiftlb/w Vk,Uk,Ib (66),(v) ++33: kshiftld/q Vk,Uk,Ib (66),(v) ++38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) ++39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) ++3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) ++3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) ++3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) ++3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) ++40: vdpps Vx,Hx,Wx,Ib (66) ++41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) ++42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) ++43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) ++44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) ++46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) ++4a: vblendvps Vx,Hx,Wx,Lx (66),(v) ++4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) ++4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) ++50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) ++51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) ++54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) ++55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) ++56: vreduceps/d Vx,Wx,Ib (66),(ev) ++57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) ++60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) ++61: vpcmpestri Vdq,Wdq,Ib (66),(v1) ++62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) ++63: vpcmpistri Vdq,Wdq,Ib (66),(v1) ++66: vfpclassps/d Vk,Wx,Ib (66),(ev) ++67: vfpclassss/d Vk,Wx,Ib (66),(ev) ++cc: sha1rnds4 Vdq,Wdq,Ib ++df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) ++f0: RORX Gy,Ey,Ib (F2),(v) ++EndTable ++ ++GrpTable: Grp1 ++0: ADD ++1: OR ++2: ADC ++3: SBB ++4: AND ++5: SUB ++6: XOR ++7: CMP ++EndTable ++ ++GrpTable: Grp1A ++0: POP ++EndTable ++ ++GrpTable: Grp2 ++0: ROL ++1: ROR ++2: RCL ++3: RCR ++4: SHL/SAL ++5: SHR ++6: ++7: SAR ++EndTable ++ ++GrpTable: Grp3_1 ++0: TEST Eb,Ib ++1: TEST Eb,Ib ++2: NOT Eb ++3: NEG Eb ++4: MUL AL,Eb ++5: IMUL AL,Eb ++6: DIV AL,Eb ++7: IDIV AL,Eb ++EndTable ++ ++GrpTable: Grp3_2 ++0: TEST Ev,Iz ++1: ++2: NOT Ev ++3: NEG Ev ++4: MUL rAX,Ev ++5: IMUL rAX,Ev ++6: DIV rAX,Ev ++7: IDIV rAX,Ev ++EndTable ++ ++GrpTable: Grp4 ++0: INC Eb ++1: DEC Eb ++EndTable ++ ++GrpTable: Grp5 ++0: INC Ev ++1: DEC Ev ++# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). ++2: CALLN Ev (f64) ++3: CALLF Ep ++4: JMPN Ev (f64) ++5: JMPF Mp ++6: PUSH Ev (d64) ++7: ++EndTable ++ ++GrpTable: Grp6 ++0: SLDT Rv/Mw ++1: STR Rv/Mw ++2: LLDT Ew ++3: LTR Ew ++4: VERR Ew ++5: VERW Ew ++EndTable ++ ++GrpTable: Grp7 ++0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) ++1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) ++2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) ++3: LIDT Ms ++4: SMSW Mw/Rv ++5: rdpkru (110),(11B) | wrpkru (111),(11B) ++6: LMSW Ew ++7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) ++EndTable ++ ++GrpTable: Grp8 ++4: BT ++5: BTS ++6: BTR ++7: BTC ++EndTable ++ ++GrpTable: Grp9 ++1: CMPXCHG8B/16B Mq/Mdq ++3: xrstors ++4: xsavec ++5: xsaves ++6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) ++7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) ++EndTable ++ ++GrpTable: Grp10 ++EndTable ++ ++# Grp11A and Grp11B are expressed as Grp11 in Intel SDM ++GrpTable: Grp11A ++0: MOV Eb,Ib ++7: XABORT Ib (000),(11B) ++EndTable ++ ++GrpTable: Grp11B ++0: MOV Eb,Iz ++7: XBEGIN Jz (000),(11B) ++EndTable ++ ++GrpTable: Grp12 ++2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) ++4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) ++6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) ++EndTable ++ ++GrpTable: Grp13 ++0: vprord/q Hx,Wx,Ib (66),(ev) ++1: vprold/q Hx,Wx,Ib (66),(ev) ++2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) ++4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) ++6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) ++EndTable ++ ++GrpTable: Grp14 ++2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) ++3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) ++6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) ++7: vpslldq Hx,Ux,Ib (66),(11B),(v1) ++EndTable ++ ++GrpTable: Grp15 ++0: fxsave | RDFSBASE Ry (F3),(11B) ++1: fxstor | RDGSBASE Ry (F3),(11B) ++2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) ++3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) ++4: XSAVE ++5: XRSTOR | lfence (11B) ++6: XSAVEOPT | clwb (66) | mfence (11B) ++7: clflush | clflushopt (66) | sfence (11B) ++EndTable ++ ++GrpTable: Grp16 ++0: prefetch NTA ++1: prefetch T0 ++2: prefetch T1 ++3: prefetch T2 ++EndTable ++ ++GrpTable: Grp17 ++1: BLSR By,Ey (v) ++2: BLSMSK By,Ey (v) ++3: BLSI By,Ey (v) ++EndTable ++ ++GrpTable: Grp18 ++1: vgatherpf0dps/d Wx (66),(ev) ++2: vgatherpf1dps/d Wx (66),(ev) ++5: vscatterpf0dps/d Wx (66),(ev) ++6: vscatterpf1dps/d Wx (66),(ev) ++EndTable ++ ++GrpTable: Grp19 ++1: vgatherpf0qps/d Wx (66),(ev) ++2: vgatherpf1qps/d Wx (66),(ev) ++5: vscatterpf0qps/d Wx (66),(ev) ++6: vscatterpf1qps/d Wx (66),(ev) ++EndTable ++ ++# AMD's Prefetch Group ++GrpTable: GrpP ++0: PREFETCH ++1: PREFETCHW ++EndTable ++ ++GrpTable: GrpPDLK ++0: MONTMUL ++1: XSHA1 ++2: XSHA2 ++EndTable ++ ++GrpTable: GrpRNG ++0: xstore-rng ++1: xcrypt-ecb ++2: xcrypt-cbc ++4: xcrypt-cfb ++5: xcrypt-ofb ++EndTable +diff --git a/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk +new file mode 100644 +index 000000000000..a3d2c62fd805 +--- /dev/null ++++ b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk +@@ -0,0 +1,392 @@ ++#!/bin/awk -f ++# gen-insn-attr-x86.awk: Instruction attribute table generator ++# Written by Masami Hiramatsu ++# ++# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c ++ ++# Awk implementation sanity check ++function check_awk_implement() { ++ if (sprintf("%x", 0) != "0") ++ return "Your awk has a printf-format problem." ++ return "" ++} ++ ++# Clear working vars ++function clear_vars() { ++ delete table ++ delete lptable2 ++ delete lptable1 ++ delete lptable3 ++ eid = -1 # escape id ++ gid = -1 # group id ++ aid = -1 # AVX id ++ tname = "" ++} ++ ++BEGIN { ++ # Implementation error checking ++ awkchecked = check_awk_implement() ++ if (awkchecked != "") { ++ print "Error: " awkchecked > "/dev/stderr" ++ print "Please try to use gawk." > "/dev/stderr" ++ exit 1 ++ } ++ ++ # Setup generating tables ++ print "/* x86 opcode map generated from x86-opcode-map.txt */" ++ print "/* Do not change this code. */\n" ++ ggid = 1 ++ geid = 1 ++ gaid = 0 ++ delete etable ++ delete gtable ++ delete atable ++ ++ opnd_expr = "^[A-Za-z/]" ++ ext_expr = "^\\(" ++ sep_expr = "^\\|$" ++ group_expr = "^Grp[0-9A-Za-z]+" ++ ++ imm_expr = "^[IJAOL][a-z]" ++ imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" ++ imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" ++ imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" ++ imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" ++ imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" ++ imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" ++ imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" ++ imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" ++ imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" ++ imm_flag["Ob"] = "INAT_MOFFSET" ++ imm_flag["Ov"] = "INAT_MOFFSET" ++ imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" ++ ++ modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" ++ force64_expr = "\\([df]64\\)" ++ rex_expr = "^REX(\\.[XRWB]+)*" ++ fpu_expr = "^ESC" # TODO ++ ++ lprefix1_expr = "\\((66|!F3)\\)" ++ lprefix2_expr = "\\(F3\\)" ++ lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)" ++ lprefix_expr = "\\((66|F2|F3)\\)" ++ max_lprefix = 4 ++ ++ # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript ++ # accepts VEX prefix ++ vexok_opcode_expr = "^[vk].*" ++ vexok_expr = "\\(v1\\)" ++ # All opcodes with (v) superscript supports *only* VEX prefix ++ vexonly_expr = "\\(v\\)" ++ # All opcodes with (ev) superscript supports *only* EVEX prefix ++ evexonly_expr = "\\(ev\\)" ++ ++ prefix_expr = "\\(Prefix\\)" ++ prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" ++ prefix_num["REPNE"] = "INAT_PFX_REPNE" ++ prefix_num["REP/REPE"] = "INAT_PFX_REPE" ++ prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" ++ prefix_num["XRELEASE"] = "INAT_PFX_REPE" ++ prefix_num["LOCK"] = "INAT_PFX_LOCK" ++ prefix_num["SEG=CS"] = "INAT_PFX_CS" ++ prefix_num["SEG=DS"] = "INAT_PFX_DS" ++ prefix_num["SEG=ES"] = "INAT_PFX_ES" ++ prefix_num["SEG=FS"] = "INAT_PFX_FS" ++ prefix_num["SEG=GS"] = "INAT_PFX_GS" ++ prefix_num["SEG=SS"] = "INAT_PFX_SS" ++ prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" ++ prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" ++ prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" ++ prefix_num["EVEX"] = "INAT_PFX_EVEX" ++ ++ clear_vars() ++} ++ ++function semantic_error(msg) { ++ print "Semantic error at " NR ": " msg > "/dev/stderr" ++ exit 1 ++} ++ ++function debug(msg) { ++ print "DEBUG: " msg ++} ++ ++function array_size(arr, i,c) { ++ c = 0 ++ for (i in arr) ++ c++ ++ return c ++} ++ ++/^Table:/ { ++ print "/* " $0 " */" ++ if (tname != "") ++ semantic_error("Hit Table: before EndTable:."); ++} ++ ++/^Referrer:/ { ++ if (NF != 1) { ++ # escape opcode table ++ ref = "" ++ for (i = 2; i <= NF; i++) ++ ref = ref $i ++ eid = escape[ref] ++ tname = sprintf("inat_escape_table_%d", eid) ++ } ++} ++ ++/^AVXcode:/ { ++ if (NF != 1) { ++ # AVX/escape opcode table ++ aid = $2 ++ if (gaid <= aid) ++ gaid = aid + 1 ++ if (tname == "") # AVX only opcode table ++ tname = sprintf("inat_avx_table_%d", $2) ++ } ++ if (aid == -1 && eid == -1) # primary opcode table ++ tname = "inat_primary_table" ++} ++ ++/^GrpTable:/ { ++ print "/* " $0 " */" ++ if (!($2 in group)) ++ semantic_error("No group: " $2 ) ++ gid = group[$2] ++ tname = "inat_group_table_" gid ++} ++ ++function print_table(tbl,name,fmt,n) ++{ ++ print "const insn_attr_t " name " = {" ++ for (i = 0; i < n; i++) { ++ id = sprintf(fmt, i) ++ if (tbl[id]) ++ print " [" id "] = " tbl[id] "," ++ } ++ print "};" ++} ++ ++/^EndTable/ { ++ if (gid != -1) { ++ # print group tables ++ if (array_size(table) != 0) { ++ print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", ++ "0x%x", 8) ++ gtable[gid,0] = tname ++ } ++ if (array_size(lptable1) != 0) { ++ print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", ++ "0x%x", 8) ++ gtable[gid,1] = tname "_1" ++ } ++ if (array_size(lptable2) != 0) { ++ print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", ++ "0x%x", 8) ++ gtable[gid,2] = tname "_2" ++ } ++ if (array_size(lptable3) != 0) { ++ print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", ++ "0x%x", 8) ++ gtable[gid,3] = tname "_3" ++ } ++ } else { ++ # print primary/escaped tables ++ if (array_size(table) != 0) { ++ print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", ++ "0x%02x", 256) ++ etable[eid,0] = tname ++ if (aid >= 0) ++ atable[aid,0] = tname ++ } ++ if (array_size(lptable1) != 0) { ++ print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", ++ "0x%02x", 256) ++ etable[eid,1] = tname "_1" ++ if (aid >= 0) ++ atable[aid,1] = tname "_1" ++ } ++ if (array_size(lptable2) != 0) { ++ print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", ++ "0x%02x", 256) ++ etable[eid,2] = tname "_2" ++ if (aid >= 0) ++ atable[aid,2] = tname "_2" ++ } ++ if (array_size(lptable3) != 0) { ++ print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", ++ "0x%02x", 256) ++ etable[eid,3] = tname "_3" ++ if (aid >= 0) ++ atable[aid,3] = tname "_3" ++ } ++ } ++ print "" ++ clear_vars() ++} ++ ++function add_flags(old,new) { ++ if (old && new) ++ return old " | " new ++ else if (old) ++ return old ++ else ++ return new ++} ++ ++# convert operands to flags. ++function convert_operands(count,opnd, i,j,imm,mod) ++{ ++ imm = null ++ mod = null ++ for (j = 1; j <= count; j++) { ++ i = opnd[j] ++ if (match(i, imm_expr) == 1) { ++ if (!imm_flag[i]) ++ semantic_error("Unknown imm opnd: " i) ++ if (imm) { ++ if (i != "Ib") ++ semantic_error("Second IMM error") ++ imm = add_flags(imm, "INAT_SCNDIMM") ++ } else ++ imm = imm_flag[i] ++ } else if (match(i, modrm_expr)) ++ mod = "INAT_MODRM" ++ } ++ return add_flags(imm, mod) ++} ++ ++/^[0-9a-f]+\:/ { ++ if (NR == 1) ++ next ++ # get index ++ idx = "0x" substr($1, 1, index($1,":") - 1) ++ if (idx in table) ++ semantic_error("Redefine " idx " in " tname) ++ ++ # check if escaped opcode ++ if ("escape" == $2) { ++ if ($3 != "#") ++ semantic_error("No escaped name") ++ ref = "" ++ for (i = 4; i <= NF; i++) ++ ref = ref $i ++ if (ref in escape) ++ semantic_error("Redefine escape (" ref ")") ++ escape[ref] = geid ++ geid++ ++ table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" ++ next ++ } ++ ++ variant = null ++ # converts ++ i = 2 ++ while (i <= NF) { ++ opcode = $(i++) ++ delete opnds ++ ext = null ++ flags = null ++ opnd = null ++ # parse one opcode ++ if (match($i, opnd_expr)) { ++ opnd = $i ++ count = split($(i++), opnds, ",") ++ flags = convert_operands(count, opnds) ++ } ++ if (match($i, ext_expr)) ++ ext = $(i++) ++ if (match($i, sep_expr)) ++ i++ ++ else if (i < NF) ++ semantic_error($i " is not a separator") ++ ++ # check if group opcode ++ if (match(opcode, group_expr)) { ++ if (!(opcode in group)) { ++ group[opcode] = ggid ++ ggid++ ++ } ++ flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") ++ } ++ # check force(or default) 64bit ++ if (match(ext, force64_expr)) ++ flags = add_flags(flags, "INAT_FORCE64") ++ ++ # check REX prefix ++ if (match(opcode, rex_expr)) ++ flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") ++ ++ # check coprocessor escape : TODO ++ if (match(opcode, fpu_expr)) ++ flags = add_flags(flags, "INAT_MODRM") ++ ++ # check VEX codes ++ if (match(ext, evexonly_expr)) ++ flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") ++ else if (match(ext, vexonly_expr)) ++ flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") ++ else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) ++ flags = add_flags(flags, "INAT_VEXOK") ++ ++ # check prefixes ++ if (match(ext, prefix_expr)) { ++ if (!prefix_num[opcode]) ++ semantic_error("Unknown prefix: " opcode) ++ flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") ++ } ++ if (length(flags) == 0) ++ continue ++ # check if last prefix ++ if (match(ext, lprefix1_expr)) { ++ lptable1[idx] = add_flags(lptable1[idx],flags) ++ variant = "INAT_VARIANT" ++ } ++ if (match(ext, lprefix2_expr)) { ++ lptable2[idx] = add_flags(lptable2[idx],flags) ++ variant = "INAT_VARIANT" ++ } ++ if (match(ext, lprefix3_expr)) { ++ lptable3[idx] = add_flags(lptable3[idx],flags) ++ variant = "INAT_VARIANT" ++ } ++ if (!match(ext, lprefix_expr)){ ++ table[idx] = add_flags(table[idx],flags) ++ } ++ } ++ if (variant) ++ table[idx] = add_flags(table[idx],variant) ++} ++ ++END { ++ if (awkchecked != "") ++ exit 1 ++ # print escape opcode map's array ++ print "/* Escape opcode map array */" ++ print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ ++ "[INAT_LSTPFX_MAX + 1] = {" ++ for (i = 0; i < geid; i++) ++ for (j = 0; j < max_lprefix; j++) ++ if (etable[i,j]) ++ print " ["i"]["j"] = "etable[i,j]"," ++ print "};\n" ++ # print group opcode map's array ++ print "/* Group opcode map array */" ++ print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ ++ "[INAT_LSTPFX_MAX + 1] = {" ++ for (i = 0; i < ggid; i++) ++ for (j = 0; j < max_lprefix; j++) ++ if (gtable[i,j]) ++ print " ["i"]["j"] = "gtable[i,j]"," ++ print "};\n" ++ # print AVX opcode map's array ++ print "/* AVX opcode map array */" ++ print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ ++ "[INAT_LSTPFX_MAX + 1] = {" ++ for (i = 0; i < gaid; i++) ++ for (j = 0; j < max_lprefix; j++) ++ if (atable[i,j]) ++ print " ["i"]["j"] = "atable[i,j]"," ++ print "};" ++} ++ +diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c +index a688a857a7ae..694abc628e9b 100644 +--- a/tools/objtool/builtin-check.c ++++ b/tools/objtool/builtin-check.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2015 Josh Poimboeuf ++ * Copyright (C) 2015-2017 Josh Poimboeuf + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License +@@ -25,1300 +25,35 @@ + * For more information, see tools/objtool/Documentation/stack-validation.txt. + */ + +-#include +-#include + #include +- + #include "builtin.h" +-#include "elf.h" +-#include "special.h" +-#include "arch.h" +-#include "warn.h" +- +-#include +- +-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +- +-#define STATE_FP_SAVED 0x1 +-#define STATE_FP_SETUP 0x2 +-#define STATE_FENTRY 0x4 +- +-struct instruction { +- struct list_head list; +- struct hlist_node hash; +- struct section *sec; +- unsigned long offset; +- unsigned int len, state; +- unsigned char type; +- unsigned long immediate; +- bool alt_group, visited, ignore_alts; +- struct symbol *call_dest; +- struct instruction *jump_dest; +- struct list_head alts; +- struct symbol *func; +-}; +- +-struct alternative { +- struct list_head list; +- struct instruction *insn; +-}; +- +-struct objtool_file { +- struct elf *elf; +- struct list_head insn_list; +- DECLARE_HASHTABLE(insn_hash, 16); +- struct section *rodata, *whitelist; +- bool ignore_unreachables, c_file; +-}; +- +-const char *objname; +-static bool nofp; +- +-static struct instruction *find_insn(struct objtool_file *file, +- struct section *sec, unsigned long offset) +-{ +- struct instruction *insn; +- +- hash_for_each_possible(file->insn_hash, insn, hash, offset) +- if (insn->sec == sec && insn->offset == offset) +- return insn; +- +- return NULL; +-} +- +-static struct instruction *next_insn_same_sec(struct objtool_file *file, +- struct instruction *insn) +-{ +- struct instruction *next = list_next_entry(insn, list); +- +- if (&next->list == &file->insn_list || next->sec != insn->sec) +- return NULL; +- +- return next; +-} +- +-static bool gcov_enabled(struct objtool_file *file) +-{ +- struct section *sec; +- struct symbol *sym; +- +- list_for_each_entry(sec, &file->elf->sections, list) +- list_for_each_entry(sym, &sec->symbol_list, list) +- if (!strncmp(sym->name, "__gcov_.", 8)) +- return true; +- +- return false; +-} +- +-#define for_each_insn(file, insn) \ +- list_for_each_entry(insn, &file->insn_list, list) +- +-#define func_for_each_insn(file, func, insn) \ +- for (insn = find_insn(file, func->sec, func->offset); \ +- insn && &insn->list != &file->insn_list && \ +- insn->sec == func->sec && \ +- insn->offset < func->offset + func->len; \ +- insn = list_next_entry(insn, list)) +- +-#define func_for_each_insn_continue_reverse(file, func, insn) \ +- for (insn = list_prev_entry(insn, list); \ +- &insn->list != &file->insn_list && \ +- insn->sec == func->sec && insn->offset >= func->offset; \ +- insn = list_prev_entry(insn, list)) +- +-#define sec_for_each_insn_from(file, insn) \ +- for (; insn; insn = next_insn_same_sec(file, insn)) +- +- +-/* +- * Check if the function has been manually whitelisted with the +- * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted +- * due to its use of a context switching instruction. +- */ +-static bool ignore_func(struct objtool_file *file, struct symbol *func) +-{ +- struct rela *rela; +- struct instruction *insn; +- +- /* check for STACK_FRAME_NON_STANDARD */ +- if (file->whitelist && file->whitelist->rela) +- list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) { +- if (rela->sym->type == STT_SECTION && +- rela->sym->sec == func->sec && +- rela->addend == func->offset) +- return true; +- if (rela->sym->type == STT_FUNC && rela->sym == func) +- return true; +- } +- +- /* check if it has a context switching instruction */ +- func_for_each_insn(file, func, insn) +- if (insn->type == INSN_CONTEXT_SWITCH) +- return true; +- +- return false; +-} +- +-/* +- * This checks to see if the given function is a "noreturn" function. +- * +- * For global functions which are outside the scope of this object file, we +- * have to keep a manual list of them. +- * +- * For local functions, we have to detect them manually by simply looking for +- * the lack of a return instruction. +- * +- * Returns: +- * -1: error +- * 0: no dead end +- * 1: dead end +- */ +-static int __dead_end_function(struct objtool_file *file, struct symbol *func, +- int recursion) +-{ +- int i; +- struct instruction *insn; +- bool empty = true; +- +- /* +- * Unfortunately these have to be hard coded because the noreturn +- * attribute isn't provided in ELF data. +- */ +- static const char * const global_noreturns[] = { +- "__stack_chk_fail", +- "panic", +- "do_exit", +- "do_task_dead", +- "__module_put_and_exit", +- "complete_and_exit", +- "kvm_spurious_fault", +- "__reiserfs_panic", +- "lbug_with_loc" +- }; +- +- if (func->bind == STB_WEAK) +- return 0; +- +- if (func->bind == STB_GLOBAL) +- for (i = 0; i < ARRAY_SIZE(global_noreturns); i++) +- if (!strcmp(func->name, global_noreturns[i])) +- return 1; +- +- if (!func->sec) +- return 0; +- +- func_for_each_insn(file, func, insn) { +- empty = false; +- +- if (insn->type == INSN_RETURN) +- return 0; +- } +- +- if (empty) +- return 0; +- +- /* +- * A function can have a sibling call instead of a return. In that +- * case, the function's dead-end status depends on whether the target +- * of the sibling call returns. +- */ +- func_for_each_insn(file, func, insn) { +- if (insn->sec != func->sec || +- insn->offset >= func->offset + func->len) +- break; +- +- if (insn->type == INSN_JUMP_UNCONDITIONAL) { +- struct instruction *dest = insn->jump_dest; +- struct symbol *dest_func; +- +- if (!dest) +- /* sibling call to another file */ +- return 0; +- +- if (dest->sec != func->sec || +- dest->offset < func->offset || +- dest->offset >= func->offset + func->len) { +- /* local sibling call */ +- dest_func = find_symbol_by_offset(dest->sec, +- dest->offset); +- if (!dest_func) +- continue; +- +- if (recursion == 5) { +- WARN_FUNC("infinite recursion (objtool bug!)", +- dest->sec, dest->offset); +- return -1; +- } +- +- return __dead_end_function(file, dest_func, +- recursion + 1); +- } +- } +- +- if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts)) +- /* sibling call */ +- return 0; +- } +- +- return 1; +-} +- +-static int dead_end_function(struct objtool_file *file, struct symbol *func) +-{ +- return __dead_end_function(file, func, 0); +-} +- +-/* +- * Call the arch-specific instruction decoder for all the instructions and add +- * them to the global instruction list. +- */ +-static int decode_instructions(struct objtool_file *file) +-{ +- struct section *sec; +- struct symbol *func; +- unsigned long offset; +- struct instruction *insn; +- int ret; +- +- list_for_each_entry(sec, &file->elf->sections, list) { +- +- if (!(sec->sh.sh_flags & SHF_EXECINSTR)) +- continue; +- +- for (offset = 0; offset < sec->len; offset += insn->len) { +- insn = malloc(sizeof(*insn)); +- memset(insn, 0, sizeof(*insn)); +- +- INIT_LIST_HEAD(&insn->alts); +- insn->sec = sec; +- insn->offset = offset; +- +- ret = arch_decode_instruction(file->elf, sec, offset, +- sec->len - offset, +- &insn->len, &insn->type, +- &insn->immediate); +- if (ret) +- return ret; +- +- if (!insn->type || insn->type > INSN_LAST) { +- WARN_FUNC("invalid instruction type %d", +- insn->sec, insn->offset, insn->type); +- return -1; +- } +- +- hash_add(file->insn_hash, &insn->hash, insn->offset); +- list_add_tail(&insn->list, &file->insn_list); +- } +- +- list_for_each_entry(func, &sec->symbol_list, list) { +- if (func->type != STT_FUNC) +- continue; +- +- if (!find_insn(file, sec, func->offset)) { +- WARN("%s(): can't find starting instruction", +- func->name); +- return -1; +- } +- +- func_for_each_insn(file, func, insn) +- if (!insn->func) +- insn->func = func; +- } +- } +- +- return 0; +-} +- +-/* +- * Warnings shouldn't be reported for ignored functions. +- */ +-static void add_ignores(struct objtool_file *file) +-{ +- struct instruction *insn; +- struct section *sec; +- struct symbol *func; +- +- list_for_each_entry(sec, &file->elf->sections, list) { +- list_for_each_entry(func, &sec->symbol_list, list) { +- if (func->type != STT_FUNC) +- continue; +- +- if (!ignore_func(file, func)) +- continue; +- +- func_for_each_insn(file, func, insn) +- insn->visited = true; +- } +- } +-} +- +-/* +- * FIXME: For now, just ignore any alternatives which add retpolines. This is +- * a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline. +- * But it at least allows objtool to understand the control flow *around* the +- * retpoline. +- */ +-static int add_nospec_ignores(struct objtool_file *file) +-{ +- struct section *sec; +- struct rela *rela; +- struct instruction *insn; +- +- sec = find_section_by_name(file->elf, ".rela.discard.nospec"); +- if (!sec) +- return 0; +- +- list_for_each_entry(rela, &sec->rela_list, list) { +- if (rela->sym->type != STT_SECTION) { +- WARN("unexpected relocation symbol type in %s", sec->name); +- return -1; +- } +- +- insn = find_insn(file, rela->sym->sec, rela->addend); +- if (!insn) { +- WARN("bad .discard.nospec entry"); +- return -1; +- } +- +- insn->ignore_alts = true; +- } +- +- return 0; +-} +- +-/* +- * Find the destination instructions for all jumps. +- */ +-static int add_jump_destinations(struct objtool_file *file) +-{ +- struct instruction *insn; +- struct rela *rela; +- struct section *dest_sec; +- unsigned long dest_off; +- +- for_each_insn(file, insn) { +- if (insn->type != INSN_JUMP_CONDITIONAL && +- insn->type != INSN_JUMP_UNCONDITIONAL) +- continue; +- +- /* skip ignores */ +- if (insn->visited) +- continue; +- +- rela = find_rela_by_dest_range(insn->sec, insn->offset, +- insn->len); +- if (!rela) { +- dest_sec = insn->sec; +- dest_off = insn->offset + insn->len + insn->immediate; +- } else if (rela->sym->type == STT_SECTION) { +- dest_sec = rela->sym->sec; +- dest_off = rela->addend + 4; +- } else if (rela->sym->sec->idx) { +- dest_sec = rela->sym->sec; +- dest_off = rela->sym->sym.st_value + rela->addend + 4; +- } else if (strstr(rela->sym->name, "_indirect_thunk_")) { +- /* +- * Retpoline jumps are really dynamic jumps in +- * disguise, so convert them accordingly. +- */ +- insn->type = INSN_JUMP_DYNAMIC; +- continue; +- } else { +- /* sibling call */ +- insn->jump_dest = 0; +- continue; +- } +- +- insn->jump_dest = find_insn(file, dest_sec, dest_off); +- if (!insn->jump_dest) { +- +- /* +- * This is a special case where an alt instruction +- * jumps past the end of the section. These are +- * handled later in handle_group_alt(). +- */ +- if (!strcmp(insn->sec->name, ".altinstr_replacement")) +- continue; +- +- WARN_FUNC("can't find jump dest instruction at %s+0x%lx", +- insn->sec, insn->offset, dest_sec->name, +- dest_off); +- return -1; +- } +- } +- +- return 0; +-} +- +-/* +- * Find the destination instructions for all calls. +- */ +-static int add_call_destinations(struct objtool_file *file) +-{ +- struct instruction *insn; +- unsigned long dest_off; +- struct rela *rela; +- +- for_each_insn(file, insn) { +- if (insn->type != INSN_CALL) +- continue; +- +- rela = find_rela_by_dest_range(insn->sec, insn->offset, +- insn->len); +- if (!rela) { +- dest_off = insn->offset + insn->len + insn->immediate; +- insn->call_dest = find_symbol_by_offset(insn->sec, +- dest_off); +- /* +- * FIXME: Thanks to retpolines, it's now considered +- * normal for a function to call within itself. So +- * disable this warning for now. +- */ +-#if 0 +- if (!insn->call_dest) { +- WARN_FUNC("can't find call dest symbol at offset 0x%lx", +- insn->sec, insn->offset, dest_off); +- return -1; +- } +-#endif +- } else if (rela->sym->type == STT_SECTION) { +- insn->call_dest = find_symbol_by_offset(rela->sym->sec, +- rela->addend+4); +- if (!insn->call_dest || +- insn->call_dest->type != STT_FUNC) { +- WARN_FUNC("can't find call dest symbol at %s+0x%x", +- insn->sec, insn->offset, +- rela->sym->sec->name, +- rela->addend + 4); +- return -1; +- } +- } else +- insn->call_dest = rela->sym; +- } +- +- return 0; +-} +- +-/* +- * The .alternatives section requires some extra special care, over and above +- * what other special sections require: +- * +- * 1. Because alternatives are patched in-place, we need to insert a fake jump +- * instruction at the end so that validate_branch() skips all the original +- * replaced instructions when validating the new instruction path. +- * +- * 2. An added wrinkle is that the new instruction length might be zero. In +- * that case the old instructions are replaced with noops. We simulate that +- * by creating a fake jump as the only new instruction. +- * +- * 3. In some cases, the alternative section includes an instruction which +- * conditionally jumps to the _end_ of the entry. We have to modify these +- * jumps' destinations to point back to .text rather than the end of the +- * entry in .altinstr_replacement. +- * +- * 4. It has been requested that we don't validate the !POPCNT feature path +- * which is a "very very small percentage of machines". +- */ +-static int handle_group_alt(struct objtool_file *file, +- struct special_alt *special_alt, +- struct instruction *orig_insn, +- struct instruction **new_insn) +-{ +- struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; +- unsigned long dest_off; +- +- last_orig_insn = NULL; +- insn = orig_insn; +- sec_for_each_insn_from(file, insn) { +- if (insn->offset >= special_alt->orig_off + special_alt->orig_len) +- break; +- +- if (special_alt->skip_orig) +- insn->type = INSN_NOP; +- +- insn->alt_group = true; +- last_orig_insn = insn; +- } +- +- if (!next_insn_same_sec(file, last_orig_insn)) { +- WARN("%s: don't know how to handle alternatives at end of section", +- special_alt->orig_sec->name); +- return -1; +- } +- +- fake_jump = malloc(sizeof(*fake_jump)); +- if (!fake_jump) { +- WARN("malloc failed"); +- return -1; +- } +- memset(fake_jump, 0, sizeof(*fake_jump)); +- INIT_LIST_HEAD(&fake_jump->alts); +- fake_jump->sec = special_alt->new_sec; +- fake_jump->offset = -1; +- fake_jump->type = INSN_JUMP_UNCONDITIONAL; +- fake_jump->jump_dest = list_next_entry(last_orig_insn, list); +- +- if (!special_alt->new_len) { +- *new_insn = fake_jump; +- return 0; +- } +- +- last_new_insn = NULL; +- insn = *new_insn; +- sec_for_each_insn_from(file, insn) { +- if (insn->offset >= special_alt->new_off + special_alt->new_len) +- break; +- +- last_new_insn = insn; +- +- if (insn->type != INSN_JUMP_CONDITIONAL && +- insn->type != INSN_JUMP_UNCONDITIONAL) +- continue; +- +- if (!insn->immediate) +- continue; +- +- dest_off = insn->offset + insn->len + insn->immediate; +- if (dest_off == special_alt->new_off + special_alt->new_len) +- insn->jump_dest = fake_jump; +- +- if (!insn->jump_dest) { +- WARN_FUNC("can't find alternative jump destination", +- insn->sec, insn->offset); +- return -1; +- } +- } +- +- if (!last_new_insn) { +- WARN_FUNC("can't find last new alternative instruction", +- special_alt->new_sec, special_alt->new_off); +- return -1; +- } +- +- list_add(&fake_jump->list, &last_new_insn->list); +- +- return 0; +-} +- +-/* +- * A jump table entry can either convert a nop to a jump or a jump to a nop. +- * If the original instruction is a jump, make the alt entry an effective nop +- * by just skipping the original instruction. +- */ +-static int handle_jump_alt(struct objtool_file *file, +- struct special_alt *special_alt, +- struct instruction *orig_insn, +- struct instruction **new_insn) +-{ +- if (orig_insn->type == INSN_NOP) +- return 0; +- +- if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) { +- WARN_FUNC("unsupported instruction at jump label", +- orig_insn->sec, orig_insn->offset); +- return -1; +- } +- +- *new_insn = list_next_entry(orig_insn, list); +- return 0; +-} +- +-/* +- * Read all the special sections which have alternate instructions which can be +- * patched in or redirected to at runtime. Each instruction having alternate +- * instruction(s) has them added to its insn->alts list, which will be +- * traversed in validate_branch(). +- */ +-static int add_special_section_alts(struct objtool_file *file) +-{ +- struct list_head special_alts; +- struct instruction *orig_insn, *new_insn; +- struct special_alt *special_alt, *tmp; +- struct alternative *alt; +- int ret; +- +- ret = special_get_alts(file->elf, &special_alts); +- if (ret) +- return ret; +- +- list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { +- +- orig_insn = find_insn(file, special_alt->orig_sec, +- special_alt->orig_off); +- if (!orig_insn) { +- WARN_FUNC("special: can't find orig instruction", +- special_alt->orig_sec, special_alt->orig_off); +- ret = -1; +- goto out; +- } +- +- /* Ignore retpoline alternatives. */ +- if (orig_insn->ignore_alts) +- continue; +- +- new_insn = NULL; +- if (!special_alt->group || special_alt->new_len) { +- new_insn = find_insn(file, special_alt->new_sec, +- special_alt->new_off); +- if (!new_insn) { +- WARN_FUNC("special: can't find new instruction", +- special_alt->new_sec, +- special_alt->new_off); +- ret = -1; +- goto out; +- } +- } ++#include "check.h" + +- if (special_alt->group) { +- ret = handle_group_alt(file, special_alt, orig_insn, +- &new_insn); +- if (ret) +- goto out; +- } else if (special_alt->jump_or_nop) { +- ret = handle_jump_alt(file, special_alt, orig_insn, +- &new_insn); +- if (ret) +- goto out; +- } ++bool no_fp, no_unreachable, retpoline, module; + +- alt = malloc(sizeof(*alt)); +- if (!alt) { +- WARN("malloc failed"); +- ret = -1; +- goto out; +- } +- +- alt->insn = new_insn; +- list_add_tail(&alt->list, &orig_insn->alts); +- +- list_del(&special_alt->list); +- free(special_alt); +- } +- +-out: +- return ret; +-} +- +-static int add_switch_table(struct objtool_file *file, struct symbol *func, +- struct instruction *insn, struct rela *table, +- struct rela *next_table) +-{ +- struct rela *rela = table; +- struct instruction *alt_insn; +- struct alternative *alt; +- +- list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { +- if (rela == next_table) +- break; +- +- if (rela->sym->sec != insn->sec || +- rela->addend <= func->offset || +- rela->addend >= func->offset + func->len) +- break; +- +- alt_insn = find_insn(file, insn->sec, rela->addend); +- if (!alt_insn) { +- WARN("%s: can't find instruction at %s+0x%x", +- file->rodata->rela->name, insn->sec->name, +- rela->addend); +- return -1; +- } +- +- alt = malloc(sizeof(*alt)); +- if (!alt) { +- WARN("malloc failed"); +- return -1; +- } +- +- alt->insn = alt_insn; +- list_add_tail(&alt->list, &insn->alts); +- } +- +- return 0; +-} +- +-/* +- * find_switch_table() - Given a dynamic jump, find the switch jump table in +- * .rodata associated with it. +- * +- * There are 3 basic patterns: +- * +- * 1. jmpq *[rodata addr](,%reg,8) +- * +- * This is the most common case by far. It jumps to an address in a simple +- * jump table which is stored in .rodata. +- * +- * 2. jmpq *[rodata addr](%rip) +- * +- * This is caused by a rare GCC quirk, currently only seen in three driver +- * functions in the kernel, only with certain obscure non-distro configs. +- * +- * As part of an optimization, GCC makes a copy of an existing switch jump +- * table, modifies it, and then hard-codes the jump (albeit with an indirect +- * jump) to use a single entry in the table. The rest of the jump table and +- * some of its jump targets remain as dead code. +- * +- * In such a case we can just crudely ignore all unreachable instruction +- * warnings for the entire object file. Ideally we would just ignore them +- * for the function, but that would require redesigning the code quite a +- * bit. And honestly that's just not worth doing: unreachable instruction +- * warnings are of questionable value anyway, and this is such a rare issue. +- * +- * 3. mov [rodata addr],%reg1 +- * ... some instructions ... +- * jmpq *(%reg1,%reg2,8) +- * +- * This is a fairly uncommon pattern which is new for GCC 6. As of this +- * writing, there are 11 occurrences of it in the allmodconfig kernel. +- * +- * TODO: Once we have DWARF CFI and smarter instruction decoding logic, +- * ensure the same register is used in the mov and jump instructions. +- */ +-static struct rela *find_switch_table(struct objtool_file *file, +- struct symbol *func, +- struct instruction *insn) +-{ +- struct rela *text_rela, *rodata_rela; +- struct instruction *orig_insn = insn; +- +- text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); +- if (text_rela && text_rela->sym == file->rodata->sym) { +- /* case 1 */ +- rodata_rela = find_rela_by_dest(file->rodata, +- text_rela->addend); +- if (rodata_rela) +- return rodata_rela; +- +- /* case 2 */ +- rodata_rela = find_rela_by_dest(file->rodata, +- text_rela->addend + 4); +- if (!rodata_rela) +- return NULL; +- file->ignore_unreachables = true; +- return rodata_rela; +- } +- +- /* case 3 */ +- func_for_each_insn_continue_reverse(file, func, insn) { +- if (insn->type == INSN_JUMP_DYNAMIC) +- break; +- +- /* allow small jumps within the range */ +- if (insn->type == INSN_JUMP_UNCONDITIONAL && +- insn->jump_dest && +- (insn->jump_dest->offset <= insn->offset || +- insn->jump_dest->offset > orig_insn->offset)) +- break; +- +- /* look for a relocation which references .rodata */ +- text_rela = find_rela_by_dest_range(insn->sec, insn->offset, +- insn->len); +- if (!text_rela || text_rela->sym != file->rodata->sym) +- continue; +- +- /* +- * Make sure the .rodata address isn't associated with a +- * symbol. gcc jump tables are anonymous data. +- */ +- if (find_symbol_containing(file->rodata, text_rela->addend)) +- continue; +- +- return find_rela_by_dest(file->rodata, text_rela->addend); +- } +- +- return NULL; +-} +- +-static int add_func_switch_tables(struct objtool_file *file, +- struct symbol *func) +-{ +- struct instruction *insn, *prev_jump = NULL; +- struct rela *rela, *prev_rela = NULL; +- int ret; +- +- func_for_each_insn(file, func, insn) { +- if (insn->type != INSN_JUMP_DYNAMIC) +- continue; +- +- rela = find_switch_table(file, func, insn); +- if (!rela) +- continue; +- +- /* +- * We found a switch table, but we don't know yet how big it +- * is. Don't add it until we reach the end of the function or +- * the beginning of another switch table in the same function. +- */ +- if (prev_jump) { +- ret = add_switch_table(file, func, prev_jump, prev_rela, +- rela); +- if (ret) +- return ret; +- } +- +- prev_jump = insn; +- prev_rela = rela; +- } +- +- if (prev_jump) { +- ret = add_switch_table(file, func, prev_jump, prev_rela, NULL); +- if (ret) +- return ret; +- } +- +- return 0; +-} +- +-/* +- * For some switch statements, gcc generates a jump table in the .rodata +- * section which contains a list of addresses within the function to jump to. +- * This finds these jump tables and adds them to the insn->alts lists. +- */ +-static int add_switch_table_alts(struct objtool_file *file) +-{ +- struct section *sec; +- struct symbol *func; +- int ret; +- +- if (!file->rodata || !file->rodata->rela) +- return 0; +- +- list_for_each_entry(sec, &file->elf->sections, list) { +- list_for_each_entry(func, &sec->symbol_list, list) { +- if (func->type != STT_FUNC) +- continue; +- +- ret = add_func_switch_tables(file, func); +- if (ret) +- return ret; +- } +- } +- +- return 0; +-} +- +-static int decode_sections(struct objtool_file *file) +-{ +- int ret; +- +- ret = decode_instructions(file); +- if (ret) +- return ret; +- +- add_ignores(file); +- +- ret = add_nospec_ignores(file); +- if (ret) +- return ret; +- +- ret = add_jump_destinations(file); +- if (ret) +- return ret; +- +- ret = add_call_destinations(file); +- if (ret) +- return ret; +- +- ret = add_special_section_alts(file); +- if (ret) +- return ret; +- +- ret = add_switch_table_alts(file); +- if (ret) +- return ret; +- +- return 0; +-} +- +-static bool is_fentry_call(struct instruction *insn) +-{ +- if (insn->type == INSN_CALL && +- insn->call_dest->type == STT_NOTYPE && +- !strcmp(insn->call_dest->name, "__fentry__")) +- return true; +- +- return false; +-} +- +-static bool has_modified_stack_frame(struct instruction *insn) +-{ +- return (insn->state & STATE_FP_SAVED) || +- (insn->state & STATE_FP_SETUP); +-} +- +-static bool has_valid_stack_frame(struct instruction *insn) +-{ +- return (insn->state & STATE_FP_SAVED) && +- (insn->state & STATE_FP_SETUP); +-} +- +-static unsigned int frame_state(unsigned long state) +-{ +- return (state & (STATE_FP_SAVED | STATE_FP_SETUP)); +-} +- +-/* +- * Follow the branch starting at the given instruction, and recursively follow +- * any other branches (jumps). Meanwhile, track the frame pointer state at +- * each instruction and validate all the rules described in +- * tools/objtool/Documentation/stack-validation.txt. +- */ +-static int validate_branch(struct objtool_file *file, +- struct instruction *first, unsigned char first_state) +-{ +- struct alternative *alt; +- struct instruction *insn; +- struct section *sec; +- struct symbol *func = NULL; +- unsigned char state; +- int ret; +- +- insn = first; +- sec = insn->sec; +- state = first_state; +- +- if (insn->alt_group && list_empty(&insn->alts)) { +- WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", +- sec, insn->offset); +- return 1; +- } +- +- while (1) { +- if (file->c_file && insn->func) { +- if (func && func != insn->func) { +- WARN("%s() falls through to next function %s()", +- func->name, insn->func->name); +- return 1; +- } +- +- func = insn->func; +- } +- +- if (insn->visited) { +- if (frame_state(insn->state) != frame_state(state)) { +- WARN_FUNC("frame pointer state mismatch", +- sec, insn->offset); +- return 1; +- } +- +- return 0; +- } +- +- insn->visited = true; +- insn->state = state; +- +- list_for_each_entry(alt, &insn->alts, list) { +- ret = validate_branch(file, alt->insn, state); +- if (ret) +- return 1; +- } +- +- switch (insn->type) { +- +- case INSN_FP_SAVE: +- if (!nofp) { +- if (state & STATE_FP_SAVED) { +- WARN_FUNC("duplicate frame pointer save", +- sec, insn->offset); +- return 1; +- } +- state |= STATE_FP_SAVED; +- } +- break; +- +- case INSN_FP_SETUP: +- if (!nofp) { +- if (state & STATE_FP_SETUP) { +- WARN_FUNC("duplicate frame pointer setup", +- sec, insn->offset); +- return 1; +- } +- state |= STATE_FP_SETUP; +- } +- break; +- +- case INSN_FP_RESTORE: +- if (!nofp) { +- if (has_valid_stack_frame(insn)) +- state &= ~STATE_FP_SETUP; +- +- state &= ~STATE_FP_SAVED; +- } +- break; +- +- case INSN_RETURN: +- if (!nofp && has_modified_stack_frame(insn)) { +- WARN_FUNC("return without frame pointer restore", +- sec, insn->offset); +- return 1; +- } +- return 0; +- +- case INSN_CALL: +- if (is_fentry_call(insn)) { +- state |= STATE_FENTRY; +- break; +- } +- +- ret = dead_end_function(file, insn->call_dest); +- if (ret == 1) +- return 0; +- if (ret == -1) +- return 1; +- +- /* fallthrough */ +- case INSN_CALL_DYNAMIC: +- if (!nofp && !has_valid_stack_frame(insn)) { +- WARN_FUNC("call without frame pointer save/setup", +- sec, insn->offset); +- return 1; +- } +- break; +- +- case INSN_JUMP_CONDITIONAL: +- case INSN_JUMP_UNCONDITIONAL: +- if (insn->jump_dest) { +- ret = validate_branch(file, insn->jump_dest, +- state); +- if (ret) +- return 1; +- } else if (has_modified_stack_frame(insn)) { +- WARN_FUNC("sibling call from callable instruction with changed frame pointer", +- sec, insn->offset); +- return 1; +- } /* else it's a sibling call */ +- +- if (insn->type == INSN_JUMP_UNCONDITIONAL) +- return 0; +- +- break; +- +- case INSN_JUMP_DYNAMIC: +- if (list_empty(&insn->alts) && +- has_modified_stack_frame(insn)) { +- WARN_FUNC("sibling call from callable instruction with changed frame pointer", +- sec, insn->offset); +- return 1; +- } +- +- return 0; +- +- case INSN_BUG: +- return 0; +- +- default: +- break; +- } +- +- insn = next_insn_same_sec(file, insn); +- if (!insn) { +- WARN("%s: unexpected end of section", sec->name); +- return 1; +- } +- } +- +- return 0; +-} +- +-static bool is_kasan_insn(struct instruction *insn) +-{ +- return (insn->type == INSN_CALL && +- !strcmp(insn->call_dest->name, "__asan_handle_no_return")); +-} +- +-static bool is_ubsan_insn(struct instruction *insn) +-{ +- return (insn->type == INSN_CALL && +- !strcmp(insn->call_dest->name, +- "__ubsan_handle_builtin_unreachable")); +-} +- +-static bool ignore_unreachable_insn(struct symbol *func, +- struct instruction *insn) +-{ +- int i; +- +- if (insn->type == INSN_NOP) +- return true; +- +- /* +- * Check if this (or a subsequent) instruction is related to +- * CONFIG_UBSAN or CONFIG_KASAN. +- * +- * End the search at 5 instructions to avoid going into the weeds. +- */ +- for (i = 0; i < 5; i++) { +- +- if (is_kasan_insn(insn) || is_ubsan_insn(insn)) +- return true; +- +- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { +- insn = insn->jump_dest; +- continue; +- } +- +- if (insn->offset + insn->len >= func->offset + func->len) +- break; +- insn = list_next_entry(insn, list); +- } +- +- return false; +-} +- +-static int validate_functions(struct objtool_file *file) +-{ +- struct section *sec; +- struct symbol *func; +- struct instruction *insn; +- int ret, warnings = 0; +- +- list_for_each_entry(sec, &file->elf->sections, list) { +- list_for_each_entry(func, &sec->symbol_list, list) { +- if (func->type != STT_FUNC) +- continue; +- +- insn = find_insn(file, sec, func->offset); +- if (!insn) +- continue; +- +- ret = validate_branch(file, insn, 0); +- warnings += ret; +- } +- } +- +- list_for_each_entry(sec, &file->elf->sections, list) { +- list_for_each_entry(func, &sec->symbol_list, list) { +- if (func->type != STT_FUNC) +- continue; +- +- func_for_each_insn(file, func, insn) { +- if (insn->visited) +- continue; +- +- insn->visited = true; +- +- if (file->ignore_unreachables || warnings || +- ignore_unreachable_insn(func, insn)) +- continue; +- +- /* +- * gcov produces a lot of unreachable +- * instructions. If we get an unreachable +- * warning and the file has gcov enabled, just +- * ignore it, and all other such warnings for +- * the file. +- */ +- if (!file->ignore_unreachables && +- gcov_enabled(file)) { +- file->ignore_unreachables = true; +- continue; +- } +- +- WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); +- warnings++; +- } +- } +- } +- +- return warnings; +-} +- +-static int validate_uncallable_instructions(struct objtool_file *file) +-{ +- struct instruction *insn; +- int warnings = 0; +- +- for_each_insn(file, insn) { +- if (!insn->visited && insn->type == INSN_RETURN) { +- +- /* +- * Don't warn about call instructions in unvisited +- * retpoline alternatives. +- */ +- if (!strcmp(insn->sec->name, ".altinstr_replacement")) +- continue; +- +- WARN_FUNC("return instruction outside of a callable function", +- insn->sec, insn->offset); +- warnings++; +- } +- } +- +- return warnings; +-} +- +-static void cleanup(struct objtool_file *file) +-{ +- struct instruction *insn, *tmpinsn; +- struct alternative *alt, *tmpalt; +- +- list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) { +- list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { +- list_del(&alt->list); +- free(alt); +- } +- list_del(&insn->list); +- hash_del(&insn->hash); +- free(insn); +- } +- elf_close(file->elf); +-} +- +-const char * const check_usage[] = { ++static const char * const check_usage[] = { + "objtool check [] file.o", + NULL, + }; + ++const struct option check_options[] = { ++ OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), ++ OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), ++ OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), ++ OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), ++ OPT_END(), ++}; ++ + int cmd_check(int argc, const char **argv) + { +- struct objtool_file file; +- int ret, warnings = 0; +- +- const struct option options[] = { +- OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"), +- OPT_END(), +- }; ++ const char *objname; + +- argc = parse_options(argc, argv, options, check_usage, 0); ++ argc = parse_options(argc, argv, check_options, check_usage, 0); + + if (argc != 1) +- usage_with_options(check_usage, options); ++ usage_with_options(check_usage, check_options); + + objname = argv[0]; + +- file.elf = elf_open(objname); +- if (!file.elf) { +- fprintf(stderr, "error reading elf file %s\n", objname); +- return 1; +- } +- +- INIT_LIST_HEAD(&file.insn_list); +- hash_init(file.insn_hash); +- file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); +- file.rodata = find_section_by_name(file.elf, ".rodata"); +- file.ignore_unreachables = false; +- file.c_file = find_section_by_name(file.elf, ".comment"); +- +- ret = decode_sections(&file); +- if (ret < 0) +- goto out; +- warnings += ret; +- +- ret = validate_functions(&file); +- if (ret < 0) +- goto out; +- warnings += ret; +- +- ret = validate_uncallable_instructions(&file); +- if (ret < 0) +- goto out; +- warnings += ret; +- +-out: +- cleanup(&file); +- +- /* ignore warnings for now until we get all the code cleaned up */ +- if (ret || warnings) +- return 0; +- return 0; ++ return check(objname, false); + } +diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c +new file mode 100644 +index 000000000000..77ea2b97117d +--- /dev/null ++++ b/tools/objtool/builtin-orc.c +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (C) 2017 Josh Poimboeuf ++ * ++ * 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, see . ++ */ ++ ++/* ++ * objtool orc: ++ * ++ * This command analyzes a .o file and adds .orc_unwind and .orc_unwind_ip ++ * sections to it, which is used by the in-kernel ORC unwinder. ++ * ++ * This command is a superset of "objtool check". ++ */ ++ ++#include ++#include "builtin.h" ++#include "check.h" ++ ++ ++static const char *orc_usage[] = { ++ "objtool orc generate [] file.o", ++ "objtool orc dump file.o", ++ NULL, ++}; ++ ++int cmd_orc(int argc, const char **argv) ++{ ++ const char *objname; ++ ++ argc--; argv++; ++ if (argc <= 0) ++ usage_with_options(orc_usage, check_options); ++ ++ if (!strncmp(argv[0], "gen", 3)) { ++ argc = parse_options(argc, argv, check_options, orc_usage, 0); ++ if (argc != 1) ++ usage_with_options(orc_usage, check_options); ++ ++ objname = argv[0]; ++ ++ return check(objname, true); ++ } ++ ++ if (!strcmp(argv[0], "dump")) { ++ if (argc != 2) ++ usage_with_options(orc_usage, check_options); ++ ++ objname = argv[1]; ++ ++ return orc_dump(objname); ++ } ++ ++ usage_with_options(orc_usage, check_options); ++ ++ return 0; ++} +diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h +index 34d2ba78a616..28ff40e19a14 100644 +--- a/tools/objtool/builtin.h ++++ b/tools/objtool/builtin.h +@@ -17,6 +17,12 @@ + #ifndef _BUILTIN_H + #define _BUILTIN_H + ++#include ++ ++extern const struct option check_options[]; ++extern bool no_fp, no_unreachable, retpoline, module; ++ + extern int cmd_check(int argc, const char **argv); ++extern int cmd_orc(int argc, const char **argv); + + #endif /* _BUILTIN_H */ +diff --git a/tools/objtool/cfi.h b/tools/objtool/cfi.h +new file mode 100644 +index 000000000000..2fe883c665c7 +--- /dev/null ++++ b/tools/objtool/cfi.h +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2015-2017 Josh Poimboeuf ++ * ++ * 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, see . ++ */ ++ ++#ifndef _OBJTOOL_CFI_H ++#define _OBJTOOL_CFI_H ++ ++#define CFI_UNDEFINED -1 ++#define CFI_CFA -2 ++#define CFI_SP_INDIRECT -3 ++#define CFI_BP_INDIRECT -4 ++ ++#define CFI_AX 0 ++#define CFI_DX 1 ++#define CFI_CX 2 ++#define CFI_BX 3 ++#define CFI_SI 4 ++#define CFI_DI 5 ++#define CFI_BP 6 ++#define CFI_SP 7 ++#define CFI_R8 8 ++#define CFI_R9 9 ++#define CFI_R10 10 ++#define CFI_R11 11 ++#define CFI_R12 12 ++#define CFI_R13 13 ++#define CFI_R14 14 ++#define CFI_R15 15 ++#define CFI_RA 16 ++#define CFI_NUM_REGS 17 ++ ++struct cfi_reg { ++ int base; ++ int offset; ++}; ++ ++struct cfi_state { ++ struct cfi_reg cfa; ++ struct cfi_reg regs[CFI_NUM_REGS]; ++}; ++ ++#endif /* _OBJTOOL_CFI_H */ +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +new file mode 100644 +index 000000000000..e128d1c71c30 +--- /dev/null ++++ b/tools/objtool/check.c +@@ -0,0 +1,2209 @@ ++/* ++ * Copyright (C) 2015-2017 Josh Poimboeuf ++ * ++ * 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, see . ++ */ ++ ++#include ++#include ++ ++#include "builtin.h" ++#include "check.h" ++#include "elf.h" ++#include "special.h" ++#include "arch.h" ++#include "warn.h" ++ ++#include ++#include ++ ++struct alternative { ++ struct list_head list; ++ struct instruction *insn; ++}; ++ ++const char *objname; ++struct cfi_state initial_func_cfi; ++ ++struct instruction *find_insn(struct objtool_file *file, ++ struct section *sec, unsigned long offset) ++{ ++ struct instruction *insn; ++ ++ hash_for_each_possible(file->insn_hash, insn, hash, offset) ++ if (insn->sec == sec && insn->offset == offset) ++ return insn; ++ ++ return NULL; ++} ++ ++static struct instruction *next_insn_same_sec(struct objtool_file *file, ++ struct instruction *insn) ++{ ++ struct instruction *next = list_next_entry(insn, list); ++ ++ if (!next || &next->list == &file->insn_list || next->sec != insn->sec) ++ return NULL; ++ ++ return next; ++} ++ ++static struct instruction *next_insn_same_func(struct objtool_file *file, ++ struct instruction *insn) ++{ ++ struct instruction *next = list_next_entry(insn, list); ++ struct symbol *func = insn->func; ++ ++ if (!func) ++ return NULL; ++ ++ if (&next->list != &file->insn_list && next->func == func) ++ return next; ++ ++ /* Check if we're already in the subfunction: */ ++ if (func == func->cfunc) ++ return NULL; ++ ++ /* Move to the subfunction: */ ++ return find_insn(file, func->cfunc->sec, func->cfunc->offset); ++} ++ ++#define func_for_each_insn_all(file, func, insn) \ ++ for (insn = find_insn(file, func->sec, func->offset); \ ++ insn; \ ++ insn = next_insn_same_func(file, insn)) ++ ++#define func_for_each_insn(file, func, insn) \ ++ for (insn = find_insn(file, func->sec, func->offset); \ ++ insn && &insn->list != &file->insn_list && \ ++ insn->sec == func->sec && \ ++ insn->offset < func->offset + func->len; \ ++ insn = list_next_entry(insn, list)) ++ ++#define func_for_each_insn_continue_reverse(file, func, insn) \ ++ for (insn = list_prev_entry(insn, list); \ ++ &insn->list != &file->insn_list && \ ++ insn->sec == func->sec && insn->offset >= func->offset; \ ++ insn = list_prev_entry(insn, list)) ++ ++#define sec_for_each_insn_from(file, insn) \ ++ for (; insn; insn = next_insn_same_sec(file, insn)) ++ ++#define sec_for_each_insn_continue(file, insn) \ ++ for (insn = next_insn_same_sec(file, insn); insn; \ ++ insn = next_insn_same_sec(file, insn)) ++ ++/* ++ * Check if the function has been manually whitelisted with the ++ * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted ++ * due to its use of a context switching instruction. ++ */ ++static bool ignore_func(struct objtool_file *file, struct symbol *func) ++{ ++ struct rela *rela; ++ ++ /* check for STACK_FRAME_NON_STANDARD */ ++ if (file->whitelist && file->whitelist->rela) ++ list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) { ++ if (rela->sym->type == STT_SECTION && ++ rela->sym->sec == func->sec && ++ rela->addend == func->offset) ++ return true; ++ if (rela->sym->type == STT_FUNC && rela->sym == func) ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * This checks to see if the given function is a "noreturn" function. ++ * ++ * For global functions which are outside the scope of this object file, we ++ * have to keep a manual list of them. ++ * ++ * For local functions, we have to detect them manually by simply looking for ++ * the lack of a return instruction. ++ * ++ * Returns: ++ * -1: error ++ * 0: no dead end ++ * 1: dead end ++ */ ++static int __dead_end_function(struct objtool_file *file, struct symbol *func, ++ int recursion) ++{ ++ int i; ++ struct instruction *insn; ++ bool empty = true; ++ ++ /* ++ * Unfortunately these have to be hard coded because the noreturn ++ * attribute isn't provided in ELF data. ++ */ ++ static const char * const global_noreturns[] = { ++ "__stack_chk_fail", ++ "panic", ++ "do_exit", ++ "do_task_dead", ++ "__module_put_and_exit", ++ "complete_and_exit", ++ "kvm_spurious_fault", ++ "__reiserfs_panic", ++ "lbug_with_loc", ++ "fortify_panic", ++ }; ++ ++ if (func->bind == STB_WEAK) ++ return 0; ++ ++ if (func->bind == STB_GLOBAL) ++ for (i = 0; i < ARRAY_SIZE(global_noreturns); i++) ++ if (!strcmp(func->name, global_noreturns[i])) ++ return 1; ++ ++ if (!func->len) ++ return 0; ++ ++ insn = find_insn(file, func->sec, func->offset); ++ if (!insn->func) ++ return 0; ++ ++ func_for_each_insn_all(file, func, insn) { ++ empty = false; ++ ++ if (insn->type == INSN_RETURN) ++ return 0; ++ } ++ ++ if (empty) ++ return 0; ++ ++ /* ++ * A function can have a sibling call instead of a return. In that ++ * case, the function's dead-end status depends on whether the target ++ * of the sibling call returns. ++ */ ++ func_for_each_insn_all(file, func, insn) { ++ if (insn->type == INSN_JUMP_UNCONDITIONAL) { ++ struct instruction *dest = insn->jump_dest; ++ ++ if (!dest) ++ /* sibling call to another file */ ++ return 0; ++ ++ if (dest->func && dest->func->pfunc != insn->func->pfunc) { ++ ++ /* local sibling call */ ++ if (recursion == 5) { ++ /* ++ * Infinite recursion: two functions ++ * have sibling calls to each other. ++ * This is a very rare case. It means ++ * they aren't dead ends. ++ */ ++ return 0; ++ } ++ ++ return __dead_end_function(file, dest->func, ++ recursion + 1); ++ } ++ } ++ ++ if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts)) ++ /* sibling call */ ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int dead_end_function(struct objtool_file *file, struct symbol *func) ++{ ++ return __dead_end_function(file, func, 0); ++} ++ ++static void clear_insn_state(struct insn_state *state) ++{ ++ int i; ++ ++ memset(state, 0, sizeof(*state)); ++ state->cfa.base = CFI_UNDEFINED; ++ for (i = 0; i < CFI_NUM_REGS; i++) { ++ state->regs[i].base = CFI_UNDEFINED; ++ state->vals[i].base = CFI_UNDEFINED; ++ } ++ state->drap_reg = CFI_UNDEFINED; ++ state->drap_offset = -1; ++} ++ ++/* ++ * Call the arch-specific instruction decoder for all the instructions and add ++ * them to the global instruction list. ++ */ ++static int decode_instructions(struct objtool_file *file) ++{ ++ struct section *sec; ++ struct symbol *func; ++ unsigned long offset; ++ struct instruction *insn; ++ int ret; ++ ++ for_each_sec(file, sec) { ++ ++ if (!(sec->sh.sh_flags & SHF_EXECINSTR)) ++ continue; ++ ++ if (strcmp(sec->name, ".altinstr_replacement") && ++ strcmp(sec->name, ".altinstr_aux") && ++ strncmp(sec->name, ".discard.", 9)) ++ sec->text = true; ++ ++ for (offset = 0; offset < sec->len; offset += insn->len) { ++ insn = malloc(sizeof(*insn)); ++ if (!insn) { ++ WARN("malloc failed"); ++ return -1; ++ } ++ memset(insn, 0, sizeof(*insn)); ++ INIT_LIST_HEAD(&insn->alts); ++ clear_insn_state(&insn->state); ++ ++ insn->sec = sec; ++ insn->offset = offset; ++ ++ ret = arch_decode_instruction(file->elf, sec, offset, ++ sec->len - offset, ++ &insn->len, &insn->type, ++ &insn->immediate, ++ &insn->stack_op); ++ if (ret) ++ goto err; ++ ++ if (!insn->type || insn->type > INSN_LAST) { ++ WARN_FUNC("invalid instruction type %d", ++ insn->sec, insn->offset, insn->type); ++ ret = -1; ++ goto err; ++ } ++ ++ hash_add(file->insn_hash, &insn->hash, insn->offset); ++ list_add_tail(&insn->list, &file->insn_list); ++ } ++ ++ list_for_each_entry(func, &sec->symbol_list, list) { ++ if (func->type != STT_FUNC) ++ continue; ++ ++ if (!find_insn(file, sec, func->offset)) { ++ WARN("%s(): can't find starting instruction", ++ func->name); ++ return -1; ++ } ++ ++ func_for_each_insn(file, func, insn) ++ if (!insn->func) ++ insn->func = func; ++ } ++ } ++ ++ return 0; ++ ++err: ++ free(insn); ++ return ret; ++} ++ ++/* ++ * Mark "ud2" instructions and manually annotated dead ends. ++ */ ++static int add_dead_ends(struct objtool_file *file) ++{ ++ struct section *sec; ++ struct rela *rela; ++ struct instruction *insn; ++ bool found; ++ ++ /* ++ * By default, "ud2" is a dead end unless otherwise annotated, because ++ * GCC 7 inserts it for certain divide-by-zero cases. ++ */ ++ for_each_insn(file, insn) ++ if (insn->type == INSN_BUG) ++ insn->dead_end = true; ++ ++ /* ++ * Check for manually annotated dead ends. ++ */ ++ sec = find_section_by_name(file->elf, ".rela.discard.unreachable"); ++ if (!sec) ++ goto reachable; ++ ++ list_for_each_entry(rela, &sec->rela_list, list) { ++ if (rela->sym->type != STT_SECTION) { ++ WARN("unexpected relocation symbol type in %s", sec->name); ++ return -1; ++ } ++ insn = find_insn(file, rela->sym->sec, rela->addend); ++ if (insn) ++ insn = list_prev_entry(insn, list); ++ else if (rela->addend == rela->sym->sec->len) { ++ found = false; ++ list_for_each_entry_reverse(insn, &file->insn_list, list) { ++ if (insn->sec == rela->sym->sec) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) { ++ WARN("can't find unreachable insn at %s+0x%x", ++ rela->sym->sec->name, rela->addend); ++ return -1; ++ } ++ } else { ++ WARN("can't find unreachable insn at %s+0x%x", ++ rela->sym->sec->name, rela->addend); ++ return -1; ++ } ++ ++ insn->dead_end = true; ++ } ++ ++reachable: ++ /* ++ * These manually annotated reachable checks are needed for GCC 4.4, ++ * where the Linux unreachable() macro isn't supported. In that case ++ * GCC doesn't know the "ud2" is fatal, so it generates code as if it's ++ * not a dead end. ++ */ ++ sec = find_section_by_name(file->elf, ".rela.discard.reachable"); ++ if (!sec) ++ return 0; ++ ++ list_for_each_entry(rela, &sec->rela_list, list) { ++ if (rela->sym->type != STT_SECTION) { ++ WARN("unexpected relocation symbol type in %s", sec->name); ++ return -1; ++ } ++ insn = find_insn(file, rela->sym->sec, rela->addend); ++ if (insn) ++ insn = list_prev_entry(insn, list); ++ else if (rela->addend == rela->sym->sec->len) { ++ found = false; ++ list_for_each_entry_reverse(insn, &file->insn_list, list) { ++ if (insn->sec == rela->sym->sec) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) { ++ WARN("can't find reachable insn at %s+0x%x", ++ rela->sym->sec->name, rela->addend); ++ return -1; ++ } ++ } else { ++ WARN("can't find reachable insn at %s+0x%x", ++ rela->sym->sec->name, rela->addend); ++ return -1; ++ } ++ ++ insn->dead_end = false; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Warnings shouldn't be reported for ignored functions. ++ */ ++static void add_ignores(struct objtool_file *file) ++{ ++ struct instruction *insn; ++ struct section *sec; ++ struct symbol *func; ++ ++ for_each_sec(file, sec) { ++ list_for_each_entry(func, &sec->symbol_list, list) { ++ if (func->type != STT_FUNC) ++ continue; ++ ++ if (!ignore_func(file, func)) ++ continue; ++ ++ func_for_each_insn_all(file, func, insn) ++ insn->ignore = true; ++ } ++ } ++} ++ ++/* ++ * FIXME: For now, just ignore any alternatives which add retpolines. This is ++ * a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline. ++ * But it at least allows objtool to understand the control flow *around* the ++ * retpoline. ++ */ ++static int add_nospec_ignores(struct objtool_file *file) ++{ ++ struct section *sec; ++ struct rela *rela; ++ struct instruction *insn; ++ ++ sec = find_section_by_name(file->elf, ".rela.discard.nospec"); ++ if (!sec) ++ return 0; ++ ++ list_for_each_entry(rela, &sec->rela_list, list) { ++ if (rela->sym->type != STT_SECTION) { ++ WARN("unexpected relocation symbol type in %s", sec->name); ++ return -1; ++ } ++ ++ insn = find_insn(file, rela->sym->sec, rela->addend); ++ if (!insn) { ++ WARN("bad .discard.nospec entry"); ++ return -1; ++ } ++ ++ insn->ignore_alts = true; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Find the destination instructions for all jumps. ++ */ ++static int add_jump_destinations(struct objtool_file *file) ++{ ++ struct instruction *insn; ++ struct rela *rela; ++ struct section *dest_sec; ++ unsigned long dest_off; ++ ++ for_each_insn(file, insn) { ++ if (insn->type != INSN_JUMP_CONDITIONAL && ++ insn->type != INSN_JUMP_UNCONDITIONAL) ++ continue; ++ ++ if (insn->ignore) ++ continue; ++ ++ rela = find_rela_by_dest_range(insn->sec, insn->offset, ++ insn->len); ++ if (!rela) { ++ dest_sec = insn->sec; ++ dest_off = insn->offset + insn->len + insn->immediate; ++ } else if (rela->sym->type == STT_SECTION) { ++ dest_sec = rela->sym->sec; ++ dest_off = rela->addend + 4; ++ } else if (rela->sym->sec->idx) { ++ dest_sec = rela->sym->sec; ++ dest_off = rela->sym->sym.st_value + rela->addend + 4; ++ } else if (strstr(rela->sym->name, "_indirect_thunk_")) { ++ /* ++ * Retpoline jumps are really dynamic jumps in ++ * disguise, so convert them accordingly. ++ */ ++ insn->type = INSN_JUMP_DYNAMIC; ++ insn->retpoline_safe = true; ++ continue; ++ } else { ++ /* sibling call */ ++ insn->jump_dest = 0; ++ continue; ++ } ++ ++ insn->jump_dest = find_insn(file, dest_sec, dest_off); ++ if (!insn->jump_dest) { ++ ++ /* ++ * This is a special case where an alt instruction ++ * jumps past the end of the section. These are ++ * handled later in handle_group_alt(). ++ */ ++ if (!strcmp(insn->sec->name, ".altinstr_replacement")) ++ continue; ++ ++ WARN_FUNC("can't find jump dest instruction at %s+0x%lx", ++ insn->sec, insn->offset, dest_sec->name, ++ dest_off); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Find the destination instructions for all calls. ++ */ ++static int add_call_destinations(struct objtool_file *file) ++{ ++ struct instruction *insn; ++ unsigned long dest_off; ++ struct rela *rela; ++ ++ for_each_insn(file, insn) { ++ if (insn->type != INSN_CALL) ++ continue; ++ ++ rela = find_rela_by_dest_range(insn->sec, insn->offset, ++ insn->len); ++ if (!rela) { ++ dest_off = insn->offset + insn->len + insn->immediate; ++ insn->call_dest = find_symbol_by_offset(insn->sec, ++ dest_off); ++ ++ if (!insn->call_dest && !insn->ignore) { ++ WARN_FUNC("unsupported intra-function call", ++ insn->sec, insn->offset); ++ if (retpoline) ++ WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); ++ return -1; ++ } ++ ++ } else if (rela->sym->type == STT_SECTION) { ++ insn->call_dest = find_symbol_by_offset(rela->sym->sec, ++ rela->addend+4); ++ if (!insn->call_dest || ++ insn->call_dest->type != STT_FUNC) { ++ WARN_FUNC("can't find call dest symbol at %s+0x%x", ++ insn->sec, insn->offset, ++ rela->sym->sec->name, ++ rela->addend + 4); ++ return -1; ++ } ++ } else ++ insn->call_dest = rela->sym; ++ } ++ ++ return 0; ++} ++ ++/* ++ * The .alternatives section requires some extra special care, over and above ++ * what other special sections require: ++ * ++ * 1. Because alternatives are patched in-place, we need to insert a fake jump ++ * instruction at the end so that validate_branch() skips all the original ++ * replaced instructions when validating the new instruction path. ++ * ++ * 2. An added wrinkle is that the new instruction length might be zero. In ++ * that case the old instructions are replaced with noops. We simulate that ++ * by creating a fake jump as the only new instruction. ++ * ++ * 3. In some cases, the alternative section includes an instruction which ++ * conditionally jumps to the _end_ of the entry. We have to modify these ++ * jumps' destinations to point back to .text rather than the end of the ++ * entry in .altinstr_replacement. ++ * ++ * 4. It has been requested that we don't validate the !POPCNT feature path ++ * which is a "very very small percentage of machines". ++ */ ++static int handle_group_alt(struct objtool_file *file, ++ struct special_alt *special_alt, ++ struct instruction *orig_insn, ++ struct instruction **new_insn) ++{ ++ struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL; ++ unsigned long dest_off; ++ ++ last_orig_insn = NULL; ++ insn = orig_insn; ++ sec_for_each_insn_from(file, insn) { ++ if (insn->offset >= special_alt->orig_off + special_alt->orig_len) ++ break; ++ ++ if (special_alt->skip_orig) ++ insn->type = INSN_NOP; ++ ++ insn->alt_group = true; ++ last_orig_insn = insn; ++ } ++ ++ if (next_insn_same_sec(file, last_orig_insn)) { ++ fake_jump = malloc(sizeof(*fake_jump)); ++ if (!fake_jump) { ++ WARN("malloc failed"); ++ return -1; ++ } ++ memset(fake_jump, 0, sizeof(*fake_jump)); ++ INIT_LIST_HEAD(&fake_jump->alts); ++ clear_insn_state(&fake_jump->state); ++ ++ fake_jump->sec = special_alt->new_sec; ++ fake_jump->offset = -1; ++ fake_jump->type = INSN_JUMP_UNCONDITIONAL; ++ fake_jump->jump_dest = list_next_entry(last_orig_insn, list); ++ fake_jump->ignore = true; ++ } ++ ++ if (!special_alt->new_len) { ++ if (!fake_jump) { ++ WARN("%s: empty alternative at end of section", ++ special_alt->orig_sec->name); ++ return -1; ++ } ++ ++ *new_insn = fake_jump; ++ return 0; ++ } ++ ++ last_new_insn = NULL; ++ insn = *new_insn; ++ sec_for_each_insn_from(file, insn) { ++ if (insn->offset >= special_alt->new_off + special_alt->new_len) ++ break; ++ ++ last_new_insn = insn; ++ ++ insn->ignore = orig_insn->ignore_alts; ++ ++ if (insn->type != INSN_JUMP_CONDITIONAL && ++ insn->type != INSN_JUMP_UNCONDITIONAL) ++ continue; ++ ++ if (!insn->immediate) ++ continue; ++ ++ dest_off = insn->offset + insn->len + insn->immediate; ++ if (dest_off == special_alt->new_off + special_alt->new_len) { ++ if (!fake_jump) { ++ WARN("%s: alternative jump to end of section", ++ special_alt->orig_sec->name); ++ return -1; ++ } ++ insn->jump_dest = fake_jump; ++ } ++ ++ if (!insn->jump_dest) { ++ WARN_FUNC("can't find alternative jump destination", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ } ++ ++ if (!last_new_insn) { ++ WARN_FUNC("can't find last new alternative instruction", ++ special_alt->new_sec, special_alt->new_off); ++ return -1; ++ } ++ ++ if (fake_jump) ++ list_add(&fake_jump->list, &last_new_insn->list); ++ ++ return 0; ++} ++ ++/* ++ * A jump table entry can either convert a nop to a jump or a jump to a nop. ++ * If the original instruction is a jump, make the alt entry an effective nop ++ * by just skipping the original instruction. ++ */ ++static int handle_jump_alt(struct objtool_file *file, ++ struct special_alt *special_alt, ++ struct instruction *orig_insn, ++ struct instruction **new_insn) ++{ ++ if (orig_insn->type == INSN_NOP) ++ return 0; ++ ++ if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) { ++ WARN_FUNC("unsupported instruction at jump label", ++ orig_insn->sec, orig_insn->offset); ++ return -1; ++ } ++ ++ *new_insn = list_next_entry(orig_insn, list); ++ return 0; ++} ++ ++/* ++ * Read all the special sections which have alternate instructions which can be ++ * patched in or redirected to at runtime. Each instruction having alternate ++ * instruction(s) has them added to its insn->alts list, which will be ++ * traversed in validate_branch(). ++ */ ++static int add_special_section_alts(struct objtool_file *file) ++{ ++ struct list_head special_alts; ++ struct instruction *orig_insn, *new_insn; ++ struct special_alt *special_alt, *tmp; ++ struct alternative *alt; ++ int ret; ++ ++ ret = special_get_alts(file->elf, &special_alts); ++ if (ret) ++ return ret; ++ ++ list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { ++ ++ orig_insn = find_insn(file, special_alt->orig_sec, ++ special_alt->orig_off); ++ if (!orig_insn) { ++ WARN_FUNC("special: can't find orig instruction", ++ special_alt->orig_sec, special_alt->orig_off); ++ ret = -1; ++ goto out; ++ } ++ ++ new_insn = NULL; ++ if (!special_alt->group || special_alt->new_len) { ++ new_insn = find_insn(file, special_alt->new_sec, ++ special_alt->new_off); ++ if (!new_insn) { ++ WARN_FUNC("special: can't find new instruction", ++ special_alt->new_sec, ++ special_alt->new_off); ++ ret = -1; ++ goto out; ++ } ++ } ++ ++ if (special_alt->group) { ++ ret = handle_group_alt(file, special_alt, orig_insn, ++ &new_insn); ++ if (ret) ++ goto out; ++ } else if (special_alt->jump_or_nop) { ++ ret = handle_jump_alt(file, special_alt, orig_insn, ++ &new_insn); ++ if (ret) ++ goto out; ++ } ++ ++ alt = malloc(sizeof(*alt)); ++ if (!alt) { ++ WARN("malloc failed"); ++ ret = -1; ++ goto out; ++ } ++ ++ alt->insn = new_insn; ++ list_add_tail(&alt->list, &orig_insn->alts); ++ ++ list_del(&special_alt->list); ++ free(special_alt); ++ } ++ ++out: ++ return ret; ++} ++ ++static int add_switch_table(struct objtool_file *file, struct instruction *insn, ++ struct rela *table, struct rela *next_table) ++{ ++ struct rela *rela = table; ++ struct instruction *alt_insn; ++ struct alternative *alt; ++ struct symbol *pfunc = insn->func->pfunc; ++ unsigned int prev_offset = 0; ++ ++ list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { ++ if (rela == next_table) ++ break; ++ ++ /* Make sure the switch table entries are consecutive: */ ++ if (prev_offset && rela->offset != prev_offset + 8) ++ break; ++ ++ /* Detect function pointers from contiguous objects: */ ++ if (rela->sym->sec == pfunc->sec && ++ rela->addend == pfunc->offset) ++ break; ++ ++ alt_insn = find_insn(file, rela->sym->sec, rela->addend); ++ if (!alt_insn) ++ break; ++ ++ /* Make sure the jmp dest is in the function or subfunction: */ ++ if (alt_insn->func->pfunc != pfunc) ++ break; ++ ++ alt = malloc(sizeof(*alt)); ++ if (!alt) { ++ WARN("malloc failed"); ++ return -1; ++ } ++ ++ alt->insn = alt_insn; ++ list_add_tail(&alt->list, &insn->alts); ++ prev_offset = rela->offset; ++ } ++ ++ if (!prev_offset) { ++ WARN_FUNC("can't find switch jump table", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * find_switch_table() - Given a dynamic jump, find the switch jump table in ++ * .rodata associated with it. ++ * ++ * There are 3 basic patterns: ++ * ++ * 1. jmpq *[rodata addr](,%reg,8) ++ * ++ * This is the most common case by far. It jumps to an address in a simple ++ * jump table which is stored in .rodata. ++ * ++ * 2. jmpq *[rodata addr](%rip) ++ * ++ * This is caused by a rare GCC quirk, currently only seen in three driver ++ * functions in the kernel, only with certain obscure non-distro configs. ++ * ++ * As part of an optimization, GCC makes a copy of an existing switch jump ++ * table, modifies it, and then hard-codes the jump (albeit with an indirect ++ * jump) to use a single entry in the table. The rest of the jump table and ++ * some of its jump targets remain as dead code. ++ * ++ * In such a case we can just crudely ignore all unreachable instruction ++ * warnings for the entire object file. Ideally we would just ignore them ++ * for the function, but that would require redesigning the code quite a ++ * bit. And honestly that's just not worth doing: unreachable instruction ++ * warnings are of questionable value anyway, and this is such a rare issue. ++ * ++ * 3. mov [rodata addr],%reg1 ++ * ... some instructions ... ++ * jmpq *(%reg1,%reg2,8) ++ * ++ * This is a fairly uncommon pattern which is new for GCC 6. As of this ++ * writing, there are 11 occurrences of it in the allmodconfig kernel. ++ * ++ * As of GCC 7 there are quite a few more of these and the 'in between' code ++ * is significant. Esp. with KASAN enabled some of the code between the mov ++ * and jmpq uses .rodata itself, which can confuse things. ++ * ++ * TODO: Once we have DWARF CFI and smarter instruction decoding logic, ++ * ensure the same register is used in the mov and jump instructions. ++ * ++ * NOTE: RETPOLINE made it harder still to decode dynamic jumps. ++ */ ++static struct rela *find_switch_table(struct objtool_file *file, ++ struct symbol *func, ++ struct instruction *insn) ++{ ++ struct rela *text_rela, *rodata_rela; ++ struct instruction *orig_insn = insn; ++ unsigned long table_offset; ++ ++ /* ++ * Backward search using the @first_jump_src links, these help avoid ++ * much of the 'in between' code. Which avoids us getting confused by ++ * it. ++ */ ++ for (; ++ &insn->list != &file->insn_list && ++ insn->sec == func->sec && ++ insn->offset >= func->offset; ++ ++ insn = insn->first_jump_src ?: list_prev_entry(insn, list)) { ++ ++ if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) ++ break; ++ ++ /* allow small jumps within the range */ ++ if (insn->type == INSN_JUMP_UNCONDITIONAL && ++ insn->jump_dest && ++ (insn->jump_dest->offset <= insn->offset || ++ insn->jump_dest->offset > orig_insn->offset)) ++ break; ++ ++ /* look for a relocation which references .rodata */ ++ text_rela = find_rela_by_dest_range(insn->sec, insn->offset, ++ insn->len); ++ if (!text_rela || text_rela->sym != file->rodata->sym) ++ continue; ++ ++ table_offset = text_rela->addend; ++ if (text_rela->type == R_X86_64_PC32) ++ table_offset += 4; ++ ++ /* ++ * Make sure the .rodata address isn't associated with a ++ * symbol. gcc jump tables are anonymous data. ++ */ ++ if (find_symbol_containing(file->rodata, table_offset)) ++ continue; ++ ++ rodata_rela = find_rela_by_dest(file->rodata, table_offset); ++ if (rodata_rela) { ++ /* ++ * Use of RIP-relative switch jumps is quite rare, and ++ * indicates a rare GCC quirk/bug which can leave dead ++ * code behind. ++ */ ++ if (text_rela->type == R_X86_64_PC32) ++ file->ignore_unreachables = true; ++ ++ return rodata_rela; ++ } ++ } ++ ++ return NULL; ++} ++ ++ ++static int add_func_switch_tables(struct objtool_file *file, ++ struct symbol *func) ++{ ++ struct instruction *insn, *last = NULL, *prev_jump = NULL; ++ struct rela *rela, *prev_rela = NULL; ++ int ret; ++ ++ func_for_each_insn_all(file, func, insn) { ++ if (!last) ++ last = insn; ++ ++ /* ++ * Store back-pointers for unconditional forward jumps such ++ * that find_switch_table() can back-track using those and ++ * avoid some potentially confusing code. ++ */ ++ if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && ++ insn->offset > last->offset && ++ insn->jump_dest->offset > insn->offset && ++ !insn->jump_dest->first_jump_src) { ++ ++ insn->jump_dest->first_jump_src = insn; ++ last = insn->jump_dest; ++ } ++ ++ if (insn->type != INSN_JUMP_DYNAMIC) ++ continue; ++ ++ rela = find_switch_table(file, func, insn); ++ if (!rela) ++ continue; ++ ++ /* ++ * We found a switch table, but we don't know yet how big it ++ * is. Don't add it until we reach the end of the function or ++ * the beginning of another switch table in the same function. ++ */ ++ if (prev_jump) { ++ ret = add_switch_table(file, prev_jump, prev_rela, rela); ++ if (ret) ++ return ret; ++ } ++ ++ prev_jump = insn; ++ prev_rela = rela; ++ } ++ ++ if (prev_jump) { ++ ret = add_switch_table(file, prev_jump, prev_rela, NULL); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/* ++ * For some switch statements, gcc generates a jump table in the .rodata ++ * section which contains a list of addresses within the function to jump to. ++ * This finds these jump tables and adds them to the insn->alts lists. ++ */ ++static int add_switch_table_alts(struct objtool_file *file) ++{ ++ struct section *sec; ++ struct symbol *func; ++ int ret; ++ ++ if (!file->rodata || !file->rodata->rela) ++ return 0; ++ ++ for_each_sec(file, sec) { ++ list_for_each_entry(func, &sec->symbol_list, list) { ++ if (func->type != STT_FUNC) ++ continue; ++ ++ ret = add_func_switch_tables(file, func); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int read_unwind_hints(struct objtool_file *file) ++{ ++ struct section *sec, *relasec; ++ struct rela *rela; ++ struct unwind_hint *hint; ++ struct instruction *insn; ++ struct cfi_reg *cfa; ++ int i; ++ ++ sec = find_section_by_name(file->elf, ".discard.unwind_hints"); ++ if (!sec) ++ return 0; ++ ++ relasec = sec->rela; ++ if (!relasec) { ++ WARN("missing .rela.discard.unwind_hints section"); ++ return -1; ++ } ++ ++ if (sec->len % sizeof(struct unwind_hint)) { ++ WARN("struct unwind_hint size mismatch"); ++ return -1; ++ } ++ ++ file->hints = true; ++ ++ for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) { ++ hint = (struct unwind_hint *)sec->data->d_buf + i; ++ ++ rela = find_rela_by_dest(sec, i * sizeof(*hint)); ++ if (!rela) { ++ WARN("can't find rela for unwind_hints[%d]", i); ++ return -1; ++ } ++ ++ insn = find_insn(file, rela->sym->sec, rela->addend); ++ if (!insn) { ++ WARN("can't find insn for unwind_hints[%d]", i); ++ return -1; ++ } ++ ++ cfa = &insn->state.cfa; ++ ++ if (hint->type == UNWIND_HINT_TYPE_SAVE) { ++ insn->save = true; ++ continue; ++ ++ } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) { ++ insn->restore = true; ++ insn->hint = true; ++ continue; ++ } ++ ++ insn->hint = true; ++ ++ switch (hint->sp_reg) { ++ case ORC_REG_UNDEFINED: ++ cfa->base = CFI_UNDEFINED; ++ break; ++ case ORC_REG_SP: ++ cfa->base = CFI_SP; ++ break; ++ case ORC_REG_BP: ++ cfa->base = CFI_BP; ++ break; ++ case ORC_REG_SP_INDIRECT: ++ cfa->base = CFI_SP_INDIRECT; ++ break; ++ case ORC_REG_R10: ++ cfa->base = CFI_R10; ++ break; ++ case ORC_REG_R13: ++ cfa->base = CFI_R13; ++ break; ++ case ORC_REG_DI: ++ cfa->base = CFI_DI; ++ break; ++ case ORC_REG_DX: ++ cfa->base = CFI_DX; ++ break; ++ default: ++ WARN_FUNC("unsupported unwind_hint sp base reg %d", ++ insn->sec, insn->offset, hint->sp_reg); ++ return -1; ++ } ++ ++ cfa->offset = hint->sp_offset; ++ insn->state.type = hint->type; ++ } ++ ++ return 0; ++} ++ ++static int read_retpoline_hints(struct objtool_file *file) ++{ ++ struct section *sec; ++ struct instruction *insn; ++ struct rela *rela; ++ ++ sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); ++ if (!sec) ++ return 0; ++ ++ list_for_each_entry(rela, &sec->rela_list, list) { ++ if (rela->sym->type != STT_SECTION) { ++ WARN("unexpected relocation symbol type in %s", sec->name); ++ return -1; ++ } ++ ++ insn = find_insn(file, rela->sym->sec, rela->addend); ++ if (!insn) { ++ WARN("bad .discard.retpoline_safe entry"); ++ return -1; ++ } ++ ++ if (insn->type != INSN_JUMP_DYNAMIC && ++ insn->type != INSN_CALL_DYNAMIC) { ++ WARN_FUNC("retpoline_safe hint not an indirect jump/call", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ insn->retpoline_safe = true; ++ } ++ ++ return 0; ++} ++ ++static int decode_sections(struct objtool_file *file) ++{ ++ int ret; ++ ++ ret = decode_instructions(file); ++ if (ret) ++ return ret; ++ ++ ret = add_dead_ends(file); ++ if (ret) ++ return ret; ++ ++ add_ignores(file); ++ ++ ret = add_nospec_ignores(file); ++ if (ret) ++ return ret; ++ ++ ret = add_jump_destinations(file); ++ if (ret) ++ return ret; ++ ++ ret = add_special_section_alts(file); ++ if (ret) ++ return ret; ++ ++ ret = add_call_destinations(file); ++ if (ret) ++ return ret; ++ ++ ret = add_switch_table_alts(file); ++ if (ret) ++ return ret; ++ ++ ret = read_unwind_hints(file); ++ if (ret) ++ return ret; ++ ++ ret = read_retpoline_hints(file); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static bool is_fentry_call(struct instruction *insn) ++{ ++ if (insn->type == INSN_CALL && ++ insn->call_dest->type == STT_NOTYPE && ++ !strcmp(insn->call_dest->name, "__fentry__")) ++ return true; ++ ++ return false; ++} ++ ++static bool has_modified_stack_frame(struct insn_state *state) ++{ ++ int i; ++ ++ if (state->cfa.base != initial_func_cfi.cfa.base || ++ state->cfa.offset != initial_func_cfi.cfa.offset || ++ state->stack_size != initial_func_cfi.cfa.offset || ++ state->drap) ++ return true; ++ ++ for (i = 0; i < CFI_NUM_REGS; i++) ++ if (state->regs[i].base != initial_func_cfi.regs[i].base || ++ state->regs[i].offset != initial_func_cfi.regs[i].offset) ++ return true; ++ ++ return false; ++} ++ ++static bool has_valid_stack_frame(struct insn_state *state) ++{ ++ if (state->cfa.base == CFI_BP && state->regs[CFI_BP].base == CFI_CFA && ++ state->regs[CFI_BP].offset == -16) ++ return true; ++ ++ if (state->drap && state->regs[CFI_BP].base == CFI_BP) ++ return true; ++ ++ return false; ++} ++ ++static int update_insn_state_regs(struct instruction *insn, struct insn_state *state) ++{ ++ struct cfi_reg *cfa = &state->cfa; ++ struct stack_op *op = &insn->stack_op; ++ ++ if (cfa->base != CFI_SP) ++ return 0; ++ ++ /* push */ ++ if (op->dest.type == OP_DEST_PUSH) ++ cfa->offset += 8; ++ ++ /* pop */ ++ if (op->src.type == OP_SRC_POP) ++ cfa->offset -= 8; ++ ++ /* add immediate to sp */ ++ if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD && ++ op->dest.reg == CFI_SP && op->src.reg == CFI_SP) ++ cfa->offset -= op->src.offset; ++ ++ return 0; ++} ++ ++static void save_reg(struct insn_state *state, unsigned char reg, int base, ++ int offset) ++{ ++ if (arch_callee_saved_reg(reg) && ++ state->regs[reg].base == CFI_UNDEFINED) { ++ state->regs[reg].base = base; ++ state->regs[reg].offset = offset; ++ } ++} ++ ++static void restore_reg(struct insn_state *state, unsigned char reg) ++{ ++ state->regs[reg].base = CFI_UNDEFINED; ++ state->regs[reg].offset = 0; ++} ++ ++/* ++ * A note about DRAP stack alignment: ++ * ++ * GCC has the concept of a DRAP register, which is used to help keep track of ++ * the stack pointer when aligning the stack. r10 or r13 is used as the DRAP ++ * register. The typical DRAP pattern is: ++ * ++ * 4c 8d 54 24 08 lea 0x8(%rsp),%r10 ++ * 48 83 e4 c0 and $0xffffffffffffffc0,%rsp ++ * 41 ff 72 f8 pushq -0x8(%r10) ++ * 55 push %rbp ++ * 48 89 e5 mov %rsp,%rbp ++ * (more pushes) ++ * 41 52 push %r10 ++ * ... ++ * 41 5a pop %r10 ++ * (more pops) ++ * 5d pop %rbp ++ * 49 8d 62 f8 lea -0x8(%r10),%rsp ++ * c3 retq ++ * ++ * There are some variations in the epilogues, like: ++ * ++ * 5b pop %rbx ++ * 41 5a pop %r10 ++ * 41 5c pop %r12 ++ * 41 5d pop %r13 ++ * 41 5e pop %r14 ++ * c9 leaveq ++ * 49 8d 62 f8 lea -0x8(%r10),%rsp ++ * c3 retq ++ * ++ * and: ++ * ++ * 4c 8b 55 e8 mov -0x18(%rbp),%r10 ++ * 48 8b 5d e0 mov -0x20(%rbp),%rbx ++ * 4c 8b 65 f0 mov -0x10(%rbp),%r12 ++ * 4c 8b 6d f8 mov -0x8(%rbp),%r13 ++ * c9 leaveq ++ * 49 8d 62 f8 lea -0x8(%r10),%rsp ++ * c3 retq ++ * ++ * Sometimes r13 is used as the DRAP register, in which case it's saved and ++ * restored beforehand: ++ * ++ * 41 55 push %r13 ++ * 4c 8d 6c 24 10 lea 0x10(%rsp),%r13 ++ * 48 83 e4 f0 and $0xfffffffffffffff0,%rsp ++ * ... ++ * 49 8d 65 f0 lea -0x10(%r13),%rsp ++ * 41 5d pop %r13 ++ * c3 retq ++ */ ++static int update_insn_state(struct instruction *insn, struct insn_state *state) ++{ ++ struct stack_op *op = &insn->stack_op; ++ struct cfi_reg *cfa = &state->cfa; ++ struct cfi_reg *regs = state->regs; ++ ++ /* stack operations don't make sense with an undefined CFA */ ++ if (cfa->base == CFI_UNDEFINED) { ++ if (insn->func) { ++ WARN_FUNC("undefined stack state", insn->sec, insn->offset); ++ return -1; ++ } ++ return 0; ++ } ++ ++ if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET) ++ return update_insn_state_regs(insn, state); ++ ++ switch (op->dest.type) { ++ ++ case OP_DEST_REG: ++ switch (op->src.type) { ++ ++ case OP_SRC_REG: ++ if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP && ++ cfa->base == CFI_SP && ++ regs[CFI_BP].base == CFI_CFA && ++ regs[CFI_BP].offset == -cfa->offset) { ++ ++ /* mov %rsp, %rbp */ ++ cfa->base = op->dest.reg; ++ state->bp_scratch = false; ++ } ++ ++ else if (op->src.reg == CFI_SP && ++ op->dest.reg == CFI_BP && state->drap) { ++ ++ /* drap: mov %rsp, %rbp */ ++ regs[CFI_BP].base = CFI_BP; ++ regs[CFI_BP].offset = -state->stack_size; ++ state->bp_scratch = false; ++ } ++ ++ else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { ++ ++ /* ++ * mov %rsp, %reg ++ * ++ * This is needed for the rare case where GCC ++ * does: ++ * ++ * mov %rsp, %rax ++ * ... ++ * mov %rax, %rsp ++ */ ++ state->vals[op->dest.reg].base = CFI_CFA; ++ state->vals[op->dest.reg].offset = -state->stack_size; ++ } ++ ++ else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP && ++ cfa->base == CFI_BP) { ++ ++ /* ++ * mov %rbp, %rsp ++ * ++ * Restore the original stack pointer (Clang). ++ */ ++ state->stack_size = -state->regs[CFI_BP].offset; ++ } ++ ++ else if (op->dest.reg == cfa->base) { ++ ++ /* mov %reg, %rsp */ ++ if (cfa->base == CFI_SP && ++ state->vals[op->src.reg].base == CFI_CFA) { ++ ++ /* ++ * This is needed for the rare case ++ * where GCC does something dumb like: ++ * ++ * lea 0x8(%rsp), %rcx ++ * ... ++ * mov %rcx, %rsp ++ */ ++ cfa->offset = -state->vals[op->src.reg].offset; ++ state->stack_size = cfa->offset; ++ ++ } else { ++ cfa->base = CFI_UNDEFINED; ++ cfa->offset = 0; ++ } ++ } ++ ++ break; ++ ++ case OP_SRC_ADD: ++ if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) { ++ ++ /* add imm, %rsp */ ++ state->stack_size -= op->src.offset; ++ if (cfa->base == CFI_SP) ++ cfa->offset -= op->src.offset; ++ break; ++ } ++ ++ if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { ++ ++ /* lea disp(%rbp), %rsp */ ++ state->stack_size = -(op->src.offset + regs[CFI_BP].offset); ++ break; ++ } ++ ++ if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { ++ ++ /* drap: lea disp(%rsp), %drap */ ++ state->drap_reg = op->dest.reg; ++ ++ /* ++ * lea disp(%rsp), %reg ++ * ++ * This is needed for the rare case where GCC ++ * does something dumb like: ++ * ++ * lea 0x8(%rsp), %rcx ++ * ... ++ * mov %rcx, %rsp ++ */ ++ state->vals[op->dest.reg].base = CFI_CFA; ++ state->vals[op->dest.reg].offset = \ ++ -state->stack_size + op->src.offset; ++ ++ break; ++ } ++ ++ if (state->drap && op->dest.reg == CFI_SP && ++ op->src.reg == state->drap_reg) { ++ ++ /* drap: lea disp(%drap), %rsp */ ++ cfa->base = CFI_SP; ++ cfa->offset = state->stack_size = -op->src.offset; ++ state->drap_reg = CFI_UNDEFINED; ++ state->drap = false; ++ break; ++ } ++ ++ if (op->dest.reg == state->cfa.base) { ++ WARN_FUNC("unsupported stack register modification", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ break; ++ ++ case OP_SRC_AND: ++ if (op->dest.reg != CFI_SP || ++ (state->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || ++ (state->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { ++ WARN_FUNC("unsupported stack pointer realignment", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ if (state->drap_reg != CFI_UNDEFINED) { ++ /* drap: and imm, %rsp */ ++ cfa->base = state->drap_reg; ++ cfa->offset = state->stack_size = 0; ++ state->drap = true; ++ } ++ ++ /* ++ * Older versions of GCC (4.8ish) realign the stack ++ * without DRAP, with a frame pointer. ++ */ ++ ++ break; ++ ++ case OP_SRC_POP: ++ if (!state->drap && op->dest.type == OP_DEST_REG && ++ op->dest.reg == cfa->base) { ++ ++ /* pop %rbp */ ++ cfa->base = CFI_SP; ++ } ++ ++ if (state->drap && cfa->base == CFI_BP_INDIRECT && ++ op->dest.type == OP_DEST_REG && ++ op->dest.reg == state->drap_reg && ++ state->drap_offset == -state->stack_size) { ++ ++ /* drap: pop %drap */ ++ cfa->base = state->drap_reg; ++ cfa->offset = 0; ++ state->drap_offset = -1; ++ ++ } else if (regs[op->dest.reg].offset == -state->stack_size) { ++ ++ /* pop %reg */ ++ restore_reg(state, op->dest.reg); ++ } ++ ++ state->stack_size -= 8; ++ if (cfa->base == CFI_SP) ++ cfa->offset -= 8; ++ ++ break; ++ ++ case OP_SRC_REG_INDIRECT: ++ if (state->drap && op->src.reg == CFI_BP && ++ op->src.offset == state->drap_offset) { ++ ++ /* drap: mov disp(%rbp), %drap */ ++ cfa->base = state->drap_reg; ++ cfa->offset = 0; ++ state->drap_offset = -1; ++ } ++ ++ if (state->drap && op->src.reg == CFI_BP && ++ op->src.offset == regs[op->dest.reg].offset) { ++ ++ /* drap: mov disp(%rbp), %reg */ ++ restore_reg(state, op->dest.reg); ++ ++ } else if (op->src.reg == cfa->base && ++ op->src.offset == regs[op->dest.reg].offset + cfa->offset) { ++ ++ /* mov disp(%rbp), %reg */ ++ /* mov disp(%rsp), %reg */ ++ restore_reg(state, op->dest.reg); ++ } ++ ++ break; ++ ++ default: ++ WARN_FUNC("unknown stack-related instruction", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ break; ++ ++ case OP_DEST_PUSH: ++ state->stack_size += 8; ++ if (cfa->base == CFI_SP) ++ cfa->offset += 8; ++ ++ if (op->src.type != OP_SRC_REG) ++ break; ++ ++ if (state->drap) { ++ if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { ++ ++ /* drap: push %drap */ ++ cfa->base = CFI_BP_INDIRECT; ++ cfa->offset = -state->stack_size; ++ ++ /* save drap so we know when to restore it */ ++ state->drap_offset = -state->stack_size; ++ ++ } else if (op->src.reg == CFI_BP && cfa->base == state->drap_reg) { ++ ++ /* drap: push %rbp */ ++ state->stack_size = 0; ++ ++ } else if (regs[op->src.reg].base == CFI_UNDEFINED) { ++ ++ /* drap: push %reg */ ++ save_reg(state, op->src.reg, CFI_BP, -state->stack_size); ++ } ++ ++ } else { ++ ++ /* push %reg */ ++ save_reg(state, op->src.reg, CFI_CFA, -state->stack_size); ++ } ++ ++ /* detect when asm code uses rbp as a scratch register */ ++ if (!no_fp && insn->func && op->src.reg == CFI_BP && ++ cfa->base != CFI_BP) ++ state->bp_scratch = true; ++ break; ++ ++ case OP_DEST_REG_INDIRECT: ++ ++ if (state->drap) { ++ if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { ++ ++ /* drap: mov %drap, disp(%rbp) */ ++ cfa->base = CFI_BP_INDIRECT; ++ cfa->offset = op->dest.offset; ++ ++ /* save drap offset so we know when to restore it */ ++ state->drap_offset = op->dest.offset; ++ } ++ ++ else if (regs[op->src.reg].base == CFI_UNDEFINED) { ++ ++ /* drap: mov reg, disp(%rbp) */ ++ save_reg(state, op->src.reg, CFI_BP, op->dest.offset); ++ } ++ ++ } else if (op->dest.reg == cfa->base) { ++ ++ /* mov reg, disp(%rbp) */ ++ /* mov reg, disp(%rsp) */ ++ save_reg(state, op->src.reg, CFI_CFA, ++ op->dest.offset - state->cfa.offset); ++ } ++ ++ break; ++ ++ case OP_DEST_LEAVE: ++ if ((!state->drap && cfa->base != CFI_BP) || ++ (state->drap && cfa->base != state->drap_reg)) { ++ WARN_FUNC("leave instruction with modified stack frame", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ /* leave (mov %rbp, %rsp; pop %rbp) */ ++ ++ state->stack_size = -state->regs[CFI_BP].offset - 8; ++ restore_reg(state, CFI_BP); ++ ++ if (!state->drap) { ++ cfa->base = CFI_SP; ++ cfa->offset -= 8; ++ } ++ ++ break; ++ ++ case OP_DEST_MEM: ++ if (op->src.type != OP_SRC_POP) { ++ WARN_FUNC("unknown stack-related memory operation", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ /* pop mem */ ++ state->stack_size -= 8; ++ if (cfa->base == CFI_SP) ++ cfa->offset -= 8; ++ ++ break; ++ ++ default: ++ WARN_FUNC("unknown stack-related instruction", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static bool insn_state_match(struct instruction *insn, struct insn_state *state) ++{ ++ struct insn_state *state1 = &insn->state, *state2 = state; ++ int i; ++ ++ if (memcmp(&state1->cfa, &state2->cfa, sizeof(state1->cfa))) { ++ WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d", ++ insn->sec, insn->offset, ++ state1->cfa.base, state1->cfa.offset, ++ state2->cfa.base, state2->cfa.offset); ++ ++ } else if (memcmp(&state1->regs, &state2->regs, sizeof(state1->regs))) { ++ for (i = 0; i < CFI_NUM_REGS; i++) { ++ if (!memcmp(&state1->regs[i], &state2->regs[i], ++ sizeof(struct cfi_reg))) ++ continue; ++ ++ WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", ++ insn->sec, insn->offset, ++ i, state1->regs[i].base, state1->regs[i].offset, ++ i, state2->regs[i].base, state2->regs[i].offset); ++ break; ++ } ++ ++ } else if (state1->type != state2->type) { ++ WARN_FUNC("stack state mismatch: type1=%d type2=%d", ++ insn->sec, insn->offset, state1->type, state2->type); ++ ++ } else if (state1->drap != state2->drap || ++ (state1->drap && state1->drap_reg != state2->drap_reg) || ++ (state1->drap && state1->drap_offset != state2->drap_offset)) { ++ WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", ++ insn->sec, insn->offset, ++ state1->drap, state1->drap_reg, state1->drap_offset, ++ state2->drap, state2->drap_reg, state2->drap_offset); ++ ++ } else ++ return true; ++ ++ return false; ++} ++ ++/* ++ * Follow the branch starting at the given instruction, and recursively follow ++ * any other branches (jumps). Meanwhile, track the frame pointer state at ++ * each instruction and validate all the rules described in ++ * tools/objtool/Documentation/stack-validation.txt. ++ */ ++static int validate_branch(struct objtool_file *file, struct instruction *first, ++ struct insn_state state) ++{ ++ struct alternative *alt; ++ struct instruction *insn, *next_insn; ++ struct section *sec; ++ struct symbol *func = NULL; ++ int ret; ++ ++ insn = first; ++ sec = insn->sec; ++ ++ if (insn->alt_group && list_empty(&insn->alts)) { ++ WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", ++ sec, insn->offset); ++ return 1; ++ } ++ ++ while (1) { ++ next_insn = next_insn_same_sec(file, insn); ++ ++ if (file->c_file && func && insn->func && func != insn->func->pfunc) { ++ WARN("%s() falls through to next function %s()", ++ func->name, insn->func->name); ++ return 1; ++ } ++ ++ func = insn->func ? insn->func->pfunc : NULL; ++ ++ if (func && insn->ignore) { ++ WARN_FUNC("BUG: why am I validating an ignored function?", ++ sec, insn->offset); ++ return 1; ++ } ++ ++ if (insn->visited) { ++ if (!insn->hint && !insn_state_match(insn, &state)) ++ return 1; ++ ++ return 0; ++ } ++ ++ if (insn->hint) { ++ if (insn->restore) { ++ struct instruction *save_insn, *i; ++ ++ i = insn; ++ save_insn = NULL; ++ func_for_each_insn_continue_reverse(file, insn->func, i) { ++ if (i->save) { ++ save_insn = i; ++ break; ++ } ++ } ++ ++ if (!save_insn) { ++ WARN_FUNC("no corresponding CFI save for CFI restore", ++ sec, insn->offset); ++ return 1; ++ } ++ ++ if (!save_insn->visited) { ++ /* ++ * Oops, no state to copy yet. ++ * Hopefully we can reach this ++ * instruction from another branch ++ * after the save insn has been ++ * visited. ++ */ ++ if (insn == first) ++ return 0; ++ ++ WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo", ++ sec, insn->offset); ++ return 1; ++ } ++ ++ insn->state = save_insn->state; ++ } ++ ++ state = insn->state; ++ ++ } else ++ insn->state = state; ++ ++ insn->visited = true; ++ ++ if (!insn->ignore_alts) { ++ list_for_each_entry(alt, &insn->alts, list) { ++ ret = validate_branch(file, alt->insn, state); ++ if (ret) ++ return 1; ++ } ++ } ++ ++ switch (insn->type) { ++ ++ case INSN_RETURN: ++ if (func && has_modified_stack_frame(&state)) { ++ WARN_FUNC("return with modified stack frame", ++ sec, insn->offset); ++ return 1; ++ } ++ ++ if (state.bp_scratch) { ++ WARN("%s uses BP as a scratch register", ++ insn->func->name); ++ return 1; ++ } ++ ++ return 0; ++ ++ case INSN_CALL: ++ if (is_fentry_call(insn)) ++ break; ++ ++ ret = dead_end_function(file, insn->call_dest); ++ if (ret == 1) ++ return 0; ++ if (ret == -1) ++ return 1; ++ ++ /* fallthrough */ ++ case INSN_CALL_DYNAMIC: ++ if (!no_fp && func && !has_valid_stack_frame(&state)) { ++ WARN_FUNC("call without frame pointer save/setup", ++ sec, insn->offset); ++ return 1; ++ } ++ break; ++ ++ case INSN_JUMP_CONDITIONAL: ++ case INSN_JUMP_UNCONDITIONAL: ++ if (insn->jump_dest && ++ (!func || !insn->jump_dest->func || ++ insn->jump_dest->func->pfunc == func)) { ++ ret = validate_branch(file, insn->jump_dest, ++ state); ++ if (ret) ++ return 1; ++ ++ } else if (func && has_modified_stack_frame(&state)) { ++ WARN_FUNC("sibling call from callable instruction with modified stack frame", ++ sec, insn->offset); ++ return 1; ++ } ++ ++ if (insn->type == INSN_JUMP_UNCONDITIONAL) ++ return 0; ++ ++ break; ++ ++ case INSN_JUMP_DYNAMIC: ++ if (func && list_empty(&insn->alts) && ++ has_modified_stack_frame(&state)) { ++ WARN_FUNC("sibling call from callable instruction with modified stack frame", ++ sec, insn->offset); ++ return 1; ++ } ++ ++ return 0; ++ ++ case INSN_CONTEXT_SWITCH: ++ if (func && (!next_insn || !next_insn->hint)) { ++ WARN_FUNC("unsupported instruction in callable function", ++ sec, insn->offset); ++ return 1; ++ } ++ return 0; ++ ++ case INSN_STACK: ++ if (update_insn_state(insn, &state)) ++ return 1; ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (insn->dead_end) ++ return 0; ++ ++ if (!next_insn) { ++ if (state.cfa.base == CFI_UNDEFINED) ++ return 0; ++ WARN("%s: unexpected end of section", sec->name); ++ return 1; ++ } ++ ++ insn = next_insn; ++ } ++ ++ return 0; ++} ++ ++static int validate_unwind_hints(struct objtool_file *file) ++{ ++ struct instruction *insn; ++ int ret, warnings = 0; ++ struct insn_state state; ++ ++ if (!file->hints) ++ return 0; ++ ++ clear_insn_state(&state); ++ ++ for_each_insn(file, insn) { ++ if (insn->hint && !insn->visited) { ++ ret = validate_branch(file, insn, state); ++ warnings += ret; ++ } ++ } ++ ++ return warnings; ++} ++ ++static int validate_retpoline(struct objtool_file *file) ++{ ++ struct instruction *insn; ++ int warnings = 0; ++ ++ for_each_insn(file, insn) { ++ if (insn->type != INSN_JUMP_DYNAMIC && ++ insn->type != INSN_CALL_DYNAMIC) ++ continue; ++ ++ if (insn->retpoline_safe) ++ continue; ++ ++ /* ++ * .init.text code is ran before userspace and thus doesn't ++ * strictly need retpolines, except for modules which are ++ * loaded late, they very much do need retpoline in their ++ * .init.text ++ */ ++ if (!strcmp(insn->sec->name, ".init.text") && !module) ++ continue; ++ ++ WARN_FUNC("indirect %s found in RETPOLINE build", ++ insn->sec, insn->offset, ++ insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); ++ ++ warnings++; ++ } ++ ++ return warnings; ++} ++ ++static bool is_kasan_insn(struct instruction *insn) ++{ ++ return (insn->type == INSN_CALL && ++ !strcmp(insn->call_dest->name, "__asan_handle_no_return")); ++} ++ ++static bool is_ubsan_insn(struct instruction *insn) ++{ ++ return (insn->type == INSN_CALL && ++ !strcmp(insn->call_dest->name, ++ "__ubsan_handle_builtin_unreachable")); ++} ++ ++static bool ignore_unreachable_insn(struct instruction *insn) ++{ ++ int i; ++ ++ if (insn->ignore || insn->type == INSN_NOP) ++ return true; ++ ++ /* ++ * Ignore any unused exceptions. This can happen when a whitelisted ++ * function has an exception table entry. ++ * ++ * Also ignore alternative replacement instructions. This can happen ++ * when a whitelisted function uses one of the ALTERNATIVE macros. ++ */ ++ if (!strcmp(insn->sec->name, ".fixup") || ++ !strcmp(insn->sec->name, ".altinstr_replacement") || ++ !strcmp(insn->sec->name, ".altinstr_aux")) ++ return true; ++ ++ /* ++ * Check if this (or a subsequent) instruction is related to ++ * CONFIG_UBSAN or CONFIG_KASAN. ++ * ++ * End the search at 5 instructions to avoid going into the weeds. ++ */ ++ if (!insn->func) ++ return false; ++ for (i = 0; i < 5; i++) { ++ ++ if (is_kasan_insn(insn) || is_ubsan_insn(insn)) ++ return true; ++ ++ if (insn->type == INSN_JUMP_UNCONDITIONAL) { ++ if (insn->jump_dest && ++ insn->jump_dest->func == insn->func) { ++ insn = insn->jump_dest; ++ continue; ++ } ++ ++ break; ++ } ++ ++ if (insn->offset + insn->len >= insn->func->offset + insn->func->len) ++ break; ++ ++ insn = list_next_entry(insn, list); ++ } ++ ++ return false; ++} ++ ++static int validate_functions(struct objtool_file *file) ++{ ++ struct section *sec; ++ struct symbol *func; ++ struct instruction *insn; ++ struct insn_state state; ++ int ret, warnings = 0; ++ ++ clear_insn_state(&state); ++ ++ state.cfa = initial_func_cfi.cfa; ++ memcpy(&state.regs, &initial_func_cfi.regs, ++ CFI_NUM_REGS * sizeof(struct cfi_reg)); ++ state.stack_size = initial_func_cfi.cfa.offset; ++ ++ for_each_sec(file, sec) { ++ list_for_each_entry(func, &sec->symbol_list, list) { ++ if (func->type != STT_FUNC || func->pfunc != func) ++ continue; ++ ++ insn = find_insn(file, sec, func->offset); ++ if (!insn || insn->ignore) ++ continue; ++ ++ ret = validate_branch(file, insn, state); ++ warnings += ret; ++ } ++ } ++ ++ return warnings; ++} ++ ++static int validate_reachable_instructions(struct objtool_file *file) ++{ ++ struct instruction *insn; ++ ++ if (file->ignore_unreachables) ++ return 0; ++ ++ for_each_insn(file, insn) { ++ if (insn->visited || ignore_unreachable_insn(insn)) ++ continue; ++ ++ WARN_FUNC("unreachable instruction", insn->sec, insn->offset); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void cleanup(struct objtool_file *file) ++{ ++ struct instruction *insn, *tmpinsn; ++ struct alternative *alt, *tmpalt; ++ ++ list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) { ++ list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { ++ list_del(&alt->list); ++ free(alt); ++ } ++ list_del(&insn->list); ++ hash_del(&insn->hash); ++ free(insn); ++ } ++ elf_close(file->elf); ++} ++ ++int check(const char *_objname, bool orc) ++{ ++ struct objtool_file file; ++ int ret, warnings = 0; ++ ++ objname = _objname; ++ ++ file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); ++ if (!file.elf) ++ return 1; ++ ++ INIT_LIST_HEAD(&file.insn_list); ++ hash_init(file.insn_hash); ++ file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); ++ file.rodata = find_section_by_name(file.elf, ".rodata"); ++ file.c_file = find_section_by_name(file.elf, ".comment"); ++ file.ignore_unreachables = no_unreachable; ++ file.hints = false; ++ ++ arch_initial_func_cfi_state(&initial_func_cfi); ++ ++ ret = decode_sections(&file); ++ if (ret < 0) ++ goto out; ++ warnings += ret; ++ ++ if (list_empty(&file.insn_list)) ++ goto out; ++ ++ if (retpoline) { ++ ret = validate_retpoline(&file); ++ if (ret < 0) ++ return ret; ++ warnings += ret; ++ } ++ ++ ret = validate_functions(&file); ++ if (ret < 0) ++ goto out; ++ warnings += ret; ++ ++ ret = validate_unwind_hints(&file); ++ if (ret < 0) ++ goto out; ++ warnings += ret; ++ ++ if (!warnings) { ++ ret = validate_reachable_instructions(&file); ++ if (ret < 0) ++ goto out; ++ warnings += ret; ++ } ++ ++ if (orc) { ++ ret = create_orc(&file); ++ if (ret < 0) ++ goto out; ++ ++ ret = create_orc_sections(&file); ++ if (ret < 0) ++ goto out; ++ ++ ret = elf_write(file.elf); ++ if (ret < 0) ++ goto out; ++ } ++ ++out: ++ cleanup(&file); ++ ++ /* ignore warnings for now until we get all the code cleaned up */ ++ if (ret || warnings) ++ return 0; ++ return 0; ++} +diff --git a/tools/objtool/check.h b/tools/objtool/check.h +new file mode 100644 +index 000000000000..c6b68fcb926f +--- /dev/null ++++ b/tools/objtool/check.h +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (C) 2017 Josh Poimboeuf ++ * ++ * 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, see . ++ */ ++ ++#ifndef _CHECK_H ++#define _CHECK_H ++ ++#include ++#include "elf.h" ++#include "cfi.h" ++#include "arch.h" ++#include "orc.h" ++#include ++ ++struct insn_state { ++ struct cfi_reg cfa; ++ struct cfi_reg regs[CFI_NUM_REGS]; ++ int stack_size; ++ unsigned char type; ++ bool bp_scratch; ++ bool drap; ++ int drap_reg, drap_offset; ++ struct cfi_reg vals[CFI_NUM_REGS]; ++}; ++ ++struct instruction { ++ struct list_head list; ++ struct hlist_node hash; ++ struct section *sec; ++ unsigned long offset; ++ unsigned int len; ++ unsigned char type; ++ unsigned long immediate; ++ bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; ++ bool retpoline_safe; ++ struct symbol *call_dest; ++ struct instruction *jump_dest; ++ struct instruction *first_jump_src; ++ struct list_head alts; ++ struct symbol *func; ++ struct stack_op stack_op; ++ struct insn_state state; ++ struct orc_entry orc; ++}; ++ ++struct objtool_file { ++ struct elf *elf; ++ struct list_head insn_list; ++ DECLARE_HASHTABLE(insn_hash, 16); ++ struct section *rodata, *whitelist; ++ bool ignore_unreachables, c_file, hints; ++}; ++ ++int check(const char *objname, bool orc); ++ ++struct instruction *find_insn(struct objtool_file *file, ++ struct section *sec, unsigned long offset); ++ ++#define for_each_insn(file, insn) \ ++ list_for_each_entry(insn, &file->insn_list, list) ++ ++#define sec_for_each_insn(file, sec, insn) \ ++ for (insn = find_insn(file, sec, 0); \ ++ insn && &insn->list != &file->insn_list && \ ++ insn->sec == sec; \ ++ insn = list_next_entry(insn, list)) ++ ++ ++#endif /* _CHECK_H */ +diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c +index faacf0c89976..4e60e105583e 100644 +--- a/tools/objtool/elf.c ++++ b/tools/objtool/elf.c +@@ -31,13 +31,6 @@ + #include "elf.h" + #include "warn.h" + +-/* +- * Fallback for systems without this "read, mmaping if possible" cmd. +- */ +-#ifndef ELF_C_READ_MMAP +-#define ELF_C_READ_MMAP ELF_C_READ +-#endif +- + struct section *find_section_by_name(struct elf *elf, const char *name) + { + struct section *sec; +@@ -86,6 +79,19 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) + return NULL; + } + ++struct symbol *find_symbol_by_name(struct elf *elf, const char *name) ++{ ++ struct section *sec; ++ struct symbol *sym; ++ ++ list_for_each_entry(sec, &elf->sections, list) ++ list_for_each_entry(sym, &sec->symbol_list, list) ++ if (!strcmp(sym->name, name)) ++ return sym; ++ ++ return NULL; ++} ++ + struct symbol *find_symbol_containing(struct section *sec, unsigned long offset) + { + struct symbol *sym; +@@ -140,12 +146,12 @@ static int read_sections(struct elf *elf) + int i; + + if (elf_getshdrnum(elf->elf, §ions_nr)) { +- perror("elf_getshdrnum"); ++ WARN_ELF("elf_getshdrnum"); + return -1; + } + + if (elf_getshdrstrndx(elf->elf, &shstrndx)) { +- perror("elf_getshdrstrndx"); ++ WARN_ELF("elf_getshdrstrndx"); + return -1; + } + +@@ -166,37 +172,37 @@ static int read_sections(struct elf *elf) + + s = elf_getscn(elf->elf, i); + if (!s) { +- perror("elf_getscn"); ++ WARN_ELF("elf_getscn"); + return -1; + } + + sec->idx = elf_ndxscn(s); + + if (!gelf_getshdr(s, &sec->sh)) { +- perror("gelf_getshdr"); ++ WARN_ELF("gelf_getshdr"); + return -1; + } + + sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); + if (!sec->name) { +- perror("elf_strptr"); ++ WARN_ELF("elf_strptr"); + return -1; + } + +- sec->elf_data = elf_getdata(s, NULL); +- if (!sec->elf_data) { +- perror("elf_getdata"); +- return -1; +- } +- +- if (sec->elf_data->d_off != 0 || +- sec->elf_data->d_size != sec->sh.sh_size) { +- WARN("unexpected data attributes for %s", sec->name); +- return -1; ++ if (sec->sh.sh_size != 0) { ++ sec->data = elf_getdata(s, NULL); ++ if (!sec->data) { ++ WARN_ELF("elf_getdata"); ++ return -1; ++ } ++ if (sec->data->d_off != 0 || ++ sec->data->d_size != sec->sh.sh_size) { ++ WARN("unexpected data attributes for %s", ++ sec->name); ++ return -1; ++ } + } +- +- sec->data = (unsigned long)sec->elf_data->d_buf; +- sec->len = sec->elf_data->d_size; ++ sec->len = sec->sh.sh_size; + } + + /* sanity check, one more call to elf_nextscn() should return NULL */ +@@ -210,10 +216,11 @@ static int read_sections(struct elf *elf) + + static int read_symbols(struct elf *elf) + { +- struct section *symtab; +- struct symbol *sym; ++ struct section *symtab, *sec; ++ struct symbol *sym, *pfunc; + struct list_head *entry, *tmp; + int symbols_nr, i; ++ char *coldstr; + + symtab = find_section_by_name(elf, ".symtab"); + if (!symtab) { +@@ -233,15 +240,15 @@ static int read_symbols(struct elf *elf) + + sym->idx = i; + +- if (!gelf_getsym(symtab->elf_data, i, &sym->sym)) { +- perror("gelf_getsym"); ++ if (!gelf_getsym(symtab->data, i, &sym->sym)) { ++ WARN_ELF("gelf_getsym"); + goto err; + } + + sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, + sym->sym.st_name); + if (!sym->name) { +- perror("elf_strptr"); ++ WARN_ELF("elf_strptr"); + goto err; + } + +@@ -288,6 +295,30 @@ static int read_symbols(struct elf *elf) + hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx); + } + ++ /* Create parent/child links for any cold subfunctions */ ++ list_for_each_entry(sec, &elf->sections, list) { ++ list_for_each_entry(sym, &sec->symbol_list, list) { ++ if (sym->type != STT_FUNC) ++ continue; ++ sym->pfunc = sym->cfunc = sym; ++ coldstr = strstr(sym->name, ".cold."); ++ if (coldstr) { ++ coldstr[0] = '\0'; ++ pfunc = find_symbol_by_name(elf, sym->name); ++ coldstr[0] = '.'; ++ ++ if (!pfunc) { ++ WARN("%s(): can't find parent function", ++ sym->name); ++ goto err; ++ } ++ ++ sym->pfunc = pfunc; ++ pfunc->cfunc = sym; ++ } ++ } ++ } ++ + return 0; + + err: +@@ -323,8 +354,8 @@ static int read_relas(struct elf *elf) + } + memset(rela, 0, sizeof(*rela)); + +- if (!gelf_getrela(sec->elf_data, i, &rela->rela)) { +- perror("gelf_getrela"); ++ if (!gelf_getrela(sec->data, i, &rela->rela)) { ++ WARN_ELF("gelf_getrela"); + return -1; + } + +@@ -348,9 +379,10 @@ static int read_relas(struct elf *elf) + return 0; + } + +-struct elf *elf_open(const char *name) ++struct elf *elf_open(const char *name, int flags) + { + struct elf *elf; ++ Elf_Cmd cmd; + + elf_version(EV_CURRENT); + +@@ -363,27 +395,28 @@ struct elf *elf_open(const char *name) + + INIT_LIST_HEAD(&elf->sections); + +- elf->name = strdup(name); +- if (!elf->name) { +- perror("strdup"); +- goto err; +- } +- +- elf->fd = open(name, O_RDONLY); ++ elf->fd = open(name, flags); + if (elf->fd == -1) { + fprintf(stderr, "objtool: Can't open '%s': %s\n", + name, strerror(errno)); + goto err; + } + +- elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); ++ if ((flags & O_ACCMODE) == O_RDONLY) ++ cmd = ELF_C_READ_MMAP; ++ else if ((flags & O_ACCMODE) == O_RDWR) ++ cmd = ELF_C_RDWR; ++ else /* O_WRONLY */ ++ cmd = ELF_C_WRITE; ++ ++ elf->elf = elf_begin(elf->fd, cmd, NULL); + if (!elf->elf) { +- perror("elf_begin"); ++ WARN_ELF("elf_begin"); + goto err; + } + + if (!gelf_getehdr(elf->elf, &elf->ehdr)) { +- perror("gelf_getehdr"); ++ WARN_ELF("gelf_getehdr"); + goto err; + } + +@@ -403,12 +436,212 @@ struct elf *elf_open(const char *name) + return NULL; + } + ++struct section *elf_create_section(struct elf *elf, const char *name, ++ size_t entsize, int nr) ++{ ++ struct section *sec, *shstrtab; ++ size_t size = entsize * nr; ++ struct Elf_Scn *s; ++ Elf_Data *data; ++ ++ sec = malloc(sizeof(*sec)); ++ if (!sec) { ++ perror("malloc"); ++ return NULL; ++ } ++ memset(sec, 0, sizeof(*sec)); ++ ++ INIT_LIST_HEAD(&sec->symbol_list); ++ INIT_LIST_HEAD(&sec->rela_list); ++ hash_init(sec->rela_hash); ++ hash_init(sec->symbol_hash); ++ ++ list_add_tail(&sec->list, &elf->sections); ++ ++ s = elf_newscn(elf->elf); ++ if (!s) { ++ WARN_ELF("elf_newscn"); ++ return NULL; ++ } ++ ++ sec->name = strdup(name); ++ if (!sec->name) { ++ perror("strdup"); ++ return NULL; ++ } ++ ++ sec->idx = elf_ndxscn(s); ++ sec->len = size; ++ sec->changed = true; ++ ++ sec->data = elf_newdata(s); ++ if (!sec->data) { ++ WARN_ELF("elf_newdata"); ++ return NULL; ++ } ++ ++ sec->data->d_size = size; ++ sec->data->d_align = 1; ++ ++ if (size) { ++ sec->data->d_buf = malloc(size); ++ if (!sec->data->d_buf) { ++ perror("malloc"); ++ return NULL; ++ } ++ memset(sec->data->d_buf, 0, size); ++ } ++ ++ if (!gelf_getshdr(s, &sec->sh)) { ++ WARN_ELF("gelf_getshdr"); ++ return NULL; ++ } ++ ++ sec->sh.sh_size = size; ++ sec->sh.sh_entsize = entsize; ++ sec->sh.sh_type = SHT_PROGBITS; ++ sec->sh.sh_addralign = 1; ++ sec->sh.sh_flags = SHF_ALLOC; ++ ++ ++ /* Add section name to .shstrtab */ ++ shstrtab = find_section_by_name(elf, ".shstrtab"); ++ if (!shstrtab) { ++ WARN("can't find .shstrtab section"); ++ return NULL; ++ } ++ ++ s = elf_getscn(elf->elf, shstrtab->idx); ++ if (!s) { ++ WARN_ELF("elf_getscn"); ++ return NULL; ++ } ++ ++ data = elf_newdata(s); ++ if (!data) { ++ WARN_ELF("elf_newdata"); ++ return NULL; ++ } ++ ++ data->d_buf = sec->name; ++ data->d_size = strlen(name) + 1; ++ data->d_align = 1; ++ ++ sec->sh.sh_name = shstrtab->len; ++ ++ shstrtab->len += strlen(name) + 1; ++ shstrtab->changed = true; ++ ++ return sec; ++} ++ ++struct section *elf_create_rela_section(struct elf *elf, struct section *base) ++{ ++ char *relaname; ++ struct section *sec; ++ ++ relaname = malloc(strlen(base->name) + strlen(".rela") + 1); ++ if (!relaname) { ++ perror("malloc"); ++ return NULL; ++ } ++ strcpy(relaname, ".rela"); ++ strcat(relaname, base->name); ++ ++ sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); ++ free(relaname); ++ if (!sec) ++ return NULL; ++ ++ base->rela = sec; ++ sec->base = base; ++ ++ sec->sh.sh_type = SHT_RELA; ++ sec->sh.sh_addralign = 8; ++ sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; ++ sec->sh.sh_info = base->idx; ++ sec->sh.sh_flags = SHF_INFO_LINK; ++ ++ return sec; ++} ++ ++int elf_rebuild_rela_section(struct section *sec) ++{ ++ struct rela *rela; ++ int nr, idx = 0, size; ++ GElf_Rela *relas; ++ ++ nr = 0; ++ list_for_each_entry(rela, &sec->rela_list, list) ++ nr++; ++ ++ size = nr * sizeof(*relas); ++ relas = malloc(size); ++ if (!relas) { ++ perror("malloc"); ++ return -1; ++ } ++ ++ sec->data->d_buf = relas; ++ sec->data->d_size = size; ++ ++ sec->sh.sh_size = size; ++ ++ idx = 0; ++ list_for_each_entry(rela, &sec->rela_list, list) { ++ relas[idx].r_offset = rela->offset; ++ relas[idx].r_addend = rela->addend; ++ relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type); ++ idx++; ++ } ++ ++ return 0; ++} ++ ++int elf_write(struct elf *elf) ++{ ++ struct section *sec; ++ Elf_Scn *s; ++ ++ /* Update section headers for changed sections: */ ++ list_for_each_entry(sec, &elf->sections, list) { ++ if (sec->changed) { ++ s = elf_getscn(elf->elf, sec->idx); ++ if (!s) { ++ WARN_ELF("elf_getscn"); ++ return -1; ++ } ++ if (!gelf_update_shdr(s, &sec->sh)) { ++ WARN_ELF("gelf_update_shdr"); ++ return -1; ++ } ++ } ++ } ++ ++ /* Make sure the new section header entries get updated properly. */ ++ elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY); ++ ++ /* Write all changes to the file. */ ++ if (elf_update(elf->elf, ELF_C_WRITE) < 0) { ++ WARN_ELF("elf_update"); ++ return -1; ++ } ++ ++ return 0; ++} ++ + void elf_close(struct elf *elf) + { + struct section *sec, *tmpsec; + struct symbol *sym, *tmpsym; + struct rela *rela, *tmprela; + ++ if (elf->elf) ++ elf_end(elf->elf); ++ ++ if (elf->fd > 0) ++ close(elf->fd); ++ + list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { + list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { + list_del(&sym->list); +@@ -423,11 +656,6 @@ void elf_close(struct elf *elf) + list_del(&sec->list); + free(sec); + } +- if (elf->name) +- free(elf->name); +- if (elf->fd > 0) +- close(elf->fd); +- if (elf->elf) +- elf_end(elf->elf); ++ + free(elf); + } +diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h +index 731973e1a3f5..de5cd2ddded9 100644 +--- a/tools/objtool/elf.h ++++ b/tools/objtool/elf.h +@@ -28,6 +28,13 @@ + # define elf_getshdrstrndx elf_getshstrndx + #endif + ++/* ++ * Fallback for systems without this "read, mmaping if possible" cmd. ++ */ ++#ifndef ELF_C_READ_MMAP ++#define ELF_C_READ_MMAP ELF_C_READ ++#endif ++ + struct section { + struct list_head list; + GElf_Shdr sh; +@@ -37,11 +44,11 @@ struct section { + DECLARE_HASHTABLE(rela_hash, 16); + struct section *base, *rela; + struct symbol *sym; +- Elf_Data *elf_data; ++ Elf_Data *data; + char *name; + int idx; +- unsigned long data; + unsigned int len; ++ bool changed, text; + }; + + struct symbol { +@@ -54,6 +61,7 @@ struct symbol { + unsigned char bind, type; + unsigned long offset; + unsigned int len; ++ struct symbol *pfunc, *cfunc; + }; + + struct rela { +@@ -76,16 +84,23 @@ struct elf { + }; + + +-struct elf *elf_open(const char *name); ++struct elf *elf_open(const char *name, int flags); + struct section *find_section_by_name(struct elf *elf, const char *name); + struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); ++struct symbol *find_symbol_by_name(struct elf *elf, const char *name); + struct symbol *find_symbol_containing(struct section *sec, unsigned long offset); + struct rela *find_rela_by_dest(struct section *sec, unsigned long offset); + struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, + unsigned int len); + struct symbol *find_containing_func(struct section *sec, unsigned long offset); ++struct section *elf_create_section(struct elf *elf, const char *name, size_t ++ entsize, int nr); ++struct section *elf_create_rela_section(struct elf *elf, struct section *base); ++int elf_rebuild_rela_section(struct section *sec); ++int elf_write(struct elf *elf); + void elf_close(struct elf *elf); + +- ++#define for_each_sec(file, sec) \ ++ list_for_each_entry(sec, &file->elf->sections, list) + + #endif /* _OBJTOOL_ELF_H */ +diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c +index 46c326db4f46..07f329919828 100644 +--- a/tools/objtool/objtool.c ++++ b/tools/objtool/objtool.c +@@ -31,11 +31,10 @@ + #include + #include + #include ++#include + + #include "builtin.h" + +-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +- + struct cmd_struct { + const char *name; + int (*fn)(int, const char **); +@@ -43,10 +42,11 @@ struct cmd_struct { + }; + + static const char objtool_usage_string[] = +- "objtool [OPTIONS] COMMAND [ARGS]"; ++ "objtool COMMAND [ARGS]"; + + static struct cmd_struct objtool_cmds[] = { + {"check", cmd_check, "Perform stack metadata validation on an object file" }, ++ {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" }, + }; + + bool help; +@@ -70,7 +70,7 @@ static void cmd_usage(void) + + printf("\n"); + +- exit(1); ++ exit(129); + } + + static void handle_options(int *argc, const char ***argv) +@@ -86,9 +86,7 @@ static void handle_options(int *argc, const char ***argv) + break; + } else { + fprintf(stderr, "Unknown option: %s\n", cmd); +- fprintf(stderr, "\n Usage: %s\n", +- objtool_usage_string); +- exit(1); ++ cmd_usage(); + } + + (*argv)++; +diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h +new file mode 100644 +index 000000000000..b0e92a6d0903 +--- /dev/null ++++ b/tools/objtool/orc.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2017 Josh Poimboeuf ++ * ++ * 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, see . ++ */ ++ ++#ifndef _ORC_H ++#define _ORC_H ++ ++#include ++ ++struct objtool_file; ++ ++int create_orc(struct objtool_file *file); ++int create_orc_sections(struct objtool_file *file); ++ ++int orc_dump(const char *objname); ++ ++#endif /* _ORC_H */ +diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c +new file mode 100644 +index 000000000000..c3343820916a +--- /dev/null ++++ b/tools/objtool/orc_dump.c +@@ -0,0 +1,213 @@ ++/* ++ * Copyright (C) 2017 Josh Poimboeuf ++ * ++ * 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, see . ++ */ ++ ++#include ++#include "orc.h" ++#include "warn.h" ++ ++static const char *reg_name(unsigned int reg) ++{ ++ switch (reg) { ++ case ORC_REG_PREV_SP: ++ return "prevsp"; ++ case ORC_REG_DX: ++ return "dx"; ++ case ORC_REG_DI: ++ return "di"; ++ case ORC_REG_BP: ++ return "bp"; ++ case ORC_REG_SP: ++ return "sp"; ++ case ORC_REG_R10: ++ return "r10"; ++ case ORC_REG_R13: ++ return "r13"; ++ case ORC_REG_BP_INDIRECT: ++ return "bp(ind)"; ++ case ORC_REG_SP_INDIRECT: ++ return "sp(ind)"; ++ default: ++ return "?"; ++ } ++} ++ ++static const char *orc_type_name(unsigned int type) ++{ ++ switch (type) { ++ case ORC_TYPE_CALL: ++ return "call"; ++ case ORC_TYPE_REGS: ++ return "regs"; ++ case ORC_TYPE_REGS_IRET: ++ return "iret"; ++ default: ++ return "?"; ++ } ++} ++ ++static void print_reg(unsigned int reg, int offset) ++{ ++ if (reg == ORC_REG_BP_INDIRECT) ++ printf("(bp%+d)", offset); ++ else if (reg == ORC_REG_SP_INDIRECT) ++ printf("(sp%+d)", offset); ++ else if (reg == ORC_REG_UNDEFINED) ++ printf("(und)"); ++ else ++ printf("%s%+d", reg_name(reg), offset); ++} ++ ++int orc_dump(const char *_objname) ++{ ++ int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0; ++ struct orc_entry *orc = NULL; ++ char *name; ++ size_t nr_sections; ++ Elf64_Addr orc_ip_addr = 0; ++ size_t shstrtab_idx; ++ Elf *elf; ++ Elf_Scn *scn; ++ GElf_Shdr sh; ++ GElf_Rela rela; ++ GElf_Sym sym; ++ Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL; ++ ++ ++ objname = _objname; ++ ++ elf_version(EV_CURRENT); ++ ++ fd = open(objname, O_RDONLY); ++ if (fd == -1) { ++ perror("open"); ++ return -1; ++ } ++ ++ elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); ++ if (!elf) { ++ WARN_ELF("elf_begin"); ++ return -1; ++ } ++ ++ if (elf_getshdrnum(elf, &nr_sections)) { ++ WARN_ELF("elf_getshdrnum"); ++ return -1; ++ } ++ ++ if (elf_getshdrstrndx(elf, &shstrtab_idx)) { ++ WARN_ELF("elf_getshdrstrndx"); ++ return -1; ++ } ++ ++ for (i = 0; i < nr_sections; i++) { ++ scn = elf_getscn(elf, i); ++ if (!scn) { ++ WARN_ELF("elf_getscn"); ++ return -1; ++ } ++ ++ if (!gelf_getshdr(scn, &sh)) { ++ WARN_ELF("gelf_getshdr"); ++ return -1; ++ } ++ ++ name = elf_strptr(elf, shstrtab_idx, sh.sh_name); ++ if (!name) { ++ WARN_ELF("elf_strptr"); ++ return -1; ++ } ++ ++ data = elf_getdata(scn, NULL); ++ if (!data) { ++ WARN_ELF("elf_getdata"); ++ return -1; ++ } ++ ++ if (!strcmp(name, ".symtab")) { ++ symtab = data; ++ } else if (!strcmp(name, ".orc_unwind")) { ++ orc = data->d_buf; ++ orc_size = sh.sh_size; ++ } else if (!strcmp(name, ".orc_unwind_ip")) { ++ orc_ip = data->d_buf; ++ orc_ip_addr = sh.sh_addr; ++ } else if (!strcmp(name, ".rela.orc_unwind_ip")) { ++ rela_orc_ip = data; ++ } ++ } ++ ++ if (!symtab || !orc || !orc_ip) ++ return 0; ++ ++ if (orc_size % sizeof(*orc) != 0) { ++ WARN("bad .orc_unwind section size"); ++ return -1; ++ } ++ ++ nr_entries = orc_size / sizeof(*orc); ++ for (i = 0; i < nr_entries; i++) { ++ if (rela_orc_ip) { ++ if (!gelf_getrela(rela_orc_ip, i, &rela)) { ++ WARN_ELF("gelf_getrela"); ++ return -1; ++ } ++ ++ if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) { ++ WARN_ELF("gelf_getsym"); ++ return -1; ++ } ++ ++ scn = elf_getscn(elf, sym.st_shndx); ++ if (!scn) { ++ WARN_ELF("elf_getscn"); ++ return -1; ++ } ++ ++ if (!gelf_getshdr(scn, &sh)) { ++ WARN_ELF("gelf_getshdr"); ++ return -1; ++ } ++ ++ name = elf_strptr(elf, shstrtab_idx, sh.sh_name); ++ if (!name || !*name) { ++ WARN_ELF("elf_strptr"); ++ return -1; ++ } ++ ++ printf("%s+%llx:", name, (unsigned long long)rela.r_addend); ++ ++ } else { ++ printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i])); ++ } ++ ++ ++ printf(" sp:"); ++ ++ print_reg(orc[i].sp_reg, orc[i].sp_offset); ++ ++ printf(" bp:"); ++ ++ print_reg(orc[i].bp_reg, orc[i].bp_offset); ++ ++ printf(" type:%s\n", orc_type_name(orc[i].type)); ++ } ++ ++ elf_end(elf); ++ close(fd); ++ ++ return 0; ++} +diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c +new file mode 100644 +index 000000000000..18384d9be4e1 +--- /dev/null ++++ b/tools/objtool/orc_gen.c +@@ -0,0 +1,221 @@ ++/* ++ * Copyright (C) 2017 Josh Poimboeuf ++ * ++ * 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, see . ++ */ ++ ++#include ++#include ++ ++#include "orc.h" ++#include "check.h" ++#include "warn.h" ++ ++int create_orc(struct objtool_file *file) ++{ ++ struct instruction *insn; ++ ++ for_each_insn(file, insn) { ++ struct orc_entry *orc = &insn->orc; ++ struct cfi_reg *cfa = &insn->state.cfa; ++ struct cfi_reg *bp = &insn->state.regs[CFI_BP]; ++ ++ if (cfa->base == CFI_UNDEFINED) { ++ orc->sp_reg = ORC_REG_UNDEFINED; ++ continue; ++ } ++ ++ switch (cfa->base) { ++ case CFI_SP: ++ orc->sp_reg = ORC_REG_SP; ++ break; ++ case CFI_SP_INDIRECT: ++ orc->sp_reg = ORC_REG_SP_INDIRECT; ++ break; ++ case CFI_BP: ++ orc->sp_reg = ORC_REG_BP; ++ break; ++ case CFI_BP_INDIRECT: ++ orc->sp_reg = ORC_REG_BP_INDIRECT; ++ break; ++ case CFI_R10: ++ orc->sp_reg = ORC_REG_R10; ++ break; ++ case CFI_R13: ++ orc->sp_reg = ORC_REG_R13; ++ break; ++ case CFI_DI: ++ orc->sp_reg = ORC_REG_DI; ++ break; ++ case CFI_DX: ++ orc->sp_reg = ORC_REG_DX; ++ break; ++ default: ++ WARN_FUNC("unknown CFA base reg %d", ++ insn->sec, insn->offset, cfa->base); ++ return -1; ++ } ++ ++ switch(bp->base) { ++ case CFI_UNDEFINED: ++ orc->bp_reg = ORC_REG_UNDEFINED; ++ break; ++ case CFI_CFA: ++ orc->bp_reg = ORC_REG_PREV_SP; ++ break; ++ case CFI_BP: ++ orc->bp_reg = ORC_REG_BP; ++ break; ++ default: ++ WARN_FUNC("unknown BP base reg %d", ++ insn->sec, insn->offset, bp->base); ++ return -1; ++ } ++ ++ orc->sp_offset = cfa->offset; ++ orc->bp_offset = bp->offset; ++ orc->type = insn->state.type; ++ } ++ ++ return 0; ++} ++ ++static int create_orc_entry(struct section *u_sec, struct section *ip_relasec, ++ unsigned int idx, struct section *insn_sec, ++ unsigned long insn_off, struct orc_entry *o) ++{ ++ struct orc_entry *orc; ++ struct rela *rela; ++ ++ if (!insn_sec->sym) { ++ WARN("missing symbol for section %s", insn_sec->name); ++ return -1; ++ } ++ ++ /* populate ORC data */ ++ orc = (struct orc_entry *)u_sec->data->d_buf + idx; ++ memcpy(orc, o, sizeof(*orc)); ++ ++ /* populate rela for ip */ ++ rela = malloc(sizeof(*rela)); ++ if (!rela) { ++ perror("malloc"); ++ return -1; ++ } ++ memset(rela, 0, sizeof(*rela)); ++ ++ rela->sym = insn_sec->sym; ++ rela->addend = insn_off; ++ rela->type = R_X86_64_PC32; ++ rela->offset = idx * sizeof(int); ++ ++ list_add_tail(&rela->list, &ip_relasec->rela_list); ++ hash_add(ip_relasec->rela_hash, &rela->hash, rela->offset); ++ ++ return 0; ++} ++ ++int create_orc_sections(struct objtool_file *file) ++{ ++ struct instruction *insn, *prev_insn; ++ struct section *sec, *u_sec, *ip_relasec; ++ unsigned int idx; ++ ++ struct orc_entry empty = { ++ .sp_reg = ORC_REG_UNDEFINED, ++ .bp_reg = ORC_REG_UNDEFINED, ++ .type = ORC_TYPE_CALL, ++ }; ++ ++ sec = find_section_by_name(file->elf, ".orc_unwind"); ++ if (sec) { ++ WARN("file already has .orc_unwind section, skipping"); ++ return -1; ++ } ++ ++ /* count the number of needed orcs */ ++ idx = 0; ++ for_each_sec(file, sec) { ++ if (!sec->text) ++ continue; ++ ++ prev_insn = NULL; ++ sec_for_each_insn(file, sec, insn) { ++ if (!prev_insn || ++ memcmp(&insn->orc, &prev_insn->orc, ++ sizeof(struct orc_entry))) { ++ idx++; ++ } ++ prev_insn = insn; ++ } ++ ++ /* section terminator */ ++ if (prev_insn) ++ idx++; ++ } ++ if (!idx) ++ return -1; ++ ++ ++ /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */ ++ sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx); ++ if (!sec) ++ return -1; ++ ++ ip_relasec = elf_create_rela_section(file->elf, sec); ++ if (!ip_relasec) ++ return -1; ++ ++ /* create .orc_unwind section */ ++ u_sec = elf_create_section(file->elf, ".orc_unwind", ++ sizeof(struct orc_entry), idx); ++ ++ /* populate sections */ ++ idx = 0; ++ for_each_sec(file, sec) { ++ if (!sec->text) ++ continue; ++ ++ prev_insn = NULL; ++ sec_for_each_insn(file, sec, insn) { ++ if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc, ++ sizeof(struct orc_entry))) { ++ ++ if (create_orc_entry(u_sec, ip_relasec, idx, ++ insn->sec, insn->offset, ++ &insn->orc)) ++ return -1; ++ ++ idx++; ++ } ++ prev_insn = insn; ++ } ++ ++ /* section terminator */ ++ if (prev_insn) { ++ if (create_orc_entry(u_sec, ip_relasec, idx, ++ prev_insn->sec, ++ prev_insn->offset + prev_insn->len, ++ &empty)) ++ return -1; ++ ++ idx++; ++ } ++ } ++ ++ if (elf_rebuild_rela_section(ip_relasec)) ++ return -1; ++ ++ return 0; ++} +diff --git a/tools/objtool/special.c b/tools/objtool/special.c +index bff8abb3a4aa..84f001d52322 100644 +--- a/tools/objtool/special.c ++++ b/tools/objtool/special.c +@@ -91,16 +91,16 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, + alt->jump_or_nop = entry->jump_or_nop; + + if (alt->group) { +- alt->orig_len = *(unsigned char *)(sec->data + offset + ++ alt->orig_len = *(unsigned char *)(sec->data->d_buf + offset + + entry->orig_len); +- alt->new_len = *(unsigned char *)(sec->data + offset + ++ alt->new_len = *(unsigned char *)(sec->data->d_buf + offset + + entry->new_len); + } + + if (entry->feature) { + unsigned short feature; + +- feature = *(unsigned short *)(sec->data + offset + ++ feature = *(unsigned short *)(sec->data->d_buf + offset + + entry->feature); + + /* +diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh +new file mode 100755 +index 000000000000..1470e74e9d66 +--- /dev/null ++++ b/tools/objtool/sync-check.sh +@@ -0,0 +1,29 @@ ++#!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 ++ ++FILES=' ++arch/x86/lib/insn.c ++arch/x86/lib/inat.c ++arch/x86/lib/x86-opcode-map.txt ++arch/x86/tools/gen-insn-attr-x86.awk ++arch/x86/include/asm/insn.h ++arch/x86/include/asm/inat.h ++arch/x86/include/asm/inat_types.h ++arch/x86/include/asm/orc_types.h ++' ++ ++check() ++{ ++ local file=$1 ++ ++ diff $file ../../$file > /dev/null || ++ echo "Warning: synced file at 'tools/objtool/$file' differs from latest kernel version at '$file'" ++} ++ ++if [ ! -d ../../kernel ] || [ ! -d ../../tools ] || [ ! -d ../objtool ]; then ++ exit 0 ++fi ++ ++for i in $FILES; do ++ check $i ++done +diff --git a/tools/objtool/warn.h b/tools/objtool/warn.h +index ac7e07523e84..afd9f7a05f6d 100644 +--- a/tools/objtool/warn.h ++++ b/tools/objtool/warn.h +@@ -18,6 +18,13 @@ + #ifndef _WARN_H + #define _WARN_H + ++#include ++#include ++#include ++#include ++#include ++#include "elf.h" ++ + extern const char *objname; + + static inline char *offstr(struct section *sec, unsigned long offset) +@@ -57,4 +64,7 @@ static inline char *offstr(struct section *sec, unsigned long offset) + free(_str); \ + }) + ++#define WARN_ELF(format, ...) \ ++ WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) ++ + #endif /* _WARN_H */ +diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST +index 0bda2cca2b3a..a4f98e131819 100644 +--- a/tools/perf/MANIFEST ++++ b/tools/perf/MANIFEST +@@ -51,6 +51,7 @@ tools/include/asm-generic/bitops/arch_hweight.h + tools/include/asm-generic/bitops/atomic.h + tools/include/asm-generic/bitops/const_hweight.h + tools/include/asm-generic/bitops/__ffs.h ++tools/include/asm-generic/bitops/__ffz.h + tools/include/asm-generic/bitops/__fls.h + tools/include/asm-generic/bitops/find.h + tools/include/asm-generic/bitops/fls64.h +@@ -60,7 +61,9 @@ tools/include/asm-generic/bitops.h + tools/include/linux/atomic.h + tools/include/linux/bitops.h + tools/include/linux/compiler.h ++tools/include/linux/compiler-gcc.h + tools/include/linux/coresight-pmu.h ++tools/include/linux/bug.h + tools/include/linux/filter.h + tools/include/linux/hash.h + tools/include/linux/kernel.h +@@ -70,12 +73,15 @@ tools/include/uapi/asm-generic/mman-common.h + tools/include/uapi/asm-generic/mman.h + tools/include/uapi/linux/bpf.h + tools/include/uapi/linux/bpf_common.h ++tools/include/uapi/linux/fcntl.h + tools/include/uapi/linux/hw_breakpoint.h + tools/include/uapi/linux/mman.h + tools/include/uapi/linux/perf_event.h ++tools/include/uapi/linux/stat.h + tools/include/linux/poison.h + tools/include/linux/rbtree.h + tools/include/linux/rbtree_augmented.h ++tools/include/linux/refcount.h + tools/include/linux/string.h + tools/include/linux/stringify.h + tools/include/linux/types.h +diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf +index 2b92ffef554b..ad3726c5754d 100644 +--- a/tools/perf/Makefile.perf ++++ b/tools/perf/Makefile.perf +@@ -177,6 +177,36 @@ ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),) + endif + endif + ++# The fixdep build - we force fixdep tool to be built as ++# the first target in the separate make session not to be ++# disturbed by any parallel make jobs. Once fixdep is done ++# we issue the requested build with FIXDEP=1 variable. ++# ++# The fixdep build is disabled for $(NON_CONFIG_TARGETS) ++# targets, because it's not necessary. ++ ++ifdef FIXDEP ++ force_fixdep := 0 ++else ++ force_fixdep := $(config) ++endif ++ ++export srctree OUTPUT RM CC CXX LD AR CFLAGS CXXFLAGS V BISON FLEX AWK ++export HOSTCC HOSTLD HOSTAR ++ ++include $(srctree)/tools/build/Makefile.include ++ ++ifeq ($(force_fixdep),1) ++goals := $(filter-out all sub-make, $(MAKECMDGOALS)) ++ ++$(goals) all: sub-make ++ ++sub-make: fixdep ++ @./check-headers.sh ++ $(Q)$(MAKE) FIXDEP=1 -f Makefile.perf $(goals) ++ ++else # force_fixdep ++ + # Set FEATURE_TESTS to 'all' so all possible feature checkers are executed. + # Without this setting the output feature dump file misses some features, for + # example, liberty. Select all checkers so we won't get an incomplete feature +@@ -348,10 +378,6 @@ strip: $(PROGRAMS) $(OUTPUT)perf + + PERF_IN := $(OUTPUT)perf-in.o + +-export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK +-export HOSTCC HOSTLD HOSTAR +-include $(srctree)/tools/build/Makefile.include +- + JEVENTS := $(OUTPUT)pmu-events/jevents + JEVENTS_IN := $(OUTPUT)pmu-events/jevents-in.o + +@@ -362,99 +388,6 @@ export JEVENTS + build := -f $(srctree)/tools/build/Makefile.build dir=. obj + + $(PERF_IN): prepare FORCE +- @(test -f ../../include/uapi/linux/perf_event.h && ( \ +- (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \ +- || echo "Warning: tools/include/uapi/linux/perf_event.h differs from kernel" >&2 )) || true +- @(test -f ../../include/linux/hash.h && ( \ +- (diff -B ../include/linux/hash.h ../../include/linux/hash.h >/dev/null) \ +- || echo "Warning: tools/include/linux/hash.h differs from kernel" >&2 )) || true +- @(test -f ../../include/uapi/linux/hw_breakpoint.h && ( \ +- (diff -B ../include/uapi/linux/hw_breakpoint.h ../../include/uapi/linux/hw_breakpoint.h >/dev/null) \ +- || echo "Warning: tools/include/uapi/linux/hw_breakpoint.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/include/asm/disabled-features.h && ( \ +- (diff -B ../arch/x86/include/asm/disabled-features.h ../../arch/x86/include/asm/disabled-features.h >/dev/null) \ +- || echo "Warning: tools/arch/x86/include/asm/disabled-features.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/include/asm/required-features.h && ( \ +- (diff -B ../arch/x86/include/asm/required-features.h ../../arch/x86/include/asm/required-features.h >/dev/null) \ +- || echo "Warning: tools/arch/x86/include/asm/required-features.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/include/asm/cpufeatures.h && ( \ +- (diff -B ../arch/x86/include/asm/cpufeatures.h ../../arch/x86/include/asm/cpufeatures.h >/dev/null) \ +- || echo "Warning: tools/arch/x86/include/asm/cpufeatures.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/lib/memcpy_64.S && ( \ +- (diff -B ../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memcpy_64.S >/dev/null) \ +- || echo "Warning: tools/arch/x86/lib/memcpy_64.S differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/lib/memset_64.S && ( \ +- (diff -B ../arch/x86/lib/memset_64.S ../../arch/x86/lib/memset_64.S >/dev/null) \ +- || echo "Warning: tools/arch/x86/lib/memset_64.S differs from kernel" >&2 )) || true +- @(test -f ../../arch/arm/include/uapi/asm/perf_regs.h && ( \ +- (diff -B ../arch/arm/include/uapi/asm/perf_regs.h ../../arch/arm/include/uapi/asm/perf_regs.h >/dev/null) \ +- || echo "Warning: tools/arch/arm/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/arm64/include/uapi/asm/perf_regs.h && ( \ +- (diff -B ../arch/arm64/include/uapi/asm/perf_regs.h ../../arch/arm64/include/uapi/asm/perf_regs.h >/dev/null) \ +- || echo "Warning: tools/arch/arm64/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/powerpc/include/uapi/asm/perf_regs.h && ( \ +- (diff -B ../arch/powerpc/include/uapi/asm/perf_regs.h ../../arch/powerpc/include/uapi/asm/perf_regs.h >/dev/null) \ +- || echo "Warning: tools/arch/powerpc/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/include/uapi/asm/perf_regs.h && ( \ +- (diff -B ../arch/x86/include/uapi/asm/perf_regs.h ../../arch/x86/include/uapi/asm/perf_regs.h >/dev/null) \ +- || echo "Warning: tools/arch/x86/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/include/uapi/asm/kvm.h && ( \ +- (diff -B ../arch/x86/include/uapi/asm/kvm.h ../../arch/x86/include/uapi/asm/kvm.h >/dev/null) \ +- || echo "Warning: tools/arch/x86/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/include/uapi/asm/kvm_perf.h && ( \ +- (diff -B ../arch/x86/include/uapi/asm/kvm_perf.h ../../arch/x86/include/uapi/asm/kvm_perf.h >/dev/null) \ +- || echo "Warning: tools/arch/x86/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/include/uapi/asm/svm.h && ( \ +- (diff -B ../arch/x86/include/uapi/asm/svm.h ../../arch/x86/include/uapi/asm/svm.h >/dev/null) \ +- || echo "Warning: tools/arch/x86/include/uapi/asm/svm.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/x86/include/uapi/asm/vmx.h && ( \ +- (diff -B ../arch/x86/include/uapi/asm/vmx.h ../../arch/x86/include/uapi/asm/vmx.h >/dev/null) \ +- || echo "Warning: tools/arch/x86/include/uapi/asm/vmx.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/powerpc/include/uapi/asm/kvm.h && ( \ +- (diff -B ../arch/powerpc/include/uapi/asm/kvm.h ../../arch/powerpc/include/uapi/asm/kvm.h >/dev/null) \ +- || echo "Warning: tools/arch/powerpc/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/s390/include/uapi/asm/kvm.h && ( \ +- (diff -B ../arch/s390/include/uapi/asm/kvm.h ../../arch/s390/include/uapi/asm/kvm.h >/dev/null) \ +- || echo "Warning: tools/arch/s390/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/s390/include/uapi/asm/kvm_perf.h && ( \ +- (diff -B ../arch/s390/include/uapi/asm/kvm_perf.h ../../arch/s390/include/uapi/asm/kvm_perf.h >/dev/null) \ +- || echo "Warning: tools/arch/s390/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/s390/include/uapi/asm/sie.h && ( \ +- (diff -B ../arch/s390/include/uapi/asm/sie.h ../../arch/s390/include/uapi/asm/sie.h >/dev/null) \ +- || echo "Warning: tools/arch/s390/include/uapi/asm/sie.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/arm/include/uapi/asm/kvm.h && ( \ +- (diff -B ../arch/arm/include/uapi/asm/kvm.h ../../arch/arm/include/uapi/asm/kvm.h >/dev/null) \ +- || echo "Warning: tools/arch/arm/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true +- @(test -f ../../arch/arm64/include/uapi/asm/kvm.h && ( \ +- (diff -B ../arch/arm64/include/uapi/asm/kvm.h ../../arch/arm64/include/uapi/asm/kvm.h >/dev/null) \ +- || echo "Warning: tools/arch/arm64/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true +- @(test -f ../../include/asm-generic/bitops/arch_hweight.h && ( \ +- (diff -B ../include/asm-generic/bitops/arch_hweight.h ../../include/asm-generic/bitops/arch_hweight.h >/dev/null) \ +- || echo "Warning: tools/include/asm-generic/bitops/arch_hweight.h differs from kernel" >&2 )) || true +- @(test -f ../../include/asm-generic/bitops/const_hweight.h && ( \ +- (diff -B ../include/asm-generic/bitops/const_hweight.h ../../include/asm-generic/bitops/const_hweight.h >/dev/null) \ +- || echo "Warning: tools/include/asm-generic/bitops/const_hweight.h differs from kernel" >&2 )) || true +- @(test -f ../../include/asm-generic/bitops/__fls.h && ( \ +- (diff -B ../include/asm-generic/bitops/__fls.h ../../include/asm-generic/bitops/__fls.h >/dev/null) \ +- || echo "Warning: tools/include/asm-generic/bitops/__fls.h differs from kernel" >&2 )) || true +- @(test -f ../../include/asm-generic/bitops/fls.h && ( \ +- (diff -B ../include/asm-generic/bitops/fls.h ../../include/asm-generic/bitops/fls.h >/dev/null) \ +- || echo "Warning: tools/include/asm-generic/bitops/fls.h differs from kernel" >&2 )) || true +- @(test -f ../../include/asm-generic/bitops/fls64.h && ( \ +- (diff -B ../include/asm-generic/bitops/fls64.h ../../include/asm-generic/bitops/fls64.h >/dev/null) \ +- || echo "Warning: tools/include/asm-generic/bitops/fls64.h differs from kernel" >&2 )) || true +- @(test -f ../../include/linux/coresight-pmu.h && ( \ +- (diff -B ../include/linux/coresight-pmu.h ../../include/linux/coresight-pmu.h >/dev/null) \ +- || echo "Warning: tools/include/linux/coresight-pmu.h differs from kernel" >&2 )) || true +- @(test -f ../../include/uapi/asm-generic/mman-common.h && ( \ +- (diff -B ../include/uapi/asm-generic/mman-common.h ../../include/uapi/asm-generic/mman-common.h >/dev/null) \ +- || echo "Warning: tools/include/uapi/asm-generic/mman-common.h differs from kernel" >&2 )) || true +- @(test -f ../../include/uapi/asm-generic/mman.h && ( \ +- (diff -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>$$" ../include/uapi/asm-generic/mman.h ../../include/uapi/asm-generic/mman.h >/dev/null) \ +- || echo "Warning: tools/include/uapi/asm-generic/mman.h differs from kernel" >&2 )) || true +- @(test -f ../../include/uapi/linux/mman.h && ( \ +- (diff -B -I "^#include <\(uapi/\)*asm/mman.h>$$" ../include/uapi/linux/mman.h ../../include/uapi/linux/mman.h >/dev/null) \ +- || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true + $(Q)$(MAKE) $(build)=perf + + $(JEVENTS_IN): FORCE +@@ -470,7 +403,7 @@ $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBTRACEEVENT_DYNAMIC_L + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ + $(PERF_IN) $(PMU_EVENTS_IN) $(LIBS) -o $@ + +-$(GTK_IN): fixdep FORCE ++$(GTK_IN): FORCE + $(Q)$(MAKE) $(build)=gtk + + $(OUTPUT)libperf-gtk.so: $(GTK_IN) $(PERFLIBS) +@@ -515,7 +448,7 @@ endif + __build-dir = $(subst $(OUTPUT),,$(dir $@)) + build-dir = $(if $(__build-dir),$(__build-dir),.) + +-prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep archheaders ++prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders + + $(OUTPUT)%.o: %.c prepare FORCE + $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ +@@ -555,7 +488,7 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) + + LIBPERF_IN := $(OUTPUT)libperf-in.o + +-$(LIBPERF_IN): prepare fixdep FORCE ++$(LIBPERF_IN): prepare FORCE + $(Q)$(MAKE) $(build)=libperf + + $(LIB_FILE): $(LIBPERF_IN) +@@ -563,10 +496,10 @@ $(LIB_FILE): $(LIBPERF_IN) + + LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) + +-$(LIBTRACEEVENT): fixdep FORCE ++$(LIBTRACEEVENT): FORCE + $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a + +-libtraceevent_plugins: fixdep FORCE ++libtraceevent_plugins: FORCE + $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins + + $(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins +@@ -579,21 +512,21 @@ $(LIBTRACEEVENT)-clean: + install-traceevent-plugins: libtraceevent_plugins + $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins + +-$(LIBAPI): fixdep FORCE ++$(LIBAPI): FORCE + $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a + + $(LIBAPI)-clean: + $(call QUIET_CLEAN, libapi) + $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null + +-$(LIBBPF): fixdep FORCE ++$(LIBBPF): FORCE + $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) + + $(LIBBPF)-clean: + $(call QUIET_CLEAN, libbpf) + $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null + +-$(LIBSUBCMD): fixdep FORCE ++$(LIBSUBCMD): FORCE + $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a + + $(LIBSUBCMD)-clean: +@@ -790,3 +723,4 @@ FORCE: + .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare + .PHONY: libtraceevent_plugins archheaders + ++endif # force_fixdep +diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +index 555263e385c9..e93ef0b38db8 100644 +--- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl ++++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +@@ -335,6 +335,9 @@ + 326 common copy_file_range sys_copy_file_range + 327 64 preadv2 sys_preadv2 + 328 64 pwritev2 sys_pwritev2 ++329 common pkey_mprotect sys_pkey_mprotect ++330 common pkey_alloc sys_pkey_alloc ++331 common pkey_free sys_pkey_free + + # + # x32-specific system call numbers start at 512 to avoid cache impact +@@ -374,5 +377,5 @@ + 543 x32 io_setup compat_sys_io_setup + 544 x32 io_submit compat_sys_io_submit + 545 x32 execveat compat_sys_execveat/ptregs +-534 x32 preadv2 compat_sys_preadv2 +-535 x32 pwritev2 compat_sys_pwritev2 ++546 x32 preadv2 compat_sys_preadv64v2 ++547 x32 pwritev2 compat_sys_pwritev64v2 +diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh +new file mode 100755 +index 000000000000..83fe2202382e +--- /dev/null ++++ b/tools/perf/check-headers.sh +@@ -0,0 +1,61 @@ ++#!/bin/sh ++ ++HEADERS=' ++include/uapi/linux/fcntl.h ++include/uapi/linux/perf_event.h ++include/uapi/linux/stat.h ++include/linux/hash.h ++include/uapi/linux/hw_breakpoint.h ++arch/x86/include/asm/disabled-features.h ++arch/x86/include/asm/required-features.h ++arch/x86/include/asm/cpufeatures.h ++arch/arm/include/uapi/asm/perf_regs.h ++arch/arm64/include/uapi/asm/perf_regs.h ++arch/powerpc/include/uapi/asm/perf_regs.h ++arch/x86/include/uapi/asm/perf_regs.h ++arch/x86/include/uapi/asm/kvm.h ++arch/x86/include/uapi/asm/kvm_perf.h ++arch/x86/include/uapi/asm/svm.h ++arch/x86/include/uapi/asm/vmx.h ++arch/powerpc/include/uapi/asm/kvm.h ++arch/s390/include/uapi/asm/kvm.h ++arch/s390/include/uapi/asm/kvm_perf.h ++arch/s390/include/uapi/asm/sie.h ++arch/arm/include/uapi/asm/kvm.h ++arch/arm64/include/uapi/asm/kvm.h ++include/asm-generic/bitops/arch_hweight.h ++include/asm-generic/bitops/const_hweight.h ++include/asm-generic/bitops/__fls.h ++include/asm-generic/bitops/fls.h ++include/asm-generic/bitops/fls64.h ++include/linux/coresight-pmu.h ++include/uapi/asm-generic/mman-common.h ++' ++ ++check () { ++ file=$1 ++ opts= ++ ++ shift ++ while [ -n "$*" ]; do ++ opts="$opts \"$1\"" ++ shift ++ done ++ ++ cmd="diff $opts ../$file ../../$file > /dev/null" ++ ++ test -f ../../$file && ++ eval $cmd || echo "Warning: $file differs from kernel" >&2 ++} ++ ++ ++# simple diff check ++for i in $HEADERS; do ++ check $i -B ++done ++ ++# diff with extra ignore lines ++check arch/x86/lib/memcpy_64.S -B -I "^EXPORT_SYMBOL" -I "^#include " ++check arch/x86/lib/memset_64.S -B -I "^EXPORT_SYMBOL" -I "^#include " ++check include/uapi/asm-generic/mman.h -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>" ++check include/uapi/linux/mman.h -B -I "^#include <\(uapi/\)*asm/mman.h>" +diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h +index 43899e0d6fa1..e72d370889f8 100644 +--- a/tools/perf/util/util.h ++++ b/tools/perf/util/util.h +@@ -23,8 +23,6 @@ + #endif + #endif + +-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +- + #ifdef __GNUC__ + #define TYPEOF(x) (__typeof__(x)) + #else diff --git a/patch/kernel/odroidxu4-next/0004-patch-4.9.106-107.patch b/patch/kernel/odroidxu4-next/0004-patch-4.9.106-107.patch new file mode 100644 index 0000000000..50f9eb8396 --- /dev/null +++ b/patch/kernel/odroidxu4-next/0004-patch-4.9.106-107.patch @@ -0,0 +1,3059 @@ +diff --git a/Makefile b/Makefile +index 48d87e3a36c1..ac30e448e0a5 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 4 + PATCHLEVEL = 9 +-SUBLEVEL = 106 ++SUBLEVEL = 107 + EXTRAVERSION = + NAME = Roaring Lionus + +diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h +index 7457ce082b5f..d32a0160c89f 100644 +--- a/arch/arm64/include/asm/atomic_lse.h ++++ b/arch/arm64/include/asm/atomic_lse.h +@@ -117,7 +117,7 @@ static inline void atomic_and(int i, atomic_t *v) + /* LSE atomics */ + " mvn %w[i], %w[i]\n" + " stclr %w[i], %[v]") +- : [i] "+r" (w0), [v] "+Q" (v->counter) ++ : [i] "+&r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : __LL_SC_CLOBBERS); + } +@@ -135,7 +135,7 @@ static inline int atomic_fetch_and##name(int i, atomic_t *v) \ + /* LSE atomics */ \ + " mvn %w[i], %w[i]\n" \ + " ldclr" #mb " %w[i], %w[i], %[v]") \ +- : [i] "+r" (w0), [v] "+Q" (v->counter) \ ++ : [i] "+&r" (w0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ +@@ -161,7 +161,7 @@ static inline void atomic_sub(int i, atomic_t *v) + /* LSE atomics */ + " neg %w[i], %w[i]\n" + " stadd %w[i], %[v]") +- : [i] "+r" (w0), [v] "+Q" (v->counter) ++ : [i] "+&r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : __LL_SC_CLOBBERS); + } +@@ -180,7 +180,7 @@ static inline int atomic_sub_return##name(int i, atomic_t *v) \ + " neg %w[i], %w[i]\n" \ + " ldadd" #mb " %w[i], w30, %[v]\n" \ + " add %w[i], %w[i], w30") \ +- : [i] "+r" (w0), [v] "+Q" (v->counter) \ ++ : [i] "+&r" (w0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS , ##cl); \ + \ +@@ -207,7 +207,7 @@ static inline int atomic_fetch_sub##name(int i, atomic_t *v) \ + /* LSE atomics */ \ + " neg %w[i], %w[i]\n" \ + " ldadd" #mb " %w[i], %w[i], %[v]") \ +- : [i] "+r" (w0), [v] "+Q" (v->counter) \ ++ : [i] "+&r" (w0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ +@@ -314,7 +314,7 @@ static inline void atomic64_and(long i, atomic64_t *v) + /* LSE atomics */ + " mvn %[i], %[i]\n" + " stclr %[i], %[v]") +- : [i] "+r" (x0), [v] "+Q" (v->counter) ++ : [i] "+&r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : __LL_SC_CLOBBERS); + } +@@ -332,7 +332,7 @@ static inline long atomic64_fetch_and##name(long i, atomic64_t *v) \ + /* LSE atomics */ \ + " mvn %[i], %[i]\n" \ + " ldclr" #mb " %[i], %[i], %[v]") \ +- : [i] "+r" (x0), [v] "+Q" (v->counter) \ ++ : [i] "+&r" (x0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ +@@ -358,7 +358,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) + /* LSE atomics */ + " neg %[i], %[i]\n" + " stadd %[i], %[v]") +- : [i] "+r" (x0), [v] "+Q" (v->counter) ++ : [i] "+&r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : __LL_SC_CLOBBERS); + } +@@ -377,7 +377,7 @@ static inline long atomic64_sub_return##name(long i, atomic64_t *v) \ + " neg %[i], %[i]\n" \ + " ldadd" #mb " %[i], x30, %[v]\n" \ + " add %[i], %[i], x30") \ +- : [i] "+r" (x0), [v] "+Q" (v->counter) \ ++ : [i] "+&r" (x0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ +@@ -404,7 +404,7 @@ static inline long atomic64_fetch_sub##name(long i, atomic64_t *v) \ + /* LSE atomics */ \ + " neg %[i], %[i]\n" \ + " ldadd" #mb " %[i], %[i], %[v]") \ +- : [i] "+r" (x0), [v] "+Q" (v->counter) \ ++ : [i] "+&r" (x0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ +@@ -516,7 +516,7 @@ static inline long __cmpxchg_double##name(unsigned long old1, \ + " eor %[old1], %[old1], %[oldval1]\n" \ + " eor %[old2], %[old2], %[oldval2]\n" \ + " orr %[old1], %[old1], %[old2]") \ +- : [old1] "+r" (x0), [old2] "+r" (x1), \ ++ : [old1] "+&r" (x0), [old2] "+&r" (x1), \ + [v] "+Q" (*(unsigned long *)ptr) \ + : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4), \ + [oldval1] "r" (oldval1), [oldval2] "r" (oldval2) \ +diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h +index 0bc0b1de90c4..4ea85ebdf4df 100644 +--- a/arch/arm64/include/asm/cpufeature.h ++++ b/arch/arm64/include/asm/cpufeature.h +@@ -9,8 +9,6 @@ + #ifndef __ASM_CPUFEATURE_H + #define __ASM_CPUFEATURE_H + +-#include +- + #include + #include + #include +@@ -27,6 +25,8 @@ + + #ifndef __ASSEMBLY__ + ++#include ++#include + #include + + /* CPU feature register tracking */ +@@ -96,6 +96,7 @@ struct arm64_cpu_capabilities { + + extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); + extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; ++extern struct static_key_false arm64_const_caps_ready; + + bool this_cpu_has_cap(unsigned int cap); + +@@ -104,14 +105,27 @@ static inline bool cpu_have_feature(unsigned int num) + return elf_hwcap & (1UL << num); + } + ++/* System capability check for constant caps */ ++static inline bool __cpus_have_const_cap(int num) ++{ ++ if (num >= ARM64_NCAPS) ++ return false; ++ return static_branch_unlikely(&cpu_hwcap_keys[num]); ++} ++ + static inline bool cpus_have_cap(unsigned int num) + { + if (num >= ARM64_NCAPS) + return false; +- if (__builtin_constant_p(num)) +- return static_branch_unlikely(&cpu_hwcap_keys[num]); ++ return test_bit(num, cpu_hwcaps); ++} ++ ++static inline bool cpus_have_const_cap(int num) ++{ ++ if (static_branch_likely(&arm64_const_caps_ready)) ++ return __cpus_have_const_cap(num); + else +- return test_bit(num, cpu_hwcaps); ++ return cpus_have_cap(num); + } + + static inline void cpus_set_cap(unsigned int num) +@@ -121,7 +135,6 @@ static inline void cpus_set_cap(unsigned int num) + num, ARM64_NCAPS); + } else { + __set_bit(num, cpu_hwcaps); +- static_branch_enable(&cpu_hwcap_keys[num]); + } + } + +@@ -200,7 +213,7 @@ static inline bool cpu_supports_mixed_endian_el0(void) + + static inline bool system_supports_32bit_el0(void) + { +- return cpus_have_cap(ARM64_HAS_32BIT_EL0); ++ return cpus_have_const_cap(ARM64_HAS_32BIT_EL0); + } + + static inline bool system_supports_mixed_endian_el0(void) +diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h +index 0a33ea304e63..2abb4493f4f6 100644 +--- a/arch/arm64/include/asm/kvm_host.h ++++ b/arch/arm64/include/asm/kvm_host.h +@@ -24,6 +24,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -358,9 +359,12 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, + unsigned long vector_ptr) + { + /* +- * Call initialization code, and switch to the full blown +- * HYP code. ++ * Call initialization code, and switch to the full blown HYP code. ++ * If the cpucaps haven't been finalized yet, something has gone very ++ * wrong, and hyp will crash and burn when it uses any ++ * cpus_have_const_cap() wrapper. + */ ++ BUG_ON(!static_branch_likely(&arm64_const_caps_ready)); + __kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr); + } + +@@ -398,7 +402,7 @@ static inline void __cpu_init_stage2(void) + + static inline bool kvm_arm_harden_branch_predictor(void) + { +- return cpus_have_cap(ARM64_HARDEN_BRANCH_PREDICTOR); ++ return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR); + } + + #endif /* __ARM64_KVM_HOST_H__ */ +diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h +index eac73a640ea7..824c83db9b47 100644 +--- a/arch/arm64/include/asm/kvm_mmu.h ++++ b/arch/arm64/include/asm/kvm_mmu.h +@@ -341,7 +341,7 @@ static inline void *kvm_get_hyp_vector(void) + vect = __bp_harden_hyp_vecs_start + + data->hyp_vectors_slot * SZ_2K; + +- if (!cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN)) ++ if (!cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN)) + vect = lm_alias(vect); + } + +diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h +index d51158a61892..6ac34c75f4e1 100644 +--- a/arch/arm64/include/asm/mmu.h ++++ b/arch/arm64/include/asm/mmu.h +@@ -37,7 +37,7 @@ typedef struct { + static inline bool arm64_kernel_unmapped_at_el0(void) + { + return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) && +- cpus_have_cap(ARM64_UNMAP_KERNEL_AT_EL0); ++ cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0); + } + + typedef void (*bp_hardening_cb_t)(void); +diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c +index a0ee01202503..7959d2c92010 100644 +--- a/arch/arm64/kernel/cpufeature.c ++++ b/arch/arm64/kernel/cpufeature.c +@@ -47,6 +47,7 @@ unsigned int compat_elf_hwcap2 __read_mostly; + #endif + + DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); ++EXPORT_SYMBOL(cpu_hwcaps); + + DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, ARM64_NCAPS); + EXPORT_SYMBOL(cpu_hwcap_keys); +@@ -762,7 +763,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, + * ThunderX leads to apparent I-cache corruption of kernel text, which + * ends as well as you might imagine. Don't even try. + */ +- if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_27456)) { ++ if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_27456)) { + str = "ARM64_WORKAROUND_CAVIUM_27456"; + __kpti_forced = -1; + } +@@ -1051,8 +1052,16 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, + */ + void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) + { +- for (; caps->matches; caps++) +- if (caps->enable && cpus_have_cap(caps->capability)) ++ for (; caps->matches; caps++) { ++ unsigned int num = caps->capability; ++ ++ if (!cpus_have_cap(num)) ++ continue; ++ ++ /* Ensure cpus_have_const_cap(num) works */ ++ static_branch_enable(&cpu_hwcap_keys[num]); ++ ++ if (caps->enable) { + /* + * Use stop_machine() as it schedules the work allowing + * us to modify PSTATE, instead of on_each_cpu() which +@@ -1060,6 +1069,8 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) + * we return. + */ + stop_machine(caps->enable, (void *)caps, cpu_online_mask); ++ } ++ } + } + + /* +@@ -1163,6 +1174,14 @@ static void __init setup_feature_capabilities(void) + enable_cpu_capabilities(arm64_features); + } + ++DEFINE_STATIC_KEY_FALSE(arm64_const_caps_ready); ++EXPORT_SYMBOL(arm64_const_caps_ready); ++ ++static void __init mark_const_caps_ready(void) ++{ ++ static_branch_enable(&arm64_const_caps_ready); ++} ++ + extern const struct arm64_cpu_capabilities arm64_errata[]; + + bool this_cpu_has_cap(unsigned int cap) +@@ -1179,6 +1198,7 @@ void __init setup_cpu_features(void) + /* Set the CPU feature capabilies */ + setup_feature_capabilities(); + enable_errata_workarounds(); ++ mark_const_caps_ready(); + setup_elf_hwcaps(arm64_elf_hwcaps); + + if (system_supports_32bit_el0()) +@@ -1203,5 +1223,5 @@ void __init setup_cpu_features(void) + static bool __maybe_unused + cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused) + { +- return (cpus_have_cap(ARM64_HAS_PAN) && !cpus_have_cap(ARM64_HAS_UAO)); ++ return (cpus_have_const_cap(ARM64_HAS_PAN) && !cpus_have_const_cap(ARM64_HAS_UAO)); + } +diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c +index 0972ce58316d..e917d119490c 100644 +--- a/arch/arm64/kernel/process.c ++++ b/arch/arm64/kernel/process.c +@@ -291,7 +291,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, + memset(childregs, 0, sizeof(struct pt_regs)); + childregs->pstate = PSR_MODE_EL1h; + if (IS_ENABLED(CONFIG_ARM64_UAO) && +- cpus_have_cap(ARM64_HAS_UAO)) ++ cpus_have_const_cap(ARM64_HAS_UAO)) + childregs->pstate |= PSR_UAO_BIT; + p->thread.cpu_context.x19 = stack_start; + p->thread.cpu_context.x20 = stk_sz; +diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c +index 6e716a5f1173..ebb575c4231b 100644 +--- a/arch/mips/kernel/process.c ++++ b/arch/mips/kernel/process.c +@@ -699,6 +699,10 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) + if (value & ~known_bits) + return -EOPNOTSUPP; + ++ /* Setting FRE without FR is not supported. */ ++ if ((value & (PR_FP_MODE_FR | PR_FP_MODE_FRE)) == PR_FP_MODE_FRE) ++ return -EOPNOTSUPP; ++ + /* Avoid inadvertently triggering emulation */ + if ((value & PR_FP_MODE_FR) && raw_cpu_has_fpu && + !(raw_current_cpu_data.fpu_id & MIPS_FPIR_F64)) +diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c +index 8f7bf74d1c0b..4f64913b4b4c 100644 +--- a/arch/mips/kernel/ptrace.c ++++ b/arch/mips/kernel/ptrace.c +@@ -838,7 +838,7 @@ long arch_ptrace(struct task_struct *child, long request, + break; + } + #endif +- tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); ++ tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); + break; + case PC: + tmp = regs->cp0_epc; +diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c +index bc9afbabbe14..b1e945738138 100644 +--- a/arch/mips/kernel/ptrace32.c ++++ b/arch/mips/kernel/ptrace32.c +@@ -107,7 +107,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, + addr & 1); + break; + } +- tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); ++ tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); + break; + case PC: + tmp = regs->cp0_epc; +diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h +index 903e76a9f158..e2200100828d 100644 +--- a/arch/powerpc/include/asm/exception-64s.h ++++ b/arch/powerpc/include/asm/exception-64s.h +@@ -51,6 +51,27 @@ + #define EX_PPR 88 /* SMT thread status register (priority) */ + #define EX_CTR 96 + ++#define STF_ENTRY_BARRIER_SLOT \ ++ STF_ENTRY_BARRIER_FIXUP_SECTION; \ ++ nop; \ ++ nop; \ ++ nop ++ ++#define STF_EXIT_BARRIER_SLOT \ ++ STF_EXIT_BARRIER_FIXUP_SECTION; \ ++ nop; \ ++ nop; \ ++ nop; \ ++ nop; \ ++ nop; \ ++ nop ++ ++/* ++ * r10 must be free to use, r13 must be paca ++ */ ++#define INTERRUPT_TO_KERNEL \ ++ STF_ENTRY_BARRIER_SLOT ++ + /* + * Macros for annotating the expected destination of (h)rfid + * +@@ -67,16 +88,19 @@ + rfid + + #define RFI_TO_USER \ ++ STF_EXIT_BARRIER_SLOT; \ + RFI_FLUSH_SLOT; \ + rfid; \ + b rfi_flush_fallback + + #define RFI_TO_USER_OR_KERNEL \ ++ STF_EXIT_BARRIER_SLOT; \ + RFI_FLUSH_SLOT; \ + rfid; \ + b rfi_flush_fallback + + #define RFI_TO_GUEST \ ++ STF_EXIT_BARRIER_SLOT; \ + RFI_FLUSH_SLOT; \ + rfid; \ + b rfi_flush_fallback +@@ -85,21 +109,25 @@ + hrfid + + #define HRFI_TO_USER \ ++ STF_EXIT_BARRIER_SLOT; \ + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback + + #define HRFI_TO_USER_OR_KERNEL \ ++ STF_EXIT_BARRIER_SLOT; \ + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback + + #define HRFI_TO_GUEST \ ++ STF_EXIT_BARRIER_SLOT; \ + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback + + #define HRFI_TO_UNKNOWN \ ++ STF_EXIT_BARRIER_SLOT; \ + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback +@@ -225,6 +253,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) + #define __EXCEPTION_PROLOG_1(area, extra, vec) \ + OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR); \ + OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR); \ ++ INTERRUPT_TO_KERNEL; \ + SAVE_CTR(r10, area); \ + mfcr r9; \ + extra(vec); \ +diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h +index 7b332342071c..0bf8202feca6 100644 +--- a/arch/powerpc/include/asm/feature-fixups.h ++++ b/arch/powerpc/include/asm/feature-fixups.h +@@ -189,6 +189,22 @@ void apply_feature_fixups(void); + void setup_feature_keys(void); + #endif + ++#define STF_ENTRY_BARRIER_FIXUP_SECTION \ ++953: \ ++ .pushsection __stf_entry_barrier_fixup,"a"; \ ++ .align 2; \ ++954: \ ++ FTR_ENTRY_OFFSET 953b-954b; \ ++ .popsection; ++ ++#define STF_EXIT_BARRIER_FIXUP_SECTION \ ++955: \ ++ .pushsection __stf_exit_barrier_fixup,"a"; \ ++ .align 2; \ ++956: \ ++ FTR_ENTRY_OFFSET 955b-956b; \ ++ .popsection; ++ + #define RFI_FLUSH_FIXUP_SECTION \ + 951: \ + .pushsection __rfi_flush_fixup,"a"; \ +@@ -200,6 +216,9 @@ void setup_feature_keys(void); + + #ifndef __ASSEMBLY__ + ++extern long stf_barrier_fallback; ++extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup; ++extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup; + extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup; + + #endif +diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h +index dc0996b9d75d..9d978102bf0d 100644 +--- a/arch/powerpc/include/asm/hvcall.h ++++ b/arch/powerpc/include/asm/hvcall.h +@@ -313,6 +313,9 @@ + #define H_CPU_CHAR_L1D_FLUSH_ORI30 (1ull << 61) // IBM bit 2 + #define H_CPU_CHAR_L1D_FLUSH_TRIG2 (1ull << 60) // IBM bit 3 + #define H_CPU_CHAR_L1D_THREAD_PRIV (1ull << 59) // IBM bit 4 ++#define H_CPU_CHAR_BRANCH_HINTS_HONORED (1ull << 58) // IBM bit 5 ++#define H_CPU_CHAR_THREAD_RECONFIG_CTRL (1ull << 57) // IBM bit 6 ++#define H_CPU_CHAR_COUNT_CACHE_DISABLED (1ull << 56) // IBM bit 7 + + #define H_CPU_BEHAV_FAVOUR_SECURITY (1ull << 63) // IBM bit 0 + #define H_CPU_BEHAV_L1D_FLUSH_PR (1ull << 62) // IBM bit 1 +diff --git a/arch/powerpc/include/asm/security_features.h b/arch/powerpc/include/asm/security_features.h +new file mode 100644 +index 000000000000..44989b22383c +--- /dev/null ++++ b/arch/powerpc/include/asm/security_features.h +@@ -0,0 +1,85 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Security related feature bit definitions. ++ * ++ * Copyright 2018, Michael Ellerman, IBM Corporation. ++ */ ++ ++#ifndef _ASM_POWERPC_SECURITY_FEATURES_H ++#define _ASM_POWERPC_SECURITY_FEATURES_H ++ ++ ++extern unsigned long powerpc_security_features; ++extern bool rfi_flush; ++ ++/* These are bit flags */ ++enum stf_barrier_type { ++ STF_BARRIER_NONE = 0x1, ++ STF_BARRIER_FALLBACK = 0x2, ++ STF_BARRIER_EIEIO = 0x4, ++ STF_BARRIER_SYNC_ORI = 0x8, ++}; ++ ++void setup_stf_barrier(void); ++void do_stf_barrier_fixups(enum stf_barrier_type types); ++ ++static inline void security_ftr_set(unsigned long feature) ++{ ++ powerpc_security_features |= feature; ++} ++ ++static inline void security_ftr_clear(unsigned long feature) ++{ ++ powerpc_security_features &= ~feature; ++} ++ ++static inline bool security_ftr_enabled(unsigned long feature) ++{ ++ return !!(powerpc_security_features & feature); ++} ++ ++ ++// Features indicating support for Spectre/Meltdown mitigations ++ ++// The L1-D cache can be flushed with ori r30,r30,0 ++#define SEC_FTR_L1D_FLUSH_ORI30 0x0000000000000001ull ++ ++// The L1-D cache can be flushed with mtspr 882,r0 (aka SPRN_TRIG2) ++#define SEC_FTR_L1D_FLUSH_TRIG2 0x0000000000000002ull ++ ++// ori r31,r31,0 acts as a speculation barrier ++#define SEC_FTR_SPEC_BAR_ORI31 0x0000000000000004ull ++ ++// Speculation past bctr is disabled ++#define SEC_FTR_BCCTRL_SERIALISED 0x0000000000000008ull ++ ++// Entries in L1-D are private to a SMT thread ++#define SEC_FTR_L1D_THREAD_PRIV 0x0000000000000010ull ++ ++// Indirect branch prediction cache disabled ++#define SEC_FTR_COUNT_CACHE_DISABLED 0x0000000000000020ull ++ ++ ++// Features indicating need for Spectre/Meltdown mitigations ++ ++// The L1-D cache should be flushed on MSR[HV] 1->0 transition (hypervisor to guest) ++#define SEC_FTR_L1D_FLUSH_HV 0x0000000000000040ull ++ ++// The L1-D cache should be flushed on MSR[PR] 0->1 transition (kernel to userspace) ++#define SEC_FTR_L1D_FLUSH_PR 0x0000000000000080ull ++ ++// A speculation barrier should be used for bounds checks (Spectre variant 1) ++#define SEC_FTR_BNDS_CHK_SPEC_BAR 0x0000000000000100ull ++ ++// Firmware configuration indicates user favours security over performance ++#define SEC_FTR_FAVOUR_SECURITY 0x0000000000000200ull ++ ++ ++// Features enabled by default ++#define SEC_FTR_DEFAULT \ ++ (SEC_FTR_L1D_FLUSH_HV | \ ++ SEC_FTR_L1D_FLUSH_PR | \ ++ SEC_FTR_BNDS_CHK_SPEC_BAR | \ ++ SEC_FTR_FAVOUR_SECURITY) ++ ++#endif /* _ASM_POWERPC_SECURITY_FEATURES_H */ +diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h +index 6825a67cc3db..3f160cd20107 100644 +--- a/arch/powerpc/include/asm/setup.h ++++ b/arch/powerpc/include/asm/setup.h +@@ -48,7 +48,7 @@ enum l1d_flush_type { + L1D_FLUSH_MTTRIG = 0x8, + }; + +-void __init setup_rfi_flush(enum l1d_flush_type, bool enable); ++void setup_rfi_flush(enum l1d_flush_type, bool enable); + void do_rfi_flush_fixups(enum l1d_flush_type types); + + #endif /* !__ASSEMBLY__ */ +diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile +index adb52d101133..13885786282b 100644 +--- a/arch/powerpc/kernel/Makefile ++++ b/arch/powerpc/kernel/Makefile +@@ -44,7 +44,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ + obj-$(CONFIG_VDSO32) += vdso32/ + obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o + obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o +-obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o ++obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o security.o + obj-$(CONFIG_PPC_BOOK3S_64) += mce.o mce_power.o + obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o + obj-$(CONFIG_PPC64) += vdso64/ +diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S +index 9e05c8828ee2..ff45d007d195 100644 +--- a/arch/powerpc/kernel/cpu_setup_power.S ++++ b/arch/powerpc/kernel/cpu_setup_power.S +@@ -28,6 +28,7 @@ _GLOBAL(__setup_cpu_power7) + beqlr + li r0,0 + mtspr SPRN_LPID,r0 ++ mtspr SPRN_PCR,r0 + mfspr r3,SPRN_LPCR + bl __init_LPCR + bl __init_tlb_power7 +@@ -41,6 +42,7 @@ _GLOBAL(__restore_cpu_power7) + beqlr + li r0,0 + mtspr SPRN_LPID,r0 ++ mtspr SPRN_PCR,r0 + mfspr r3,SPRN_LPCR + bl __init_LPCR + bl __init_tlb_power7 +@@ -57,6 +59,7 @@ _GLOBAL(__setup_cpu_power8) + beqlr + li r0,0 + mtspr SPRN_LPID,r0 ++ mtspr SPRN_PCR,r0 + mfspr r3,SPRN_LPCR + ori r3, r3, LPCR_PECEDH + bl __init_LPCR +@@ -78,6 +81,7 @@ _GLOBAL(__restore_cpu_power8) + beqlr + li r0,0 + mtspr SPRN_LPID,r0 ++ mtspr SPRN_PCR,r0 + mfspr r3,SPRN_LPCR + ori r3, r3, LPCR_PECEDH + bl __init_LPCR +@@ -98,6 +102,7 @@ _GLOBAL(__setup_cpu_power9) + li r0,0 + mtspr SPRN_LPID,r0 + mtspr SPRN_PID,r0 ++ mtspr SPRN_PCR,r0 + mfspr r3,SPRN_LPCR + LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE) + or r3, r3, r4 +@@ -121,6 +126,7 @@ _GLOBAL(__restore_cpu_power9) + li r0,0 + mtspr SPRN_LPID,r0 + mtspr SPRN_PID,r0 ++ mtspr SPRN_PCR,r0 + mfspr r3,SPRN_LPCR + LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE) + or r3, r3, r4 +diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S +index 94b5dfb087e9..d50cc9b38b80 100644 +--- a/arch/powerpc/kernel/exceptions-64s.S ++++ b/arch/powerpc/kernel/exceptions-64s.S +@@ -846,7 +846,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM) + #endif + + +-EXC_REAL_MASKABLE(decrementer, 0x900, 0x980) ++EXC_REAL_OOL_MASKABLE(decrementer, 0x900, 0x980) + EXC_VIRT_MASKABLE(decrementer, 0x4900, 0x4980, 0x900) + TRAMP_KVM(PACA_EXGEN, 0x900) + EXC_COMMON_ASYNC(decrementer_common, 0x900, timer_interrupt) +@@ -884,6 +884,7 @@ BEGIN_FTR_SECTION \ + END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ + mr r9,r13 ; \ + GET_PACA(r13) ; \ ++ INTERRUPT_TO_KERNEL ; \ + mfspr r11,SPRN_SRR0 ; \ + 0: + +@@ -1353,6 +1354,19 @@ masked_##_H##interrupt: \ + ##_H##RFI_TO_KERNEL; \ + b . + ++TRAMP_REAL_BEGIN(stf_barrier_fallback) ++ std r9,PACA_EXRFI+EX_R9(r13) ++ std r10,PACA_EXRFI+EX_R10(r13) ++ sync ++ ld r9,PACA_EXRFI+EX_R9(r13) ++ ld r10,PACA_EXRFI+EX_R10(r13) ++ ori 31,31,0 ++ .rept 14 ++ b 1f ++1: ++ .endr ++ blr ++ + /* + * Real mode exceptions actually use this too, but alternate + * instruction code patches (which end up in the common .text area) +diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c +new file mode 100644 +index 000000000000..2277df84ef6e +--- /dev/null ++++ b/arch/powerpc/kernel/security.c +@@ -0,0 +1,237 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// ++// Security related flags and so on. ++// ++// Copyright 2018, Michael Ellerman, IBM Corporation. ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++ ++unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; ++ ++ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ bool thread_priv; ++ ++ thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); ++ ++ if (rfi_flush || thread_priv) { ++ struct seq_buf s; ++ seq_buf_init(&s, buf, PAGE_SIZE - 1); ++ ++ seq_buf_printf(&s, "Mitigation: "); ++ ++ if (rfi_flush) ++ seq_buf_printf(&s, "RFI Flush"); ++ ++ if (rfi_flush && thread_priv) ++ seq_buf_printf(&s, ", "); ++ ++ if (thread_priv) ++ seq_buf_printf(&s, "L1D private per thread"); ++ ++ seq_buf_printf(&s, "\n"); ++ ++ return s.len; ++ } ++ ++ if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && ++ !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) ++ return sprintf(buf, "Not affected\n"); ++ ++ return sprintf(buf, "Vulnerable\n"); ++} ++ ++ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ if (!security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) ++ return sprintf(buf, "Not affected\n"); ++ ++ return sprintf(buf, "Vulnerable\n"); ++} ++ ++ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ bool bcs, ccd, ori; ++ struct seq_buf s; ++ ++ seq_buf_init(&s, buf, PAGE_SIZE - 1); ++ ++ bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED); ++ ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); ++ ori = security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31); ++ ++ if (bcs || ccd) { ++ seq_buf_printf(&s, "Mitigation: "); ++ ++ if (bcs) ++ seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); ++ ++ if (bcs && ccd) ++ seq_buf_printf(&s, ", "); ++ ++ if (ccd) ++ seq_buf_printf(&s, "Indirect branch cache disabled"); ++ } else ++ seq_buf_printf(&s, "Vulnerable"); ++ ++ if (ori) ++ seq_buf_printf(&s, ", ori31 speculation barrier enabled"); ++ ++ seq_buf_printf(&s, "\n"); ++ ++ return s.len; ++} ++ ++/* ++ * Store-forwarding barrier support. ++ */ ++ ++static enum stf_barrier_type stf_enabled_flush_types; ++static bool no_stf_barrier; ++bool stf_barrier; ++ ++static int __init handle_no_stf_barrier(char *p) ++{ ++ pr_info("stf-barrier: disabled on command line."); ++ no_stf_barrier = true; ++ return 0; ++} ++ ++early_param("no_stf_barrier", handle_no_stf_barrier); ++ ++/* This is the generic flag used by other architectures */ ++static int __init handle_ssbd(char *p) ++{ ++ if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { ++ /* Until firmware tells us, we have the barrier with auto */ ++ return 0; ++ } else if (strncmp(p, "off", 3) == 0) { ++ handle_no_stf_barrier(NULL); ++ return 0; ++ } else ++ return 1; ++ ++ return 0; ++} ++early_param("spec_store_bypass_disable", handle_ssbd); ++ ++/* This is the generic flag used by other architectures */ ++static int __init handle_no_ssbd(char *p) ++{ ++ handle_no_stf_barrier(NULL); ++ return 0; ++} ++early_param("nospec_store_bypass_disable", handle_no_ssbd); ++ ++static void stf_barrier_enable(bool enable) ++{ ++ if (enable) ++ do_stf_barrier_fixups(stf_enabled_flush_types); ++ else ++ do_stf_barrier_fixups(STF_BARRIER_NONE); ++ ++ stf_barrier = enable; ++} ++ ++void setup_stf_barrier(void) ++{ ++ enum stf_barrier_type type; ++ bool enable, hv; ++ ++ hv = cpu_has_feature(CPU_FTR_HVMODE); ++ ++ /* Default to fallback in case fw-features are not available */ ++ if (cpu_has_feature(CPU_FTR_ARCH_300)) ++ type = STF_BARRIER_EIEIO; ++ else if (cpu_has_feature(CPU_FTR_ARCH_207S)) ++ type = STF_BARRIER_SYNC_ORI; ++ else if (cpu_has_feature(CPU_FTR_ARCH_206)) ++ type = STF_BARRIER_FALLBACK; ++ else ++ type = STF_BARRIER_NONE; ++ ++ enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && ++ (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || ++ (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); ++ ++ if (type == STF_BARRIER_FALLBACK) { ++ pr_info("stf-barrier: fallback barrier available\n"); ++ } else if (type == STF_BARRIER_SYNC_ORI) { ++ pr_info("stf-barrier: hwsync barrier available\n"); ++ } else if (type == STF_BARRIER_EIEIO) { ++ pr_info("stf-barrier: eieio barrier available\n"); ++ } ++ ++ stf_enabled_flush_types = type; ++ ++ if (!no_stf_barrier) ++ stf_barrier_enable(enable); ++} ++ ++ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { ++ const char *type; ++ switch (stf_enabled_flush_types) { ++ case STF_BARRIER_EIEIO: ++ type = "eieio"; ++ break; ++ case STF_BARRIER_SYNC_ORI: ++ type = "hwsync"; ++ break; ++ case STF_BARRIER_FALLBACK: ++ type = "fallback"; ++ break; ++ default: ++ type = "unknown"; ++ } ++ return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); ++ } ++ ++ if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && ++ !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) ++ return sprintf(buf, "Not affected\n"); ++ ++ return sprintf(buf, "Vulnerable\n"); ++} ++ ++#ifdef CONFIG_DEBUG_FS ++static int stf_barrier_set(void *data, u64 val) ++{ ++ bool enable; ++ ++ if (val == 1) ++ enable = true; ++ else if (val == 0) ++ enable = false; ++ else ++ return -EINVAL; ++ ++ /* Only do anything if we're changing state */ ++ if (enable != stf_barrier) ++ stf_barrier_enable(enable); ++ ++ return 0; ++} ++ ++static int stf_barrier_get(void *data, u64 *val) ++{ ++ *val = stf_barrier ? 1 : 0; ++ return 0; ++} ++ ++DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n"); ++ ++static __init int stf_barrier_debugfs_init(void) ++{ ++ debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier); ++ return 0; ++} ++device_initcall(stf_barrier_debugfs_init); ++#endif /* CONFIG_DEBUG_FS */ +diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c +index 5243501d95ef..fdba10695208 100644 +--- a/arch/powerpc/kernel/setup_64.c ++++ b/arch/powerpc/kernel/setup_64.c +@@ -679,6 +679,7 @@ static int __init disable_hardlockup_detector(void) + return 0; + } + early_initcall(disable_hardlockup_detector); ++#endif /* CONFIG_HARDLOCKUP_DETECTOR */ + + #ifdef CONFIG_PPC_BOOK3S_64 + static enum l1d_flush_type enabled_flush_types; +@@ -716,9 +717,6 @@ static void do_nothing(void *unused) + + void rfi_flush_enable(bool enable) + { +- if (rfi_flush == enable) +- return; +- + if (enable) { + do_rfi_flush_fixups(enabled_flush_types); + on_each_cpu(do_nothing, NULL, 1); +@@ -728,11 +726,15 @@ void rfi_flush_enable(bool enable) + rfi_flush = enable; + } + +-static void init_fallback_flush(void) ++static void __ref init_fallback_flush(void) + { + u64 l1d_size, limit; + int cpu; + ++ /* Only allocate the fallback flush area once (at boot time). */ ++ if (l1d_flush_fallback_area) ++ return; ++ + l1d_size = ppc64_caches.dsize; + limit = min(safe_stack_limit(), ppc64_rma_size); + +@@ -750,18 +752,18 @@ static void init_fallback_flush(void) + } + } + +-void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) ++void setup_rfi_flush(enum l1d_flush_type types, bool enable) + { + if (types & L1D_FLUSH_FALLBACK) { +- pr_info("rfi-flush: Using fallback displacement flush\n"); ++ pr_info("rfi-flush: fallback displacement flush available\n"); + init_fallback_flush(); + } + + if (types & L1D_FLUSH_ORI) +- pr_info("rfi-flush: Using ori type flush\n"); ++ pr_info("rfi-flush: ori type flush available\n"); + + if (types & L1D_FLUSH_MTTRIG) +- pr_info("rfi-flush: Using mttrig type flush\n"); ++ pr_info("rfi-flush: mttrig type flush available\n"); + + enabled_flush_types = types; + +@@ -772,13 +774,19 @@ void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) + #ifdef CONFIG_DEBUG_FS + static int rfi_flush_set(void *data, u64 val) + { ++ bool enable; ++ + if (val == 1) +- rfi_flush_enable(true); ++ enable = true; + else if (val == 0) +- rfi_flush_enable(false); ++ enable = false; + else + return -EINVAL; + ++ /* Only do anything if we're changing state */ ++ if (enable != rfi_flush) ++ rfi_flush_enable(enable); ++ + return 0; + } + +@@ -797,13 +805,4 @@ static __init int rfi_flush_debugfs_init(void) + } + device_initcall(rfi_flush_debugfs_init); + #endif +- +-ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- if (rfi_flush) +- return sprintf(buf, "Mitigation: RFI Flush\n"); +- +- return sprintf(buf, "Vulnerable\n"); +-} + #endif /* CONFIG_PPC_BOOK3S_64 */ +-#endif +diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S +index b61fb7902018..c16fddbb6ab8 100644 +--- a/arch/powerpc/kernel/vmlinux.lds.S ++++ b/arch/powerpc/kernel/vmlinux.lds.S +@@ -133,6 +133,20 @@ SECTIONS + RODATA + + #ifdef CONFIG_PPC64 ++ . = ALIGN(8); ++ __stf_entry_barrier_fixup : AT(ADDR(__stf_entry_barrier_fixup) - LOAD_OFFSET) { ++ __start___stf_entry_barrier_fixup = .; ++ *(__stf_entry_barrier_fixup) ++ __stop___stf_entry_barrier_fixup = .; ++ } ++ ++ . = ALIGN(8); ++ __stf_exit_barrier_fixup : AT(ADDR(__stf_exit_barrier_fixup) - LOAD_OFFSET) { ++ __start___stf_exit_barrier_fixup = .; ++ *(__stf_exit_barrier_fixup) ++ __stop___stf_exit_barrier_fixup = .; ++ } ++ + . = ALIGN(8); + __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) { + __start___rfi_flush_fixup = .; +diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c +index 46c8338a61bc..cf1398e3c2e0 100644 +--- a/arch/powerpc/lib/feature-fixups.c ++++ b/arch/powerpc/lib/feature-fixups.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -117,6 +118,120 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) + } + + #ifdef CONFIG_PPC_BOOK3S_64 ++void do_stf_entry_barrier_fixups(enum stf_barrier_type types) ++{ ++ unsigned int instrs[3], *dest; ++ long *start, *end; ++ int i; ++ ++ start = PTRRELOC(&__start___stf_entry_barrier_fixup), ++ end = PTRRELOC(&__stop___stf_entry_barrier_fixup); ++ ++ instrs[0] = 0x60000000; /* nop */ ++ instrs[1] = 0x60000000; /* nop */ ++ instrs[2] = 0x60000000; /* nop */ ++ ++ i = 0; ++ if (types & STF_BARRIER_FALLBACK) { ++ instrs[i++] = 0x7d4802a6; /* mflr r10 */ ++ instrs[i++] = 0x60000000; /* branch patched below */ ++ instrs[i++] = 0x7d4803a6; /* mtlr r10 */ ++ } else if (types & STF_BARRIER_EIEIO) { ++ instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ ++ } else if (types & STF_BARRIER_SYNC_ORI) { ++ instrs[i++] = 0x7c0004ac; /* hwsync */ ++ instrs[i++] = 0xe94d0000; /* ld r10,0(r13) */ ++ instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ ++ } ++ ++ for (i = 0; start < end; start++, i++) { ++ dest = (void *)start + *start; ++ ++ pr_devel("patching dest %lx\n", (unsigned long)dest); ++ ++ patch_instruction(dest, instrs[0]); ++ ++ if (types & STF_BARRIER_FALLBACK) ++ patch_branch(dest + 1, (unsigned long)&stf_barrier_fallback, ++ BRANCH_SET_LINK); ++ else ++ patch_instruction(dest + 1, instrs[1]); ++ ++ patch_instruction(dest + 2, instrs[2]); ++ } ++ ++ printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i, ++ (types == STF_BARRIER_NONE) ? "no" : ++ (types == STF_BARRIER_FALLBACK) ? "fallback" : ++ (types == STF_BARRIER_EIEIO) ? "eieio" : ++ (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" ++ : "unknown"); ++} ++ ++void do_stf_exit_barrier_fixups(enum stf_barrier_type types) ++{ ++ unsigned int instrs[6], *dest; ++ long *start, *end; ++ int i; ++ ++ start = PTRRELOC(&__start___stf_exit_barrier_fixup), ++ end = PTRRELOC(&__stop___stf_exit_barrier_fixup); ++ ++ instrs[0] = 0x60000000; /* nop */ ++ instrs[1] = 0x60000000; /* nop */ ++ instrs[2] = 0x60000000; /* nop */ ++ instrs[3] = 0x60000000; /* nop */ ++ instrs[4] = 0x60000000; /* nop */ ++ instrs[5] = 0x60000000; /* nop */ ++ ++ i = 0; ++ if (types & STF_BARRIER_FALLBACK || types & STF_BARRIER_SYNC_ORI) { ++ if (cpu_has_feature(CPU_FTR_HVMODE)) { ++ instrs[i++] = 0x7db14ba6; /* mtspr 0x131, r13 (HSPRG1) */ ++ instrs[i++] = 0x7db04aa6; /* mfspr r13, 0x130 (HSPRG0) */ ++ } else { ++ instrs[i++] = 0x7db243a6; /* mtsprg 2,r13 */ ++ instrs[i++] = 0x7db142a6; /* mfsprg r13,1 */ ++ } ++ instrs[i++] = 0x7c0004ac; /* hwsync */ ++ instrs[i++] = 0xe9ad0000; /* ld r13,0(r13) */ ++ instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ ++ if (cpu_has_feature(CPU_FTR_HVMODE)) { ++ instrs[i++] = 0x7db14aa6; /* mfspr r13, 0x131 (HSPRG1) */ ++ } else { ++ instrs[i++] = 0x7db242a6; /* mfsprg r13,2 */ ++ } ++ } else if (types & STF_BARRIER_EIEIO) { ++ instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ ++ } ++ ++ for (i = 0; start < end; start++, i++) { ++ dest = (void *)start + *start; ++ ++ pr_devel("patching dest %lx\n", (unsigned long)dest); ++ ++ patch_instruction(dest, instrs[0]); ++ patch_instruction(dest + 1, instrs[1]); ++ patch_instruction(dest + 2, instrs[2]); ++ patch_instruction(dest + 3, instrs[3]); ++ patch_instruction(dest + 4, instrs[4]); ++ patch_instruction(dest + 5, instrs[5]); ++ } ++ printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i, ++ (types == STF_BARRIER_NONE) ? "no" : ++ (types == STF_BARRIER_FALLBACK) ? "fallback" : ++ (types == STF_BARRIER_EIEIO) ? "eieio" : ++ (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" ++ : "unknown"); ++} ++ ++ ++void do_stf_barrier_fixups(enum stf_barrier_type types) ++{ ++ do_stf_entry_barrier_fixups(types); ++ do_stf_exit_barrier_fixups(types); ++} ++ + void do_rfi_flush_fixups(enum l1d_flush_type types) + { + unsigned int instrs[3], *dest; +@@ -153,7 +268,14 @@ void do_rfi_flush_fixups(enum l1d_flush_type types) + patch_instruction(dest + 2, instrs[2]); + } + +- printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i); ++ printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i, ++ (types == L1D_FLUSH_NONE) ? "no" : ++ (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" : ++ (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG) ++ ? "ori+mttrig type" ++ : "ori type" : ++ (types & L1D_FLUSH_MTTRIG) ? "mttrig type" ++ : "unknown"); + } + #endif /* CONFIG_PPC_BOOK3S_64 */ + +diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c +index 6f8b4c19373a..17203abf38e8 100644 +--- a/arch/powerpc/platforms/powernv/setup.c ++++ b/arch/powerpc/platforms/powernv/setup.c +@@ -37,53 +37,92 @@ + #include + #include + #include ++#include + + #include "powernv.h" + ++ ++static bool fw_feature_is(const char *state, const char *name, ++ struct device_node *fw_features) ++{ ++ struct device_node *np; ++ bool rc = false; ++ ++ np = of_get_child_by_name(fw_features, name); ++ if (np) { ++ rc = of_property_read_bool(np, state); ++ of_node_put(np); ++ } ++ ++ return rc; ++} ++ ++static void init_fw_feat_flags(struct device_node *np) ++{ ++ if (fw_feature_is("enabled", "inst-spec-barrier-ori31,31,0", np)) ++ security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); ++ ++ if (fw_feature_is("enabled", "fw-bcctrl-serialized", np)) ++ security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); ++ ++ if (fw_feature_is("enabled", "inst-l1d-flush-ori30,30,0", np)) ++ security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); ++ ++ if (fw_feature_is("enabled", "inst-l1d-flush-trig2", np)) ++ security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); ++ ++ if (fw_feature_is("enabled", "fw-l1d-thread-split", np)) ++ security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); ++ ++ if (fw_feature_is("enabled", "fw-count-cache-disabled", np)) ++ security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); ++ ++ /* ++ * The features below are enabled by default, so we instead look to see ++ * if firmware has *disabled* them, and clear them if so. ++ */ ++ if (fw_feature_is("disabled", "speculation-policy-favor-security", np)) ++ security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); ++ ++ if (fw_feature_is("disabled", "needs-l1d-flush-msr-pr-0-to-1", np)) ++ security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); ++ ++ if (fw_feature_is("disabled", "needs-l1d-flush-msr-hv-1-to-0", np)) ++ security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); ++ ++ if (fw_feature_is("disabled", "needs-spec-barrier-for-bound-checks", np)) ++ security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); ++} ++ + static void pnv_setup_rfi_flush(void) + { + struct device_node *np, *fw_features; + enum l1d_flush_type type; +- int enable; ++ bool enable; + + /* Default to fallback in case fw-features are not available */ + type = L1D_FLUSH_FALLBACK; +- enable = 1; + + np = of_find_node_by_name(NULL, "ibm,opal"); + fw_features = of_get_child_by_name(np, "fw-features"); + of_node_put(np); + + if (fw_features) { +- np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2"); +- if (np && of_property_read_bool(np, "enabled")) +- type = L1D_FLUSH_MTTRIG; ++ init_fw_feat_flags(fw_features); ++ of_node_put(fw_features); + +- of_node_put(np); ++ if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) ++ type = L1D_FLUSH_MTTRIG; + +- np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0"); +- if (np && of_property_read_bool(np, "enabled")) ++ if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) + type = L1D_FLUSH_ORI; +- +- of_node_put(np); +- +- /* Enable unless firmware says NOT to */ +- enable = 2; +- np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0"); +- if (np && of_property_read_bool(np, "disabled")) +- enable--; +- +- of_node_put(np); +- +- np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1"); +- if (np && of_property_read_bool(np, "disabled")) +- enable--; +- +- of_node_put(np); +- of_node_put(fw_features); + } + +- setup_rfi_flush(type, enable > 0); ++ enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ ++ (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || \ ++ security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV)); ++ ++ setup_rfi_flush(type, enable); + } + + static void __init pnv_setup_arch(void) +@@ -91,6 +130,7 @@ static void __init pnv_setup_arch(void) + set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); + + pnv_setup_rfi_flush(); ++ setup_stf_barrier(); + + /* Initialize SMP */ + pnv_smp_init(); +diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c +index 6a5e7467445c..3784a7abfcc8 100644 +--- a/arch/powerpc/platforms/pseries/mobility.c ++++ b/arch/powerpc/platforms/pseries/mobility.c +@@ -314,6 +314,9 @@ void post_mobility_fixup(void) + printk(KERN_ERR "Post-mobility device tree update " + "failed: %d\n", rc); + ++ /* Possibly switch to a new RFI flush type */ ++ pseries_setup_rfi_flush(); ++ + return; + } + +diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h +index b1be7b713fe6..62ff57cf6c24 100644 +--- a/arch/powerpc/platforms/pseries/pseries.h ++++ b/arch/powerpc/platforms/pseries/pseries.h +@@ -79,4 +79,6 @@ extern struct pci_controller_ops pseries_pci_controller_ops; + + unsigned long pseries_memory_block_size(void); + ++void pseries_setup_rfi_flush(void); ++ + #endif /* _PSERIES_PSERIES_H */ +diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c +index 1845fc611912..91ade7755823 100644 +--- a/arch/powerpc/platforms/pseries/setup.c ++++ b/arch/powerpc/platforms/pseries/setup.c +@@ -66,6 +66,7 @@ + #include + #include + #include ++#include + + #include "pseries.h" + +@@ -450,35 +451,78 @@ static void __init find_and_init_phbs(void) + of_pci_check_probe_only(); + } + +-static void pseries_setup_rfi_flush(void) ++static void init_cpu_char_feature_flags(struct h_cpu_char_result *result) ++{ ++ /* ++ * The features below are disabled by default, so we instead look to see ++ * if firmware has *enabled* them, and set them if so. ++ */ ++ if (result->character & H_CPU_CHAR_SPEC_BAR_ORI31) ++ security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); ++ ++ if (result->character & H_CPU_CHAR_BCCTRL_SERIALISED) ++ security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); ++ ++ if (result->character & H_CPU_CHAR_L1D_FLUSH_ORI30) ++ security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); ++ ++ if (result->character & H_CPU_CHAR_L1D_FLUSH_TRIG2) ++ security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); ++ ++ if (result->character & H_CPU_CHAR_L1D_THREAD_PRIV) ++ security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); ++ ++ if (result->character & H_CPU_CHAR_COUNT_CACHE_DISABLED) ++ security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); ++ ++ /* ++ * The features below are enabled by default, so we instead look to see ++ * if firmware has *disabled* them, and clear them if so. ++ */ ++ if (!(result->behaviour & H_CPU_BEHAV_FAVOUR_SECURITY)) ++ security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); ++ ++ if (!(result->behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) ++ security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); ++ ++ if (!(result->behaviour & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR)) ++ security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); ++} ++ ++void pseries_setup_rfi_flush(void) + { + struct h_cpu_char_result result; + enum l1d_flush_type types; + bool enable; + long rc; + +- /* Enable by default */ +- enable = true; ++ /* ++ * Set features to the defaults assumed by init_cpu_char_feature_flags() ++ * so it can set/clear again any features that might have changed after ++ * migration, and in case the hypercall fails and it is not even called. ++ */ ++ powerpc_security_features = SEC_FTR_DEFAULT; + + rc = plpar_get_cpu_characteristics(&result); +- if (rc == H_SUCCESS) { +- types = L1D_FLUSH_NONE; ++ if (rc == H_SUCCESS) ++ init_cpu_char_feature_flags(&result); + +- if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2) +- types |= L1D_FLUSH_MTTRIG; +- if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30) +- types |= L1D_FLUSH_ORI; ++ /* ++ * We're the guest so this doesn't apply to us, clear it to simplify ++ * handling of it elsewhere. ++ */ ++ security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); + +- /* Use fallback if nothing set in hcall */ +- if (types == L1D_FLUSH_NONE) +- types = L1D_FLUSH_FALLBACK; ++ types = L1D_FLUSH_FALLBACK; + +- if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) +- enable = false; +- } else { +- /* Default to fallback if case hcall is not available */ +- types = L1D_FLUSH_FALLBACK; +- } ++ if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) ++ types |= L1D_FLUSH_MTTRIG; ++ ++ if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) ++ types |= L1D_FLUSH_ORI; ++ ++ enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ ++ security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR); + + setup_rfi_flush(types, enable); + } +@@ -501,6 +545,7 @@ static void __init pSeries_setup_arch(void) + fwnmi_init(); + + pseries_setup_rfi_flush(); ++ setup_stf_barrier(); + + /* By default, only probe PCI (can be overridden by rtas_pci) */ + pci_add_flags(PCI_PROBE_ONLY); +diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c +index f87a55d77094..9b3f2e212b37 100644 +--- a/arch/sparc/kernel/ds.c ++++ b/arch/sparc/kernel/ds.c +@@ -908,7 +908,7 @@ static int register_services(struct ds_info *dp) + pbuf.req.handle = cp->handle; + pbuf.req.major = 1; + pbuf.req.minor = 0; +- strcpy(pbuf.req.svc_id, cp->service_id); ++ strcpy(pbuf.id_buf, cp->service_id); + + err = __ds_send(lp, &pbuf, msg_len); + if (err > 0) +diff --git a/arch/sparc/lib/multi3.S b/arch/sparc/lib/multi3.S +index d6b6c97fe3c7..703127aaf4a5 100644 +--- a/arch/sparc/lib/multi3.S ++++ b/arch/sparc/lib/multi3.S +@@ -5,26 +5,26 @@ + .align 4 + ENTRY(__multi3) /* %o0 = u, %o1 = v */ + mov %o1, %g1 +- srl %o3, 0, %g4 +- mulx %g4, %g1, %o1 ++ srl %o3, 0, %o4 ++ mulx %o4, %g1, %o1 + srlx %g1, 0x20, %g3 +- mulx %g3, %g4, %g5 +- sllx %g5, 0x20, %o5 +- srl %g1, 0, %g4 ++ mulx %g3, %o4, %g7 ++ sllx %g7, 0x20, %o5 ++ srl %g1, 0, %o4 + sub %o1, %o5, %o5 + srlx %o5, 0x20, %o5 +- addcc %g5, %o5, %g5 ++ addcc %g7, %o5, %g7 + srlx %o3, 0x20, %o5 +- mulx %g4, %o5, %g4 ++ mulx %o4, %o5, %o4 + mulx %g3, %o5, %o5 + sethi %hi(0x80000000), %g3 +- addcc %g5, %g4, %g5 +- srlx %g5, 0x20, %g5 ++ addcc %g7, %o4, %g7 ++ srlx %g7, 0x20, %g7 + add %g3, %g3, %g3 + movcc %xcc, %g0, %g3 +- addcc %o5, %g5, %o5 +- sllx %g4, 0x20, %g4 +- add %o1, %g4, %o1 ++ addcc %o5, %g7, %o5 ++ sllx %o4, 0x20, %o4 ++ add %o1, %o4, %o1 + add %o5, %g3, %g2 + mulx %g1, %o2, %g1 + add %g1, %g2, %g1 +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index e3a3f5a64884..2986a13b9786 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -472,6 +472,12 @@ static void __init xen_init_cpuid_mask(void) + cpuid_leaf1_ecx_set_mask = (1 << (X86_FEATURE_MWAIT % 32)); + } + ++static void __init xen_init_capabilities(void) ++{ ++ if (xen_pv_domain()) ++ setup_force_cpu_cap(X86_FEATURE_XENPV); ++} ++ + static void xen_set_debugreg(int reg, unsigned long val) + { + HYPERVISOR_set_debugreg(reg, val); +@@ -1634,6 +1640,7 @@ asmlinkage __visible void __init xen_start_kernel(void) + + xen_init_irq_ops(); + xen_init_cpuid_mask(); ++ xen_init_capabilities(); + + #ifdef CONFIG_X86_LOCAL_APIC + /* +@@ -1978,12 +1985,6 @@ bool xen_hvm_need_lapic(void) + } + EXPORT_SYMBOL_GPL(xen_hvm_need_lapic); + +-static void xen_set_cpu_features(struct cpuinfo_x86 *c) +-{ +- if (xen_pv_domain()) +- set_cpu_cap(c, X86_FEATURE_XENPV); +-} +- + static void xen_pin_vcpu(int cpu) + { + static bool disable_pinning; +@@ -2030,7 +2031,6 @@ const struct hypervisor_x86 x86_hyper_xen = { + .init_platform = xen_hvm_guest_init, + #endif + .x2apic_available = xen_x2apic_para_available, +- .set_cpu_features = xen_set_cpu_features, + .pin_vcpu = xen_pin_vcpu, + }; + EXPORT_SYMBOL(x86_hyper_xen); +diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c +index 6b54e02da10c..e48140e76043 100644 +--- a/drivers/dma-buf/dma-buf.c ++++ b/drivers/dma-buf/dma-buf.c +@@ -551,7 +551,7 @@ EXPORT_SYMBOL_GPL(dma_buf_detach); + struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, + enum dma_data_direction direction) + { +- struct sg_table *sg_table = ERR_PTR(-EINVAL); ++ struct sg_table *sg_table; + + might_sleep(); + +diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c +index 3e6fe82c6d64..4d49fa0911c6 100644 +--- a/drivers/gpu/drm/drm_dp_helper.c ++++ b/drivers/gpu/drm/drm_dp_helper.c +@@ -1065,6 +1065,7 @@ int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]) + static const u16 psr_setup_time_us[] = { + PSR_SETUP_TIME(330), + PSR_SETUP_TIME(275), ++ PSR_SETUP_TIME(220), + PSR_SETUP_TIME(165), + PSR_SETUP_TIME(110), + PSR_SETUP_TIME(55), +diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c +index 3517c0ed984a..479d64184da5 100644 +--- a/drivers/gpu/drm/i915/intel_lvds.c ++++ b/drivers/gpu/drm/i915/intel_lvds.c +@@ -864,6 +864,14 @@ static const struct dmi_system_id intel_no_lvds[] = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"), + }, + }, ++ { ++ .callback = intel_no_lvds_dmi_callback, ++ .ident = "Radiant P845", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "P845"), ++ }, ++ }, + + { } /* terminating entry */ + }; +diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c +index 877a0ed76abf..c38645106783 100644 +--- a/drivers/hwtracing/stm/core.c ++++ b/drivers/hwtracing/stm/core.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include "stm.h" + + #include +@@ -682,7 +683,7 @@ static void stm_device_release(struct device *dev) + { + struct stm_device *stm = to_stm_device(dev); + +- kfree(stm); ++ vfree(stm); + } + + int stm_register_device(struct device *parent, struct stm_data *stm_data, +@@ -699,7 +700,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, + return -EINVAL; + + nmasters = stm_data->sw_end - stm_data->sw_start + 1; +- stm = kzalloc(sizeof(*stm) + nmasters * sizeof(void *), GFP_KERNEL); ++ stm = vzalloc(sizeof(*stm) + nmasters * sizeof(void *)); + if (!stm) + return -ENOMEM; + +@@ -752,7 +753,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, + /* matches device_initialize() above */ + put_device(&stm->dev); + err_free: +- kfree(stm); ++ vfree(stm); + + return err; + } +diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c +index c5b999f0c519..7ef9b13262a8 100644 +--- a/drivers/iio/buffer/kfifo_buf.c ++++ b/drivers/iio/buffer/kfifo_buf.c +@@ -24,6 +24,13 @@ static inline int __iio_allocate_kfifo(struct iio_kfifo *buf, + if ((length == 0) || (bytes_per_datum == 0)) + return -EINVAL; + ++ /* ++ * Make sure we don't overflow an unsigned int after kfifo rounds up to ++ * the next power of 2. ++ */ ++ if (roundup_pow_of_two(length) > UINT_MAX / bytes_per_datum) ++ return -EINVAL; ++ + return __kfifo_alloc((struct __kfifo *)&buf->kf, length, + bytes_per_datum, GFP_KERNEL); + } +diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c +index ae04826e82fc..a32dd851e712 100644 +--- a/drivers/infiniband/core/cache.c ++++ b/drivers/infiniband/core/cache.c +@@ -437,7 +437,7 @@ static int __ib_cache_gid_get(struct ib_device *ib_dev, u8 port, int index, + return -EINVAL; + + if (table->data_vec[index].props & GID_TABLE_ENTRY_INVALID) +- return -EAGAIN; ++ return -EINVAL; + + memcpy(gid, &table->data_vec[index].gid, sizeof(*gid)); + if (attr) { +diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c +index e23b2495d52e..05b8695a6369 100644 +--- a/drivers/input/mouse/elan_i2c_smbus.c ++++ b/drivers/input/mouse/elan_i2c_smbus.c +@@ -130,7 +130,7 @@ static int elan_smbus_get_baseline_data(struct i2c_client *client, + bool max_baseline, u8 *value) + { + int error; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + error = i2c_smbus_read_block_data(client, + max_baseline ? +@@ -149,7 +149,7 @@ static int elan_smbus_get_version(struct i2c_client *client, + bool iap, u8 *version) + { + int error; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + error = i2c_smbus_read_block_data(client, + iap ? ETP_SMBUS_IAP_VERSION_CMD : +@@ -169,7 +169,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, + u8 *ic_type, u8 *version) + { + int error; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + error = i2c_smbus_read_block_data(client, + ETP_SMBUS_SM_VERSION_CMD, val); +@@ -186,7 +186,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, + static int elan_smbus_get_product_id(struct i2c_client *client, u16 *id) + { + int error; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + error = i2c_smbus_read_block_data(client, + ETP_SMBUS_UNIQUEID_CMD, val); +@@ -203,7 +203,7 @@ static int elan_smbus_get_checksum(struct i2c_client *client, + bool iap, u16 *csum) + { + int error; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + error = i2c_smbus_read_block_data(client, + iap ? ETP_SMBUS_FW_CHECKSUM_CMD : +@@ -224,7 +224,7 @@ static int elan_smbus_get_max(struct i2c_client *client, + { + int ret; + int error; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); + if (ret != 3) { +@@ -244,7 +244,7 @@ static int elan_smbus_get_resolution(struct i2c_client *client, + { + int ret; + int error; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RESOLUTION_CMD, val); + if (ret != 3) { +@@ -265,7 +265,7 @@ static int elan_smbus_get_num_traces(struct i2c_client *client, + { + int ret; + int error; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + ret = i2c_smbus_read_block_data(client, ETP_SMBUS_XY_TRACENUM_CMD, val); + if (ret != 3) { +@@ -292,7 +292,7 @@ static int elan_smbus_iap_get_mode(struct i2c_client *client, + { + int error; + u16 constant; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + error = i2c_smbus_read_block_data(client, ETP_SMBUS_IAP_CTRL_CMD, val); + if (error < 0) { +@@ -343,7 +343,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client) + int len; + int error; + enum tp_mode mode; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + u8 cmd[4] = {0x0F, 0x78, 0x00, 0x06}; + u16 password; + +@@ -417,7 +417,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client, + struct device *dev = &client->dev; + int error; + u16 result; +- u8 val[3]; ++ u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; + + /* + * Due to the limitation of smbus protocol limiting +diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c +index 0b1d5bdd0862..f7b8681aed3f 100644 +--- a/drivers/irqchip/irq-gic-v3.c ++++ b/drivers/irqchip/irq-gic-v3.c +@@ -120,11 +120,10 @@ static void gic_redist_wait_for_rwp(void) + } + + #ifdef CONFIG_ARM64 +-static DEFINE_STATIC_KEY_FALSE(is_cavium_thunderx); + + static u64 __maybe_unused gic_read_iar(void) + { +- if (static_branch_unlikely(&is_cavium_thunderx)) ++ if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_23154)) + return gic_read_iar_cavium_thunderx(); + else + return gic_read_iar_common(); +@@ -908,14 +907,6 @@ static const struct irq_domain_ops partition_domain_ops = { + .select = gic_irq_domain_select, + }; + +-static void gicv3_enable_quirks(void) +-{ +-#ifdef CONFIG_ARM64 +- if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_23154)) +- static_branch_enable(&is_cavium_thunderx); +-#endif +-} +- + static int __init gic_init_bases(void __iomem *dist_base, + struct redist_region *rdist_regs, + u32 nr_redist_regions, +@@ -938,8 +929,6 @@ static int __init gic_init_bases(void __iomem *dist_base, + gic_data.nr_redist_regions = nr_redist_regions; + gic_data.redist_stride = redist_stride; + +- gicv3_enable_quirks(); +- + /* + * Find out how many interrupts are supported. + * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) +diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c +index bcbb80ff86a7..1a92cd719e19 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c ++++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c +@@ -142,16 +142,17 @@ static void mlx4_en_free_frag(struct mlx4_en_priv *priv, + struct mlx4_en_rx_alloc *frags, + int i) + { +- const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i]; +- u32 next_frag_end = frags[i].page_offset + 2 * frag_info->frag_stride; +- +- +- if (next_frag_end > frags[i].page_size) +- dma_unmap_page(priv->ddev, frags[i].dma, frags[i].page_size, +- frag_info->dma_dir); ++ if (frags[i].page) { ++ const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i]; ++ u32 next_frag_end = frags[i].page_offset + ++ 2 * frag_info->frag_stride; + +- if (frags[i].page) ++ if (next_frag_end > frags[i].page_size) { ++ dma_unmap_page(priv->ddev, frags[i].dma, ++ frags[i].page_size, frag_info->dma_dir); ++ } + put_page(frags[i].page); ++ } + } + + static int mlx4_en_init_allocator(struct mlx4_en_priv *priv, +@@ -586,21 +587,28 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, + int length) + { + struct skb_frag_struct *skb_frags_rx = skb_shinfo(skb)->frags; +- struct mlx4_en_frag_info *frag_info; + int nr; + dma_addr_t dma; + + /* Collect used fragments while replacing them in the HW descriptors */ + for (nr = 0; nr < priv->num_frags; nr++) { +- frag_info = &priv->frag_info[nr]; ++ struct mlx4_en_frag_info *frag_info = &priv->frag_info[nr]; ++ u32 next_frag_end = frags[nr].page_offset + ++ 2 * frag_info->frag_stride; ++ + if (length <= frag_info->frag_prefix_size) + break; + if (unlikely(!frags[nr].page)) + goto fail; + + dma = be64_to_cpu(rx_desc->data[nr].addr); +- dma_sync_single_for_cpu(priv->ddev, dma, frag_info->frag_size, +- DMA_FROM_DEVICE); ++ if (next_frag_end > frags[nr].page_size) ++ dma_unmap_page(priv->ddev, frags[nr].dma, ++ frags[nr].page_size, frag_info->dma_dir); ++ else ++ dma_sync_single_for_cpu(priv->ddev, dma, ++ frag_info->frag_size, ++ DMA_FROM_DEVICE); + + /* Save page reference in skb */ + __skb_frag_set_page(&skb_frags_rx[nr], frags[nr].page); +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c +index ec2ea56f7933..fdbd35954d15 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c +@@ -304,9 +304,6 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, + writeVal = 0x00000000; + if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) + writeVal = writeVal - 0x06060606; +- else if (rtlpriv->dm.dynamic_txhighpower_lvl == +- TXHIGHPWRLEVEL_BT2) +- writeVal = writeVal; + *(p_outwriteval + rf) = writeVal; + } + } +diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c +index 056845bdf67b..bedce3453dd3 100644 +--- a/drivers/pinctrl/qcom/pinctrl-msm.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm.c +@@ -790,7 +790,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) + return -EINVAL; + + chip = &pctrl->chip; +- chip->base = -1; ++ chip->base = 0; + chip->ngpio = ngpio; + chip->label = dev_name(pctrl->dev); + chip->parent = pctrl->dev; +diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c +index f9a245465fd0..6a25bfd4541e 100644 +--- a/drivers/platform/chrome/cros_ec_lpc.c ++++ b/drivers/platform/chrome/cros_ec_lpc.c +@@ -49,7 +49,6 @@ static int ec_response_timed_out(void) + static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, + struct cros_ec_command *msg) + { +- struct ec_host_request *request; + struct ec_host_response response; + u8 sum = 0; + int i; +@@ -62,8 +61,6 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, + for (i = 0; i < ret; i++) + outb(ec->dout[i], EC_LPC_ADDR_HOST_PACKET + i); + +- request = (struct ec_host_request *)ec->dout; +- + /* Here we go */ + outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD); + +diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c +index e3cd3ece4412..c3d1891d2d3f 100644 +--- a/drivers/scsi/scsi_transport_srp.c ++++ b/drivers/scsi/scsi_transport_srp.c +@@ -52,6 +52,8 @@ struct srp_internal { + struct transport_container rport_attr_cont; + }; + ++static int scsi_is_srp_rport(const struct device *dev); ++ + #define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t) + + #define dev_to_rport(d) container_of(d, struct srp_rport, dev) +@@ -61,9 +63,24 @@ static inline struct Scsi_Host *rport_to_shost(struct srp_rport *r) + return dev_to_shost(r->dev.parent); + } + ++static int find_child_rport(struct device *dev, void *data) ++{ ++ struct device **child = data; ++ ++ if (scsi_is_srp_rport(dev)) { ++ WARN_ON_ONCE(*child); ++ *child = dev; ++ } ++ return 0; ++} ++ + static inline struct srp_rport *shost_to_rport(struct Scsi_Host *shost) + { +- return transport_class_to_srp_rport(&shost->shost_gendev); ++ struct device *child = NULL; ++ ++ WARN_ON_ONCE(device_for_each_child(&shost->shost_gendev, &child, ++ find_child_rport) < 0); ++ return child ? dev_to_rport(child) : NULL; + } + + /** +@@ -637,7 +654,8 @@ static enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd) + struct srp_rport *rport = shost_to_rport(shost); + + pr_debug("timeout for sdev %s\n", dev_name(&sdev->sdev_gendev)); +- return rport->fast_io_fail_tmo < 0 && rport->dev_loss_tmo < 0 && ++ return rport && rport->fast_io_fail_tmo < 0 && ++ rport->dev_loss_tmo < 0 && + i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ? + BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; + } +diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h +index 845b874e2977..5bb2316f60bf 100644 +--- a/drivers/scsi/ufs/ufs.h ++++ b/drivers/scsi/ufs/ufs.h +@@ -145,7 +145,7 @@ enum attr_idn { + /* Descriptor idn for Query requests */ + enum desc_idn { + QUERY_DESC_IDN_DEVICE = 0x0, +- QUERY_DESC_IDN_CONFIGURAION = 0x1, ++ QUERY_DESC_IDN_CONFIGURATION = 0x1, + QUERY_DESC_IDN_UNIT = 0x2, + QUERY_DESC_IDN_RFU_0 = 0x3, + QUERY_DESC_IDN_INTERCONNECT = 0x4, +@@ -161,19 +161,13 @@ enum desc_header_offset { + QUERY_DESC_DESC_TYPE_OFFSET = 0x01, + }; + +-enum ufs_desc_max_size { +- QUERY_DESC_DEVICE_MAX_SIZE = 0x1F, +- QUERY_DESC_CONFIGURAION_MAX_SIZE = 0x90, +- QUERY_DESC_UNIT_MAX_SIZE = 0x23, +- QUERY_DESC_INTERCONNECT_MAX_SIZE = 0x06, +- /* +- * Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes +- * of descriptor header. +- */ +- QUERY_DESC_STRING_MAX_SIZE = 0xFE, +- QUERY_DESC_GEOMETRY_MAX_SIZE = 0x44, +- QUERY_DESC_POWER_MAX_SIZE = 0x62, +- QUERY_DESC_RFU_MAX_SIZE = 0x00, ++enum ufs_desc_def_size { ++ QUERY_DESC_DEVICE_DEF_SIZE = 0x40, ++ QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90, ++ QUERY_DESC_UNIT_DEF_SIZE = 0x23, ++ QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, ++ QUERY_DESC_GEOMETRY_DEF_SIZE = 0x44, ++ QUERY_DESC_POWER_DEF_SIZE = 0x62, + }; + + /* Unit descriptor parameters offsets in bytes*/ +@@ -522,4 +516,16 @@ struct ufs_dev_info { + bool is_lu_power_on_wp; + }; + ++#define MAX_MODEL_LEN 16 ++/** ++ * ufs_dev_desc - ufs device details from the device descriptor ++ * ++ * @wmanufacturerid: card details ++ * @model: card model ++ */ ++struct ufs_dev_desc { ++ u16 wmanufacturerid; ++ char model[MAX_MODEL_LEN + 1]; ++}; ++ + #endif /* End of Header */ +diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h +index 08b799d4efcc..71f73d1d1ad1 100644 +--- a/drivers/scsi/ufs/ufs_quirks.h ++++ b/drivers/scsi/ufs/ufs_quirks.h +@@ -21,41 +21,28 @@ + #define UFS_ANY_VENDOR 0xFFFF + #define UFS_ANY_MODEL "ANY_MODEL" + +-#define MAX_MODEL_LEN 16 +- + #define UFS_VENDOR_TOSHIBA 0x198 + #define UFS_VENDOR_SAMSUNG 0x1CE + #define UFS_VENDOR_SKHYNIX 0x1AD + +-/** +- * ufs_device_info - ufs device details +- * @wmanufacturerid: card details +- * @model: card model +- */ +-struct ufs_device_info { +- u16 wmanufacturerid; +- char model[MAX_MODEL_LEN + 1]; +-}; +- + /** + * ufs_dev_fix - ufs device quirk info + * @card: ufs card details + * @quirk: device quirk + */ + struct ufs_dev_fix { +- struct ufs_device_info card; ++ struct ufs_dev_desc card; + unsigned int quirk; + }; + + #define END_FIX { { 0 }, 0 } + + /* add specific device quirk */ +-#define UFS_FIX(_vendor, _model, _quirk) \ +- { \ +- .card.wmanufacturerid = (_vendor),\ +- .card.model = (_model), \ +- .quirk = (_quirk), \ +- } ++#define UFS_FIX(_vendor, _model, _quirk) { \ ++ .card.wmanufacturerid = (_vendor),\ ++ .card.model = (_model), \ ++ .quirk = (_quirk), \ ++} + + /* + * If UFS device is having issue in processing LCC (Line Control +@@ -144,7 +131,4 @@ struct ufs_dev_fix { + */ + #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8) + +-struct ufs_hba; +-void ufs_advertise_fixup_device(struct ufs_hba *hba); +- + #endif /* UFS_QUIRKS_H_ */ +diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c +index 98a7111dd53f..86a3110c6d75 100644 +--- a/drivers/scsi/ufs/ufshcd.c ++++ b/drivers/scsi/ufs/ufshcd.c +@@ -98,19 +98,6 @@ + _ret; \ + }) + +-static u32 ufs_query_desc_max_size[] = { +- QUERY_DESC_DEVICE_MAX_SIZE, +- QUERY_DESC_CONFIGURAION_MAX_SIZE, +- QUERY_DESC_UNIT_MAX_SIZE, +- QUERY_DESC_RFU_MAX_SIZE, +- QUERY_DESC_INTERCONNECT_MAX_SIZE, +- QUERY_DESC_STRING_MAX_SIZE, +- QUERY_DESC_RFU_MAX_SIZE, +- QUERY_DESC_GEOMETRY_MAX_SIZE, +- QUERY_DESC_POWER_MAX_SIZE, +- QUERY_DESC_RFU_MAX_SIZE, +-}; +- + enum { + UFSHCD_MAX_CHANNEL = 0, + UFSHCD_MAX_ID = 1, +@@ -1961,7 +1948,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, + goto out; + } + +- if (*buf_len <= QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { ++ if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { + dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n", + __func__, *buf_len); + err = -EINVAL; +@@ -2040,6 +2027,92 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, + } + EXPORT_SYMBOL(ufshcd_query_descriptor_retry); + ++/** ++ * ufshcd_read_desc_length - read the specified descriptor length from header ++ * @hba: Pointer to adapter instance ++ * @desc_id: descriptor idn value ++ * @desc_index: descriptor index ++ * @desc_length: pointer to variable to read the length of descriptor ++ * ++ * Return 0 in case of success, non-zero otherwise ++ */ ++static int ufshcd_read_desc_length(struct ufs_hba *hba, ++ enum desc_idn desc_id, ++ int desc_index, ++ int *desc_length) ++{ ++ int ret; ++ u8 header[QUERY_DESC_HDR_SIZE]; ++ int header_len = QUERY_DESC_HDR_SIZE; ++ ++ if (desc_id >= QUERY_DESC_IDN_MAX) ++ return -EINVAL; ++ ++ ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, ++ desc_id, desc_index, 0, header, ++ &header_len); ++ ++ if (ret) { ++ dev_err(hba->dev, "%s: Failed to get descriptor header id %d", ++ __func__, desc_id); ++ return ret; ++ } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) { ++ dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch", ++ __func__, header[QUERY_DESC_DESC_TYPE_OFFSET], ++ desc_id); ++ ret = -EINVAL; ++ } ++ ++ *desc_length = header[QUERY_DESC_LENGTH_OFFSET]; ++ return ret; ++ ++} ++ ++/** ++ * ufshcd_map_desc_id_to_length - map descriptor IDN to its length ++ * @hba: Pointer to adapter instance ++ * @desc_id: descriptor idn value ++ * @desc_len: mapped desc length (out) ++ * ++ * Return 0 in case of success, non-zero otherwise ++ */ ++int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, ++ enum desc_idn desc_id, int *desc_len) ++{ ++ switch (desc_id) { ++ case QUERY_DESC_IDN_DEVICE: ++ *desc_len = hba->desc_size.dev_desc; ++ break; ++ case QUERY_DESC_IDN_POWER: ++ *desc_len = hba->desc_size.pwr_desc; ++ break; ++ case QUERY_DESC_IDN_GEOMETRY: ++ *desc_len = hba->desc_size.geom_desc; ++ break; ++ case QUERY_DESC_IDN_CONFIGURATION: ++ *desc_len = hba->desc_size.conf_desc; ++ break; ++ case QUERY_DESC_IDN_UNIT: ++ *desc_len = hba->desc_size.unit_desc; ++ break; ++ case QUERY_DESC_IDN_INTERCONNECT: ++ *desc_len = hba->desc_size.interc_desc; ++ break; ++ case QUERY_DESC_IDN_STRING: ++ *desc_len = QUERY_DESC_MAX_SIZE; ++ break; ++ case QUERY_DESC_IDN_RFU_0: ++ case QUERY_DESC_IDN_RFU_1: ++ *desc_len = 0; ++ break; ++ default: ++ *desc_len = 0; ++ return -EINVAL; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(ufshcd_map_desc_id_to_length); ++ + /** + * ufshcd_read_desc_param - read the specified descriptor parameter + * @hba: Pointer to adapter instance +@@ -2054,50 +2127,64 @@ EXPORT_SYMBOL(ufshcd_query_descriptor_retry); + static int ufshcd_read_desc_param(struct ufs_hba *hba, + enum desc_idn desc_id, + int desc_index, +- u32 param_offset, ++ u8 param_offset, + u8 *param_read_buf, +- u32 param_size) ++ u8 param_size) + { + int ret; + u8 *desc_buf; +- u32 buff_len; ++ int buff_len; + bool is_kmalloc = true; + +- /* safety checks */ +- if (desc_id >= QUERY_DESC_IDN_MAX) ++ /* Safety check */ ++ if (desc_id >= QUERY_DESC_IDN_MAX || !param_size) + return -EINVAL; + +- buff_len = ufs_query_desc_max_size[desc_id]; +- if ((param_offset + param_size) > buff_len) +- return -EINVAL; ++ /* Get the max length of descriptor from structure filled up at probe ++ * time. ++ */ ++ ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len); + +- if (!param_offset && (param_size == buff_len)) { +- /* memory space already available to hold full descriptor */ +- desc_buf = param_read_buf; +- is_kmalloc = false; +- } else { +- /* allocate memory to hold full descriptor */ ++ /* Sanity checks */ ++ if (ret || !buff_len) { ++ dev_err(hba->dev, "%s: Failed to get full descriptor length", ++ __func__); ++ return ret; ++ } ++ ++ /* Check whether we need temp memory */ ++ if (param_offset != 0 || param_size < buff_len) { + desc_buf = kmalloc(buff_len, GFP_KERNEL); + if (!desc_buf) + return -ENOMEM; ++ } else { ++ desc_buf = param_read_buf; ++ is_kmalloc = false; + } + ++ /* Request for full descriptor */ + ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, +- desc_id, desc_index, 0, desc_buf, +- &buff_len); +- +- if (ret || (buff_len < ufs_query_desc_max_size[desc_id]) || +- (desc_buf[QUERY_DESC_LENGTH_OFFSET] != +- ufs_query_desc_max_size[desc_id]) +- || (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id)) { +- dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d param_offset %d buff_len %d ret %d", +- __func__, desc_id, param_offset, buff_len, ret); +- if (!ret) +- ret = -EINVAL; ++ desc_id, desc_index, 0, ++ desc_buf, &buff_len); ++ ++ if (ret) { ++ dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", ++ __func__, desc_id, desc_index, param_offset, ret); ++ goto out; ++ } + ++ /* Sanity check */ ++ if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) { ++ dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header", ++ __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]); ++ ret = -EINVAL; + goto out; + } + ++ /* Check wherher we will not copy more data, than available */ ++ if (is_kmalloc && param_size > buff_len) ++ param_size = buff_len; ++ + if (is_kmalloc) + memcpy(param_read_buf, &desc_buf[param_offset], param_size); + out: +@@ -4789,8 +4876,8 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba, + static void ufshcd_init_icc_levels(struct ufs_hba *hba) + { + int ret; +- int buff_len = QUERY_DESC_POWER_MAX_SIZE; +- u8 desc_buf[QUERY_DESC_POWER_MAX_SIZE]; ++ int buff_len = hba->desc_size.pwr_desc; ++ u8 desc_buf[hba->desc_size.pwr_desc]; + + ret = ufshcd_read_power_desc(hba, desc_buf, buff_len); + if (ret) { +@@ -4883,16 +4970,15 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) + return ret; + } + +-static int ufs_get_device_info(struct ufs_hba *hba, +- struct ufs_device_info *card_data) ++static int ufs_get_device_desc(struct ufs_hba *hba, ++ struct ufs_dev_desc *dev_desc) + { + int err; + u8 model_index; +- u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1] = {0}; +- u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; ++ u8 str_desc_buf[QUERY_DESC_MAX_SIZE + 1] = {0}; ++ u8 desc_buf[hba->desc_size.dev_desc]; + +- err = ufshcd_read_device_desc(hba, desc_buf, +- QUERY_DESC_DEVICE_MAX_SIZE); ++ err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc); + if (err) { + dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n", + __func__, err); +@@ -4903,50 +4989,40 @@ static int ufs_get_device_info(struct ufs_hba *hba, + * getting vendor (manufacturerID) and Bank Index in big endian + * format + */ +- card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | ++ dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | + desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; + + model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; + + err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, +- QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); ++ QUERY_DESC_MAX_SIZE, ASCII_STD); + if (err) { + dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n", + __func__, err); + goto out; + } + +- str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; +- strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), ++ str_desc_buf[QUERY_DESC_MAX_SIZE] = '\0'; ++ strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), + min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], + MAX_MODEL_LEN)); + + /* Null terminate the model string */ +- card_data->model[MAX_MODEL_LEN] = '\0'; ++ dev_desc->model[MAX_MODEL_LEN] = '\0'; + + out: + return err; + } + +-void ufs_advertise_fixup_device(struct ufs_hba *hba) ++static void ufs_fixup_device_setup(struct ufs_hba *hba, ++ struct ufs_dev_desc *dev_desc) + { +- int err; + struct ufs_dev_fix *f; +- struct ufs_device_info card_data; +- +- card_data.wmanufacturerid = 0; +- +- err = ufs_get_device_info(hba, &card_data); +- if (err) { +- dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", +- __func__, err); +- return; +- } + + for (f = ufs_fixups; f->quirk; f++) { +- if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || +- (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && +- (STR_PRFX_EQUAL(f->card.model, card_data.model) || ++ if ((f->card.wmanufacturerid == dev_desc->wmanufacturerid || ++ f->card.wmanufacturerid == UFS_ANY_VENDOR) && ++ (STR_PRFX_EQUAL(f->card.model, dev_desc->model) || + !strcmp(f->card.model, UFS_ANY_MODEL))) + hba->dev_quirks |= f->quirk; + } +@@ -5116,6 +5192,51 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) + ufshcd_vops_apply_dev_quirks(hba); + } + ++static void ufshcd_init_desc_sizes(struct ufs_hba *hba) ++{ ++ int err; ++ ++ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0, ++ &hba->desc_size.dev_desc); ++ if (err) ++ hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; ++ ++ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0, ++ &hba->desc_size.pwr_desc); ++ if (err) ++ hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; ++ ++ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0, ++ &hba->desc_size.interc_desc); ++ if (err) ++ hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; ++ ++ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0, ++ &hba->desc_size.conf_desc); ++ if (err) ++ hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; ++ ++ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0, ++ &hba->desc_size.unit_desc); ++ if (err) ++ hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; ++ ++ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0, ++ &hba->desc_size.geom_desc); ++ if (err) ++ hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; ++} ++ ++static void ufshcd_def_desc_sizes(struct ufs_hba *hba) ++{ ++ hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; ++ hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; ++ hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; ++ hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; ++ hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; ++ hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; ++} ++ + /** + * ufshcd_probe_hba - probe hba to detect device and initialize + * @hba: per-adapter instance +@@ -5124,6 +5245,7 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) + */ + static int ufshcd_probe_hba(struct ufs_hba *hba) + { ++ struct ufs_dev_desc card = {0}; + int ret; + + ret = ufshcd_link_startup(hba); +@@ -5147,7 +5269,17 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) + if (ret) + goto out; + +- ufs_advertise_fixup_device(hba); ++ /* Init check for device descriptor sizes */ ++ ufshcd_init_desc_sizes(hba); ++ ++ ret = ufs_get_device_desc(hba, &card); ++ if (ret) { ++ dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", ++ __func__, ret); ++ goto out; ++ } ++ ++ ufs_fixup_device_setup(hba, &card); + ufshcd_tune_unipro_params(hba); + + ret = ufshcd_set_vccq_rail_unused(hba, +@@ -5173,6 +5305,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) + + /* set the state as operational after switching to desired gear */ + hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; ++ + /* + * If we are in error handling context or in power management callbacks + * context, no need to scan the host +@@ -6549,6 +6682,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) + hba->mmio_base = mmio_base; + hba->irq = irq; + ++ /* Set descriptor lengths to specification defaults */ ++ ufshcd_def_desc_sizes(hba); ++ + err = ufshcd_hba_init(hba); + if (err) + goto out_error; +diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h +index f2170d5058a8..6dbd2e176333 100644 +--- a/drivers/scsi/ufs/ufshcd.h ++++ b/drivers/scsi/ufs/ufshcd.h +@@ -205,6 +205,15 @@ struct ufs_dev_cmd { + struct ufs_query query; + }; + ++struct ufs_desc_size { ++ int dev_desc; ++ int pwr_desc; ++ int geom_desc; ++ int interc_desc; ++ int unit_desc; ++ int conf_desc; ++}; ++ + /** + * struct ufs_clk_info - UFS clock related info + * @list: list headed by hba->clk_list_head +@@ -388,6 +397,7 @@ struct ufs_init_prefetch { + * @clk_list_head: UFS host controller clocks list node head + * @pwr_info: holds current power mode + * @max_pwr_info: keeps the device max valid pwm ++ * @desc_size: descriptor sizes reported by device + * @urgent_bkops_lvl: keeps track of urgent bkops level for device + * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for + * device is known or not. +@@ -563,6 +573,8 @@ struct ufs_hba { + + enum bkops_status urgent_bkops_lvl; + bool is_urgent_bkops_lvl_checked; ++ ++ struct ufs_desc_size desc_size; + }; + + /* Returns true if clocks can be gated. Otherwise false */ +@@ -736,6 +748,10 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, + enum flag_idn idn, bool *flag_res); + int ufshcd_hold(struct ufs_hba *hba, bool async); + void ufshcd_release(struct ufs_hba *hba); ++ ++int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, ++ int *desc_length); ++ + u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba); + + /* Wrapper functions for safely calling variant operations */ +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index b42d7f1c9089..6b1863293fe1 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -2320,12 +2320,67 @@ static int __init pl011_console_setup(struct console *co, char *options) + return uart_set_options(&uap->port, co, baud, parity, bits, flow); + } + ++/** ++ * pl011_console_match - non-standard console matching ++ * @co: registering console ++ * @name: name from console command line ++ * @idx: index from console command line ++ * @options: ptr to option string from console command line ++ * ++ * Only attempts to match console command lines of the form: ++ * console=pl011,mmio|mmio32,[,] ++ * console=pl011,0x[,] ++ * This form is used to register an initial earlycon boot console and ++ * replace it with the amba_console at pl011 driver init. ++ * ++ * Performs console setup for a match (as required by interface) ++ * If no are specified, then assume the h/w is already setup. ++ * ++ * Returns 0 if console matches; otherwise non-zero to use default matching ++ */ ++static int __init pl011_console_match(struct console *co, char *name, int idx, ++ char *options) ++{ ++ unsigned char iotype; ++ resource_size_t addr; ++ int i; ++ ++ if (strcmp(name, "pl011") != 0) ++ return -ENODEV; ++ ++ if (uart_parse_earlycon(options, &iotype, &addr, &options)) ++ return -ENODEV; ++ ++ if (iotype != UPIO_MEM && iotype != UPIO_MEM32) ++ return -ENODEV; ++ ++ /* try to match the port specified on the command line */ ++ for (i = 0; i < ARRAY_SIZE(amba_ports); i++) { ++ struct uart_port *port; ++ ++ if (!amba_ports[i]) ++ continue; ++ ++ port = &amba_ports[i]->port; ++ ++ if (port->mapbase != addr) ++ continue; ++ ++ co->index = i; ++ port->cons = co; ++ return pl011_console_setup(co, options); ++ } ++ ++ return -ENODEV; ++} ++ + static struct uart_driver amba_reg; + static struct console amba_console = { + .name = "ttyAMA", + .write = pl011_console_write, + .device = uart_console_device, + .setup = pl011_console_setup, ++ .match = pl011_console_match, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &amba_reg, +diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c +index d98531823998..46b4dea7a0ec 100644 +--- a/drivers/usb/serial/cp210x.c ++++ b/drivers/usb/serial/cp210x.c +@@ -33,7 +33,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); + static void cp210x_close(struct usb_serial_port *); + static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *); + static void cp210x_get_termios_port(struct usb_serial_port *port, +- unsigned int *cflagp, unsigned int *baudp); ++ tcflag_t *cflagp, unsigned int *baudp); + static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, + struct ktermios *); + static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, +@@ -728,7 +728,7 @@ static void cp210x_get_termios(struct tty_struct *tty, + &tty->termios.c_cflag, &baud); + tty_encode_baud_rate(tty, baud, baud); + } else { +- unsigned int cflag; ++ tcflag_t cflag; + cflag = 0; + cp210x_get_termios_port(port, &cflag, &baud); + } +@@ -739,10 +739,10 @@ static void cp210x_get_termios(struct tty_struct *tty, + * This is the heart of cp210x_get_termios which always uses a &usb_serial_port. + */ + static void cp210x_get_termios_port(struct usb_serial_port *port, +- unsigned int *cflagp, unsigned int *baudp) ++ tcflag_t *cflagp, unsigned int *baudp) + { + struct device *dev = &port->dev; +- unsigned int cflag; ++ tcflag_t cflag; + struct cp210x_flow_ctl flow_ctl; + u32 baud; + u16 bits; +diff --git a/fs/aio.c b/fs/aio.c +index 42d8c09311d1..b1170a7affe2 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -636,9 +636,8 @@ static void free_ioctx_users(struct percpu_ref *ref) + while (!list_empty(&ctx->active_reqs)) { + req = list_first_entry(&ctx->active_reqs, + struct aio_kiocb, ki_list); +- +- list_del_init(&req->ki_list); + kiocb_cancel(req); ++ list_del_init(&req->ki_list); + } + + spin_unlock_irq(&ctx->ctx_lock); +diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c +index c3702cda010a..e567551402a6 100644 +--- a/fs/xfs/libxfs/xfs_alloc.c ++++ b/fs/xfs/libxfs/xfs_alloc.c +@@ -2034,6 +2034,93 @@ xfs_alloc_space_available( + return true; + } + ++/* ++ * Check the agfl fields of the agf for inconsistency or corruption. The purpose ++ * is to detect an agfl header padding mismatch between current and early v5 ++ * kernels. This problem manifests as a 1-slot size difference between the ++ * on-disk flcount and the active [first, last] range of a wrapped agfl. This ++ * may also catch variants of agfl count corruption unrelated to padding. Either ++ * way, we'll reset the agfl and warn the user. ++ * ++ * Return true if a reset is required before the agfl can be used, false ++ * otherwise. ++ */ ++static bool ++xfs_agfl_needs_reset( ++ struct xfs_mount *mp, ++ struct xfs_agf *agf) ++{ ++ uint32_t f = be32_to_cpu(agf->agf_flfirst); ++ uint32_t l = be32_to_cpu(agf->agf_fllast); ++ uint32_t c = be32_to_cpu(agf->agf_flcount); ++ int agfl_size = XFS_AGFL_SIZE(mp); ++ int active; ++ ++ /* no agfl header on v4 supers */ ++ if (!xfs_sb_version_hascrc(&mp->m_sb)) ++ return false; ++ ++ /* ++ * The agf read verifier catches severe corruption of these fields. ++ * Repeat some sanity checks to cover a packed -> unpacked mismatch if ++ * the verifier allows it. ++ */ ++ if (f >= agfl_size || l >= agfl_size) ++ return true; ++ if (c > agfl_size) ++ return true; ++ ++ /* ++ * Check consistency between the on-disk count and the active range. An ++ * agfl padding mismatch manifests as an inconsistent flcount. ++ */ ++ if (c && l >= f) ++ active = l - f + 1; ++ else if (c) ++ active = agfl_size - f + l + 1; ++ else ++ active = 0; ++ ++ return active != c; ++} ++ ++/* ++ * Reset the agfl to an empty state. Ignore/drop any existing blocks since the ++ * agfl content cannot be trusted. Warn the user that a repair is required to ++ * recover leaked blocks. ++ * ++ * The purpose of this mechanism is to handle filesystems affected by the agfl ++ * header padding mismatch problem. A reset keeps the filesystem online with a ++ * relatively minor free space accounting inconsistency rather than suffer the ++ * inevitable crash from use of an invalid agfl block. ++ */ ++static void ++xfs_agfl_reset( ++ struct xfs_trans *tp, ++ struct xfs_buf *agbp, ++ struct xfs_perag *pag) ++{ ++ struct xfs_mount *mp = tp->t_mountp; ++ struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); ++ ++ ASSERT(pag->pagf_agflreset); ++ trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_); ++ ++ xfs_warn(mp, ++ "WARNING: Reset corrupted AGFL on AG %u. %d blocks leaked. " ++ "Please unmount and run xfs_repair.", ++ pag->pag_agno, pag->pagf_flcount); ++ ++ agf->agf_flfirst = 0; ++ agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1); ++ agf->agf_flcount = 0; ++ xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLLAST | ++ XFS_AGF_FLCOUNT); ++ ++ pag->pagf_flcount = 0; ++ pag->pagf_agflreset = false; ++} ++ + /* + * Decide whether to use this allocation group for this allocation. + * If so, fix up the btree freelist's size. +@@ -2095,6 +2182,10 @@ xfs_alloc_fix_freelist( + } + } + ++ /* reset a padding mismatched agfl before final free space check */ ++ if (pag->pagf_agflreset) ++ xfs_agfl_reset(tp, agbp, pag); ++ + /* If there isn't enough total space or single-extent, reject it. */ + need = xfs_alloc_min_freelist(mp, pag); + if (!xfs_alloc_space_available(args, need, flags)) +@@ -2251,6 +2342,7 @@ xfs_alloc_get_freelist( + agf->agf_flfirst = 0; + + pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); ++ ASSERT(!pag->pagf_agflreset); + be32_add_cpu(&agf->agf_flcount, -1); + xfs_trans_agflist_delta(tp, -1); + pag->pagf_flcount--; +@@ -2362,6 +2454,7 @@ xfs_alloc_put_freelist( + agf->agf_fllast = 0; + + pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); ++ ASSERT(!pag->pagf_agflreset); + be32_add_cpu(&agf->agf_flcount, 1); + xfs_trans_agflist_delta(tp, 1); + pag->pagf_flcount++; +@@ -2568,6 +2661,7 @@ xfs_alloc_read_agf( + pag->pagb_count = 0; + pag->pagb_tree = RB_ROOT; + pag->pagf_init = 1; ++ pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf); + } + #ifdef DEBUG + else if (!XFS_FORCED_SHUTDOWN(mp)) { +diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h +index 5415f9031ef8..7cb099e1c84c 100644 +--- a/fs/xfs/xfs_mount.h ++++ b/fs/xfs/xfs_mount.h +@@ -368,6 +368,7 @@ typedef struct xfs_perag { + char pagi_inodeok; /* The agi is ok for inodes */ + __uint8_t pagf_levels[XFS_BTNUM_AGF]; + /* # of levels in bno & cnt btree */ ++ bool pagf_agflreset; /* agfl requires reset before use */ + __uint32_t pagf_flcount; /* count of blocks in freelist */ + xfs_extlen_t pagf_freeblks; /* total free blocks */ + xfs_extlen_t pagf_longest; /* longest free space */ +diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h +index bdf69e1c7410..42a7c0da898f 100644 +--- a/fs/xfs/xfs_trace.h ++++ b/fs/xfs/xfs_trace.h +@@ -1516,7 +1516,7 @@ TRACE_EVENT(xfs_trans_commit_lsn, + __entry->lsn) + ); + +-TRACE_EVENT(xfs_agf, ++DECLARE_EVENT_CLASS(xfs_agf_class, + TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, + unsigned long caller_ip), + TP_ARGS(mp, agf, flags, caller_ip), +@@ -1572,6 +1572,13 @@ TRACE_EVENT(xfs_agf, + __entry->longest, + (void *)__entry->caller_ip) + ); ++#define DEFINE_AGF_EVENT(name) \ ++DEFINE_EVENT(xfs_agf_class, name, \ ++ TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, \ ++ unsigned long caller_ip), \ ++ TP_ARGS(mp, agf, flags, caller_ip)) ++DEFINE_AGF_EVENT(xfs_agf); ++DEFINE_AGF_EVENT(xfs_agfl_reset); + + TRACE_EVENT(xfs_free_extent, + TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, +diff --git a/include/linux/tcp.h b/include/linux/tcp.h +index f50b717ce644..d0c3615f9050 100644 +--- a/include/linux/tcp.h ++++ b/include/linux/tcp.h +@@ -337,7 +337,7 @@ struct tcp_sock { + + /* Receiver queue space */ + struct { +- int space; ++ u32 space; + u32 seq; + u32 time; + } rcvq_space; +diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h +index 7290eacc8cee..b902f106f69a 100644 +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -2379,7 +2379,7 @@ enum nl80211_attrs { + #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS + #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS + +-#define NL80211_WIPHY_NAME_MAXLEN 128 ++#define NL80211_WIPHY_NAME_MAXLEN 64 + + #define NL80211_MAX_SUPP_RATES 32 + #define NL80211_MAX_SUPP_HT_RATES 77 +diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c +index 6721a1e89f39..88f398af57fa 100644 +--- a/kernel/trace/trace_events_trigger.c ++++ b/kernel/trace/trace_events_trigger.c +@@ -481,9 +481,10 @@ clear_event_triggers(struct trace_array *tr) + struct trace_event_file *file; + + list_for_each_entry(file, &tr->events, list) { +- struct event_trigger_data *data; +- list_for_each_entry_rcu(data, &file->triggers, list) { ++ struct event_trigger_data *data, *n; ++ list_for_each_entry_safe(data, n, &file->triggers, list) { + trace_event_trigger_enable_disable(file, 0); ++ list_del_rcu(&data->list); + if (data->ops->free) + data->ops->free(data->ops, data); + } +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 2d4b6478237b..f03ca5ab86b1 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -1393,7 +1393,7 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode) + return ret; + + mapping = page_mapping(page); +- migrate_dirty = mapping && mapping->a_ops->migratepage; ++ migrate_dirty = !mapping || mapping->a_ops->migratepage; + unlock_page(page); + if (!migrate_dirty) + return ret; +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 52b0a84be765..94a55b83e48c 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -581,8 +581,8 @@ static inline void tcp_rcv_rtt_measure_ts(struct sock *sk, + void tcp_rcv_space_adjust(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); ++ u32 copied; + int time; +- int copied; + + time = tcp_time_stamp - tp->rcvq_space.time; + if (time < (tp->rcv_rtt_est.rtt >> 3) || tp->rcv_rtt_est.rtt == 0) +@@ -604,12 +604,13 @@ void tcp_rcv_space_adjust(struct sock *sk) + + if (sysctl_tcp_moderate_rcvbuf && + !(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) { +- int rcvwin, rcvmem, rcvbuf; ++ int rcvmem, rcvbuf; ++ u64 rcvwin; + + /* minimal window to cope with packet losses, assuming + * steady state. Add some cushion because of small variations. + */ +- rcvwin = (copied << 1) + 16 * tp->advmss; ++ rcvwin = ((u64)copied << 1) + 16 * tp->advmss; + + /* If rate increased by 25%, + * assume slow start, rcvwin = 3 * copied +@@ -629,7 +630,8 @@ void tcp_rcv_space_adjust(struct sock *sk) + while (tcp_win_from_space(rcvmem) < tp->advmss) + rcvmem += 128; + +- rcvbuf = min(rcvwin / tp->advmss * rcvmem, sysctl_tcp_rmem[2]); ++ do_div(rcvwin, tp->advmss); ++ rcvbuf = min_t(u64, rcvwin * rcvmem, sysctl_tcp_rmem[2]); + if (rcvbuf > sk->sk_rcvbuf) { + sk->sk_rcvbuf = rcvbuf; + +diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c +index 7bf8b005a178..1e6f23f77f15 100644 +--- a/security/integrity/ima/ima_appraise.c ++++ b/security/integrity/ima/ima_appraise.c +@@ -389,14 +389,10 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, + result = ima_protect_xattr(dentry, xattr_name, xattr_value, + xattr_value_len); + if (result == 1) { +- bool digsig; +- + if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST)) + return -EINVAL; +- digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG); +- if (!digsig && (ima_appraise & IMA_APPRAISE_ENFORCE)) +- return -EPERM; +- ima_reset_appraise_flags(d_backing_inode(dentry), digsig); ++ ima_reset_appraise_flags(d_backing_inode(dentry), ++ (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0); + result = 0; + } + return result; +diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c +index d656b7c98394..bfc4ffa1fa1a 100644 +--- a/security/selinux/ss/services.c ++++ b/security/selinux/ss/services.c +@@ -1435,7 +1435,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, + scontext_len, &context, def_sid); + if (rc == -EINVAL && force) { + context.str = str; +- context.len = scontext_len; ++ context.len = strlen(str) + 1; + str = NULL; + } else if (rc) + goto out_unlock; +diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c +index a086c35f91bb..79a9fdf94d38 100644 +--- a/sound/soc/intel/common/sst-firmware.c ++++ b/sound/soc/intel/common/sst-firmware.c +@@ -274,7 +274,6 @@ int sst_dma_new(struct sst_dsp *sst) + struct sst_pdata *sst_pdata = sst->pdata; + struct sst_dma *dma; + struct resource mem; +- const char *dma_dev_name; + int ret = 0; + + if (sst->pdata->resindex_dma_base == -1) +@@ -285,7 +284,6 @@ int sst_dma_new(struct sst_dsp *sst) + * is attached to the ADSP IP. */ + switch (sst->pdata->dma_engine) { + case SST_DMA_TYPE_DW: +- dma_dev_name = "dw_dmac"; + break; + default: + dev_err(sst->dev, "error: invalid DMA engine %d\n", diff --git a/patch/kernel/odroidxu4-next/0004-patch-4.9.107-108.patch b/patch/kernel/odroidxu4-next/0004-patch-4.9.107-108.patch new file mode 100644 index 0000000000..f710a0f446 --- /dev/null +++ b/patch/kernel/odroidxu4-next/0004-patch-4.9.107-108.patch @@ -0,0 +1,775 @@ +diff --git a/Documentation/networking/netdev-FAQ.txt b/Documentation/networking/netdev-FAQ.txt +index a20b2fae942b..56af008e9258 100644 +--- a/Documentation/networking/netdev-FAQ.txt ++++ b/Documentation/networking/netdev-FAQ.txt +@@ -168,6 +168,15 @@ A: No. See above answer. In short, if you think it really belongs in + dash marker line as described in Documentation/SubmittingPatches to + temporarily embed that information into the patch that you send. + ++Q: Are all networking bug fixes backported to all stable releases? ++ ++A: Due to capacity, Dave could only take care of the backports for the last ++ 2 stable releases. For earlier stable releases, each stable branch maintainer ++ is supposed to take care of them. If you find any patch is missing from an ++ earlier stable branch, please notify stable@vger.kernel.org with either a ++ commit ID or a formal patch backported, and CC Dave and other relevant ++ networking developers. ++ + Q: Someone said that the comment style and coding convention is different + for the networking content. Is this true? + +diff --git a/Makefile b/Makefile +index ac30e448e0a5..1fa9daf219c4 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 4 + PATCHLEVEL = 9 +-SUBLEVEL = 107 ++SUBLEVEL = 108 + EXTRAVERSION = + NAME = Roaring Lionus + +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index 4ef267fb635a..e783a5daaab2 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -352,8 +352,6 @@ SECTIONS + DISCARDS + /DISCARD/ : { + *(.eh_frame) +- *(__func_stack_frame_non_standard) +- *(__unreachable) + } + } + +diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h +index c38369781239..8a841b9d8f84 100644 +--- a/arch/x86/kvm/cpuid.h ++++ b/arch/x86/kvm/cpuid.h +@@ -179,7 +179,7 @@ static inline bool guest_cpuid_has_spec_ctrl(struct kvm_vcpu *vcpu) + if (best && (best->ebx & bit(X86_FEATURE_AMD_IBRS))) + return true; + best = kvm_find_cpuid_entry(vcpu, 7, 0); +- return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_SSBD))); ++ return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_SPEC_CTRL_SSBD))); + } + + static inline bool guest_cpuid_has_arch_capabilities(struct kvm_vcpu *vcpu) +diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c +index 9ff853229957..8d097d10fd13 100644 +--- a/drivers/char/tpm/tpm-chip.c ++++ b/drivers/char/tpm/tpm-chip.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include "tpm.h" + #include "tpm_eventlog.h" + +@@ -388,8 +389,20 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip) + */ + int tpm_chip_register(struct tpm_chip *chip) + { ++#ifdef CONFIG_OF ++ struct device_node *np; ++#endif + int rc; + ++#ifdef CONFIG_OF ++ np = of_find_node_by_name(NULL, "vtpm"); ++ if (np) { ++ if (of_property_read_bool(np, "powered-while-suspended")) ++ chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; ++ } ++ of_node_put(np); ++#endif ++ + if (chip->ops->flags & TPM_OPS_AUTO_STARTUP) { + if (chip->flags & TPM_CHIP_FLAG_TPM2) + rc = tpm2_auto_startup(chip); +diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c +index 830d7e30e508..faf2db122ab9 100644 +--- a/drivers/char/tpm/tpm-interface.c ++++ b/drivers/char/tpm/tpm-interface.c +@@ -803,6 +803,10 @@ int tpm_do_selftest(struct tpm_chip *chip) + loops = jiffies_to_msecs(duration) / delay_msec; + + rc = tpm_continue_selftest(chip); ++ if (rc == TPM_ERR_INVALID_POSTINIT) { ++ chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; ++ dev_info(&chip->dev, "TPM not ready (%d)\n", rc); ++ } + /* This may fail if there was no TPM driver during a suspend/resume + * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) + */ +@@ -969,6 +973,9 @@ int tpm_pm_suspend(struct device *dev) + if (chip == NULL) + return -ENODEV; + ++ if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) ++ return 0; ++ + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + tpm2_shutdown(chip, TPM2_SU_STATE); + return 0; +diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h +index aa4299cf7e5a..a4fc2badf633 100644 +--- a/drivers/char/tpm/tpm.h ++++ b/drivers/char/tpm/tpm.h +@@ -143,6 +143,7 @@ enum tpm_chip_flags { + TPM_CHIP_FLAG_TPM2 = BIT(1), + TPM_CHIP_FLAG_IRQ = BIT(2), + TPM_CHIP_FLAG_VIRTUAL = BIT(3), ++ TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), + }; + + struct tpm_chip { +diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c +index f5815e1a4390..c37b7b5f1dd3 100644 +--- a/drivers/gpu/drm/drm_fops.c ++++ b/drivers/gpu/drm/drm_fops.c +@@ -198,6 +198,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) + return -ENOMEM; + + filp->private_data = priv; ++ filp->f_mode |= FMODE_UNSIGNED_OFFSET; + priv->filp = filp; + priv->pid = get_pid(task_pid(current)); + priv->minor = minor; +diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c +index d91dd580e978..37aaea88a6ad 100644 +--- a/drivers/isdn/hardware/eicon/diva.c ++++ b/drivers/isdn/hardware/eicon/diva.c +@@ -387,10 +387,10 @@ void divasa_xdi_driver_unload(void) + ** Receive and process command from user mode utility + */ + void *diva_xdi_open_adapter(void *os_handle, const void __user *src, +- int length, ++ int length, void *mptr, + divas_xdi_copy_from_user_fn_t cp_fn) + { +- diva_xdi_um_cfg_cmd_t msg; ++ diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; + diva_os_xdi_adapter_t *a = NULL; + diva_os_spin_lock_magic_t old_irql; + struct list_head *tmp; +@@ -400,21 +400,21 @@ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, + length, sizeof(diva_xdi_um_cfg_cmd_t))) + return NULL; + } +- if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) { ++ if ((*cp_fn) (os_handle, msg, src, sizeof(*msg)) <= 0) { + DBG_ERR(("A: A(?) open, write error")) + return NULL; + } + diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter"); + list_for_each(tmp, &adapter_queue) { + a = list_entry(tmp, diva_os_xdi_adapter_t, link); +- if (a->controller == (int)msg.adapter) ++ if (a->controller == (int)msg->adapter) + break; + a = NULL; + } + diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter"); + + if (!a) { +- DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter)) ++ DBG_ERR(("A: A(%d) open, adapter not found", msg->adapter)) + } + + return (a); +@@ -436,8 +436,10 @@ void diva_xdi_close_adapter(void *adapter, void *os_handle) + + int + diva_xdi_write(void *adapter, void *os_handle, const void __user *src, +- int length, divas_xdi_copy_from_user_fn_t cp_fn) ++ int length, void *mptr, ++ divas_xdi_copy_from_user_fn_t cp_fn) + { ++ diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; + diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; + void *data; + +@@ -458,7 +460,13 @@ diva_xdi_write(void *adapter, void *os_handle, const void __user *src, + return (-2); + } + +- length = (*cp_fn) (os_handle, data, src, length); ++ if (msg) { ++ *(diva_xdi_um_cfg_cmd_t *)data = *msg; ++ length = (*cp_fn) (os_handle, (char *)data + sizeof(*msg), ++ src + sizeof(*msg), length - sizeof(*msg)); ++ } else { ++ length = (*cp_fn) (os_handle, data, src, length); ++ } + if (length > 0) { + if ((*(a->interface.cmd_proc)) + (a, (diva_xdi_um_cfg_cmd_t *) data, length)) { +diff --git a/drivers/isdn/hardware/eicon/diva.h b/drivers/isdn/hardware/eicon/diva.h +index e979085d1b89..a0a607c0c32e 100644 +--- a/drivers/isdn/hardware/eicon/diva.h ++++ b/drivers/isdn/hardware/eicon/diva.h +@@ -19,10 +19,11 @@ int diva_xdi_read(void *adapter, void *os_handle, void __user *dst, + int max_length, divas_xdi_copy_to_user_fn_t cp_fn); + + int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, +- int length, divas_xdi_copy_from_user_fn_t cp_fn); ++ int length, void *msg, ++ divas_xdi_copy_from_user_fn_t cp_fn); + + void *diva_xdi_open_adapter(void *os_handle, const void __user *src, +- int length, ++ int length, void *msg, + divas_xdi_copy_from_user_fn_t cp_fn); + + void diva_xdi_close_adapter(void *adapter, void *os_handle); +diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c +index 32f34511c416..1e8b9918bfce 100644 +--- a/drivers/isdn/hardware/eicon/divasmain.c ++++ b/drivers/isdn/hardware/eicon/divasmain.c +@@ -591,19 +591,22 @@ static int divas_release(struct inode *inode, struct file *file) + static ssize_t divas_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + { ++ diva_xdi_um_cfg_cmd_t msg; + int ret = -EINVAL; + + if (!file->private_data) { + file->private_data = diva_xdi_open_adapter(file, buf, +- count, ++ count, &msg, + xdi_copy_from_user); +- } +- if (!file->private_data) { +- return (-ENODEV); ++ if (!file->private_data) ++ return (-ENODEV); ++ ret = diva_xdi_write(file->private_data, file, ++ buf, count, &msg, xdi_copy_from_user); ++ } else { ++ ret = diva_xdi_write(file->private_data, file, ++ buf, count, NULL, xdi_copy_from_user); + } + +- ret = diva_xdi_write(file->private_data, file, +- buf, count, xdi_copy_from_user); + switch (ret) { + case -1: /* Message should be removed from rx mailbox first */ + ret = -EBUSY; +@@ -622,11 +625,12 @@ static ssize_t divas_write(struct file *file, const char __user *buf, + static ssize_t divas_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) + { ++ diva_xdi_um_cfg_cmd_t msg; + int ret = -EINVAL; + + if (!file->private_data) { + file->private_data = diva_xdi_open_adapter(file, buf, +- count, ++ count, &msg, + xdi_copy_from_user); + } + if (!file->private_data) { +diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c +index 3ec647e8b9c6..35fd57fdeba9 100644 +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -373,9 +373,6 @@ static void __cache_size_refresh(void) + static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, + enum data_mode *data_mode) + { +- unsigned noio_flag; +- void *ptr; +- + if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) { + *data_mode = DATA_MODE_SLAB; + return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask); +@@ -399,16 +396,16 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, + * all allocations done by this process (including pagetables) are done + * as if GFP_NOIO was specified. + */ ++ if (gfp_mask & __GFP_NORETRY) { ++ unsigned noio_flag = memalloc_noio_save(); ++ void *ptr = __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, ++ PAGE_KERNEL); + +- if (gfp_mask & __GFP_NORETRY) +- noio_flag = memalloc_noio_save(); +- +- ptr = __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, PAGE_KERNEL); +- +- if (gfp_mask & __GFP_NORETRY) + memalloc_noio_restore(noio_flag); ++ return ptr; ++ } + +- return ptr; ++ return __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, PAGE_KERNEL); + } + + /* +diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +index 1fb80100e5e7..912900db935f 100644 +--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c ++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +@@ -594,7 +594,7 @@ static void bnx2x_ets_e3b0_nig_disabled(const struct link_params *params, + * slots for the highest priority. + */ + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS : +- NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); ++ NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + /* Mapping between the CREDIT_WEIGHT registers and actual client + * numbers + */ +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index dda63b26e370..99f593be26e2 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -2541,11 +2541,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + pci_set_master(pdev); + + /* Query PCI controller on system for DMA addressing +- * limitation for the device. Try 64-bit first, and ++ * limitation for the device. Try 47-bit first, and + * fail to 32-bit. + */ + +- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); ++ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(47)); + if (err) { + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { +@@ -2559,10 +2559,10 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + goto err_out_release_regions; + } + } else { +- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); ++ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(47)); + if (err) { + dev_err(dev, "Unable to obtain %u-bit DMA " +- "for consistent allocations, aborting\n", 64); ++ "for consistent allocations, aborting\n", 47); + goto err_out_release_regions; + } + using_dac = 1; +diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c +index 474ff36b9755..71578d48efbc 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/qp.c ++++ b/drivers/net/ethernet/mellanox/mlx4/qp.c +@@ -392,11 +392,11 @@ struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + struct mlx4_qp *qp; + +- spin_lock(&qp_table->lock); ++ spin_lock_irq(&qp_table->lock); + + qp = __mlx4_qp_lookup(dev, qpn); + +- spin_unlock(&qp_table->lock); ++ spin_unlock_irq(&qp_table->lock); + return qp; + } + +diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c +index 457e30427535..f1956c4d02a0 100644 +--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c ++++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c +@@ -54,7 +54,7 @@ + #define ILT_CFG_REG(cli, reg) PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET + + /* ILT entry structure */ +-#define ILT_ENTRY_PHY_ADDR_MASK 0x000FFFFFFFFFFFULL ++#define ILT_ENTRY_PHY_ADDR_MASK (~0ULL >> 12) + #define ILT_ENTRY_PHY_ADDR_SHIFT 0 + #define ILT_ENTRY_VALID_MASK 0x1ULL + #define ILT_ENTRY_VALID_SHIFT 52 +diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c +index 49bbc6826883..9a7dca2bb618 100644 +--- a/drivers/net/phy/bcm-cygnus.c ++++ b/drivers/net/phy/bcm-cygnus.c +@@ -61,17 +61,17 @@ static int bcm_cygnus_afe_config(struct phy_device *phydev) + return rc; + + /* make rcal=100, since rdb default is 000 */ +- rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB1, 0x10); ++ rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10); + if (rc < 0) + return rc; + + /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */ +- rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x10); ++ rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10); + if (rc < 0) + return rc; + + /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */ +- rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x00); ++ rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00); + + return 0; + } +diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h +index b2091c88b44d..ce16b26d49ff 100644 +--- a/drivers/net/phy/bcm-phy-lib.h ++++ b/drivers/net/phy/bcm-phy-lib.h +@@ -14,11 +14,18 @@ + #ifndef _LINUX_BCM_PHY_LIB_H + #define _LINUX_BCM_PHY_LIB_H + ++#include + #include + + int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val); + int bcm_phy_read_exp(struct phy_device *phydev, u16 reg); + ++static inline int bcm_phy_write_exp_sel(struct phy_device *phydev, ++ u16 reg, u16 val) ++{ ++ return bcm_phy_write_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER, val); ++} ++ + int bcm_phy_write_misc(struct phy_device *phydev, + u16 reg, u16 chl, u16 value); + int bcm_phy_read_misc(struct phy_device *phydev, +diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c +index 9636da0b6efc..caff474d2ee2 100644 +--- a/drivers/net/phy/bcm7xxx.c ++++ b/drivers/net/phy/bcm7xxx.c +@@ -48,10 +48,10 @@ + static void r_rc_cal_reset(struct phy_device *phydev) + { + /* Reset R_CAL/RC_CAL Engine */ +- bcm_phy_write_exp(phydev, 0x00b0, 0x0010); ++ bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0010); + + /* Disable Reset R_AL/RC_CAL Engine */ +- bcm_phy_write_exp(phydev, 0x00b0, 0x0000); ++ bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0000); + } + + static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev) +diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c +index 36963685d42a..f9ec00981b1e 100644 +--- a/drivers/net/team/team.c ++++ b/drivers/net/team/team.c +@@ -1004,7 +1004,8 @@ static void team_port_disable(struct team *team, + static void ___team_compute_features(struct team *team) + { + struct team_port *port; +- u32 vlan_features = TEAM_VLAN_FEATURES & NETIF_F_ALL_FOR_ALL; ++ netdev_features_t vlan_features = TEAM_VLAN_FEATURES & ++ NETIF_F_ALL_FOR_ALL; + netdev_features_t enc_features = TEAM_ENC_FEATURES; + unsigned short max_hard_header_len = ETH_HLEN; + unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE | +diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c +index 3a98f3762a4c..4c8baba72933 100644 +--- a/drivers/net/usb/cdc_mbim.c ++++ b/drivers/net/usb/cdc_mbim.c +@@ -608,7 +608,7 @@ static const struct driver_info cdc_mbim_info_ndp_to_end = { + */ + static const struct driver_info cdc_mbim_info_avoid_altsetting_toggle = { + .description = "CDC MBIM", +- .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN, ++ .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN | FLAG_SEND_ZLP, + .bind = cdc_mbim_bind, + .unbind = cdc_mbim_unbind, + .manage_power = cdc_mbim_manage_power, +diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c +index fce49ebc575d..c81bc4efe1a6 100644 +--- a/drivers/vhost/vhost.c ++++ b/drivers/vhost/vhost.c +@@ -938,6 +938,7 @@ int vhost_process_iotlb_msg(struct vhost_dev *dev, + { + int ret = 0; + ++ mutex_lock(&dev->mutex); + vhost_dev_lock_vqs(dev); + switch (msg->type) { + case VHOST_IOTLB_UPDATE: +@@ -967,6 +968,8 @@ int vhost_process_iotlb_msg(struct vhost_dev *dev, + } + + vhost_dev_unlock_vqs(dev); ++ mutex_unlock(&dev->mutex); ++ + return ret; + } + ssize_t vhost_chr_write_iter(struct vhost_dev *dev, +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index c5eafcdb3664..92f3b231d5a2 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -59,7 +59,8 @@ + BTRFS_HEADER_FLAG_RELOC |\ + BTRFS_SUPER_FLAG_ERROR |\ + BTRFS_SUPER_FLAG_SEEDING |\ +- BTRFS_SUPER_FLAG_METADUMP) ++ BTRFS_SUPER_FLAG_METADUMP |\ ++ BTRFS_SUPER_FLAG_METADUMP_V2) + + static const struct extent_io_ops btree_extent_io_ops; + static void end_workqueue_fn(struct btrfs_work *work); +diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h +index 2214b2f9c73c..ad793c69cc46 100644 +--- a/include/linux/compiler-gcc.h ++++ b/include/linux/compiler-gcc.h +@@ -206,7 +206,7 @@ + #ifdef CONFIG_STACK_VALIDATION + #define annotate_unreachable() ({ \ + asm("1:\t\n" \ +- ".pushsection __unreachable, \"a\"\t\n" \ ++ ".pushsection .discard.unreachable\t\n" \ + ".long 1b\t\n" \ + ".popsection\t\n"); \ + }) +diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h +index d5ad15a106a7..c794c9af6c0f 100644 +--- a/include/uapi/linux/btrfs_tree.h ++++ b/include/uapi/linux/btrfs_tree.h +@@ -452,6 +452,7 @@ struct btrfs_free_space_header { + + #define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) + #define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) ++#define BTRFS_SUPER_FLAG_METADUMP_V2 (1ULL << 34) + + + /* +diff --git a/mm/mmap.c b/mm/mmap.c +index 45ac5b973459..aa97074a4a99 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -1312,6 +1312,35 @@ static inline int mlock_future_check(struct mm_struct *mm, + return 0; + } + ++static inline u64 file_mmap_size_max(struct file *file, struct inode *inode) ++{ ++ if (S_ISREG(inode->i_mode)) ++ return MAX_LFS_FILESIZE; ++ ++ if (S_ISBLK(inode->i_mode)) ++ return MAX_LFS_FILESIZE; ++ ++ /* Special "we do even unsigned file positions" case */ ++ if (file->f_mode & FMODE_UNSIGNED_OFFSET) ++ return 0; ++ ++ /* Yes, random drivers might want more. But I'm tired of buggy drivers */ ++ return ULONG_MAX; ++} ++ ++static inline bool file_mmap_ok(struct file *file, struct inode *inode, ++ unsigned long pgoff, unsigned long len) ++{ ++ u64 maxsize = file_mmap_size_max(file, inode); ++ ++ if (maxsize && len > maxsize) ++ return false; ++ maxsize -= len; ++ if (pgoff > maxsize >> PAGE_SHIFT) ++ return false; ++ return true; ++} ++ + /* + * The caller must hold down_write(¤t->mm->mmap_sem). + */ +@@ -1384,6 +1413,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, + if (file) { + struct inode *inode = file_inode(file); + ++ if (!file_mmap_ok(file, inode, pgoff, len)) ++ return -EOVERFLOW; ++ + switch (flags & MAP_TYPE) { + case MAP_SHARED: + if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE)) +diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c +index c2339b865164..f3a0ad14b454 100644 +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -1914,6 +1914,10 @@ static int do_setlink(const struct sk_buff *skb, + const struct net_device_ops *ops = dev->netdev_ops; + int err; + ++ err = validate_linkmsg(dev, tb); ++ if (err < 0) ++ return err; ++ + if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { + struct net *net = rtnl_link_get_net(dev_net(dev), tb); + if (IS_ERR(net)) { +@@ -2234,10 +2238,6 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) + goto errout; + } + +- err = validate_linkmsg(dev, tb); +- if (err < 0) +- goto errout; +- + err = do_setlink(skb, dev, ifm, tb, ifname, 0); + errout: + return err; +diff --git a/net/dccp/proto.c b/net/dccp/proto.c +index ff3b058cf58c..936dab12f99f 100644 +--- a/net/dccp/proto.c ++++ b/net/dccp/proto.c +@@ -280,9 +280,7 @@ int dccp_disconnect(struct sock *sk, int flags) + + dccp_clear_xmit_timers(sk); + ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); +- ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); + dp->dccps_hc_rx_ccid = NULL; +- dp->dccps_hc_tx_ccid = NULL; + + __skb_queue_purge(&sk->sk_receive_queue); + __skb_queue_purge(&sk->sk_write_queue); +diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c +index e1be24416c0e..d476b7950adf 100644 +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -979,6 +979,8 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) + if (val == TCP_CA_UNSPEC) + return -EINVAL; + } else { ++ if (nla_len(nla) != sizeof(u32)) ++ return false; + val = nla_get_u32(nla); + } + if (type == RTAX_ADVMSS && val > 65535 - 40) +diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c +index 5ddd64995e73..dd80276a8205 100644 +--- a/net/ipv4/ip_sockglue.c ++++ b/net/ipv4/ip_sockglue.c +@@ -503,8 +503,6 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) + int err; + int copied; + +- WARN_ON_ONCE(sk->sk_family == AF_INET6); +- + err = -EAGAIN; + skb = sock_dequeue_err_skb(sk); + if (!skb) +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index e8560031a0be..eb9046eae581 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -487,7 +487,8 @@ int ip6_forward(struct sk_buff *skb) + send redirects to source routed frames. + We don't send redirects to frames decapsulated from IPsec. + */ +- if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) { ++ if (IP6CB(skb)->iif == dst->dev->ifindex && ++ opt->srcrt == 0 && !skb_sec_path(skb)) { + struct in6_addr *target = NULL; + struct inet_peer *peer; + struct rt6_info *rt; +diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c +index a30e7e925c9b..4b93ad4fe6d8 100644 +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -1789,7 +1789,8 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns + ret = 0; + if (!ip6mr_new_table(net, v)) + ret = -ENOMEM; +- raw6_sk(sk)->ip6mr_table = v; ++ else ++ raw6_sk(sk)->ip6mr_table = v; + rtnl_unlock(); + return ret; + } +diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c +index 3fe80e104b58..21f3bf2125f4 100644 +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -1538,6 +1538,12 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) + ops_data_buf[NDISC_OPS_REDIRECT_DATA_SPACE], *ops_data = NULL; + bool ret; + ++ if (netif_is_l3_master(skb->dev)) { ++ dev = __dev_get_by_index(dev_net(skb->dev), IPCB(skb)->iif); ++ if (!dev) ++ return; ++ } ++ + if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { + ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n", + dev->name); +diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c +index cc306defcc19..553d0ad4a2fa 100644 +--- a/net/kcm/kcmsock.c ++++ b/net/kcm/kcmsock.c +@@ -1671,7 +1671,7 @@ static struct file *kcm_clone(struct socket *osock) + __module_get(newsock->ops->owner); + + newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL, +- &kcm_proto, true); ++ &kcm_proto, false); + if (!newsk) { + sock_release(newsock); + return ERR_PTR(-ENOMEM); +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index b2b50756263b..2c4a47f29f36 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -2918,7 +2918,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) + if (unlikely(offset < 0)) + goto out_free; + } else if (reserve) { +- skb_push(skb, reserve); ++ skb_reserve(skb, -reserve); + } + + /* Returns -EFAULT on error */ +@@ -4299,7 +4299,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, + goto out; + if (po->tp_version >= TPACKET_V3 && + req->tp_block_size <= +- BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv)) ++ BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv) + sizeof(struct tpacket3_hdr)) + goto out; + if (unlikely(req->tp_frame_size < po->tp_hdrlen + + po->tp_reserve)) +diff --git a/net/sctp/transport.c b/net/sctp/transport.c +index ce54dce13ddb..03d71cd97ec0 100644 +--- a/net/sctp/transport.c ++++ b/net/sctp/transport.c +@@ -608,7 +608,7 @@ unsigned long sctp_transport_timeout(struct sctp_transport *trans) + trans->state != SCTP_PF) + timeout += trans->hbinterval; + +- return timeout; ++ return max_t(unsigned long, timeout, HZ / 5); + } + + /* Reset transport variables to their initial values */ +diff --git a/scripts/Makefile.build b/scripts/Makefile.build +index 7675d11ee65e..abfd4f4b66dd 100644 +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -253,6 +253,9 @@ objtool_args = check + ifndef CONFIG_FRAME_POINTER + objtool_args += --no-fp + endif ++ifdef CONFIG_GCOV_KERNEL ++objtool_args += --no-unreachable ++endif + + # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory + # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file +diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c +index 297b079ae4d9..27aac273205b 100644 +--- a/scripts/kconfig/confdata.c ++++ b/scripts/kconfig/confdata.c +@@ -745,7 +745,7 @@ int conf_write(const char *name) + struct menu *menu; + const char *basename; + const char *str; +- char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; ++ char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8]; + char *env; + + dirname[0] = 0;