diff options
author | Mark Brown <broonie@kernel.org> | 2015-01-19 19:09:14 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-01-19 19:09:14 +0000 |
commit | acdf91f9c4d791cec5ca7b4ecae9522bd7054b05 (patch) | |
tree | 1b793271aa3cf3c24a189c1dc25eea29757cabbf | |
parent | 326dc1f1f301eaaf91619c359b85cd98c2ff4374 (diff) | |
parent | 890ca6222dbe3c4c0719748aa9030e0ce1aa5c11 (diff) |
Merge remote-tracking branch 'lsk/v3.14/topic/aosp' into linux-linaro-lsk-v3.14-android
Conflicts:
arch/arm64/Kconfig
arch/arm64/crypto/Makefile
arch/arm64/crypto/aes-glue.c
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/thread_info.h
arch/arm64/include/asm/unistd32.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/entry.S
arch/arm64/kernel/ptrace.c
drivers/base/cpu.c
drivers/of/fdt.c
fs/pstore/inode.c
kernel/futex.c
199 files changed, 7154 insertions, 1566 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index ab42c95f9985..982587b92373 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -56,6 +56,15 @@ ip_forward_use_pmtu - BOOLEAN 0 - disabled 1 - enabled +fwmark_reflect - BOOLEAN + Controls the fwmark of kernel-generated IPv4 reply packets that are not + associated with a socket for example, TCP RSTs or ICMP echo replies). + If unset, these packets have a fwmark of zero. If set, they have the + fwmark of the packet they are replying to. Similarly affects the fwmark + used by internal routing lookups triggered by incoming packets, such as + the ones used for Path MTU Discovery. + Default: 0 + route/max_size - INTEGER Maximum number of routes allowed in the kernel. Increase this when using large numbers of interfaces and/or routes. @@ -505,6 +514,16 @@ tcp_fastopen - INTEGER See include/net/tcp.h and the code for more details. +tcp_fwmark_accept - BOOLEAN + If set, incoming connections to listening sockets that do not have a + socket mark will set the mark of the accepting socket to the fwmark of + the incoming SYN packet. This will cause all packets on that connection + (starting from the first SYNACK) to be sent with that fwmark. The + listening socket's mark is unchanged. Listening sockets that already + have a fwmark set via setsockopt(SOL_SOCKET, SO_MARK, ...) are + unaffected. + Default: 0 + tcp_syn_retries - INTEGER Number of times initial SYNs for an active TCP connection attempt will be retransmitted. Should not be higher than 255. Default value @@ -1181,6 +1200,15 @@ conf/all/forwarding - BOOLEAN proxy_ndp - BOOLEAN Do proxy ndp. +fwmark_reflect - BOOLEAN + Controls the fwmark of kernel-generated IPv6 reply packets that are not + associated with a socket for example, TCP RSTs or ICMPv6 echo replies). + If unset, these packets have a fwmark of zero. If set, they have the + fwmark of the packet they are replying to. Similarly affects the fwmark + used by internal routing lookups triggered by incoming packets, such as + the ones used for Path MTU Discovery. + Default: 0 + conf/interface/*: Change special settings per interface. @@ -1420,6 +1448,19 @@ suppress_frag_ndisc - INTEGER 1 - (default) discard fragmented neighbor discovery packets 0 - allow fragmented neighbor discovery packets +optimistic_dad - BOOLEAN + Whether to perform Optimistic Duplicate Address Detection (RFC 4429). + 0: disabled (default) + 1: enabled + +use_optimistic - BOOLEAN + If enabled, do not classify optimistic addresses as deprecated during + source address selection. Preferred addresses will still be chosen + before optimistic addresses, subject to other ranking in the source + address selection algorithm. + 0: disabled (default) + 1: enabled + icmp/*: ratelimit - INTEGER Limit the maximal rates for sending ICMPv6 packets. diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg index 04c7148cf637..d8503e450957 100644 --- a/android/configs/android-base.cfg +++ b/android/configs/android-base.cfg @@ -5,8 +5,8 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_ANDROID_INTF_ALARM_DEV=y -CONFIG_ANDROID_LOGGER=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ARMV7_COMPAT=y CONFIG_ASHMEM=y CONFIG_BLK_DEV_DM=y CONFIG_BLK_DEV_INITRD=y @@ -25,6 +25,7 @@ CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_INET=y CONFIG_INET_ESP=y +CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_MANGLE=y diff --git a/arch/Kconfig b/arch/Kconfig index 80bbb8ccd0d1..34e8b9160da7 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -325,6 +325,7 @@ config HAVE_ARCH_SECCOMP_FILTER - secure_computing is called from a ptrace_event()-safe context - secure_computing return value is checked and a return value of -1 results in the system call being skipped immediately. + - seccomp syscall wired up config SECCOMP_FILTER def_bool y diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 4fb337ca0cb7..f4a38a76db64 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -24,49 +24,3 @@ config TI_PRIV_EDMA config FIQ_GLUE bool select FIQ - -config FIQ_DEBUGGER - bool "FIQ Mode Serial Debugger" - select FIQ - select FIQ_GLUE - default n - help - The FIQ serial debugger can accept commands even when the - kernel is unresponsive due to being stuck with interrupts - disabled. - - -config FIQ_DEBUGGER_NO_SLEEP - bool "Keep serial debugger active" - depends on FIQ_DEBUGGER - default n - help - Enables the serial debugger at boot. Passing - fiq_debugger.no_sleep on the kernel commandline will - override this config option. - -config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON - bool "Don't disable wakeup IRQ when debugger is active" - depends on FIQ_DEBUGGER - default n - help - Don't disable the wakeup irq when enabling the uart clock. This will - cause extra interrupts, but it makes the serial debugger usable with - on some MSM radio builds that ignore the uart clock request in power - collapse. - -config FIQ_DEBUGGER_CONSOLE - bool "Console on FIQ Serial Debugger port" - depends on FIQ_DEBUGGER - default n - help - Enables a console so that printk messages are displayed on - the debugger serial port as the occur. - -config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE - bool "Put the FIQ debugger into console mode by default" - depends on FIQ_DEBUGGER_CONSOLE - default n - help - If enabled, this puts the fiq debugger into console mode by default. - Otherwise, the fiq debugger will start out in debug mode. diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 14e592312033..5748afda0681 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -4,7 +4,6 @@ obj-y += firmware.o -obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger.o obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o obj-$(CONFIG_ICST) += icst.o obj-$(CONFIG_SA1111) += sa1111.o diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index 81cda39860c5..b48fa341648d 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile @@ -5,10 +5,14 @@ obj-$(CONFIG_CRYPTO_AES_ARM) += aes-arm.o obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o +obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o +obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o aes-arm-y := aes-armv4.o aes_glue.o aes-arm-bs-y := aesbs-core.o aesbs-glue.o sha1-arm-y := sha1-armv4-large.o sha1_glue.o +sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o +sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) > $(@) diff --git a/arch/arm/crypto/sha1-armv7-neon.S b/arch/arm/crypto/sha1-armv7-neon.S new file mode 100644 index 000000000000..50013c0e2864 --- /dev/null +++ b/arch/arm/crypto/sha1-armv7-neon.S @@ -0,0 +1,634 @@ +/* sha1-armv7-neon.S - ARM/NEON accelerated SHA-1 transform function + * + * Copyright © 2013-2014 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * 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. + */ + +#include <linux/linkage.h> + + +.syntax unified +.code 32 +.fpu neon + +.text + + +/* Context structure */ + +#define state_h0 0 +#define state_h1 4 +#define state_h2 8 +#define state_h3 12 +#define state_h4 16 + + +/* Constants */ + +#define K1 0x5A827999 +#define K2 0x6ED9EBA1 +#define K3 0x8F1BBCDC +#define K4 0xCA62C1D6 +.align 4 +.LK_VEC: +.LK1: .long K1, K1, K1, K1 +.LK2: .long K2, K2, K2, K2 +.LK3: .long K3, K3, K3, K3 +.LK4: .long K4, K4, K4, K4 + + +/* Register macros */ + +#define RSTATE r0 +#define RDATA r1 +#define RNBLKS r2 +#define ROLDSTACK r3 +#define RWK lr + +#define _a r4 +#define _b r5 +#define _c r6 +#define _d r7 +#define _e r8 + +#define RT0 r9 +#define RT1 r10 +#define RT2 r11 +#define RT3 r12 + +#define W0 q0 +#define W1 q1 +#define W2 q2 +#define W3 q3 +#define W4 q4 +#define W5 q5 +#define W6 q6 +#define W7 q7 + +#define tmp0 q8 +#define tmp1 q9 +#define tmp2 q10 +#define tmp3 q11 + +#define qK1 q12 +#define qK2 q13 +#define qK3 q14 +#define qK4 q15 + + +/* Round function macros. */ + +#define WK_offs(i) (((i) & 15) * 4) + +#define _R_F1(a,b,c,d,e,i,pre1,pre2,pre3,i16,\ + W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + ldr RT3, [sp, WK_offs(i)]; \ + pre1(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \ + bic RT0, d, b; \ + add e, e, a, ror #(32 - 5); \ + and RT1, c, b; \ + pre2(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \ + add RT0, RT0, RT3; \ + add e, e, RT1; \ + ror b, #(32 - 30); \ + pre3(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \ + add e, e, RT0; + +#define _R_F2(a,b,c,d,e,i,pre1,pre2,pre3,i16,\ + W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + ldr RT3, [sp, WK_offs(i)]; \ + pre1(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \ + eor RT0, d, b; \ + add e, e, a, ror #(32 - 5); \ + eor RT0, RT0, c; \ + pre2(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \ + add e, e, RT3; \ + ror b, #(32 - 30); \ + pre3(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \ + add e, e, RT0; \ + +#define _R_F3(a,b,c,d,e,i,pre1,pre2,pre3,i16,\ + W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + ldr RT3, [sp, WK_offs(i)]; \ + pre1(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \ + eor RT0, b, c; \ + and RT1, b, c; \ + add e, e, a, ror #(32 - 5); \ + pre2(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \ + and RT0, RT0, d; \ + add RT1, RT1, RT3; \ + add e, e, RT0; \ + ror b, #(32 - 30); \ + pre3(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \ + add e, e, RT1; + +#define _R_F4(a,b,c,d,e,i,pre1,pre2,pre3,i16,\ + W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + _R_F2(a,b,c,d,e,i,pre1,pre2,pre3,i16,\ + W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) + +#define _R(a,b,c,d,e,f,i,pre1,pre2,pre3,i16,\ + W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + _R_##f(a,b,c,d,e,i,pre1,pre2,pre3,i16,\ + W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) + +#define R(a,b,c,d,e,f,i) \ + _R_##f(a,b,c,d,e,i,dummy,dummy,dummy,i16,\ + W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) + +#define dummy(...) + + +/* Input expansion macros. */ + +/********* Precalc macros for rounds 0-15 *************************************/ + +#define W_PRECALC_00_15() \ + add RWK, sp, #(WK_offs(0)); \ + \ + vld1.32 {tmp0, tmp1}, [RDATA]!; \ + vrev32.8 W0, tmp0; /* big => little */ \ + vld1.32 {tmp2, tmp3}, [RDATA]!; \ + vadd.u32 tmp0, W0, curK; \ + vrev32.8 W7, tmp1; /* big => little */ \ + vrev32.8 W6, tmp2; /* big => little */ \ + vadd.u32 tmp1, W7, curK; \ + vrev32.8 W5, tmp3; /* big => little */ \ + vadd.u32 tmp2, W6, curK; \ + vst1.32 {tmp0, tmp1}, [RWK]!; \ + vadd.u32 tmp3, W5, curK; \ + vst1.32 {tmp2, tmp3}, [RWK]; \ + +#define WPRECALC_00_15_0(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vld1.32 {tmp0, tmp1}, [RDATA]!; \ + +#define WPRECALC_00_15_1(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + add RWK, sp, #(WK_offs(0)); \ + +#define WPRECALC_00_15_2(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vrev32.8 W0, tmp0; /* big => little */ \ + +#define WPRECALC_00_15_3(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vld1.32 {tmp2, tmp3}, [RDATA]!; \ + +#define WPRECALC_00_15_4(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vadd.u32 tmp0, W0, curK; \ + +#define WPRECALC_00_15_5(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vrev32.8 W7, tmp1; /* big => little */ \ + +#define WPRECALC_00_15_6(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vrev32.8 W6, tmp2; /* big => little */ \ + +#define WPRECALC_00_15_7(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vadd.u32 tmp1, W7, curK; \ + +#define WPRECALC_00_15_8(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vrev32.8 W5, tmp3; /* big => little */ \ + +#define WPRECALC_00_15_9(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vadd.u32 tmp2, W6, curK; \ + +#define WPRECALC_00_15_10(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vst1.32 {tmp0, tmp1}, [RWK]!; \ + +#define WPRECALC_00_15_11(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vadd.u32 tmp3, W5, curK; \ + +#define WPRECALC_00_15_12(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vst1.32 {tmp2, tmp3}, [RWK]; \ + + +/********* Precalc macros for rounds 16-31 ************************************/ + +#define WPRECALC_16_31_0(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + veor tmp0, tmp0; \ + vext.8 W, W_m16, W_m12, #8; \ + +#define WPRECALC_16_31_1(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + add RWK, sp, #(WK_offs(i)); \ + vext.8 tmp0, W_m04, tmp0, #4; \ + +#define WPRECALC_16_31_2(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + veor tmp0, tmp0, W_m16; \ + veor.32 W, W, W_m08; \ + +#define WPRECALC_16_31_3(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + veor tmp1, tmp1; \ + veor W, W, tmp0; \ + +#define WPRECALC_16_31_4(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vshl.u32 tmp0, W, #1; \ + +#define WPRECALC_16_31_5(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vext.8 tmp1, tmp1, W, #(16-12); \ + vshr.u32 W, W, #31; \ + +#define WPRECALC_16_31_6(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vorr tmp0, tmp0, W; \ + vshr.u32 W, tmp1, #30; \ + +#define WPRECALC_16_31_7(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vshl.u32 tmp1, tmp1, #2; \ + +#define WPRECALC_16_31_8(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + veor tmp0, tmp0, W; \ + +#define WPRECALC_16_31_9(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + veor W, tmp0, tmp1; \ + +#define WPRECALC_16_31_10(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vadd.u32 tmp0, W, curK; \ + +#define WPRECALC_16_31_11(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vst1.32 {tmp0}, [RWK]; + + +/********* Precalc macros for rounds 32-79 ************************************/ + +#define WPRECALC_32_79_0(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + veor W, W_m28; \ + +#define WPRECALC_32_79_1(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vext.8 tmp0, W_m08, W_m04, #8; \ + +#define WPRECALC_32_79_2(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + veor W, W_m16; \ + +#define WPRECALC_32_79_3(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + veor W, tmp0; \ + +#define WPRECALC_32_79_4(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + add RWK, sp, #(WK_offs(i&~3)); \ + +#define WPRECALC_32_79_5(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vshl.u32 tmp1, W, #2; \ + +#define WPRECALC_32_79_6(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vshr.u32 tmp0, W, #30; \ + +#define WPRECALC_32_79_7(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vorr W, tmp0, tmp1; \ + +#define WPRECALC_32_79_8(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vadd.u32 tmp0, W, curK; \ + +#define WPRECALC_32_79_9(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \ + vst1.32 {tmp0}, [RWK]; + + +/* + * Transform nblks*64 bytes (nblks*16 32-bit words) at DATA. + * + * unsigned int + * sha1_transform_neon (void *ctx, const unsigned char *data, + * unsigned int nblks) + */ +.align 3 +ENTRY(sha1_transform_neon) + /* input: + * r0: ctx, CTX + * r1: data (64*nblks bytes) + * r2: nblks + */ + + cmp RNBLKS, #0; + beq .Ldo_nothing; + + push {r4-r12, lr}; + /*vpush {q4-q7};*/ + + adr RT3, .LK_VEC; + + mov ROLDSTACK, sp; + + /* Align stack. */ + sub RT0, sp, #(16*4); + and RT0, #(~(16-1)); + mov sp, RT0; + + vld1.32 {qK1-qK2}, [RT3]!; /* Load K1,K2 */ + + /* Get the values of the chaining variables. */ + ldm RSTATE, {_a-_e}; + + vld1.32 {qK3-qK4}, [RT3]; /* Load K3,K4 */ + +#undef curK +#define curK qK1 + /* Precalc 0-15. */ + W_PRECALC_00_15(); + +.Loop: + /* Transform 0-15 + Precalc 16-31. */ + _R( _a, _b, _c, _d, _e, F1, 0, + WPRECALC_16_31_0, WPRECALC_16_31_1, WPRECALC_16_31_2, 16, + W4, W5, W6, W7, W0, _, _, _ ); + _R( _e, _a, _b, _c, _d, F1, 1, + WPRECALC_16_31_3, WPRECALC_16_31_4, WPRECALC_16_31_5, 16, + W4, W5, W6, W7, W0, _, _, _ ); + _R( _d, _e, _a, _b, _c, F1, 2, + WPRECALC_16_31_6, WPRECALC_16_31_7, WPRECALC_16_31_8, 16, + W4, W5, W6, W7, W0, _, _, _ ); + _R( _c, _d, _e, _a, _b, F1, 3, + WPRECALC_16_31_9, WPRECALC_16_31_10,WPRECALC_16_31_11,16, + W4, W5, W6, W7, W0, _, _, _ ); + +#undef curK +#define curK qK2 + _R( _b, _c, _d, _e, _a, F1, 4, + WPRECALC_16_31_0, WPRECALC_16_31_1, WPRECALC_16_31_2, 20, + W3, W4, W5, W6, W7, _, _, _ ); + _R( _a, _b, _c, _d, _e, F1, 5, + WPRECALC_16_31_3, WPRECALC_16_31_4, WPRECALC_16_31_5, 20, + W3, W4, W5, W6, W7, _, _, _ ); + _R( _e, _a, _b, _c, _d, F1, 6, + WPRECALC_16_31_6, WPRECALC_16_31_7, WPRECALC_16_31_8, 20, + W3, W4, W5, W6, W7, _, _, _ ); + _R( _d, _e, _a, _b, _c, F1, 7, + WPRECALC_16_31_9, WPRECALC_16_31_10,WPRECALC_16_31_11,20, + W3, W4, W5, W6, W7, _, _, _ ); + + _R( _c, _d, _e, _a, _b, F1, 8, + WPRECALC_16_31_0, WPRECALC_16_31_1, WPRECALC_16_31_2, 24, + W2, W3, W4, W5, W6, _, _, _ ); + _R( _b, _c, _d, _e, _a, F1, 9, + WPRECALC_16_31_3, WPRECALC_16_31_4, WPRECALC_16_31_5, 24, + W2, W3, W4, W5, W6, _, _, _ ); + _R( _a, _b, _c, _d, _e, F1, 10, + WPRECALC_16_31_6, WPRECALC_16_31_7, WPRECALC_16_31_8, 24, + W2, W3, W4, W5, W6, _, _, _ ); + _R( _e, _a, _b, _c, _d, F1, 11, + WPRECALC_16_31_9, WPRECALC_16_31_10,WPRECALC_16_31_11,24, + W2, W3, W4, W5, W6, _, _, _ ); + + _R( _d, _e, _a, _b, _c, F1, 12, + WPRECALC_16_31_0, WPRECALC_16_31_1, WPRECALC_16_31_2, 28, + W1, W2, W3, W4, W5, _, _, _ ); + _R( _c, _d, _e, _a, _b, F1, 13, + WPRECALC_16_31_3, WPRECALC_16_31_4, WPRECALC_16_31_5, 28, + W1, W2, W3, W4, W5, _, _, _ ); + _R( _b, _c, _d, _e, _a, F1, 14, + WPRECALC_16_31_6, WPRECALC_16_31_7, WPRECALC_16_31_8, 28, + W1, W2, W3, W4, W5, _, _, _ ); + _R( _a, _b, _c, _d, _e, F1, 15, + WPRECALC_16_31_9, WPRECALC_16_31_10,WPRECALC_16_31_11,28, + W1, W2, W3, W4, W5, _, _, _ ); + + /* Transform 16-63 + Precalc 32-79. */ + _R( _e, _a, _b, _c, _d, F1, 16, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 32, + W0, W1, W2, W3, W4, W5, W6, W7); + _R( _d, _e, _a, _b, _c, F1, 17, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 32, + W0, W1, W2, W3, W4, W5, W6, W7); + _R( _c, _d, _e, _a, _b, F1, 18, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 32, + W0, W1, W2, W3, W4, W5, W6, W7); + _R( _b, _c, _d, _e, _a, F1, 19, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 32, + W0, W1, W2, W3, W4, W5, W6, W7); + + _R( _a, _b, _c, _d, _e, F2, 20, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 36, + W7, W0, W1, W2, W3, W4, W5, W6); + _R( _e, _a, _b, _c, _d, F2, 21, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 36, + W7, W0, W1, W2, W3, W4, W5, W6); + _R( _d, _e, _a, _b, _c, F2, 22, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 36, + W7, W0, W1, W2, W3, W4, W5, W6); + _R( _c, _d, _e, _a, _b, F2, 23, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 36, + W7, W0, W1, W2, W3, W4, W5, W6); + +#undef curK +#define curK qK3 + _R( _b, _c, _d, _e, _a, F2, 24, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 40, + W6, W7, W0, W1, W2, W3, W4, W5); + _R( _a, _b, _c, _d, _e, F2, 25, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 40, + W6, W7, W0, W1, W2, W3, W4, W5); + _R( _e, _a, _b, _c, _d, F2, 26, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 40, + W6, W7, W0, W1, W2, W3, W4, W5); + _R( _d, _e, _a, _b, _c, F2, 27, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 40, + W6, W7, W0, W1, W2, W3, W4, W5); + + _R( _c, _d, _e, _a, _b, F2, 28, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 44, + W5, W6, W7, W0, W1, W2, W3, W4); + _R( _b, _c, _d, _e, _a, F2, 29, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 44, + W5, W6, W7, W0, W1, W2, W3, W4); + _R( _a, _b, _c, _d, _e, F2, 30, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 44, + W5, W6, W7, W0, W1, W2, W3, W4); + _R( _e, _a, _b, _c, _d, F2, 31, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 44, + W5, W6, W7, W0, W1, W2, W3, W4); + + _R( _d, _e, _a, _b, _c, F2, 32, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 48, + W4, W5, W6, W7, W0, W1, W2, W3); + _R( _c, _d, _e, _a, _b, F2, 33, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 48, + W4, W5, W6, W7, W0, W1, W2, W3); + _R( _b, _c, _d, _e, _a, F2, 34, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 48, + W4, W5, W6, W7, W0, W1, W2, W3); + _R( _a, _b, _c, _d, _e, F2, 35, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 48, + W4, W5, W6, W7, W0, W1, W2, W3); + + _R( _e, _a, _b, _c, _d, F2, 36, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 52, + W3, W4, W5, W6, W7, W0, W1, W2); + _R( _d, _e, _a, _b, _c, F2, 37, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 52, + W3, W4, W5, W6, W7, W0, W1, W2); + _R( _c, _d, _e, _a, _b, F2, 38, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 52, + W3, W4, W5, W6, W7, W0, W1, W2); + _R( _b, _c, _d, _e, _a, F2, 39, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 52, + W3, W4, W5, W6, W7, W0, W1, W2); + + _R( _a, _b, _c, _d, _e, F3, 40, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 56, + W2, W3, W4, W5, W6, W7, W0, W1); + _R( _e, _a, _b, _c, _d, F3, 41, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 56, + W2, W3, W4, W5, W6, W7, W0, W1); + _R( _d, _e, _a, _b, _c, F3, 42, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 56, + W2, W3, W4, W5, W6, W7, W0, W1); + _R( _c, _d, _e, _a, _b, F3, 43, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 56, + W2, W3, W4, W5, W6, W7, W0, W1); + +#undef curK +#define curK qK4 + _R( _b, _c, _d, _e, _a, F3, 44, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 60, + W1, W2, W3, W4, W5, W6, W7, W0); + _R( _a, _b, _c, _d, _e, F3, 45, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 60, + W1, W2, W3, W4, W5, W6, W7, W0); + _R( _e, _a, _b, _c, _d, F3, 46, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 60, + W1, W2, W3, W4, W5, W6, W7, W0); + _R( _d, _e, _a, _b, _c, F3, 47, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 60, + W1, W2, W3, W4, W5, W6, W7, W0); + + _R( _c, _d, _e, _a, _b, F3, 48, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 64, + W0, W1, W2, W3, W4, W5, W6, W7); + _R( _b, _c, _d, _e, _a, F3, 49, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 64, + W0, W1, W2, W3, W4, W5, W6, W7); + _R( _a, _b, _c, _d, _e, F3, 50, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 64, + W0, W1, W2, W3, W4, W5, W6, W7); + _R( _e, _a, _b, _c, _d, F3, 51, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 64, + W0, W1, W2, W3, W4, W5, W6, W7); + + _R( _d, _e, _a, _b, _c, F3, 52, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 68, + W7, W0, W1, W2, W3, W4, W5, W6); + _R( _c, _d, _e, _a, _b, F3, 53, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 68, + W7, W0, W1, W2, W3, W4, W5, W6); + _R( _b, _c, _d, _e, _a, F3, 54, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 68, + W7, W0, W1, W2, W3, W4, W5, W6); + _R( _a, _b, _c, _d, _e, F3, 55, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 68, + W7, W0, W1, W2, W3, W4, W5, W6); + + _R( _e, _a, _b, _c, _d, F3, 56, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 72, + W6, W7, W0, W1, W2, W3, W4, W5); + _R( _d, _e, _a, _b, _c, F3, 57, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 72, + W6, W7, W0, W1, W2, W3, W4, W5); + _R( _c, _d, _e, _a, _b, F3, 58, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 72, + W6, W7, W0, W1, W2, W3, W4, W5); + _R( _b, _c, _d, _e, _a, F3, 59, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 72, + W6, W7, W0, W1, W2, W3, W4, W5); + + subs RNBLKS, #1; + + _R( _a, _b, _c, _d, _e, F4, 60, + WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 76, + W5, W6, W7, W0, W1, W2, W3, W4); + _R( _e, _a, _b, _c, _d, F4, 61, + WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 76, + W5, W6, W7, W0, W1, W2, W3, W4); + _R( _d, _e, _a, _b, _c, F4, 62, + WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 76, + W5, W6, W7, W0, W1, W2, W3, W4); + _R( _c, _d, _e, _a, _b, F4, 63, + WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 76, + W5, W6, W7, W0, W1, W2, W3, W4); + + beq .Lend; + + /* Transform 64-79 + Precalc 0-15 of next block. */ +#undef curK +#define curK qK1 + _R( _b, _c, _d, _e, _a, F4, 64, + WPRECALC_00_15_0, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _a, _b, _c, _d, _e, F4, 65, + WPRECALC_00_15_1, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _e, _a, _b, _c, _d, F4, 66, + WPRECALC_00_15_2, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _d, _e, _a, _b, _c, F4, 67, + WPRECALC_00_15_3, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + + _R( _c, _d, _e, _a, _b, F4, 68, + dummy, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _b, _c, _d, _e, _a, F4, 69, + dummy, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _a, _b, _c, _d, _e, F4, 70, + WPRECALC_00_15_4, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _e, _a, _b, _c, _d, F4, 71, + WPRECALC_00_15_5, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + + _R( _d, _e, _a, _b, _c, F4, 72, + dummy, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _c, _d, _e, _a, _b, F4, 73, + dummy, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _b, _c, _d, _e, _a, F4, 74, + WPRECALC_00_15_6, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _a, _b, _c, _d, _e, F4, 75, + WPRECALC_00_15_7, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + + _R( _e, _a, _b, _c, _d, F4, 76, + WPRECALC_00_15_8, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _d, _e, _a, _b, _c, F4, 77, + WPRECALC_00_15_9, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _c, _d, _e, _a, _b, F4, 78, + WPRECALC_00_15_10, dummy, dummy, _, _, _, _, _, _, _, _, _ ); + _R( _b, _c, _d, _e, _a, F4, 79, + WPRECALC_00_15_11, dummy, WPRECALC_00_15_12, _, _, _, _, _, _, _, _, _ ); + + /* Update the chaining variables. */ + ldm RSTATE, {RT0-RT3}; + add _a, RT0; + ldr RT0, [RSTATE, #state_h4]; + add _b, RT1; + add _c, RT2; + add _d, RT3; + add _e, RT0; + stm RSTATE, {_a-_e}; + + b .Loop; + +.Lend: + /* Transform 64-79 */ + R( _b, _c, _d, _e, _a, F4, 64 ); + R( _a, _b, _c, _d, _e, F4, 65 ); + R( _e, _a, _b, _c, _d, F4, 66 ); + R( _d, _e, _a, _b, _c, F4, 67 ); + R( _c, _d, _e, _a, _b, F4, 68 ); + R( _b, _c, _d, _e, _a, F4, 69 ); + R( _a, _b, _c, _d, _e, F4, 70 ); + R( _e, _a, _b, _c, _d, F4, 71 ); + R( _d, _e, _a, _b, _c, F4, 72 ); + R( _c, _d, _e, _a, _b, F4, 73 ); + R( _b, _c, _d, _e, _a, F4, 74 ); + R( _a, _b, _c, _d, _e, F4, 75 ); + R( _e, _a, _b, _c, _d, F4, 76 ); + R( _d, _e, _a, _b, _c, F4, 77 ); + R( _c, _d, _e, _a, _b, F4, 78 ); + R( _b, _c, _d, _e, _a, F4, 79 ); + + mov sp, ROLDSTACK; + + /* Update the chaining variables. */ + ldm RSTATE, {RT0-RT3}; + add _a, RT0; + ldr RT0, [RSTATE, #state_h4]; + add _b, RT1; + add _c, RT2; + add _d, RT3; + /*vpop {q4-q7};*/ + add _e, RT0; + stm RSTATE, {_a-_e}; + + pop {r4-r12, pc}; + +.Ldo_nothing: + bx lr +ENDPROC(sha1_transform_neon) diff --git a/arch/arm/crypto/sha1_glue.c b/arch/arm/crypto/sha1_glue.c index 76cd976230bc..84f2a756588b 100644 --- a/arch/arm/crypto/sha1_glue.c +++ b/arch/arm/crypto/sha1_glue.c @@ -23,32 +23,27 @@ #include <linux/types.h> #include <crypto/sha.h> #include <asm/byteorder.h> +#include <asm/crypto/sha1.h> -struct SHA1_CTX { - uint32_t h0,h1,h2,h3,h4; - u64 count; - u8 data[SHA1_BLOCK_SIZE]; -}; -asmlinkage void sha1_block_data_order(struct SHA1_CTX *digest, +asmlinkage void sha1_block_data_order(u32 *digest, const unsigned char *data, unsigned int rounds); static int sha1_init(struct shash_desc *desc) { - struct SHA1_CTX *sctx = shash_desc_ctx(desc); - memset(sctx, 0, sizeof(*sctx)); - sctx->h0 = SHA1_H0; - sctx->h1 = SHA1_H1; - sctx->h2 = SHA1_H2; - sctx->h3 = SHA1_H3; - sctx->h4 = SHA1_H4; + struct sha1_state *sctx = shash_desc_ctx(desc); + + *sctx = (struct sha1_state){ + .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, + }; + return 0; } -static int __sha1_update(struct SHA1_CTX *sctx, const u8 *data, - unsigned int len, unsigned int partial) +static int __sha1_update(struct sha1_state *sctx, const u8 *data, + unsigned int len, unsigned int partial) { unsigned int done = 0; @@ -56,43 +51,44 @@ static int __sha1_update(struct SHA1_CTX *sctx, const u8 *data, if (partial) { done = SHA1_BLOCK_SIZE - partial; - memcpy(sctx->data + partial, data, done); - sha1_block_data_order(sctx, sctx->data, 1); + memcpy(sctx->buffer + partial, data, done); + sha1_block_data_order(sctx->state, sctx->buffer, 1); } if (len - done >= SHA1_BLOCK_SIZE) { const unsigned int rounds = (len - done) / SHA1_BLOCK_SIZE; - sha1_block_data_order(sctx, data + done, rounds); + sha1_block_data_order(sctx->state, data + done, rounds); done += rounds * SHA1_BLOCK_SIZE; } - memcpy(sctx->data, data + done, len - done); + memcpy(sctx->buffer, data + done, len - done); return 0; } -static int sha1_update(struct shash_desc *desc, const u8 *data, - unsigned int len) +int sha1_update_arm(struct shash_desc *desc, const u8 *data, + unsigned int len) { - struct SHA1_CTX *sctx = shash_desc_ctx(desc); + struct sha1_state *sctx = shash_desc_ctx(desc); unsigned int partial = sctx->count % SHA1_BLOCK_SIZE; int res; /* Handle the fast case right here */ if (partial + len < SHA1_BLOCK_SIZE) { sctx->count += len; - memcpy(sctx->data + partial, data, len); + memcpy(sctx->buffer + partial, data, len); return 0; } res = __sha1_update(sctx, data, len, partial); return res; } +EXPORT_SYMBOL_GPL(sha1_update_arm); /* Add padding and return the message digest. */ static int sha1_final(struct shash_desc *desc, u8 *out) { - struct SHA1_CTX *sctx = shash_desc_ctx(desc); + struct sha1_state *sctx = shash_desc_ctx(desc); unsigned int i, index, padlen; __be32 *dst = (__be32 *)out; __be64 bits; @@ -106,7 +102,7 @@ static int sha1_final(struct shash_desc *desc, u8 *out) /* We need to fill a whole block for __sha1_update() */ if (padlen <= 56) { sctx->count += padlen; - memcpy(sctx->data + index, padding, padlen); + memcpy(sctx->buffer + index, padding, padlen); } else { __sha1_update(sctx, padding, padlen, index); } @@ -114,7 +110,7 @@ static int sha1_final(struct shash_desc *desc, u8 *out) /* Store state in digest */ for (i = 0; i < 5; i++) - dst[i] = cpu_to_be32(((u32 *)sctx)[i]); + dst[i] = cpu_to_be32(sctx->state[i]); /* Wipe context */ memset(sctx, 0, sizeof(*sctx)); @@ -124,7 +120,7 @@ static int sha1_final(struct shash_desc *desc, u8 *out) static int sha1_export(struct shash_desc *desc, void *out) { - struct SHA1_CTX *sctx = shash_desc_ctx(desc); + struct sha1_state *sctx = shash_desc_ctx(desc); memcpy(out, sctx, sizeof(*sctx)); return 0; } @@ -132,7 +128,7 @@ static int sha1_export(struct shash_desc *desc, void *out) static int sha1_import(struct shash_desc *desc, const void *in) { - struct SHA1_CTX *sctx = shash_desc_ctx(desc); + struct sha1_state *sctx = shash_desc_ctx(desc); memcpy(sctx, in, sizeof(*sctx)); return 0; } @@ -141,12 +137,12 @@ static int sha1_import(struct shash_desc *desc, const void *in) static struct shash_alg alg = { .digestsize = SHA1_DIGEST_SIZE, .init = sha1_init, - .update = sha1_update, + .update = sha1_update_arm, .final = sha1_final, .export = sha1_export, .import = sha1_import, - .descsize = sizeof(struct SHA1_CTX), - .statesize = sizeof(struct SHA1_CTX), + .descsize = sizeof(struct sha1_state), + .statesize = sizeof(struct sha1_state), .base = { .cra_name = "sha1", .cra_driver_name= "sha1-asm", diff --git a/arch/arm/crypto/sha1_neon_glue.c b/arch/arm/crypto/sha1_neon_glue.c new file mode 100644 index 000000000000..6f1b411b1d55 --- /dev/null +++ b/arch/arm/crypto/sha1_neon_glue.c @@ -0,0 +1,197 @@ +/* + * Glue code for the SHA1 Secure Hash Algorithm assembler implementation using + * ARM NEON instructions. + * + * Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is based on sha1_generic.c and sha1_ssse3_glue.c: + * Copyright (c) Alan Smithee. + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> + * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> + * Copyright (c) Mathias Krause <minipli@googlemail.com> + * Copyright (c) Chandramouli Narayanan <mouli@linux.intel.com> + * + * 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. + * + */ + +#include <crypto/internal/hash.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/cryptohash.h> +#include <linux/types.h> +#include <crypto/sha.h> +#include <asm/byteorder.h> +#include <asm/neon.h> +#include <asm/simd.h> +#include <asm/crypto/sha1.h> + + +asmlinkage void sha1_transform_neon(void *state_h, const char *data, + unsigned int rounds); + + +static int sha1_neon_init(struct shash_desc *desc) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + *sctx = (struct sha1_state){ + .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, + }; + + return 0; +} + +static int __sha1_neon_update(struct shash_desc *desc, const u8 *data, + unsigned int len, unsigned int partial) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + unsigned int done = 0; + + sctx->count += len; + + if (partial) { + done = SHA1_BLOCK_SIZE - partial; + memcpy(sctx->buffer + partial, data, done); + sha1_transform_neon(sctx->state, sctx->buffer, 1); + } + + if (len - done >= SHA1_BLOCK_SIZE) { + const unsigned int rounds = (len - done) / SHA1_BLOCK_SIZE; + + sha1_transform_neon(sctx->state, data + done, rounds); + done += rounds * SHA1_BLOCK_SIZE; + } + + memcpy(sctx->buffer, data + done, len - done); + + return 0; +} + +static int sha1_neon_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE; + int res; + + /* Handle the fast case right here */ + if (partial + len < SHA1_BLOCK_SIZE) { + sctx->count += len; + memcpy(sctx->buffer + partial, data, len); + + return 0; + } + + if (!may_use_simd()) { + res = sha1_update_arm(desc, data, len); + } else { + kernel_neon_begin(); + res = __sha1_neon_update(desc, data, len, partial); + kernel_neon_end(); + } + + return res; +} + + +/* Add padding and return the message digest. */ +static int sha1_neon_final(struct shash_desc *desc, u8 *out) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + unsigned int i, index, padlen; + __be32 *dst = (__be32 *)out; + __be64 bits; + static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, }; + + bits = cpu_to_be64(sctx->count << 3); + + /* Pad out to 56 mod 64 and append length */ + index = sctx->count % SHA1_BLOCK_SIZE; + padlen = (index < 56) ? (56 - index) : ((SHA1_BLOCK_SIZE+56) - index); + if (!may_use_simd()) { + sha1_update_arm(desc, padding, padlen); + sha1_update_arm(desc, (const u8 *)&bits, sizeof(bits)); + } else { + kernel_neon_begin(); + /* We need to fill a whole block for __sha1_neon_update() */ + if (padlen <= 56) { + sctx->count += padlen; + memcpy(sctx->buffer + index, padding, padlen); + } else { + __sha1_neon_update(desc, padding, padlen, index); + } + __sha1_neon_update(desc, (const u8 *)&bits, sizeof(bits), 56); + kernel_neon_end(); + } + + /* Store state in digest */ + for (i = 0; i < 5; i++) + dst[i] = cpu_to_be32(sctx->state[i]); + + /* Wipe context */ + memset(sctx, 0, sizeof(*sctx)); + + return 0; +} + +static int sha1_neon_export(struct shash_desc *desc, void *out) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + + return 0; +} + +static int sha1_neon_import(struct shash_desc *desc, const void *in) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + + return 0; +} + +static struct shash_alg alg = { + .digestsize = SHA1_DIGEST_SIZE, + .init = sha1_neon_init, + .update = sha1_neon_update, + .final = sha1_neon_final, + .export = sha1_neon_export, + .import = sha1_neon_import, + .descsize = sizeof(struct sha1_state), + .statesize = sizeof(struct sha1_state), + .base = { + .cra_name = "sha1", + .cra_driver_name = "sha1-neon", + .cra_priority = 250, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int __init sha1_neon_mod_init(void) +{ + if (!cpu_has_neon()) + return -ENODEV; + + return crypto_register_shash(&alg); +} + +static void __exit sha1_neon_mod_fini(void) +{ + crypto_unregister_shash(&alg); +} + +module_init(sha1_neon_mod_init); +module_exit(sha1_neon_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, NEON accelerated"); +MODULE_ALIAS("sha1"); diff --git a/arch/arm/crypto/sha512-armv7-neon.S b/arch/arm/crypto/sha512-armv7-neon.S new file mode 100644 index 000000000000..fe99472e507c --- /dev/null +++ b/arch/arm/crypto/sha512-armv7-neon.S @@ -0,0 +1,455 @@ +/* sha512-armv7-neon.S - ARM/NEON assembly implementation of SHA-512 transform + * + * Copyright © 2013-2014 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * 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. + */ + +#include <linux/linkage.h> + + +.syntax unified +.code 32 +.fpu neon + +.text + +/* structure of SHA512_CONTEXT */ +#define hd_a 0 +#define hd_b ((hd_a) + 8) +#define hd_c ((hd_b) + 8) +#define hd_d ((hd_c) + 8) +#define hd_e ((hd_d) + 8) +#define hd_f ((hd_e) + 8) +#define hd_g ((hd_f) + 8) + +/* register macros */ +#define RK %r2 + +#define RA d0 +#define RB d1 +#define RC d2 +#define RD d3 +#define RE d4 +#define RF d5 +#define RG d6 +#define RH d7 + +#define RT0 d8 +#define RT1 d9 +#define RT2 d10 +#define RT3 d11 +#define RT4 d12 +#define RT5 d13 +#define RT6 d14 +#define RT7 d15 + +#define RT01q q4 +#define RT23q q5 +#define RT45q q6 +#define RT67q q7 + +#define RW0 d16 +#define RW1 d17 +#define RW2 d18 +#define RW3 d19 +#define RW4 d20 +#define RW5 d21 +#define RW6 d22 +#define RW7 d23 +#define RW8 d24 +#define RW9 d25 +#define RW10 d26 +#define RW11 d27 +#define RW12 d28 +#define RW13 d29 +#define RW14 d30 +#define RW15 d31 + +#define RW01q q8 +#define RW23q q9 +#define RW45q q10 +#define RW67q q11 +#define RW89q q12 +#define RW1011q q13 +#define RW1213q q14 +#define RW1415q q15 + +/*********************************************************************** + * ARM assembly implementation of sha512 transform + ***********************************************************************/ +#define rounds2_0_63(ra, rb, rc, rd, re, rf, rg, rh, rw0, rw1, rw01q, rw2, \ + rw23q, rw1415q, rw9, rw10, interleave_op, arg1) \ + /* t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; */ \ + vshr.u64 RT2, re, #14; \ + vshl.u64 RT3, re, #64 - 14; \ + interleave_op(arg1); \ + vshr.u64 RT4, re, #18; \ + vshl.u64 RT5, re, #64 - 18; \ + vld1.64 {RT0}, [RK]!; \ + veor.64 RT23q, RT23q, RT45q; \ + vshr.u64 RT4, re, #41; \ + vshl.u64 RT5, re, #64 - 41; \ + vadd.u64 RT0, RT0, rw0; \ + veor.64 RT23q, RT23q, RT45q; \ + vmov.64 RT7, re; \ + veor.64 RT1, RT2, RT3; \ + vbsl.64 RT7, rf, rg; \ + \ + vadd.u64 RT1, RT1, rh; \ + vshr.u64 RT2, ra, #28; \ + vshl.u64 RT3, ra, #64 - 28; \ + vadd.u64 RT1, RT1, RT0; \ + vshr.u64 RT4, ra, #34; \ + vshl.u64 RT5, ra, #64 - 34; \ + vadd.u64 RT1, RT1, RT7; \ + \ + /* h = Sum0 (a) + Maj (a, b, c); */ \ + veor.64 RT23q, RT23q, RT45q; \ + vshr.u64 RT4, ra, #39; \ + vshl.u64 RT5, ra, #64 - 39; \ + veor.64 RT0, ra, rb; \ + veor.64 RT23q, RT23q, RT45q; \ + vbsl.64 RT0, rc, rb; \ + vadd.u64 rd, rd, RT1; /* d+=t1; */ \ + veor.64 rh, RT2, RT3; \ + \ + /* t1 = g + Sum1 (d) + Ch (d, e, f) + k[t] + w[t]; */ \ + vshr.u64 RT2, rd, #14; \ + vshl.u64 RT3, rd, #64 - 14; \ + vadd.u64 rh, rh, RT0; \ + vshr.u64 RT4, rd, #18; \ + vshl.u64 RT5, rd, #64 - 18; \ + vadd.u64 rh, rh, RT1; /* h+=t1; */ \ + vld1.64 {RT0}, [RK]!; \ + veor.64 RT23q, RT23q, RT45q; \ + vshr.u64 RT4, rd, #41; \ + vshl.u64 RT5, rd, #64 - 41; \ + vadd.u64 RT0, RT0, rw1; \ + veor.64 RT23q, RT23q, RT45q; \ + vmov.64 RT7, rd; \ + veor.64 RT1, RT2, RT3; \ + vbsl.64 RT7, re, rf; \ + \ + vadd.u64 RT1, RT1, rg; \ + vshr.u64 RT2, rh, #28; \ + vshl.u64 RT3, rh, #64 - 28; \ + vadd.u64 RT1, RT1, RT0; \ + vshr.u64 RT4, rh, #34; \ + vshl.u64 RT5, rh, #64 - 34; \ + vadd.u64 RT1, RT1, RT7; \ + \ + /* g = Sum0 (h) + Maj (h, a, b); */ \ + veor.64 RT23q, RT23q, RT45q; \ + vshr.u64 RT4, rh, #39; \ + vshl.u64 RT5, rh, #64 - 39; \ + veor.64 RT0, rh, ra; \ + veor.64 RT23q, RT23q, RT45q; \ + vbsl.64 RT0, rb, ra; \ + vadd.u64 rc, rc, RT1; /* c+=t1; */ \ + veor.64 rg, RT2, RT3; \ + \ + /* w[0] += S1 (w[14]) + w[9] + S0 (w[1]); */ \ + /* w[1] += S1 (w[15]) + w[10] + S0 (w[2]); */ \ + \ + /**** S0(w[1:2]) */ \ + \ + /* w[0:1] += w[9:10] */ \ + /* RT23q = rw1:rw2 */ \ + vext.u64 RT23q, rw01q, rw23q, #1; \ + vadd.u64 rw0, rw9; \ + vadd.u64 rg, rg, RT0; \ + vadd.u64 rw1, rw10;\ + vadd.u64 rg, rg, RT1; /* g+=t1; */ \ + \ + vshr.u64 RT45q, RT23q, #1; \ + vshl.u64 RT67q, RT23q, #64 - 1; \ + vshr.u64 RT01q, RT23q, #8; \ + veor.u64 RT45q, RT45q, RT67q; \ + vshl.u64 RT67q, RT23q, #64 - 8; \ + veor.u64 RT45q, RT45q, RT01q; \ + vshr.u64 RT01q, RT23q, #7; \ + veor.u64 RT45q, RT45q, RT67q; \ + \ + /**** S1(w[14:15]) */ \ + vshr.u64 RT23q, rw1415q, #6; \ + veor.u64 RT01q, RT01q, RT45q; \ + vshr.u64 RT45q, rw1415q, #19; \ + vshl.u64 RT67q, rw1415q, #64 - 19; \ + veor.u64 RT23q, RT23q, RT45q; \ + vshr.u64 RT45q, rw1415q, #61; \ + veor.u64 RT23q, RT23q, RT67q; \ + vshl.u64 RT67q, rw1415q, #64 - 61; \ + veor.u64 RT23q, RT23q, RT45q; \ + vadd.u64 rw01q, RT01q; /* w[0:1] += S(w[1:2]) */ \ + veor.u64 RT01q, RT23q, RT67q; +#define vadd_RT01q(rw01q) \ + /* w[0:1] += S(w[14:15]) */ \ + vadd.u64 rw01q, RT01q; + +#define dummy(_) /*_*/ + +#define rounds2_64_79(ra, rb, rc, rd, re, rf, rg, rh, rw0, rw1, \ + interleave_op1, arg1, interleave_op2, arg2) \ + /* t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; */ \ + vshr.u64 RT2, re, #14; \ + vshl.u64 RT3, re, #64 - 14; \ + interleave_op1(arg1); \ + vshr.u64 RT4, re, #18; \ + vshl.u64 RT5, re, #64 - 18; \ + interleave_op2(arg2); \ + vld1.64 {RT0}, [RK]!; \ + veor.64 RT23q, RT23q, RT45q; \ + vshr.u64 RT4, re, #41; \ + vshl.u64 RT5, re, #64 - 41; \ + vadd.u64 RT0, RT0, rw0; \ + veor.64 RT23q, RT23q, RT45q; \ + vmov.64 RT7, re; \ + veor.64 RT1, RT2, RT3; \ + vbsl.64 RT7, rf, rg; \ + \ + vadd.u64 RT1, RT1, rh; \ + vshr.u64 RT2, ra, #28; \ + vshl.u64 RT3, ra, #64 - 28; \ + vadd.u64 RT1, RT1, RT0; \ + vshr.u64 RT4, ra, #34; \ + vshl.u64 RT5, ra, #64 - 34; \ + vadd.u64 RT1, RT1, RT7; \ + \ + /* h = Sum0 (a) + Maj (a, b, c); */ \ + veor.64 RT23q, RT23q, RT45q; \ + vshr.u64 RT4, ra, #39; \ + vshl.u64 RT5, ra, #64 - 39; \ + veor.64 RT0, ra, rb; \ + veor.64 RT23q, RT23q, RT45q; \ + vbsl.64 RT0, rc, rb; \ + vadd.u64 rd, rd, RT1; /* d+=t1; */ \ + veor.64 rh, RT2, RT3; \ + \ + /* t1 = g + Sum1 (d) + Ch (d, e, f) + k[t] + w[t]; */ \ + vshr.u64 RT2, rd, #14; \ + vshl.u64 RT3, rd, #64 - 14; \ + vadd.u64 rh, rh, RT0; \ + vshr.u64 RT4, rd, #18; \ + vshl.u64 RT5, rd, #64 - 18; \ + vadd.u64 rh, rh, RT1; /* h+=t1; */ \ + vld1.64 {RT0}, [RK]!; \ + veor.64 RT23q, RT23q, RT45q; \ + vshr.u64 RT4, rd, #41; \ + vshl.u64 RT5, rd, #64 - 41; \ + vadd.u64 RT0, RT0, rw1; \ + veor.64 RT23q, RT23q, RT45q; \ + vmov.64 RT7, rd; \ + veor.64 RT1, RT2, RT3; \ + vbsl.64 RT7, re, rf; \ + \ + vadd.u64 RT1, RT1, rg; \ + vshr.u64 RT2, rh, #28; \ + vshl.u64 RT3, rh, #64 - 28; \ + vadd.u64 RT1, RT1, RT0; \ + vshr.u64 RT4, rh, #34; \ + vshl.u64 RT5, rh, #64 - 34; \ + vadd.u64 RT1, RT1, RT7; \ + \ + /* g = Sum0 (h) + Maj (h, a, b); */ \ + veor.64 RT23q, RT23q, RT45q; \ + vshr.u64 RT4, rh, #39; \ + vshl.u64 RT5, rh, #64 - 39; \ + veor.64 RT0, rh, ra; \ + veor.64 RT23q, RT23q, RT45q; \ + vbsl.64 RT0, rb, ra; \ + vadd.u64 rc, rc, RT1; /* c+=t1; */ \ + veor.64 rg, RT2, RT3; +#define vadd_rg_RT0(rg) \ + vadd.u64 rg, rg, RT0; +#define vadd_rg_RT1(rg) \ + vadd.u64 rg, rg, RT1; /* g+=t1; */ + +.align 3 +ENTRY(sha512_transform_neon) + /* Input: + * %r0: SHA512_CONTEXT + * %r1: data + * %r2: u64 k[] constants + * %r3: nblks + */ + push {%lr}; + + mov %lr, #0; + + /* Load context to d0-d7 */ + vld1.64 {RA-RD}, [%r0]!; + vld1.64 {RE-RH}, [%r0]; + sub %r0, #(4*8); + + /* Load input to w[16], d16-d31 */ + /* NOTE: Assumes that on ARMv7 unaligned accesses are always allowed. */ + vld1.64 {RW0-RW3}, [%r1]!; + vld1.64 {RW4-RW7}, [%r1]!; + vld1.64 {RW8-RW11}, [%r1]!; + vld1.64 {RW12-RW15}, [%r1]!; +#ifdef __ARMEL__ + /* byteswap */ + vrev64.8 RW01q, RW01q; + vrev64.8 RW23q, RW23q; + vrev64.8 RW45q, RW45q; + vrev64.8 RW67q, RW67q; + vrev64.8 RW89q, RW89q; + vrev64.8 RW1011q, RW1011q; + vrev64.8 RW1213q, RW1213q; + vrev64.8 RW1415q, RW1415q; +#endif + + /* EABI says that d8-d15 must be preserved by callee. */ + /*vpush {RT0-RT7};*/ + +.Loop: + rounds2_0_63(RA, RB, RC, RD, RE, RF, RG, RH, RW0, RW1, RW01q, RW2, + RW23q, RW1415q, RW9, RW10, dummy, _); + b .Lenter_rounds; + +.Loop_rounds: + rounds2_0_63(RA, RB, RC, RD, RE, RF, RG, RH, RW0, RW1, RW01q, RW2, + RW23q, RW1415q, RW9, RW10, vadd_RT01q, RW1415q); +.Lenter_rounds: + rounds2_0_63(RG, RH, RA, RB, RC, RD, RE, RF, RW2, RW3, RW23q, RW4, + RW45q, RW01q, RW11, RW12, vadd_RT01q, RW01q); + rounds2_0_63(RE, RF, RG, RH, RA, RB, RC, RD, RW4, RW5, RW45q, RW6, + RW67q, RW23q, RW13, RW14, vadd_RT01q, RW23q); + rounds2_0_63(RC, RD, RE, RF, RG, RH, RA, RB, RW6, RW7, RW67q, RW8, + RW89q, RW45q, RW15, RW0, vadd_RT01q, RW45q); + rounds2_0_63(RA, RB, RC, RD, RE, RF, RG, RH, RW8, RW9, RW89q, RW10, + RW1011q, RW67q, RW1, RW2, vadd_RT01q, RW67q); + rounds2_0_63(RG, RH, RA, RB, RC, RD, RE, RF, RW10, RW11, RW1011q, RW12, + RW1213q, RW89q, RW3, RW4, vadd_RT01q, RW89q); + add %lr, #16; + rounds2_0_63(RE, RF, RG, RH, RA, RB, RC, RD, RW12, RW13, RW1213q, RW14, + RW1415q, RW1011q, RW5, RW6, vadd_RT01q, RW1011q); + cmp %lr, #64; + rounds2_0_63(RC, RD, RE, RF, RG, RH, RA, RB, RW14, RW15, RW1415q, RW0, + RW01q, RW1213q, RW7, RW8, vadd_RT01q, RW1213q); + bne .Loop_rounds; + + subs %r3, #1; + + rounds2_64_79(RA, RB, RC, RD, RE, RF, RG, RH, RW0, RW1, + vadd_RT01q, RW1415q, dummy, _); + rounds2_64_79(RG, RH, RA, RB, RC, RD, RE, RF, RW2, RW3, + vadd_rg_RT0, RG, vadd_rg_RT1, RG); + beq .Lhandle_tail; + vld1.64 {RW0-RW3}, [%r1]!; + rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW4, RW5, + vadd_rg_RT0, RE, vadd_rg_RT1, RE); + rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW6, RW7, + vadd_rg_RT0, RC, vadd_rg_RT1, RC); +#ifdef __ARMEL__ + vrev64.8 RW01q, RW01q; + vrev64.8 RW23q, RW23q; +#endif + vld1.64 {RW4-RW7}, [%r1]!; + rounds2_64_79(RA, RB, RC, RD, RE, RF, RG, RH, RW8, RW9, + vadd_rg_RT0, RA, vadd_rg_RT1, RA); + rounds2_64_79(RG, RH, RA, RB, RC, RD, RE, RF, RW10, RW11, + vadd_rg_RT0, RG, vadd_rg_RT1, RG); +#ifdef __ARMEL__ + vrev64.8 RW45q, RW45q; + vrev64.8 RW67q, RW67q; +#endif + vld1.64 {RW8-RW11}, [%r1]!; + rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW12, RW13, + vadd_rg_RT0, RE, vadd_rg_RT1, RE); + rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW14, RW15, + vadd_rg_RT0, RC, vadd_rg_RT1, RC); +#ifdef __ARMEL__ + vrev64.8 RW89q, RW89q; + vrev64.8 RW1011q, RW1011q; +#endif + vld1.64 {RW12-RW15}, [%r1]!; + vadd_rg_RT0(RA); + vadd_rg_RT1(RA); + + /* Load context */ + vld1.64 {RT0-RT3}, [%r0]!; + vld1.64 {RT4-RT7}, [%r0]; + sub %r0, #(4*8); + +#ifdef __ARMEL__ + vrev64.8 RW1213q, RW1213q; + vrev64.8 RW1415q, RW1415q; +#endif + + vadd.u64 RA, RT0; + vadd.u64 RB, RT1; + vadd.u64 RC, RT2; + vadd.u64 RD, RT3; + vadd.u64 RE, RT4; + vadd.u64 RF, RT5; + vadd.u64 RG, RT6; + vadd.u64 RH, RT7; + + /* Store the first half of context */ + vst1.64 {RA-RD}, [%r0]!; + sub RK, $(8*80); + vst1.64 {RE-RH}, [%r0]; /* Store the last half of context */ + mov %lr, #0; + sub %r0, #(4*8); + + b .Loop; + +.Lhandle_tail: + rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW4, RW5, + vadd_rg_RT0, RE, vadd_rg_RT1, RE); + rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW6, RW7, + vadd_rg_RT0, RC, vadd_rg_RT1, RC); + rounds2_64_79(RA, RB, RC, RD, RE, RF, RG, RH, RW8, RW9, + vadd_rg_RT0, RA, vadd_rg_RT1, RA); + rounds2_64_79(RG, RH, RA, RB, RC, RD, RE, RF, RW10, RW11, + vadd_rg_RT0, RG, vadd_rg_RT1, RG); + rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW12, RW13, + vadd_rg_RT0, RE, vadd_rg_RT1, RE); + rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW14, RW15, + vadd_rg_RT0, RC, vadd_rg_RT1, RC); + + /* Load context to d16-d23 */ + vld1.64 {RW0-RW3}, [%r0]!; + vadd_rg_RT0(RA); + vld1.64 {RW4-RW7}, [%r0]; + vadd_rg_RT1(RA); + sub %r0, #(4*8); + + vadd.u64 RA, RW0; + vadd.u64 RB, RW1; + vadd.u64 RC, RW2; + vadd.u64 RD, RW3; + vadd.u64 RE, RW4; + vadd.u64 RF, RW5; + vadd.u64 RG, RW6; + vadd.u64 RH, RW7; + + /* Store the first half of context */ + vst1.64 {RA-RD}, [%r0]!; + + /* Clear used registers */ + /* d16-d31 */ + veor.u64 RW01q, RW01q; + veor.u64 RW23q, RW23q; + veor.u64 RW45q, RW45q; + veor.u64 RW67q, RW67q; + vst1.64 {RE-RH}, [%r0]; /* Store the last half of context */ + veor.u64 RW89q, RW89q; + veor.u64 RW1011q, RW1011q; + veor.u64 RW1213q, RW1213q; + veor.u64 RW1415q, RW1415q; + /* d8-d15 */ + /*vpop {RT0-RT7};*/ + /* d0-d7 (q0-q3) */ + veor.u64 %q0, %q0; + veor.u64 %q1, %q1; + veor.u64 %q2, %q2; + veor.u64 %q3, %q3; + + pop {%pc}; +ENDPROC(sha512_transform_neon) diff --git a/arch/arm/crypto/sha512_neon_glue.c b/arch/arm/crypto/sha512_neon_glue.c new file mode 100644 index 000000000000..0d2758ff5e12 --- /dev/null +++ b/arch/arm/crypto/sha512_neon_glue.c @@ -0,0 +1,305 @@ +/* + * Glue code for the SHA512 Secure Hash Algorithm assembly implementation + * using NEON instructions. + * + * Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is based on sha512_ssse3_glue.c: + * Copyright (C) 2013 Intel Corporation + * Author: Tim Chen <tim.c.chen@linux.intel.com> + * + * 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. + * + */ + +#include <crypto/internal/hash.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/cryptohash.h> +#include <linux/types.h> +#include <linux/string.h> +#include <crypto/sha.h> +#include <asm/byteorder.h> +#include <asm/simd.h> +#include <asm/neon.h> + + +static const u64 sha512_k[] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + + +asmlinkage void sha512_transform_neon(u64 *digest, const void *data, + const u64 k[], unsigned int num_blks); + + +static int sha512_neon_init(struct shash_desc *desc) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA512_H0; + sctx->state[1] = SHA512_H1; + sctx->state[2] = SHA512_H2; + sctx->state[3] = SHA512_H3; + sctx->state[4] = SHA512_H4; + sctx->state[5] = SHA512_H5; + sctx->state[6] = SHA512_H6; + sctx->state[7] = SHA512_H7; + sctx->count[0] = sctx->count[1] = 0; + + return 0; +} + +static int __sha512_neon_update(struct shash_desc *desc, const u8 *data, + unsigned int len, unsigned int partial) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + unsigned int done = 0; + + sctx->count[0] += len; + if (sctx->count[0] < len) + sctx->count[1]++; + + if (partial) { + done = SHA512_BLOCK_SIZE - partial; + memcpy(sctx->buf + partial, data, done); + sha512_transform_neon(sctx->state, sctx->buf, sha512_k, 1); + } + + if (len - done >= SHA512_BLOCK_SIZE) { + const unsigned int rounds = (len - done) / SHA512_BLOCK_SIZE; + + sha512_transform_neon(sctx->state, data + done, sha512_k, + rounds); + + done += rounds * SHA512_BLOCK_SIZE; + } + + memcpy(sctx->buf, data + done, len - done); + + return 0; +} + +static int sha512_neon_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE; + int res; + + /* Handle the fast case right here */ + if (partial + len < SHA512_BLOCK_SIZE) { + sctx->count[0] += len; + if (sctx->count[0] < len) + sctx->count[1]++; + memcpy(sctx->buf + partial, data, len); + + return 0; + } + + if (!may_use_simd()) { + res = crypto_sha512_update(desc, data, len); + } else { + kernel_neon_begin(); + res = __sha512_neon_update(desc, data, len, partial); + kernel_neon_end(); + } + + return res; +} + + +/* Add padding and return the message digest. */ +static int sha512_neon_final(struct shash_desc *desc, u8 *out) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + unsigned int i, index, padlen; + __be64 *dst = (__be64 *)out; + __be64 bits[2]; + static const u8 padding[SHA512_BLOCK_SIZE] = { 0x80, }; + + /* save number of bits */ + bits[1] = cpu_to_be64(sctx->count[0] << 3); + bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61); + + /* Pad out to 112 mod 128 and append length */ + index = sctx->count[0] & 0x7f; + padlen = (index < 112) ? (112 - index) : ((128+112) - index); + + if (!may_use_simd()) { + crypto_sha512_update(desc, padding, padlen); + crypto_sha512_update(desc, (const u8 *)&bits, sizeof(bits)); + } else { + kernel_neon_begin(); + /* We need to fill a whole block for __sha512_neon_update() */ + if (padlen <= 112) { + sctx->count[0] += padlen; + if (sctx->count[0] < padlen) + sctx->count[1]++; + memcpy(sctx->buf + index, padding, padlen); + } else { + __sha512_neon_update(desc, padding, padlen, index); + } + __sha512_neon_update(desc, (const u8 *)&bits, + sizeof(bits), 112); + kernel_neon_end(); + } + + /* Store state in digest */ + for (i = 0; i < 8; i++) + dst[i] = cpu_to_be64(sctx->state[i]); + + /* Wipe context */ + memset(sctx, 0, sizeof(*sctx)); + + return 0; +} + +static int sha512_neon_export(struct shash_desc *desc, void *out) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + + return 0; +} + +static int sha512_neon_import(struct shash_desc *desc, const void *in) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + + return 0; +} + +static int sha384_neon_init(struct shash_desc *desc) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA384_H0; + sctx->state[1] = SHA384_H1; + sctx->state[2] = SHA384_H2; + sctx->state[3] = SHA384_H3; + sctx->state[4] = SHA384_H4; + sctx->state[5] = SHA384_H5; + sctx->state[6] = SHA384_H6; + sctx->state[7] = SHA384_H7; + + sctx->count[0] = sctx->count[1] = 0; + + return 0; +} + +static int sha384_neon_final(struct shash_desc *desc, u8 *hash) +{ + u8 D[SHA512_DIGEST_SIZE]; + + sha512_neon_final(desc, D); + + memcpy(hash, D, SHA384_DIGEST_SIZE); + memset(D, 0, SHA512_DIGEST_SIZE); + + return 0; +} + +static struct shash_alg algs[] = { { + .digestsize = SHA512_DIGEST_SIZE, + .init = sha512_neon_init, + .update = sha512_neon_update, + .final = sha512_neon_final, + .export = sha512_neon_export, + .import = sha512_neon_import, + .descsize = sizeof(struct sha512_state), + .statesize = sizeof(struct sha512_state), + .base = { + .cra_name = "sha512", + .cra_driver_name = "sha512-neon", + .cra_priority = 250, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA512_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}, { + .digestsize = SHA384_DIGEST_SIZE, + .init = sha384_neon_init, + .update = sha512_neon_update, + .final = sha384_neon_final, + .export = sha512_neon_export, + .import = sha512_neon_import, + .descsize = sizeof(struct sha512_state), + .statesize = sizeof(struct sha512_state), + .base = { + .cra_name = "sha384", + .cra_driver_name = "sha384-neon", + .cra_priority = 250, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA384_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +} }; + +static int __init sha512_neon_mod_init(void) +{ + if (!cpu_has_neon()) + return -ENODEV; + + return crypto_register_shashes(algs, ARRAY_SIZE(algs)); +} + +static void __exit sha512_neon_mod_fini(void) +{ + crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); +} + +module_init(sha512_neon_mod_init); +module_exit(sha512_neon_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA512 Secure Hash Algorithm, NEON accelerated"); + +MODULE_ALIAS("sha512"); +MODULE_ALIAS("sha384"); diff --git a/arch/arm/include/asm/crypto/sha1.h b/arch/arm/include/asm/crypto/sha1.h new file mode 100644 index 000000000000..75e6a417416b --- /dev/null +++ b/arch/arm/include/asm/crypto/sha1.h @@ -0,0 +1,10 @@ +#ifndef ASM_ARM_CRYPTO_SHA1_H +#define ASM_ARM_CRYPTO_SHA1_H + +#include <linux/crypto.h> +#include <crypto/sha.h> + +extern int sha1_update_arm(struct shash_desc *desc, const u8 *data, + unsigned int len); + +#endif diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h index 73ddd7239b33..ed805f1d3785 100644 --- a/arch/arm/include/asm/syscall.h +++ b/arch/arm/include/asm/syscall.h @@ -103,8 +103,7 @@ static inline void syscall_set_arguments(struct task_struct *task, memcpy(®s->ARM_r0 + i, args, n * sizeof(args[0])); } -static inline int syscall_get_arch(struct task_struct *task, - struct pt_regs *regs) +static inline int syscall_get_arch(void) { /* ARM tasks don't change audit architectures on the fly. */ return AUDIT_ARCH_ARM; diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h index c3776331f407..6e104d9f103a 100644 --- a/arch/arm/include/uapi/asm/unistd.h +++ b/arch/arm/include/uapi/asm/unistd.h @@ -408,6 +408,10 @@ #define __NR_finit_module (__NR_SYSCALL_BASE+379) #define __NR_sched_setattr (__NR_SYSCALL_BASE+380) #define __NR_sched_getattr (__NR_SYSCALL_BASE+381) +/* Reserve for later +#define __NR_renameat2 (__NR_SYSCALL_BASE+382) +*/ +#define __NR_seccomp (__NR_SYSCALL_BASE+383) /* * The following SWIs are ARM private. diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 166e945de832..b75c9688b343 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -391,6 +391,9 @@ CALL(sys_finit_module) /* 380 */ CALL(sys_sched_setattr) CALL(sys_sched_getattr) + CALL(sys_ni_syscall) /* reserved sys_renameat2 */ + CALL(sys_seccomp) + #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 0dd3b79b15c3..0c27ed6f3f23 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -908,7 +908,7 @@ enum ptrace_syscall_dir { PTRACE_SYSCALL_EXIT, }; -static int tracehook_report_syscall(struct pt_regs *regs, +static void tracehook_report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir) { unsigned long ip; @@ -926,7 +926,6 @@ static int tracehook_report_syscall(struct pt_regs *regs, current_thread_info()->syscall = -1; regs->ARM_ip = ip; - return current_thread_info()->syscall; } asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) @@ -938,7 +937,9 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) return -1; if (test_thread_flag(TIF_SYSCALL_TRACE)) - scno = tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); + tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); + + scno = current_thread_info()->syscall; if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_enter(regs, scno); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 372eb823e92f..9c26826df30b 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -12,6 +12,7 @@ config ARM64 select ARM_ARCH_TIMER select ARM_GIC select ARM_GIC_V3 + select AUDIT_ARCH_COMPAT_GENERIC select BUILDTIME_EXTABLE_SORT select CLONE_BACKWARDS select COMMON_CLK @@ -30,8 +31,10 @@ config ARM64 select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select HARDIRQS_SW_RESEND + select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_KGDB + select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_C_RECORDMCOUNT select HAVE_DEBUG_BUGVERBOSE @@ -325,6 +328,31 @@ config HOTPLUG_CPU Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu. +config SWP_EMULATE + bool "Emulate SWP/SWPB instructions" + help + ARMv6 architecture deprecates use of the SWP/SWPB instructions. ARMv8 + oblosetes the use of SWP/SWPB instructions. ARMv7 multiprocessing + extensions introduce the ability to disable these instructions, + triggering an undefined instruction exception when executed. Say Y + here to enable software emulation of these instructions for userspace + (not kernel) using LDREX/STREX. Also creates /proc/cpu/swp_emulation + for statistics. + + In some older versions of glibc [<=2.8] SWP is used during futex + trylock() operations with the assumption that the code will not + be preempted. This invalid assumption may be more likely to fail + with SWP emulation enabled, leading to deadlock of the user + application. + + NOTE: when accessing uncached shared regions, LDREX/STREX rely + on an external transaction monitoring block called a global + monitor to maintain update atomicity. If your system does not + implement a global monitor, this option can cause programs that + perform SWP operations to uncached memory to deadlock. + + If unsure, say Y. + source kernel/Kconfig.preempt config HZ @@ -355,6 +383,27 @@ config HW_PERF_EVENTS Enable hardware performance counter support for perf events. If disabled, perf events will use software events only. +config ARMV7_COMPAT + bool "Kernel support for ARMv7 applications" + depends on COMPAT + select SWP_EMULATE + help + This option enables features that allow that ran on an ARMv7 or older + processor to continue functioning. + + If you want to execute ARMv7 applications, say Y + +config ARMV7_COMPAT_CPUINFO + bool "Report backwards compatible cpu features in /proc/cpuinfo" + depends on ARMV7_COMPAT + default y + help + This option makes /proc/cpuinfo list CPU features that an ARMv7 or + earlier kernel would report, but are not optional on an ARMv8 or later + processor. + + If you want to execute ARMv7 applications, say Y + config SYS_SUPPORTS_HUGETLBFS def_bool y @@ -385,6 +434,19 @@ config FORCE_MAX_ZONEORDER default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE) default "11" +config SECCOMP + bool "Enable seccomp to safely compute untrusted bytecode" + ---help--- + This kernel feature is useful for number crunching applications + that may need to compute untrusted bytecode during their + execution. By using pipes or other transports made available to + the process as file descriptors supporting the read/write + syscalls, it's possible to isolate those applications in + their own address space using seccomp. Once seccomp is + enabled via prctl(PR_SET_SECCOMP), it cannot be disabled + and the task is only allowed to execute a few safe syscalls + defined by each seccomp mode. + endmenu menu "Boot options" @@ -397,6 +459,23 @@ config CMDLINE entering them here. As a minimum, you should specify the the root device (e.g. root=/dev/nfs). +choice + prompt "Kernel command line type" if CMDLINE != "" + default CMDLINE_FROM_BOOTLOADER + +config CMDLINE_FROM_BOOTLOADER + bool "Use bootloader kernel arguments if available" + help + Uses the command-line options passed by the boot loader. If + the boot loader doesn't provide any, the default kernel command + string provided in CMDLINE will be used. + +config CMDLINE_EXTEND + bool "Extend bootloader kernel arguments" + help + The command-line arguments provided by the boot loader will be + appended to the default kernel command string. + config CMDLINE_FORCE bool "Always use the default kernel command string" help @@ -404,6 +483,22 @@ config CMDLINE_FORCE loader passes other arguments to the kernel. This is useful if you cannot or don't want to change the command-line options your boot loader passes to the kernel. +endchoice + +config BUILD_ARM64_APPENDED_DTB_IMAGE + bool "Build a concatenated Image.gz/dtb by default" + depends on OF + help + Enabling this option will cause a concatenated Image.gz and list of + DTBs to be built by default (instead of a standalone Image.gz.) + The image will built in arch/arm64/boot/Image.gz-dtb + +config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES + string "Default dtb names" + depends on BUILD_ARM64_APPENDED_DTB_IMAGE + help + Space separated list of names of dtbs to append when + building a concatenated Image.gz-dtb. endmenu diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 8185a913c5ed..88975057c6c6 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -20,6 +20,7 @@ LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) KBUILD_DEFCONFIG := defconfig KBUILD_CFLAGS += -mgeneral-regs-only +KBUILD_CFLAGS += -fno-pic ifeq ($(CONFIG_CPU_BIG_ENDIAN), y) KBUILD_CPPFLAGS += -mbig-endian AS += -EB @@ -50,7 +51,12 @@ libs-y := arch/arm64/lib/ $(libs-y) libs-y += $(LIBGCC) # Default target when executing plain make +ifeq ($(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE),y) +KBUILD_IMAGE := Image.gz-dtb +else KBUILD_IMAGE := Image.gz +endif + KBUILD_DTBS := dtbs all: $(KBUILD_IMAGE) $(KBUILD_DTBS) @@ -69,6 +75,9 @@ zinstall install: vmlinux dtbs: scripts $(Q)$(MAKE) $(build)=$(boot)/dts dtbs +Image.gz-dtb: vmlinux scripts dtbs + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + PHONY += vdso_install vdso_install: $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@ diff --git a/arch/arm64/boot/.gitignore b/arch/arm64/boot/.gitignore index 8dab0bb6ae66..eb3551131b1e 100644 --- a/arch/arm64/boot/.gitignore +++ b/arch/arm64/boot/.gitignore @@ -1,2 +1,3 @@ Image Image.gz +Image.gz-dtb diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index 5a0e3ab854a5..df519849fa00 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -14,14 +14,27 @@ # Based on the ia64 boot/Makefile. # +include $(srctree)/arch/arm64/boot/dts/Makefile + targets := Image Image.gz +DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES)) +ifneq ($(DTB_NAMES),) +DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) +else +DTB_LIST := $(dtb-y) +endif +DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST)) + $(obj)/Image: vmlinux FORCE $(call if_changed,objcopy) $(obj)/Image.gz: $(obj)/Image FORCE $(call if_changed,gzip) +$(obj)/Image.gz-dtb: $(obj)/Image.gz $(DTB_OBJS) FORCE + $(call if_changed,cat) + install: $(obj)/Image $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ $(obj)/Image System.map "$(INSTALL_PATH)" diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index 3391691a85f1..49d0a64c53e7 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -4,8 +4,15 @@ dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb targets += dtbs -targets += $(dtb-y) -dtbs: $(addprefix $(obj)/, $(dtb-y)) +DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES)) +ifneq ($(DTB_NAMES),) +DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) +else +DTB_LIST := $(dtb-y) +endif +targets += $(DTB_LIST) -clean-files := *.dtb +dtbs: $(addprefix $(obj)/, $(DTB_LIST)) + +clean-files := dts/*.dtb *.dtb diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index 2070a56ecc46..a3f935fde975 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -35,4 +35,4 @@ AFLAGS_aes-neon.o := -DINTERLEAVE=4 CFLAGS_aes-glue-ce.o := -DUSE_V8_CRYPTO_EXTENSIONS $(obj)/aes-glue-%.o: $(src)/aes-glue.c FORCE - $(call if_changed_dep,cc_o_c) + $(call if_changed_rule,cc_o_c) diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c index 60f2f4c12256..79cd911ef88c 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c @@ -106,7 +106,7 @@ static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { aes_ecb_encrypt(walk.dst.virt.addr, walk.src.virt.addr, (u8 *)ctx->key_enc, rounds, blocks, first); - err = blkcipher_walk_done(desc, &walk, 0); + err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE); } kernel_neon_end(); return err; @@ -128,7 +128,7 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { aes_ecb_decrypt(walk.dst.virt.addr, walk.src.virt.addr, (u8 *)ctx->key_dec, rounds, blocks, first); - err = blkcipher_walk_done(desc, &walk, 0); + err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE); } kernel_neon_end(); return err; @@ -151,7 +151,7 @@ static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, (u8 *)ctx->key_enc, rounds, blocks, walk.iv, first); - err = blkcipher_walk_done(desc, &walk, 0); + err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE); } kernel_neon_end(); return err; @@ -174,7 +174,7 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, (u8 *)ctx->key_dec, rounds, blocks, walk.iv, first); - err = blkcipher_walk_done(desc, &walk, 0); + err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE); } kernel_neon_end(); return err; @@ -243,7 +243,7 @@ static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, aes_xts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, (u8 *)ctx->key1.key_enc, rounds, blocks, (u8 *)ctx->key2.key_enc, walk.iv, first); - err = blkcipher_walk_done(desc, &walk, 0); + err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE); } kernel_neon_end(); @@ -267,7 +267,7 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, (u8 *)ctx->key1.key_dec, rounds, blocks, (u8 *)ctx->key2.key_enc, walk.iv, first); - err = blkcipher_walk_done(desc, &walk, 0); + err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE); } kernel_neon_end(); diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index 56de5aadede2..e94e8dde78b4 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -205,6 +205,13 @@ typedef struct compat_siginfo { compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */ int _fd; } _sigpoll; + + /* SIGSYS */ + struct { + compat_uptr_t _call_addr; /* calling user insn */ + int _syscall; /* triggering system call number */ + unsigned int _arch; /* AUDIT_ARCH_* of syscall */ + } _sigsys; } _sifields; } compat_siginfo_t; diff --git a/arch/arm64/include/asm/opcodes.h b/arch/arm64/include/asm/opcodes.h new file mode 100644 index 000000000000..fd189a522aee --- /dev/null +++ b/arch/arm64/include/asm/opcodes.h @@ -0,0 +1,231 @@ +/* + * Copied from arch/arm/include/asm/opcodes.h + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARM_OPCODES_H +#define __ASM_ARM_OPCODES_H + +#ifndef __ASSEMBLY__ +#include <linux/linkage.h> +extern asmlinkage unsigned int arm_check_condition(u32 opcode, u64 psr); +#endif + +#define ARM_OPCODE_CONDTEST_FAIL 0 +#define ARM_OPCODE_CONDTEST_PASS 1 +#define ARM_OPCODE_CONDTEST_UNCOND 2 + + +/* + * Assembler opcode byteswap helpers. + * These are only intended for use by this header: don't use them directly, + * because they will be suboptimal in most cases. + */ +#define ___asm_opcode_swab32(x) ( \ + (((x) << 24) & 0xFF000000) \ + | (((x) << 8) & 0x00FF0000) \ + | (((x) >> 8) & 0x0000FF00) \ + | (((x) >> 24) & 0x000000FF) \ +) +#define ___asm_opcode_swab16(x) ( \ + (((x) << 8) & 0xFF00) \ + | (((x) >> 8) & 0x00FF) \ +) +#define ___asm_opcode_swahb32(x) ( \ + (((x) << 8) & 0xFF00FF00) \ + | (((x) >> 8) & 0x00FF00FF) \ +) +#define ___asm_opcode_swahw32(x) ( \ + (((x) << 16) & 0xFFFF0000) \ + | (((x) >> 16) & 0x0000FFFF) \ +) +#define ___asm_opcode_identity32(x) ((x) & 0xFFFFFFFF) +#define ___asm_opcode_identity16(x) ((x) & 0xFFFF) + + +/* + * Opcode byteswap helpers + * + * These macros help with converting instructions between a canonical integer + * format and in-memory representation, in an endianness-agnostic manner. + * + * __mem_to_opcode_*() convert from in-memory representation to canonical form. + * __opcode_to_mem_*() convert from canonical form to in-memory representation. + * + * + * Canonical instruction representation: + * + * ARM: 0xKKLLMMNN + * Thumb 16-bit: 0x0000KKLL, where KK < 0xE8 + * Thumb 32-bit: 0xKKLLMMNN, where KK >= 0xE8 + * + * There is no way to distinguish an ARM instruction in canonical representation + * from a Thumb instruction (just as these cannot be distinguished in memory). + * Where this distinction is important, it needs to be tracked separately. + * + * Note that values in the range 0x0000E800..0xE7FFFFFF intentionally do not + * represent any valid Thumb-2 instruction. For this range, + * __opcode_is_thumb32() and __opcode_is_thumb16() will both be false. + * + * The ___asm variants are intended only for use by this header, in situations + * involving inline assembler. For .S files, the normal __opcode_*() macros + * should do the right thing. + */ +#ifdef __ASSEMBLY__ + +#define ___opcode_swab32(x) ___asm_opcode_swab32(x) +#define ___opcode_swab16(x) ___asm_opcode_swab16(x) +#define ___opcode_swahb32(x) ___asm_opcode_swahb32(x) +#define ___opcode_swahw32(x) ___asm_opcode_swahw32(x) +#define ___opcode_identity32(x) ___asm_opcode_identity32(x) +#define ___opcode_identity16(x) ___asm_opcode_identity16(x) + +#else /* ! __ASSEMBLY__ */ + +#include <linux/types.h> +#include <linux/swab.h> + +#define ___opcode_swab32(x) swab32(x) +#define ___opcode_swab16(x) swab16(x) +#define ___opcode_swahb32(x) swahb32(x) +#define ___opcode_swahw32(x) swahw32(x) +#define ___opcode_identity32(x) ((u32)(x)) +#define ___opcode_identity16(x) ((u16)(x)) + +#endif /* ! __ASSEMBLY__ */ + + +#ifdef CONFIG_CPU_ENDIAN_BE8 + +#define __opcode_to_mem_arm(x) ___opcode_swab32(x) +#define __opcode_to_mem_thumb16(x) ___opcode_swab16(x) +#define __opcode_to_mem_thumb32(x) ___opcode_swahb32(x) +#define ___asm_opcode_to_mem_arm(x) ___asm_opcode_swab32(x) +#define ___asm_opcode_to_mem_thumb16(x) ___asm_opcode_swab16(x) +#define ___asm_opcode_to_mem_thumb32(x) ___asm_opcode_swahb32(x) + +#else /* ! CONFIG_CPU_ENDIAN_BE8 */ + +#define __opcode_to_mem_arm(x) ___opcode_identity32(x) +#define __opcode_to_mem_thumb16(x) ___opcode_identity16(x) +#define ___asm_opcode_to_mem_arm(x) ___asm_opcode_identity32(x) +#define ___asm_opcode_to_mem_thumb16(x) ___asm_opcode_identity16(x) +#ifndef CONFIG_CPU_ENDIAN_BE32 +/* + * On BE32 systems, using 32-bit accesses to store Thumb instructions will not + * work in all cases, due to alignment constraints. For now, a correct + * version is not provided for BE32. + */ +#define __opcode_to_mem_thumb32(x) ___opcode_swahw32(x) +#define ___asm_opcode_to_mem_thumb32(x) ___asm_opcode_swahw32(x) +#endif + +#endif /* ! CONFIG_CPU_ENDIAN_BE8 */ + +#define __mem_to_opcode_arm(x) __opcode_to_mem_arm(x) +#define __mem_to_opcode_thumb16(x) __opcode_to_mem_thumb16(x) +#ifndef CONFIG_CPU_ENDIAN_BE32 +#define __mem_to_opcode_thumb32(x) __opcode_to_mem_thumb32(x) +#endif + +/* Operations specific to Thumb opcodes */ + +/* Instruction size checks: */ +#define __opcode_is_thumb32(x) ( \ + ((x) & 0xF8000000) == 0xE8000000 \ + || ((x) & 0xF0000000) == 0xF0000000 \ +) +#define __opcode_is_thumb16(x) ( \ + ((x) & 0xFFFF0000) == 0 \ + && !(((x) & 0xF800) == 0xE800 || ((x) & 0xF000) == 0xF000) \ +) + +/* Operations to construct or split 32-bit Thumb instructions: */ +#define __opcode_thumb32_first(x) (___opcode_identity16((x) >> 16)) +#define __opcode_thumb32_second(x) (___opcode_identity16(x)) +#define __opcode_thumb32_compose(first, second) ( \ + (___opcode_identity32(___opcode_identity16(first)) << 16) \ + | ___opcode_identity32(___opcode_identity16(second)) \ +) +#define ___asm_opcode_thumb32_first(x) (___asm_opcode_identity16((x) >> 16)) +#define ___asm_opcode_thumb32_second(x) (___asm_opcode_identity16(x)) +#define ___asm_opcode_thumb32_compose(first, second) ( \ + (___asm_opcode_identity32(___asm_opcode_identity16(first)) << 16) \ + | ___asm_opcode_identity32(___asm_opcode_identity16(second)) \ +) + +/* + * Opcode injection helpers + * + * In rare cases it is necessary to assemble an opcode which the + * assembler does not support directly, or which would normally be + * rejected because of the CFLAGS or AFLAGS used to build the affected + * file. + * + * Before using these macros, consider carefully whether it is feasible + * instead to change the build flags for your file, or whether it really + * makes sense to support old assembler versions when building that + * particular kernel feature. + * + * The macros defined here should only be used where there is no viable + * alternative. + * + * + * __inst_arm(x): emit the specified ARM opcode + * __inst_thumb16(x): emit the specified 16-bit Thumb opcode + * __inst_thumb32(x): emit the specified 32-bit Thumb opcode + * + * __inst_arm_thumb16(arm, thumb): emit either the specified arm or + * 16-bit Thumb opcode, depending on whether an ARM or Thumb-2 + * kernel is being built + * + * __inst_arm_thumb32(arm, thumb): emit either the specified arm or + * 32-bit Thumb opcode, depending on whether an ARM or Thumb-2 + * kernel is being built + * + * + * Note that using these macros directly is poor practice. Instead, you + * should use them to define human-readable wrapper macros to encode the + * instructions that you care about. In code which might run on ARMv7 or + * above, you can usually use the __inst_arm_thumb{16,32} macros to + * specify the ARM and Thumb alternatives at the same time. This ensures + * that the correct opcode gets emitted depending on the instruction set + * used for the kernel build. + * + * Look at opcodes-virt.h for an example of how to use these macros. + */ +#include <linux/stringify.h> + +#define __inst_arm(x) ___inst_arm(___asm_opcode_to_mem_arm(x)) +#define __inst_thumb32(x) ___inst_thumb32( \ + ___asm_opcode_to_mem_thumb16(___asm_opcode_thumb32_first(x)), \ + ___asm_opcode_to_mem_thumb16(___asm_opcode_thumb32_second(x)) \ +) +#define __inst_thumb16(x) ___inst_thumb16(___asm_opcode_to_mem_thumb16(x)) + +#ifdef CONFIG_THUMB2_KERNEL +#define __inst_arm_thumb16(arm_opcode, thumb_opcode) \ + __inst_thumb16(thumb_opcode) +#define __inst_arm_thumb32(arm_opcode, thumb_opcode) \ + __inst_thumb32(thumb_opcode) +#else +#define __inst_arm_thumb16(arm_opcode, thumb_opcode) __inst_arm(arm_opcode) +#define __inst_arm_thumb32(arm_opcode, thumb_opcode) __inst_arm(arm_opcode) +#endif + +/* Helpers for the helpers. Don't use these directly. */ +#ifdef __ASSEMBLY__ +#define ___inst_arm(x) .long x +#define ___inst_thumb16(x) .short x +#define ___inst_thumb32(first, second) .short first, second +#else +#define ___inst_arm(x) ".long " __stringify(x) "\n\t" +#define ___inst_thumb16(x) ".short " __stringify(x) "\n\t" +#define ___inst_thumb32(first, second) \ + ".short " __stringify(first) ", " __stringify(second) "\n\t" +#endif + +#endif /* __ASM_ARM_OPCODES_H */ diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 45b20cd6cbca..001b764fffa1 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -136,8 +136,8 @@ extern struct task_struct *cpu_switch_to(struct task_struct *prev, #define task_pt_regs(p) \ ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) -#define KSTK_EIP(tsk) task_pt_regs(tsk)->pc -#define KSTK_ESP(tsk) task_pt_regs(tsk)->sp +#define KSTK_EIP(tsk) ((unsigned long)task_pt_regs(tsk)->pc) +#define KSTK_ESP(tsk) user_stack_pointer(task_pt_regs(tsk)) /* * Prefetching support diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index a429b5940be2..c29d88526405 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -61,6 +61,15 @@ #define COMPAT_PT_TEXT_ADDR 0x10000 #define COMPAT_PT_DATA_ADDR 0x10004 #define COMPAT_PT_TEXT_END_ADDR 0x10008 + +/* + * used to skip a system call when tracer changes its number to -1 + * with ptrace(PTRACE_SET_SYSCALL) + */ +#define RET_SKIP_SYSCALL -1 +#define RET_SKIP_SYSCALL_TRACE -2 +#define IS_SKIP_SYSCALL(no) ((int)(no & 0xffffffff) == -1) + #ifndef __ASSEMBLY__ /* sizeof(struct user) for AArch32 */ @@ -133,7 +142,7 @@ struct pt_regs { (!((regs)->pstate & PSR_F_BIT)) #define user_stack_pointer(regs) \ - (!compat_user_mode(regs)) ? ((regs)->sp) : ((regs)->compat_sp) + (!compat_user_mode(regs) ? (regs)->sp : (regs)->compat_sp) static inline unsigned long regs_return_value(struct pt_regs *regs) { @@ -178,5 +187,13 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define profile_pc(regs) instruction_pointer(regs) #endif +/* + * True if instr is a 32-bit thumb instruction. This works if instr + * is the first or only half-word of a thumb instruction. It also works + * when instr holds all 32-bits of a wide thumb instruction if stored + * in the form (first_half<<16)|(second_half) + */ +#define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800) + #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/arm64/include/asm/seccomp.h b/arch/arm64/include/asm/seccomp.h new file mode 100644 index 000000000000..bec3a43f7b17 --- /dev/null +++ b/arch/arm64/include/asm/seccomp.h @@ -0,0 +1,25 @@ +/* + * arch/arm64/include/asm/seccomp.h + * + * Copyright (C) 2014 Linaro Limited + * Author: AKASHI Takahiro <takahiro.akashi <at> linaro.org> + * + * 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 + * published by the Free Software Foundation. + */ +#ifndef _ASM_SECCOMP_H +#define _ASM_SECCOMP_H + +#include <asm/unistd.h> + +#ifdef CONFIG_COMPAT +#define __NR_seccomp_read_32 __NR_compat_read +#define __NR_seccomp_write_32 __NR_compat_write +#define __NR_seccomp_exit_32 __NR_compat_exit +#define __NR_seccomp_sigreturn_32 __NR_compat_rt_sigreturn +#endif /* CONFIG_COMPAT */ + +#include <asm-generic/seccomp.h> + +#endif /* _ASM_SECCOMP_H */ diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h index 383771eb0b87..709a574468f0 100644 --- a/arch/arm64/include/asm/syscall.h +++ b/arch/arm64/include/asm/syscall.h @@ -16,6 +16,8 @@ #ifndef __ASM_SYSCALL_H #define __ASM_SYSCALL_H +#include <uapi/linux/audit.h> +#include <linux/compat.h> #include <linux/err.h> extern const void *sys_call_table[]; @@ -105,4 +107,16 @@ static inline void syscall_set_arguments(struct task_struct *task, memcpy(®s->regs[i], args, n * sizeof(args[0])); } +/* + * We don't care about endianness (__AUDIT_ARCH_LE bit) here because + * AArch64 has the same system calls both on little- and big- endian. + */ +static inline int syscall_get_arch(void) +{ + if (is_compat_task()) + return AUDIT_ARCH_ARM; + + return AUDIT_ARCH_AARCH64; +} + #endif /* __ASM_SYSCALL_H */ diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 8da65c37193d..d609bed26f2e 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -121,11 +121,11 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_NOHZ (1 << TIF_NOHZ) +#define _TIF_FOREIGN_FPSTATE (1 << TIF_FOREIGN_FPSTATE) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) -#define _TIF_FOREIGN_FPSTATE (1 << TIF_FOREIGN_FPSTATE) #define _TIF_32BIT (1 << TIF_32BIT) #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index 10ca8ff93cc2..75f51eadb9eb 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -18,6 +18,19 @@ #ifndef __ASM_TRAP_H #define __ASM_TRAP_H +#include <linux/list.h> + +struct undef_hook { + struct list_head node; + u32 instr_mask; + u32 instr_val; + u32 pstate_mask; + u32 pstate_val; + int (*fn)(struct pt_regs *regs, unsigned int instr); +}; + +void register_undef_hook(struct undef_hook *hook); + static inline int in_exception_text(unsigned long ptr) { extern char __exception_text_start[]; diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index c335479c2638..f67d0ec20f94 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -25,7 +25,27 @@ #define __ARCH_WANT_COMPAT_SYS_SENDFILE #define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_VFORK + +/* + * Compat syscall numbers used by the AArch64 kernel. + */ +#define __NR_compat_restart_syscall 0 +#define __NR_compat_exit 1 +#define __NR_compat_read 3 +#define __NR_compat_write 4 +#define __NR_compat_sigreturn 119 +#define __NR_compat_rt_sigreturn 173 + +/* + * The following SVCs are ARM private. + */ +#define __ARM_NR_COMPAT_BASE 0x0f0000 +#define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2) +#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5) + +#define __NR_compat_syscalls 384 #endif + #define __ARCH_WANT_SYS_CLONE #include <uapi/asm/unistd.h> diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index faa0e1ce59df..76d094565090 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h @@ -21,402 +21,771 @@ #define __SYSCALL(x, y) #endif -__SYSCALL(0, sys_restart_syscall) -__SYSCALL(1, sys_exit) -__SYSCALL(2, sys_fork) -__SYSCALL(3, sys_read) -__SYSCALL(4, sys_write) -__SYSCALL(5, compat_sys_open) -__SYSCALL(6, sys_close) -__SYSCALL(7, sys_ni_syscall) /* 7 was sys_waitpid */ -__SYSCALL(8, sys_creat) -__SYSCALL(9, sys_link) -__SYSCALL(10, sys_unlink) -__SYSCALL(11, compat_sys_execve) -__SYSCALL(12, sys_chdir) -__SYSCALL(13, sys_ni_syscall) /* 13 was sys_time */ -__SYSCALL(14, sys_mknod) -__SYSCALL(15, sys_chmod) -__SYSCALL(16, sys_lchown16) -__SYSCALL(17, sys_ni_syscall) /* 17 was sys_break */ -__SYSCALL(18, sys_ni_syscall) /* 18 was sys_stat */ -__SYSCALL(19, compat_sys_lseek) -__SYSCALL(20, sys_getpid) -__SYSCALL(21, compat_sys_mount) -__SYSCALL(22, sys_ni_syscall) /* 22 was sys_umount */ -__SYSCALL(23, sys_setuid16) -__SYSCALL(24, sys_getuid16) -__SYSCALL(25, sys_ni_syscall) /* 25 was sys_stime */ -__SYSCALL(26, compat_sys_ptrace) -__SYSCALL(27, sys_ni_syscall) /* 27 was sys_alarm */ -__SYSCALL(28, sys_ni_syscall) /* 28 was sys_fstat */ -__SYSCALL(29, sys_pause) -__SYSCALL(30, sys_ni_syscall) /* 30 was sys_utime */ -__SYSCALL(31, sys_ni_syscall) /* 31 was sys_stty */ -__SYSCALL(32, sys_ni_syscall) /* 32 was sys_gtty */ -__SYSCALL(33, sys_access) -__SYSCALL(34, sys_nice) -__SYSCALL(35, sys_ni_syscall) /* 35 was sys_ftime */ -__SYSCALL(36, sys_sync) -__SYSCALL(37, sys_kill) -__SYSCALL(38, sys_rename) -__SYSCALL(39, sys_mkdir) -__SYSCALL(40, sys_rmdir) -__SYSCALL(41, sys_dup) -__SYSCALL(42, sys_pipe) -__SYSCALL(43, compat_sys_times) -__SYSCALL(44, sys_ni_syscall) /* 44 was sys_prof */ -__SYSCALL(45, sys_brk) -__SYSCALL(46, sys_setgid16) -__SYSCALL(47, sys_getgid16) -__SYSCALL(48, sys_ni_syscall) /* 48 was sys_signal */ -__SYSCALL(49, sys_geteuid16) -__SYSCALL(50, sys_getegid16) -__SYSCALL(51, sys_acct) -__SYSCALL(52, sys_umount) -__SYSCALL(53, sys_ni_syscall) /* 53 was sys_lock */ -__SYSCALL(54, compat_sys_ioctl) -__SYSCALL(55, compat_sys_fcntl) -__SYSCALL(56, sys_ni_syscall) /* 56 was sys_mpx */ -__SYSCALL(57, sys_setpgid) -__SYSCALL(58, sys_ni_syscall) /* 58 was sys_ulimit */ -__SYSCALL(59, sys_ni_syscall) /* 59 was sys_olduname */ -__SYSCALL(60, sys_umask) -__SYSCALL(61, sys_chroot) -__SYSCALL(62, compat_sys_ustat) -__SYSCALL(63, sys_dup2) -__SYSCALL(64, sys_getppid) -__SYSCALL(65, sys_getpgrp) -__SYSCALL(66, sys_setsid) -__SYSCALL(67, compat_sys_sigaction) -__SYSCALL(68, sys_ni_syscall) /* 68 was sys_sgetmask */ -__SYSCALL(69, sys_ni_syscall) /* 69 was sys_ssetmask */ -__SYSCALL(70, sys_setreuid16) -__SYSCALL(71, sys_setregid16) -__SYSCALL(72, sys_sigsuspend) -__SYSCALL(73, compat_sys_sigpending) -__SYSCALL(74, sys_sethostname) -__SYSCALL(75, compat_sys_setrlimit) -__SYSCALL(76, sys_ni_syscall) /* 76 was compat_sys_getrlimit */ -__SYSCALL(77, compat_sys_getrusage) -__SYSCALL(78, compat_sys_gettimeofday) -__SYSCALL(79, compat_sys_settimeofday) -__SYSCALL(80, sys_getgroups16) -__SYSCALL(81, sys_setgroups16) -__SYSCALL(82, sys_ni_syscall) /* 82 was compat_sys_select */ -__SYSCALL(83, sys_symlink) -__SYSCALL(84, sys_ni_syscall) /* 84 was sys_lstat */ -__SYSCALL(85, sys_readlink) -__SYSCALL(86, sys_uselib) -__SYSCALL(87, sys_swapon) -__SYSCALL(88, sys_reboot) -__SYSCALL(89, sys_ni_syscall) /* 89 was sys_readdir */ -__SYSCALL(90, sys_ni_syscall) /* 90 was sys_mmap */ -__SYSCALL(91, sys_munmap) -__SYSCALL(92, compat_sys_truncate) -__SYSCALL(93, compat_sys_ftruncate) -__SYSCALL(94, sys_fchmod) -__SYSCALL(95, sys_fchown16) -__SYSCALL(96, sys_getpriority) -__SYSCALL(97, sys_setpriority) -__SYSCALL(98, sys_ni_syscall) /* 98 was sys_profil */ -__SYSCALL(99, compat_sys_statfs) -__SYSCALL(100, compat_sys_fstatfs) -__SYSCALL(101, sys_ni_syscall) /* 101 was sys_ioperm */ -__SYSCALL(102, sys_ni_syscall) /* 102 was sys_socketcall */ -__SYSCALL(103, sys_syslog) -__SYSCALL(104, compat_sys_setitimer) -__SYSCALL(105, compat_sys_getitimer) -__SYSCALL(106, compat_sys_newstat) -__SYSCALL(107, compat_sys_newlstat) -__SYSCALL(108, compat_sys_newfstat) -__SYSCALL(109, sys_ni_syscall) /* 109 was sys_uname */ -__SYSCALL(110, sys_ni_syscall) /* 110 was sys_iopl */ -__SYSCALL(111, sys_vhangup) -__SYSCALL(112, sys_ni_syscall) /* 112 was sys_idle */ -__SYSCALL(113, sys_ni_syscall) /* 113 was sys_syscall */ -__SYSCALL(114, compat_sys_wait4) -__SYSCALL(115, sys_swapoff) -__SYSCALL(116, compat_sys_sysinfo) -__SYSCALL(117, sys_ni_syscall) /* 117 was sys_ipc */ -__SYSCALL(118, sys_fsync) -__SYSCALL(119, compat_sys_sigreturn_wrapper) -__SYSCALL(120, sys_clone) -__SYSCALL(121, sys_setdomainname) -__SYSCALL(122, sys_newuname) -__SYSCALL(123, sys_ni_syscall) /* 123 was sys_modify_ldt */ -__SYSCALL(124, compat_sys_adjtimex) -__SYSCALL(125, sys_mprotect) -__SYSCALL(126, compat_sys_sigprocmask) -__SYSCALL(127, sys_ni_syscall) /* 127 was sys_create_module */ -__SYSCALL(128, sys_init_module) -__SYSCALL(129, sys_delete_module) -__SYSCALL(130, sys_ni_syscall) /* 130 was sys_get_kernel_syms */ -__SYSCALL(131, sys_quotactl) -__SYSCALL(132, sys_getpgid) -__SYSCALL(133, sys_fchdir) -__SYSCALL(134, sys_bdflush) -__SYSCALL(135, sys_sysfs) -__SYSCALL(136, sys_personality) -__SYSCALL(137, sys_ni_syscall) /* 137 was sys_afs_syscall */ -__SYSCALL(138, sys_setfsuid16) -__SYSCALL(139, sys_setfsgid16) -__SYSCALL(140, sys_llseek) -__SYSCALL(141, compat_sys_getdents) -__SYSCALL(142, compat_sys_select) -__SYSCALL(143, sys_flock) -__SYSCALL(144, sys_msync) -__SYSCALL(145, compat_sys_readv) -__SYSCALL(146, compat_sys_writev) -__SYSCALL(147, sys_getsid) -__SYSCALL(148, sys_fdatasync) -__SYSCALL(149, compat_sys_sysctl) -__SYSCALL(150, sys_mlock) -__SYSCALL(151, sys_munlock) -__SYSCALL(152, sys_mlockall) -__SYSCALL(153, sys_munlockall) -__SYSCALL(154, sys_sched_setparam) -__SYSCALL(155, sys_sched_getparam) -__SYSCALL(156, sys_sched_setscheduler) -__SYSCALL(157, sys_sched_getscheduler) -__SYSCALL(158, sys_sched_yield) -__SYSCALL(159, sys_sched_get_priority_max) -__SYSCALL(160, sys_sched_get_priority_min) -__SYSCALL(161, compat_sys_sched_rr_get_interval) -__SYSCALL(162, compat_sys_nanosleep) -__SYSCALL(163, sys_mremap) -__SYSCALL(164, sys_setresuid16) -__SYSCALL(165, sys_getresuid16) -__SYSCALL(166, sys_ni_syscall) /* 166 was sys_vm86 */ -__SYSCALL(167, sys_ni_syscall) /* 167 was sys_query_module */ -__SYSCALL(168, sys_poll) -__SYSCALL(169, sys_ni_syscall) -__SYSCALL(170, sys_setresgid16) -__SYSCALL(171, sys_getresgid16) -__SYSCALL(172, sys_prctl) -__SYSCALL(173, compat_sys_rt_sigreturn_wrapper) -__SYSCALL(174, compat_sys_rt_sigaction) -__SYSCALL(175, compat_sys_rt_sigprocmask) -__SYSCALL(176, compat_sys_rt_sigpending) -__SYSCALL(177, compat_sys_rt_sigtimedwait) -__SYSCALL(178, compat_sys_rt_sigqueueinfo) -__SYSCALL(179, compat_sys_rt_sigsuspend) -__SYSCALL(180, compat_sys_pread64_wrapper) -__SYSCALL(181, compat_sys_pwrite64_wrapper) -__SYSCALL(182, sys_chown16) -__SYSCALL(183, sys_getcwd) -__SYSCALL(184, sys_capget) -__SYSCALL(185, sys_capset) -__SYSCALL(186, compat_sys_sigaltstack) -__SYSCALL(187, compat_sys_sendfile) -__SYSCALL(188, sys_ni_syscall) /* 188 reserved */ -__SYSCALL(189, sys_ni_syscall) /* 189 reserved */ -__SYSCALL(190, sys_vfork) -__SYSCALL(191, compat_sys_getrlimit) /* SuS compliant getrlimit */ -__SYSCALL(192, sys_mmap_pgoff) -__SYSCALL(193, compat_sys_truncate64_wrapper) -__SYSCALL(194, compat_sys_ftruncate64_wrapper) -__SYSCALL(195, sys_stat64) -__SYSCALL(196, sys_lstat64) -__SYSCALL(197, sys_fstat64) -__SYSCALL(198, sys_lchown) -__SYSCALL(199, sys_getuid) -__SYSCALL(200, sys_getgid) -__SYSCALL(201, sys_geteuid) -__SYSCALL(202, sys_getegid) -__SYSCALL(203, sys_setreuid) -__SYSCALL(204, sys_setregid) -__SYSCALL(205, sys_getgroups) -__SYSCALL(206, sys_setgroups) -__SYSCALL(207, sys_fchown) -__SYSCALL(208, sys_setresuid) -__SYSCALL(209, sys_getresuid) -__SYSCALL(210, sys_setresgid) -__SYSCALL(211, sys_getresgid) -__SYSCALL(212, sys_chown) -__SYSCALL(213, sys_setuid) -__SYSCALL(214, sys_setgid) -__SYSCALL(215, sys_setfsuid) -__SYSCALL(216, sys_setfsgid) -__SYSCALL(217, compat_sys_getdents64) -__SYSCALL(218, sys_pivot_root) -__SYSCALL(219, sys_mincore) -__SYSCALL(220, sys_madvise) -__SYSCALL(221, compat_sys_fcntl64) -__SYSCALL(222, sys_ni_syscall) /* 222 for tux */ -__SYSCALL(223, sys_ni_syscall) /* 223 is unused */ -__SYSCALL(224, sys_gettid) -__SYSCALL(225, compat_sys_readahead_wrapper) -__SYSCALL(226, sys_setxattr) -__SYSCALL(227, sys_lsetxattr) -__SYSCALL(228, sys_fsetxattr) -__SYSCALL(229, sys_getxattr) -__SYSCALL(230, sys_lgetxattr) -__SYSCALL(231, sys_fgetxattr) -__SYSCALL(232, sys_listxattr) -__SYSCALL(233, sys_llistxattr) -__SYSCALL(234, sys_flistxattr) -__SYSCALL(235, sys_removexattr) -__SYSCALL(236, sys_lremovexattr) -__SYSCALL(237, sys_fremovexattr) -__SYSCALL(238, sys_tkill) -__SYSCALL(239, sys_sendfile64) -__SYSCALL(240, compat_sys_futex) -__SYSCALL(241, compat_sys_sched_setaffinity) -__SYSCALL(242, compat_sys_sched_getaffinity) -__SYSCALL(243, compat_sys_io_setup) -__SYSCALL(244, sys_io_destroy) -__SYSCALL(245, compat_sys_io_getevents) -__SYSCALL(246, compat_sys_io_submit) -__SYSCALL(247, sys_io_cancel) -__SYSCALL(248, sys_exit_group) -__SYSCALL(249, compat_sys_lookup_dcookie) -__SYSCALL(250, sys_epoll_create) -__SYSCALL(251, sys_epoll_ctl) -__SYSCALL(252, sys_epoll_wait) -__SYSCALL(253, sys_remap_file_pages) -__SYSCALL(254, sys_ni_syscall) /* 254 for set_thread_area */ -__SYSCALL(255, sys_ni_syscall) /* 255 for get_thread_area */ -__SYSCALL(256, sys_set_tid_address) -__SYSCALL(257, compat_sys_timer_create) -__SYSCALL(258, compat_sys_timer_settime) -__SYSCALL(259, compat_sys_timer_gettime) -__SYSCALL(260, sys_timer_getoverrun) -__SYSCALL(261, sys_timer_delete) -__SYSCALL(262, compat_sys_clock_settime) -__SYSCALL(263, compat_sys_clock_gettime) -__SYSCALL(264, compat_sys_clock_getres) -__SYSCALL(265, compat_sys_clock_nanosleep) -__SYSCALL(266, compat_sys_statfs64_wrapper) -__SYSCALL(267, compat_sys_fstatfs64_wrapper) -__SYSCALL(268, sys_tgkill) -__SYSCALL(269, compat_sys_utimes) -__SYSCALL(270, compat_sys_fadvise64_64_wrapper) -__SYSCALL(271, sys_pciconfig_iobase) -__SYSCALL(272, sys_pciconfig_read) -__SYSCALL(273, sys_pciconfig_write) -__SYSCALL(274, compat_sys_mq_open) -__SYSCALL(275, sys_mq_unlink) -__SYSCALL(276, compat_sys_mq_timedsend) -__SYSCALL(277, compat_sys_mq_timedreceive) -__SYSCALL(278, compat_sys_mq_notify) -__SYSCALL(279, compat_sys_mq_getsetattr) -__SYSCALL(280, compat_sys_waitid) -__SYSCALL(281, sys_socket) -__SYSCALL(282, sys_bind) -__SYSCALL(283, sys_connect) -__SYSCALL(284, sys_listen) -__SYSCALL(285, sys_accept) -__SYSCALL(286, sys_getsockname) -__SYSCALL(287, sys_getpeername) -__SYSCALL(288, sys_socketpair) -__SYSCALL(289, sys_send) -__SYSCALL(290, sys_sendto) -__SYSCALL(291, compat_sys_recv) -__SYSCALL(292, compat_sys_recvfrom) -__SYSCALL(293, sys_shutdown) -__SYSCALL(294, compat_sys_setsockopt) -__SYSCALL(295, compat_sys_getsockopt) -__SYSCALL(296, compat_sys_sendmsg) -__SYSCALL(297, compat_sys_recvmsg) -__SYSCALL(298, sys_semop) -__SYSCALL(299, sys_semget) -__SYSCALL(300, compat_sys_semctl) -__SYSCALL(301, compat_sys_msgsnd) -__SYSCALL(302, compat_sys_msgrcv) -__SYSCALL(303, sys_msgget) -__SYSCALL(304, compat_sys_msgctl) -__SYSCALL(305, compat_sys_shmat) -__SYSCALL(306, sys_shmdt) -__SYSCALL(307, sys_shmget) -__SYSCALL(308, compat_sys_shmctl) -__SYSCALL(309, sys_add_key) -__SYSCALL(310, sys_request_key) -__SYSCALL(311, compat_sys_keyctl) -__SYSCALL(312, compat_sys_semtimedop) -__SYSCALL(313, sys_ni_syscall) -__SYSCALL(314, sys_ioprio_set) -__SYSCALL(315, sys_ioprio_get) -__SYSCALL(316, sys_inotify_init) -__SYSCALL(317, sys_inotify_add_watch) -__SYSCALL(318, sys_inotify_rm_watch) -__SYSCALL(319, compat_sys_mbind) -__SYSCALL(320, compat_sys_get_mempolicy) -__SYSCALL(321, compat_sys_set_mempolicy) -__SYSCALL(322, compat_sys_openat) -__SYSCALL(323, sys_mkdirat) -__SYSCALL(324, sys_mknodat) -__SYSCALL(325, sys_fchownat) -__SYSCALL(326, compat_sys_futimesat) -__SYSCALL(327, sys_fstatat64) -__SYSCALL(328, sys_unlinkat) -__SYSCALL(329, sys_renameat) -__SYSCALL(330, sys_linkat) -__SYSCALL(331, sys_symlinkat) -__SYSCALL(332, sys_readlinkat) -__SYSCALL(333, sys_fchmodat) -__SYSCALL(334, sys_faccessat) -__SYSCALL(335, compat_sys_pselect6) -__SYSCALL(336, compat_sys_ppoll) -__SYSCALL(337, sys_unshare) -__SYSCALL(338, compat_sys_set_robust_list) -__SYSCALL(339, compat_sys_get_robust_list) -__SYSCALL(340, sys_splice) -__SYSCALL(341, compat_sys_sync_file_range2_wrapper) -__SYSCALL(342, sys_tee) -__SYSCALL(343, compat_sys_vmsplice) -__SYSCALL(344, compat_sys_move_pages) -__SYSCALL(345, sys_getcpu) -__SYSCALL(346, compat_sys_epoll_pwait) -__SYSCALL(347, compat_sys_kexec_load) -__SYSCALL(348, compat_sys_utimensat) -__SYSCALL(349, compat_sys_signalfd) -__SYSCALL(350, sys_timerfd_create) -__SYSCALL(351, sys_eventfd) -__SYSCALL(352, compat_sys_fallocate_wrapper) -__SYSCALL(353, compat_sys_timerfd_settime) -__SYSCALL(354, compat_sys_timerfd_gettime) -__SYSCALL(355, compat_sys_signalfd4) -__SYSCALL(356, sys_eventfd2) -__SYSCALL(357, sys_epoll_create1) -__SYSCALL(358, sys_dup3) -__SYSCALL(359, sys_pipe2) -__SYSCALL(360, sys_inotify_init1) -__SYSCALL(361, compat_sys_preadv) -__SYSCALL(362, compat_sys_pwritev) -__SYSCALL(363, compat_sys_rt_tgsigqueueinfo) -__SYSCALL(364, sys_perf_event_open) -__SYSCALL(365, compat_sys_recvmmsg) -__SYSCALL(366, sys_accept4) -__SYSCALL(367, sys_fanotify_init) -__SYSCALL(368, compat_sys_fanotify_mark) -__SYSCALL(369, sys_prlimit64) -__SYSCALL(370, sys_name_to_handle_at) -__SYSCALL(371, compat_sys_open_by_handle_at) -__SYSCALL(372, compat_sys_clock_adjtime) -__SYSCALL(373, sys_syncfs) -__SYSCALL(374, compat_sys_sendmmsg) -__SYSCALL(375, sys_setns) -__SYSCALL(376, compat_sys_process_vm_readv) -__SYSCALL(377, compat_sys_process_vm_writev) -__SYSCALL(378, sys_kcmp) -__SYSCALL(379, sys_finit_module) -__SYSCALL(380, sys_sched_setattr) -__SYSCALL(381, sys_sched_getattr) - -#define __NR_compat_syscalls 382 - -/* - * Compat syscall numbers used by the AArch64 kernel. - */ -#define __NR_compat_restart_syscall 0 -#define __NR_compat_sigreturn 119 -#define __NR_compat_rt_sigreturn 173 - - -/* - * The following SVCs are ARM private. - */ -#define __ARM_NR_COMPAT_BASE 0x0f0000 -#define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2) -#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5) +#define __NR_restart_syscall 0 +__SYSCALL(__NR_restart_syscall, sys_restart_syscall) +#define __NR_exit 1 +__SYSCALL(__NR_exit, sys_exit) +#define __NR_fork 2 +__SYSCALL(__NR_fork, sys_fork) +#define __NR_read 3 +__SYSCALL(__NR_read, sys_read) +#define __NR_write 4 +__SYSCALL(__NR_write, sys_write) +#define __NR_open 5 +__SYSCALL(__NR_open, compat_sys_open) +#define __NR_close 6 +__SYSCALL(__NR_close, sys_close) + /* 7 was sys_waitpid */ +__SYSCALL(7, sys_ni_syscall) +#define __NR_creat 8 +__SYSCALL(__NR_creat, sys_creat) +#define __NR_link 9 +__SYSCALL(__NR_link, sys_link) +#define __NR_unlink 10 +__SYSCALL(__NR_unlink, sys_unlink) +#define __NR_execve 11 +__SYSCALL(__NR_execve, compat_sys_execve) +#define __NR_chdir 12 +__SYSCALL(__NR_chdir, sys_chdir) + /* 13 was sys_time */ +__SYSCALL(13, sys_ni_syscall) +#define __NR_mknod 14 +__SYSCALL(__NR_mknod, sys_mknod) +#define __NR_chmod 15 +__SYSCALL(__NR_chmod, sys_chmod) +#define __NR_lchown 16 +__SYSCALL(__NR_lchown, sys_lchown16) + /* 17 was sys_break */ +__SYSCALL(17, sys_ni_syscall) + /* 18 was sys_stat */ +__SYSCALL(18, sys_ni_syscall) +#define __NR_lseek 19 +__SYSCALL(__NR_lseek, compat_sys_lseek) +#define __NR_getpid 20 +__SYSCALL(__NR_getpid, sys_getpid) +#define __NR_mount 21 +__SYSCALL(__NR_mount, compat_sys_mount) + /* 22 was sys_umount */ +__SYSCALL(22, sys_ni_syscall) +#define __NR_setuid 23 +__SYSCALL(__NR_setuid, sys_setuid16) +#define __NR_getuid 24 +__SYSCALL(__NR_getuid, sys_getuid16) + /* 25 was sys_stime */ +__SYSCALL(25, sys_ni_syscall) +#define __NR_ptrace 26 +__SYSCALL(__NR_ptrace, compat_sys_ptrace) + /* 27 was sys_alarm */ +__SYSCALL(27, sys_ni_syscall) + /* 28 was sys_fstat */ +__SYSCALL(28, sys_ni_syscall) +#define __NR_pause 29 +__SYSCALL(__NR_pause, sys_pause) + /* 30 was sys_utime */ +__SYSCALL(30, sys_ni_syscall) + /* 31 was sys_stty */ +__SYSCALL(31, sys_ni_syscall) + /* 32 was sys_gtty */ +__SYSCALL(32, sys_ni_syscall) +#define __NR_access 33 +__SYSCALL(__NR_access, sys_access) +#define __NR_nice 34 +__SYSCALL(__NR_nice, sys_nice) + /* 35 was sys_ftime */ +__SYSCALL(35, sys_ni_syscall) +#define __NR_sync 36 +__SYSCALL(__NR_sync, sys_sync) +#define __NR_kill 37 +__SYSCALL(__NR_kill, sys_kill) +#define __NR_rename 38 +__SYSCALL(__NR_rename, sys_rename) +#define __NR_mkdir 39 +__SYSCALL(__NR_mkdir, sys_mkdir) +#define __NR_rmdir 40 +__SYSCALL(__NR_rmdir, sys_rmdir) +#define __NR_dup 41 +__SYSCALL(__NR_dup, sys_dup) +#define __NR_pipe 42 +__SYSCALL(__NR_pipe, sys_pipe) +#define __NR_times 43 +__SYSCALL(__NR_times, compat_sys_times) + /* 44 was sys_prof */ +__SYSCALL(44, sys_ni_syscall) +#define __NR_brk 45 +__SYSCALL(__NR_brk, sys_brk) +#define __NR_setgid 46 +__SYSCALL(__NR_setgid, sys_setgid16) +#define __NR_getgid 47 +__SYSCALL(__NR_getgid, sys_getgid16) + /* 48 was sys_signal */ +__SYSCALL(48, sys_ni_syscall) +#define __NR_geteuid 49 +__SYSCALL(__NR_geteuid, sys_geteuid16) +#define __NR_getegid 50 +__SYSCALL(__NR_getegid, sys_getegid16) +#define __NR_acct 51 +__SYSCALL(__NR_acct, sys_acct) +#define __NR_umount2 52 +__SYSCALL(__NR_umount2, sys_umount) + /* 53 was sys_lock */ +__SYSCALL(53, sys_ni_syscall) +#define __NR_ioctl 54 +__SYSCALL(__NR_ioctl, compat_sys_ioctl) +#define __NR_fcntl 55 +__SYSCALL(__NR_fcntl, compat_sys_fcntl) + /* 56 was sys_mpx */ +__SYSCALL(56, sys_ni_syscall) +#define __NR_setpgid 57 +__SYSCALL(__NR_setpgid, sys_setpgid) + /* 58 was sys_ulimit */ +__SYSCALL(58, sys_ni_syscall) + /* 59 was sys_olduname */ +__SYSCALL(59, sys_ni_syscall) +#define __NR_umask 60 +__SYSCALL(__NR_umask, sys_umask) +#define __NR_chroot 61 +__SYSCALL(__NR_chroot, sys_chroot) +#define __NR_ustat 62 +__SYSCALL(__NR_ustat, compat_sys_ustat) +#define __NR_dup2 63 +__SYSCALL(__NR_dup2, sys_dup2) +#define __NR_getppid 64 +__SYSCALL(__NR_getppid, sys_getppid) +#define __NR_getpgrp 65 +__SYSCALL(__NR_getpgrp, sys_getpgrp) +#define __NR_setsid 66 +__SYSCALL(__NR_setsid, sys_setsid) +#define __NR_sigaction 67 +__SYSCALL(__NR_sigaction, compat_sys_sigaction) + /* 68 was sys_sgetmask */ +__SYSCALL(68, sys_ni_syscall) + /* 69 was sys_ssetmask */ +__SYSCALL(69, sys_ni_syscall) +#define __NR_setreuid 70 +__SYSCALL(__NR_setreuid, sys_setreuid16) +#define __NR_setregid 71 +__SYSCALL(__NR_setregid, sys_setregid16) +#define __NR_sigsuspend 72 +__SYSCALL(__NR_sigsuspend, sys_sigsuspend) +#define __NR_sigpending 73 +__SYSCALL(__NR_sigpending, compat_sys_sigpending) +#define __NR_sethostname 74 +__SYSCALL(__NR_sethostname, sys_sethostname) +#define __NR_setrlimit 75 +__SYSCALL(__NR_setrlimit, compat_sys_setrlimit) + /* 76 was compat_sys_getrlimit */ +__SYSCALL(76, sys_ni_syscall) +#define __NR_getrusage 77 +__SYSCALL(__NR_getrusage, compat_sys_getrusage) +#define __NR_gettimeofday 78 +__SYSCALL(__NR_gettimeofday, compat_sys_gettimeofday) +#define __NR_settimeofday 79 +__SYSCALL(__NR_settimeofday, compat_sys_settimeofday) +#define __NR_getgroups 80 +__SYSCALL(__NR_getgroups, sys_getgroups16) +#define __NR_setgroups 81 +__SYSCALL(__NR_setgroups, sys_setgroups16) + /* 82 was compat_sys_select */ +__SYSCALL(82, sys_ni_syscall) +#define __NR_symlink 83 +__SYSCALL(__NR_symlink, sys_symlink) + /* 84 was sys_lstat */ +__SYSCALL(84, sys_ni_syscall) +#define __NR_readlink 85 +__SYSCALL(__NR_readlink, sys_readlink) +#define __NR_uselib 86 +__SYSCALL(__NR_uselib, sys_uselib) +#define __NR_swapon 87 +__SYSCALL(__NR_swapon, sys_swapon) +#define __NR_reboot 88 +__SYSCALL(__NR_reboot, sys_reboot) + /* 89 was sys_readdir */ +__SYSCALL(89, sys_ni_syscall) + /* 90 was sys_mmap */ +__SYSCALL(90, sys_ni_syscall) +#define __NR_munmap 91 +__SYSCALL(__NR_munmap, sys_munmap) +#define __NR_truncate 92 +__SYSCALL(__NR_truncate, compat_sys_truncate) +#define __NR_ftruncate 93 +__SYSCALL(__NR_ftruncate, compat_sys_ftruncate) +#define __NR_fchmod 94 +__SYSCALL(__NR_fchmod, sys_fchmod) +#define __NR_fchown 95 +__SYSCALL(__NR_fchown, sys_fchown16) +#define __NR_getpriority 96 +__SYSCALL(__NR_getpriority, sys_getpriority) +#define __NR_setpriority 97 +__SYSCALL(__NR_setpriority, sys_setpriority) + /* 98 was sys_profil */ +__SYSCALL(98, sys_ni_syscall) +#define __NR_statfs 99 +__SYSCALL(__NR_statfs, compat_sys_statfs) +#define __NR_fstatfs 100 +__SYSCALL(__NR_fstatfs, compat_sys_fstatfs) + /* 101 was sys_ioperm */ +__SYSCALL(101, sys_ni_syscall) + /* 102 was sys_socketcall */ +__SYSCALL(102, sys_ni_syscall) +#define __NR_syslog 103 +__SYSCALL(__NR_syslog, sys_syslog) +#define __NR_setitimer 104 +__SYSCALL(__NR_setitimer, compat_sys_setitimer) +#define __NR_getitimer 105 +__SYSCALL(__NR_getitimer, compat_sys_getitimer) +#define __NR_stat 106 +__SYSCALL(__NR_stat, compat_sys_newstat) +#define __NR_lstat 107 +__SYSCALL(__NR_lstat, compat_sys_newlstat) +#define __NR_fstat 108 +__SYSCALL(__NR_fstat, compat_sys_newfstat) + /* 109 was sys_uname */ +__SYSCALL(109, sys_ni_syscall) + /* 110 was sys_iopl */ +__SYSCALL(110, sys_ni_syscall) +#define __NR_vhangup 111 +__SYSCALL(__NR_vhangup, sys_vhangup) + /* 112 was sys_idle */ +__SYSCALL(112, sys_ni_syscall) + /* 113 was sys_syscall */ +__SYSCALL(113, sys_ni_syscall) +#define __NR_wait4 114 +__SYSCALL(__NR_wait4, compat_sys_wait4) +#define __NR_swapoff 115 +__SYSCALL(__NR_swapoff, sys_swapoff) +#define __NR_sysinfo 116 +__SYSCALL(__NR_sysinfo, compat_sys_sysinfo) + /* 117 was sys_ipc */ +__SYSCALL(117, sys_ni_syscall) +#define __NR_fsync 118 +__SYSCALL(__NR_fsync, sys_fsync) +#define __NR_sigreturn 119 +__SYSCALL(__NR_sigreturn, compat_sys_sigreturn_wrapper) +#define __NR_clone 120 +__SYSCALL(__NR_clone, sys_clone) +#define __NR_setdomainname 121 +__SYSCALL(__NR_setdomainname, sys_setdomainname) +#define __NR_uname 122 +__SYSCALL(__NR_uname, sys_newuname) + /* 123 was sys_modify_ldt */ +__SYSCALL(123, sys_ni_syscall) +#define __NR_adjtimex 124 +__SYSCALL(__NR_adjtimex, compat_sys_adjtimex) +#define __NR_mprotect 125 +__SYSCALL(__NR_mprotect, sys_mprotect) +#define __NR_sigprocmask 126 +__SYSCALL(__NR_sigprocmask, compat_sys_sigprocmask) + /* 127 was sys_create_module */ +__SYSCALL(127, sys_ni_syscall) +#define __NR_init_module 128 +__SYSCALL(__NR_init_module, sys_init_module) +#define __NR_delete_module 129 +__SYSCALL(__NR_delete_module, sys_delete_module) + /* 130 was sys_get_kernel_syms */ +__SYSCALL(130, sys_ni_syscall) +#define __NR_quotactl 131 +__SYSCALL(__NR_quotactl, sys_quotactl) +#define __NR_getpgid 132 +__SYSCALL(__NR_getpgid, sys_getpgid) +#define __NR_fchdir 133 +__SYSCALL(__NR_fchdir, sys_fchdir) +#define __NR_bdflush 134 +__SYSCALL(__NR_bdflush, sys_bdflush) +#define __NR_sysfs 135 +__SYSCALL(__NR_sysfs, sys_sysfs) +#define __NR_personality 136 +__SYSCALL(__NR_personality, sys_personality) + /* 137 was sys_afs_syscall */ +__SYSCALL(137, sys_ni_syscall) +#define __NR_setfsuid 138 +__SYSCALL(__NR_setfsuid, sys_setfsuid16) +#define __NR_setfsgid 139 +__SYSCALL(__NR_setfsgid, sys_setfsgid16) +#define __NR__llseek 140 +__SYSCALL(__NR__llseek, sys_llseek) +#define __NR_getdents 141 +__SYSCALL(__NR_getdents, compat_sys_getdents) +#define __NR__newselect 142 +__SYSCALL(__NR__newselect, compat_sys_select) +#define __NR_flock 143 +__SYSCALL(__NR_flock, sys_flock) +#define __NR_msync 144 +__SYSCALL(__NR_msync, sys_msync) +#define __NR_readv 145 +__SYSCALL(__NR_readv, compat_sys_readv) +#define __NR_writev 146 +__SYSCALL(__NR_writev, compat_sys_writev) +#define __NR_getsid 147 +__SYSCALL(__NR_getsid, sys_getsid) +#define __NR_fdatasync 148 +__SYSCALL(__NR_fdatasync, sys_fdatasync) +#define __NR__sysctl 149 +__SYSCALL(__NR__sysctl, compat_sys_sysctl) +#define __NR_mlock 150 +__SYSCALL(__NR_mlock, sys_mlock) +#define __NR_munlock 151 +__SYSCALL(__NR_munlock, sys_munlock) +#define __NR_mlockall 152 +__SYSCALL(__NR_mlockall, sys_mlockall) +#define __NR_munlockall 153 +__SYSCALL(__NR_munlockall, sys_munlockall) +#define __NR_sched_setparam 154 +__SYSCALL(__NR_sched_setparam, sys_sched_setparam) +#define __NR_sched_getparam 155 +__SYSCALL(__NR_sched_getparam, sys_sched_getparam) +#define __NR_sched_setscheduler 156 +__SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler) +#define __NR_sched_getscheduler 157 +__SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler) +#define __NR_sched_yield 158 +__SYSCALL(__NR_sched_yield, sys_sched_yield) +#define __NR_sched_get_priority_max 159 +__SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max) +#define __NR_sched_get_priority_min 160 +__SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min) +#define __NR_sched_rr_get_interval 161 +__SYSCALL(__NR_sched_rr_get_interval, compat_sys_sched_rr_get_interval) +#define __NR_nanosleep 162 +__SYSCALL(__NR_nanosleep, compat_sys_nanosleep) +#define __NR_mremap 163 +__SYSCALL(__NR_mremap, sys_mremap) +#define __NR_setresuid 164 +__SYSCALL(__NR_setresuid, sys_setresuid16) +#define __NR_getresuid 165 +__SYSCALL(__NR_getresuid, sys_getresuid16) + /* 166 was sys_vm86 */ +__SYSCALL(166, sys_ni_syscall) + /* 167 was sys_query_module */ +__SYSCALL(167, sys_ni_syscall) +#define __NR_poll 168 +__SYSCALL(__NR_poll, sys_poll) +#define __NR_nfsservctl 169 +__SYSCALL(__NR_nfsservctl, sys_ni_syscall) +#define __NR_setresgid 170 +__SYSCALL(__NR_setresgid, sys_setresgid16) +#define __NR_getresgid 171 +__SYSCALL(__NR_getresgid, sys_getresgid16) +#define __NR_prctl 172 +__SYSCALL(__NR_prctl, sys_prctl) +#define __NR_rt_sigreturn 173 +__SYSCALL(__NR_rt_sigreturn, compat_sys_rt_sigreturn_wrapper) +#define __NR_rt_sigaction 174 +__SYSCALL(__NR_rt_sigaction, compat_sys_rt_sigaction) +#define __NR_rt_sigprocmask 175 +__SYSCALL(__NR_rt_sigprocmask, compat_sys_rt_sigprocmask) +#define __NR_rt_sigpending 176 +__SYSCALL(__NR_rt_sigpending, compat_sys_rt_sigpending) +#define __NR_rt_sigtimedwait 177 +__SYSCALL(__NR_rt_sigtimedwait, compat_sys_rt_sigtimedwait) +#define __NR_rt_sigqueueinfo 178 +__SYSCALL(__NR_rt_sigqueueinfo, compat_sys_rt_sigqueueinfo) +#define __NR_rt_sigsuspend 179 +__SYSCALL(__NR_rt_sigsuspend, compat_sys_rt_sigsuspend) +#define __NR_pread64 180 +__SYSCALL(__NR_pread64, compat_sys_pread64_wrapper) +#define __NR_pwrite64 181 +__SYSCALL(__NR_pwrite64, compat_sys_pwrite64_wrapper) +#define __NR_chown 182 +__SYSCALL(__NR_chown, sys_chown16) +#define __NR_getcwd 183 +__SYSCALL(__NR_getcwd, sys_getcwd) +#define __NR_capget 184 +__SYSCALL(__NR_capget, sys_capget) +#define __NR_capset 185 +__SYSCALL(__NR_capset, sys_capset) +#define __NR_sigaltstack 186 +__SYSCALL(__NR_sigaltstack, compat_sys_sigaltstack) +#define __NR_sendfile 187 +__SYSCALL(__NR_sendfile, compat_sys_sendfile) + /* 188 reserved */ +__SYSCALL(188, sys_ni_syscall) + /* 189 reserved */ +__SYSCALL(189, sys_ni_syscall) +#define __NR_vfork 190 +__SYSCALL(__NR_vfork, sys_vfork) +#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */ +__SYSCALL(__NR_ugetrlimit, compat_sys_getrlimit) /* SuS compliant getrlimit */ +#define __NR_mmap2 192 +__SYSCALL(__NR_mmap2, sys_mmap_pgoff) +#define __NR_truncate64 193 +__SYSCALL(__NR_truncate64, compat_sys_truncate64_wrapper) +#define __NR_ftruncate64 194 +__SYSCALL(__NR_ftruncate64, compat_sys_ftruncate64_wrapper) +#define __NR_stat64 195 +__SYSCALL(__NR_stat64, sys_stat64) +#define __NR_lstat64 196 +__SYSCALL(__NR_lstat64, sys_lstat64) +#define __NR_fstat64 197 +__SYSCALL(__NR_fstat64, sys_fstat64) +#define __NR_lchown32 198 +__SYSCALL(__NR_lchown32, sys_lchown) +#define __NR_getuid32 199 +__SYSCALL(__NR_getuid32, sys_getuid) +#define __NR_getgid32 200 +__SYSCALL(__NR_getgid32, sys_getgid) +#define __NR_geteuid32 201 +__SYSCALL(__NR_geteuid32, sys_geteuid) +#define __NR_getegid32 202 +__SYSCALL(__NR_getegid32, sys_getegid) +#define __NR_setreuid32 203 +__SYSCALL(__NR_setreuid32, sys_setreuid) +#define __NR_setregid32 204 +__SYSCALL(__NR_setregid32, sys_setregid) +#define __NR_getgroups32 205 +__SYSCALL(__NR_getgroups32, sys_getgroups) +#define __NR_setgroups32 206 +__SYSCALL(__NR_setgroups32, sys_setgroups) +#define __NR_fchown32 207 +__SYSCALL(__NR_fchown32, sys_fchown) +#define __NR_setresuid32 208 +__SYSCALL(__NR_setresuid32, sys_setresuid) +#define __NR_getresuid32 209 +__SYSCALL(__NR_getresuid32, sys_getresuid) +#define __NR_setresgid32 210 +__SYSCALL(__NR_setresgid32, sys_setresgid) +#define __NR_getresgid32 211 +__SYSCALL(__NR_getresgid32, sys_getresgid) +#define __NR_chown32 212 +__SYSCALL(__NR_chown32, sys_chown) +#define __NR_setuid32 213 +__SYSCALL(__NR_setuid32, sys_setuid) +#define __NR_setgid32 214 +__SYSCALL(__NR_setgid32, sys_setgid) +#define __NR_setfsuid32 215 +__SYSCALL(__NR_setfsuid32, sys_setfsuid) +#define __NR_setfsgid32 216 +__SYSCALL(__NR_setfsgid32, sys_setfsgid) +#define __NR_getdents64 217 +__SYSCALL(__NR_getdents64, compat_sys_getdents64) +#define __NR_pivot_root 218 +__SYSCALL(__NR_pivot_root, sys_pivot_root) +#define __NR_mincore 219 +__SYSCALL(__NR_mincore, sys_mincore) +#define __NR_madvise 220 +__SYSCALL(__NR_madvise, sys_madvise) +#define __NR_fcntl64 221 +__SYSCALL(__NR_fcntl64, compat_sys_fcntl64) + /* 222 for tux */ +__SYSCALL(222, sys_ni_syscall) + /* 223 is unused */ +__SYSCALL(223, sys_ni_syscall) +#define __NR_gettid 224 +__SYSCALL(__NR_gettid, sys_gettid) +#define __NR_readahead 225 +__SYSCALL(__NR_readahead, compat_sys_readahead_wrapper) +#define __NR_setxattr 226 +__SYSCALL(__NR_setxattr, sys_setxattr) +#define __NR_lsetxattr 227 +__SYSCALL(__NR_lsetxattr, sys_lsetxattr) +#define __NR_fsetxattr 228 +__SYSCALL(__NR_fsetxattr, sys_fsetxattr) +#define __NR_getxattr 229 +__SYSCALL(__NR_getxattr, sys_getxattr) +#define __NR_lgetxattr 230 +__SYSCALL(__NR_lgetxattr, sys_lgetxattr) +#define __NR_fgetxattr 231 +__SYSCALL(__NR_fgetxattr, sys_fgetxattr) +#define __NR_listxattr 232 +__SYSCALL(__NR_listxattr, sys_listxattr) +#define __NR_llistxattr 233 +__SYSCALL(__NR_llistxattr, sys_llistxattr) +#define __NR_flistxattr 234 +__SYSCALL(__NR_flistxattr, sys_flistxattr) +#define __NR_removexattr 235 +__SYSCALL(__NR_removexattr, sys_removexattr) +#define __NR_lremovexattr 236 +__SYSCALL(__NR_lremovexattr, sys_lremovexattr) +#define __NR_fremovexattr 237 +__SYSCALL(__NR_fremovexattr, sys_fremovexattr) +#define __NR_tkill 238 +__SYSCALL(__NR_tkill, sys_tkill) +#define __NR_sendfile64 239 +__SYSCALL(__NR_sendfile64, sys_sendfile64) +#define __NR_futex 240 +__SYSCALL(__NR_futex, compat_sys_futex) +#define __NR_sched_setaffinity 241 +__SYSCALL(__NR_sched_setaffinity, compat_sys_sched_setaffinity) +#define __NR_sched_getaffinity 242 +__SYSCALL(__NR_sched_getaffinity, compat_sys_sched_getaffinity) +#define __NR_io_setup 243 +__SYSCALL(__NR_io_setup, compat_sys_io_setup) +#define __NR_io_destroy 244 +__SYSCALL(__NR_io_destroy, sys_io_destroy) +#define __NR_io_getevents 245 +__SYSCALL(__NR_io_getevents, compat_sys_io_getevents) +#define __NR_io_submit 246 +__SYSCALL(__NR_io_submit, compat_sys_io_submit) +#define __NR_io_cancel 247 +__SYSCALL(__NR_io_cancel, sys_io_cancel) +#define __NR_exit_group 248 +__SYSCALL(__NR_exit_group, sys_exit_group) +#define __NR_lookup_dcookie 249 +__SYSCALL(__NR_lookup_dcookie, compat_sys_lookup_dcookie) +#define __NR_epoll_create 250 +__SYSCALL(__NR_epoll_create, sys_epoll_create) +#define __NR_epoll_ctl 251 +__SYSCALL(__NR_epoll_ctl, sys_epoll_ctl) +#define __NR_epoll_wait 252 +__SYSCALL(__NR_epoll_wait, sys_epoll_wait) +#define __NR_remap_file_pages 253 +__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages) + /* 254 for set_thread_area */ +__SYSCALL(254, sys_ni_syscall) + /* 255 for get_thread_area */ +__SYSCALL(255, sys_ni_syscall) +#define __NR_set_tid_address 256 +__SYSCALL(__NR_set_tid_address, sys_set_tid_address) +#define __NR_timer_create 257 +__SYSCALL(__NR_timer_create, compat_sys_timer_create) +#define __NR_timer_settime 258 +__SYSCALL(__NR_timer_settime, compat_sys_timer_settime) +#define __NR_timer_gettime 259 +__SYSCALL(__NR_timer_gettime, compat_sys_timer_gettime) +#define __NR_timer_getoverrun 260 +__SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun) +#define __NR_timer_delete 261 +__SYSCALL(__NR_timer_delete, sys_timer_delete) +#define __NR_clock_settime 262 +__SYSCALL(__NR_clock_settime, compat_sys_clock_settime) +#define __NR_clock_gettime 263 +__SYSCALL(__NR_clock_gettime, compat_sys_clock_gettime) +#define __NR_clock_getres 264 +__SYSCALL(__NR_clock_getres, compat_sys_clock_getres) +#define __NR_clock_nanosleep 265 +__SYSCALL(__NR_clock_nanosleep, compat_sys_clock_nanosleep) +#define __NR_statfs64 266 +__SYSCALL(__NR_statfs64, compat_sys_statfs64_wrapper) +#define __NR_fstatfs64 267 +__SYSCALL(__NR_fstatfs64, compat_sys_fstatfs64_wrapper) +#define __NR_tgkill 268 +__SYSCALL(__NR_tgkill, sys_tgkill) +#define __NR_utimes 269 +__SYSCALL(__NR_utimes, compat_sys_utimes) +#define __NR_arm_fadvise64_64 270 +__SYSCALL(__NR_arm_fadvise64_64, compat_sys_fadvise64_64_wrapper) +#define __NR_pciconfig_iobase 271 +__SYSCALL(__NR_pciconfig_iobase, sys_pciconfig_iobase) +#define __NR_pciconfig_read 272 +__SYSCALL(__NR_pciconfig_read, sys_pciconfig_read) +#define __NR_pciconfig_write 273 +__SYSCALL(__NR_pciconfig_write, sys_pciconfig_write) +#define __NR_mq_open 274 +__SYSCALL(__NR_mq_open, compat_sys_mq_open) +#define __NR_mq_unlink 275 +__SYSCALL(__NR_mq_unlink, sys_mq_unlink) +#define __NR_mq_timedsend 276 +__SYSCALL(__NR_mq_timedsend, compat_sys_mq_timedsend) +#define __NR_mq_timedreceive 277 +__SYSCALL(__NR_mq_timedreceive, compat_sys_mq_timedreceive) +#define __NR_mq_notify 278 +__SYSCALL(__NR_mq_notify, compat_sys_mq_notify) +#define __NR_mq_getsetattr 279 +__SYSCALL(__NR_mq_getsetattr, compat_sys_mq_getsetattr) +#define __NR_waitid 280 +__SYSCALL(__NR_waitid, compat_sys_waitid) +#define __NR_socket 281 +__SYSCALL(__NR_socket, sys_socket) +#define __NR_bind 282 +__SYSCALL(__NR_bind, sys_bind) +#define __NR_connect 283 +__SYSCALL(__NR_connect, sys_connect) +#define __NR_listen 284 +__SYSCALL(__NR_listen, sys_listen) +#define __NR_accept 285 +__SYSCALL(__NR_accept, sys_accept) +#define __NR_getsockname 286 +__SYSCALL(__NR_getsockname, sys_getsockname) +#define __NR_getpeername 287 +__SYSCALL(__NR_getpeername, sys_getpeername) +#define __NR_socketpair 288 +__SYSCALL(__NR_socketpair, sys_socketpair) +#define __NR_send 289 +__SYSCALL(__NR_send, sys_send) +#define __NR_sendto 290 +__SYSCALL(__NR_sendto, sys_sendto) +#define __NR_recv 291 +__SYSCALL(__NR_recv, compat_sys_recv) +#define __NR_recvfrom 292 +__SYSCALL(__NR_recvfrom, compat_sys_recvfrom) +#define __NR_shutdown 293 +__SYSCALL(__NR_shutdown, sys_shutdown) +#define __NR_setsockopt 294 +__SYSCALL(__NR_setsockopt, compat_sys_setsockopt) +#define __NR_getsockopt 295 +__SYSCALL(__NR_getsockopt, compat_sys_getsockopt) +#define __NR_sendmsg 296 +__SYSCALL(__NR_sendmsg, compat_sys_sendmsg) +#define __NR_recvmsg 297 +__SYSCALL(__NR_recvmsg, compat_sys_recvmsg) +#define __NR_semop 298 +__SYSCALL(__NR_semop, sys_semop) +#define __NR_semget 299 +__SYSCALL(__NR_semget, sys_semget) +#define __NR_semctl 300 +__SYSCALL(__NR_semctl, compat_sys_semctl) +#define __NR_msgsnd 301 +__SYSCALL(__NR_msgsnd, compat_sys_msgsnd) +#define __NR_msgrcv 302 +__SYSCALL(__NR_msgrcv, compat_sys_msgrcv) +#define __NR_msgget 303 +__SYSCALL(__NR_msgget, sys_msgget) +#define __NR_msgctl 304 +__SYSCALL(__NR_msgctl, compat_sys_msgctl) +#define __NR_shmat 305 +__SYSCALL(__NR_shmat, compat_sys_shmat) +#define __NR_shmdt 306 +__SYSCALL(__NR_shmdt, sys_shmdt) +#define __NR_shmget 307 +__SYSCALL(__NR_shmget, sys_shmget) +#define __NR_shmctl 308 +__SYSCALL(__NR_shmctl, compat_sys_shmctl) +#define __NR_add_key 309 +__SYSCALL(__NR_add_key, sys_add_key) +#define __NR_request_key 310 +__SYSCALL(__NR_request_key, sys_request_key) +#define __NR_keyctl 311 +__SYSCALL(__NR_keyctl, compat_sys_keyctl) +#define __NR_semtimedop 312 +__SYSCALL(__NR_semtimedop, compat_sys_semtimedop) +#define __NR_vserver 313 +__SYSCALL(__NR_vserver, sys_ni_syscall) +#define __NR_ioprio_set 314 +__SYSCALL(__NR_ioprio_set, sys_ioprio_set) +#define __NR_ioprio_get 315 +__SYSCALL(__NR_ioprio_get, sys_ioprio_get) +#define __NR_inotify_init 316 +__SYSCALL(__NR_inotify_init, sys_inotify_init) +#define __NR_inotify_add_watch 317 +__SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch) +#define __NR_inotify_rm_watch 318 +__SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch) +#define __NR_mbind 319 +__SYSCALL(__NR_mbind, compat_sys_mbind) +#define __NR_get_mempolicy 320 +__SYSCALL(__NR_get_mempolicy, compat_sys_get_mempolicy) +#define __NR_set_mempolicy 321 +__SYSCALL(__NR_set_mempolicy, compat_sys_set_mempolicy) +#define __NR_openat 322 +__SYSCALL(__NR_openat, compat_sys_openat) +#define __NR_mkdirat 323 +__SYSCALL(__NR_mkdirat, sys_mkdirat) +#define __NR_mknodat 324 +__SYSCALL(__NR_mknodat, sys_mknodat) +#define __NR_fchownat 325 +__SYSCALL(__NR_fchownat, sys_fchownat) +#define __NR_futimesat 326 +__SYSCALL(__NR_futimesat, compat_sys_futimesat) +#define __NR_fstatat64 327 +__SYSCALL(__NR_fstatat64, sys_fstatat64) +#define __NR_unlinkat 328 +__SYSCALL(__NR_unlinkat, sys_unlinkat) +#define __NR_renameat 329 +__SYSCALL(__NR_renameat, sys_renameat) +#define __NR_linkat 330 +__SYSCALL(__NR_linkat, sys_linkat) +#define __NR_symlinkat 331 +__SYSCALL(__NR_symlinkat, sys_symlinkat) +#define __NR_readlinkat 332 +__SYSCALL(__NR_readlinkat, sys_readlinkat) +#define __NR_fchmodat 333 +__SYSCALL(__NR_fchmodat, sys_fchmodat) +#define __NR_faccessat 334 +__SYSCALL(__NR_faccessat, sys_faccessat) +#define __NR_pselect6 335 +__SYSCALL(__NR_pselect6, compat_sys_pselect6) +#define __NR_ppoll 336 +__SYSCALL(__NR_ppoll, compat_sys_ppoll) +#define __NR_unshare 337 +__SYSCALL(__NR_unshare, sys_unshare) +#define __NR_set_robust_list 338 +__SYSCALL(__NR_set_robust_list, compat_sys_set_robust_list) +#define __NR_get_robust_list 339 +__SYSCALL(__NR_get_robust_list, compat_sys_get_robust_list) +#define __NR_splice 340 +__SYSCALL(__NR_splice, sys_splice) +#define __NR_sync_file_range2 341 +__SYSCALL(__NR_sync_file_range2, compat_sys_sync_file_range2_wrapper) +#define __NR_tee 342 +__SYSCALL(__NR_tee, sys_tee) +#define __NR_vmsplice 343 +__SYSCALL(__NR_vmsplice, compat_sys_vmsplice) +#define __NR_move_pages 344 +__SYSCALL(__NR_move_pages, compat_sys_move_pages) +#define __NR_getcpu 345 +__SYSCALL(__NR_getcpu, sys_getcpu) +#define __NR_epoll_pwait 346 +__SYSCALL(__NR_epoll_pwait, compat_sys_epoll_pwait) +#define __NR_kexec_load 347 +__SYSCALL(__NR_kexec_load, compat_sys_kexec_load) +#define __NR_utimensat 348 +__SYSCALL(__NR_utimensat, compat_sys_utimensat) +#define __NR_signalfd 349 +__SYSCALL(__NR_signalfd, compat_sys_signalfd) +#define __NR_timerfd_create 350 +__SYSCALL(__NR_timerfd_create, sys_timerfd_create) +#define __NR_eventfd 351 +__SYSCALL(__NR_eventfd, sys_eventfd) +#define __NR_fallocate 352 +__SYSCALL(__NR_fallocate, compat_sys_fallocate_wrapper) +#define __NR_timerfd_settime 353 +__SYSCALL(__NR_timerfd_settime, compat_sys_timerfd_settime) +#define __NR_timerfd_gettime 354 +__SYSCALL(__NR_timerfd_gettime, compat_sys_timerfd_gettime) +#define __NR_signalfd4 355 +__SYSCALL(__NR_signalfd4, compat_sys_signalfd4) +#define __NR_eventfd2 356 +__SYSCALL(__NR_eventfd2, sys_eventfd2) +#define __NR_epoll_create1 357 +__SYSCALL(__NR_epoll_create1, sys_epoll_create1) +#define __NR_dup3 358 +__SYSCALL(__NR_dup3, sys_dup3) +#define __NR_pipe2 359 +__SYSCALL(__NR_pipe2, sys_pipe2) +#define __NR_inotify_init1 360 +__SYSCALL(__NR_inotify_init1, sys_inotify_init1) +#define __NR_preadv 361 +__SYSCALL(__NR_preadv, compat_sys_preadv) +#define __NR_pwritev 362 +__SYSCALL(__NR_pwritev, compat_sys_pwritev) +#define __NR_rt_tgsigqueueinfo 363 +__SYSCALL(__NR_rt_tgsigqueueinfo, compat_sys_rt_tgsigqueueinfo) +#define __NR_perf_event_open 364 +__SYSCALL(__NR_perf_event_open, sys_perf_event_open) +#define __NR_recvmmsg 365 +__SYSCALL(__NR_recvmmsg, compat_sys_recvmmsg) +#define __NR_accept4 366 +__SYSCALL(__NR_accept4, sys_accept4) +#define __NR_fanotify_init 367 +__SYSCALL(__NR_fanotify_init, sys_fanotify_init) +#define __NR_fanotify_mark 368 +__SYSCALL(__NR_fanotify_mark, compat_sys_fanotify_mark) +#define __NR_prlimit64 369 +__SYSCALL(__NR_prlimit64, sys_prlimit64) +#define __NR_name_to_handle_at 370 +__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at) +#define __NR_open_by_handle_at 371 +__SYSCALL(__NR_open_by_handle_at, compat_sys_open_by_handle_at) +#define __NR_clock_adjtime 372 +__SYSCALL(__NR_clock_adjtime, compat_sys_clock_adjtime) +#define __NR_syncfs 373 +__SYSCALL(__NR_syncfs, sys_syncfs) +#define __NR_sendmmsg 374 +__SYSCALL(__NR_sendmmsg, compat_sys_sendmmsg) +#define __NR_setns 375 +__SYSCALL(__NR_setns, sys_setns) +#define __NR_process_vm_readv 376 +__SYSCALL(__NR_process_vm_readv, compat_sys_process_vm_readv) +#define __NR_process_vm_writev 377 +__SYSCALL(__NR_process_vm_writev, compat_sys_process_vm_writev) +#define __NR_kcmp 378 +__SYSCALL(__NR_kcmp, sys_kcmp) +#define __NR_finit_module 379 +__SYSCALL(__NR_finit_module, sys_finit_module) +/* #define __NR_sched_setattr 380 */ +__SYSCALL(380, sys_ni_syscall) +/* #define __NR_sched_getattr 381 */ +__SYSCALL(381, sys_ni_syscall) +/* #define __NR_renameat2 382 */ +__SYSCALL(382, sys_ni_syscall) +#define __NR_seccomp 383 +__SYSCALL(__NR_seccomp, sys_seccomp) diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h index 6913643bbe54..49c61746297d 100644 --- a/arch/arm64/include/uapi/asm/ptrace.h +++ b/arch/arm64/include/uapi/asm/ptrace.h @@ -23,6 +23,7 @@ #include <asm/hwcap.h> +#define PTRACE_SET_SYSCALL 23 /* * PSR bits diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 6ae85d55308b..97f5bbee095b 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -13,9 +13,10 @@ CFLAGS_REMOVE_return_address.o = -pg arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ entry-fpsimd.o process.o ptrace.o setup.o signal.o \ sys.o stacktrace.o time.o traps.o io.o vdso.o \ - hyp-stub.o psci.o cpu_ops.o insn.o return_address.o + hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \ + opcodes.o -arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ +arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ sys_compat.o arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o @@ -26,9 +27,12 @@ arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o +arm64-obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o arm64-obj-$(CONFIG_KGDB) += kgdb.o +obj-$(CONFIG_SWP_EMULATE) += swp_emulate.o + obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) head-y := head.o diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index a010e3af4597..34ac40e49acc 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -25,9 +25,9 @@ #include <asm/asm-offsets.h> #include <asm/errno.h> #include <asm/esr.h> +#include <asm/ptrace.h> #include <asm/thread_info.h> #include <asm/unistd.h> -#include <asm/unistd32.h> /* * Context tracking subsystem. Used to instrument transitions @@ -694,6 +694,10 @@ __sys_trace: mov x0, sp bl syscall_trace_enter adr lr, __sys_trace_return // return address + cmp w0, #RET_SKIP_SYSCALL_TRACE // skip syscall and tracing? + b.eq ret_to_user + cmp w0, #RET_SKIP_SYSCALL // skip syscall? + b.eq __sys_trace_return_skipped uxtw scno, w0 // syscall number (possibly new) mov x1, sp // pointer to regs cmp scno, sc_nr // check upper syscall limit @@ -707,6 +711,7 @@ __sys_trace: __sys_trace_return: str x0, [sp] // save returned x0 +__sys_trace_return_skipped: // x0 already in regs[0] mov x0, sp bl syscall_trace_exit b ret_to_user diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index ad8aebb1cdef..3dca15634e69 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -270,6 +270,7 @@ static int fpsimd_cpu_pm_notifier(struct notifier_block *self, case CPU_PM_ENTER: if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE)) fpsimd_save_state(¤t->thread.fpsimd_state); + this_cpu_write(fpsimd_last_state, NULL); break; case CPU_PM_EXIT: if (current->mm) diff --git a/arch/arm64/kernel/kuser32.S b/arch/arm64/kernel/kuser32.S index 7787208e8cc6..997e6b27ff6a 100644 --- a/arch/arm64/kernel/kuser32.S +++ b/arch/arm64/kernel/kuser32.S @@ -28,7 +28,7 @@ * See Documentation/arm/kernel_user_helpers.txt for formal definitions. */ -#include <asm/unistd32.h> +#include <asm/unistd.h> .align 5 .globl __kuser_helper_start diff --git a/arch/arm64/kernel/opcodes.c b/arch/arm64/kernel/opcodes.c new file mode 100644 index 000000000000..ceb5a04a1e12 --- /dev/null +++ b/arch/arm64/kernel/opcodes.c @@ -0,0 +1,72 @@ +/* + * Copied from linux/arch/arm/kernel/opcodes.c + * + * A32 condition code lookup feature moved from nwfpe/fpopcode.c + * + * 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 + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <asm/opcodes.h> + +#define ARM_OPCODE_CONDITION_UNCOND 0xf + +/* + * condition code lookup table + * index into the table is test code: EQ, NE, ... LT, GT, AL, NV + * + * bit position in short is condition code: NZCV + */ +static const unsigned short cc_map[16] = { + 0xF0F0, /* EQ == Z set */ + 0x0F0F, /* NE */ + 0xCCCC, /* CS == C set */ + 0x3333, /* CC */ + 0xFF00, /* MI == N set */ + 0x00FF, /* PL */ + 0xAAAA, /* VS == V set */ + 0x5555, /* VC */ + 0x0C0C, /* HI == C set && Z clear */ + 0xF3F3, /* LS == C clear || Z set */ + 0xAA55, /* GE == (N==V) */ + 0x55AA, /* LT == (N!=V) */ + 0x0A05, /* GT == (!Z && (N==V)) */ + 0xF5FA, /* LE == (Z || (N!=V)) */ + 0xFFFF, /* AL always */ + 0 /* NV */ +}; + +/* + * Returns: + * ARM_OPCODE_CONDTEST_FAIL - if condition fails + * ARM_OPCODE_CONDTEST_PASS - if condition passes (including AL) + * ARM_OPCODE_CONDTEST_UNCOND - if NV condition, or separate unconditional + * opcode space from v5 onwards + * + * Code that tests whether a conditional instruction would pass its condition + * check should check that return value == ARM_OPCODE_CONDTEST_PASS. + * + * Code that tests if a condition means that the instruction would be executed + * (regardless of conditional or unconditional) should instead check that the + * return value != ARM_OPCODE_CONDTEST_FAIL. + */ +asmlinkage unsigned int arm_check_condition(u32 opcode, u64 psr) +{ + u32 cc_bits = opcode >> 28; + u32 psr_cond = (u32)(psr & 0xffffffff) >> 28; + unsigned int ret; + + if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) { + if ((cc_map[cc_bits] >> (psr_cond)) & 1) + ret = ARM_OPCODE_CONDTEST_PASS; + else + ret = ARM_OPCODE_CONDTEST_FAIL; + } else { + ret = ARM_OPCODE_CONDTEST_UNCOND; + } + + return ret; +} +EXPORT_SYMBOL_GPL(arm_check_condition); diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 6601cda23170..9164efd66159 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -146,6 +146,70 @@ void machine_restart(char *cmd) while (1); } +/* + * dump a block of kernel memory from around the given address + */ +static void show_data(unsigned long addr, int nbytes, const char *name) +{ + int i, j; + int nlines; + u32 *p; + + /* + * don't attempt to dump non-kernel addresses or + * values that are probably just small negative numbers + */ + if (addr < PAGE_OFFSET || addr > -256UL) + return; + + printk("\n%s: %#lx:\n", name, addr); + + /* + * round address down to a 32 bit boundary + * and always dump a multiple of 32 bytes + */ + p = (u32 *)(addr & ~(sizeof(u32) - 1)); + nbytes += (addr & (sizeof(u32) - 1)); + nlines = (nbytes + 31) / 32; + + + for (i = 0; i < nlines; i++) { + /* + * just display low 16 bits of address to keep + * each line of the dump < 80 characters + */ + printk("%04lx ", (unsigned long)p & 0xffff); + for (j = 0; j < 8; j++) { + u32 data; + if (probe_kernel_address(p, data)) { + printk(" ********"); + } else { + printk(" %08x", data); + } + ++p; + } + printk("\n"); + } +} + +static void show_extra_register_data(struct pt_regs *regs, int nbytes) +{ + mm_segment_t fs; + unsigned int i; + + fs = get_fs(); + set_fs(KERNEL_DS); + show_data(regs->pc - nbytes, nbytes * 2, "PC"); + show_data(regs->regs[30] - nbytes, nbytes * 2, "LR"); + show_data(regs->sp - nbytes, nbytes * 2, "SP"); + for (i = 0; i < 30; i++) { + char name[4]; + snprintf(name, sizeof(name), "X%u", i); + show_data(regs->regs[i] - nbytes, nbytes * 2, name); + } + set_fs(fs); +} + void __show_regs(struct pt_regs *regs) { int i, top_reg; @@ -172,6 +236,8 @@ void __show_regs(struct pt_regs *regs) if (i % 2 == 0) printk("\n"); } + if (!user_mode(regs)) + show_extra_register_data(regs, 128); printk("\n"); } diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 167c5edecad4..50b26f12d63c 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -19,6 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/audit.h> #include <linux/compat.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -26,6 +27,7 @@ #include <linux/smp.h> #include <linux/ptrace.h> #include <linux/user.h> +#include <linux/seccomp.h> #include <linux/security.h> #include <linux/init.h> #include <linux/signal.h> @@ -39,6 +41,7 @@ #include <asm/compat.h> #include <asm/debug-monitors.h> #include <asm/pgtable.h> +#include <asm/syscall.h> #include <asm/traps.h> #include <asm/system_misc.h> @@ -1076,7 +1079,19 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { - return ptrace_request(child, request, addr, data); + int ret; + + switch (request) { + case PTRACE_SET_SYSCALL: + task_pt_regs(child)->syscallno = data; + ret = 0; + break; + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; } enum ptrace_syscall_dir { @@ -1108,19 +1123,42 @@ static void tracehook_report_syscall(struct pt_regs *regs, asmlinkage int syscall_trace_enter(struct pt_regs *regs) { + unsigned int saved_syscallno = regs->syscallno; + + /* Do the secure computing check first; failures should be fast. */ + if (secure_computing(regs->syscallno) == -1) + return RET_SKIP_SYSCALL_TRACE; + if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) - trace_sys_enter(regs, regs->syscallno); + if (IS_SKIP_SYSCALL(regs->syscallno)) { + /* + * RESTRICTION: we can't modify a return value of user + * issued syscall(-1) here. In order to ease this flavor, + * we need to treat whatever value in x0 as a return value, + * but this might result in a bogus value being returned. + */ + /* + * NOTE: syscallno may also be set to -1 if fatal signal is + * detected in tracehook_report_syscall_entry(), but since + * a value set to x0 here is not used in this case, we may + * neglect the case. + */ + if (!test_thread_flag(TIF_SYSCALL_TRACE) || + (IS_SKIP_SYSCALL(saved_syscallno))) + regs->regs[0] = -ENOSYS; + } + + audit_syscall_entry(syscall_get_arch(), regs->syscallno, + regs->orig_x0, regs->regs[1], regs->regs[2], regs->regs[3]); return regs->syscallno; } asmlinkage void syscall_trace_exit(struct pt_regs *regs) { - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) - trace_sys_exit(regs, regs_return_value(regs)); + audit_syscall_exit(regs); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT); diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index b46ceb905ca3..f601a7fee397 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -451,9 +451,20 @@ static int c_show(struct seq_file *m, void *v) for (i = 0; hwcap_str[i]; i++) if (elf_hwcap & (1 << i)) seq_printf(m, "%s ", hwcap_str[i]); +#ifdef CONFIG_ARMV7_COMPAT_CPUINFO + if (is_compat_task()) { + /* Print out the non-optional ARMv8 HW capabilities */ + seq_printf(m, "wp half thumb fastmult vfp edsp neon vfpv3 tlsi "); + seq_printf(m, "vfpv4 idiva idivt "); + } +#endif seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); - seq_printf(m, "CPU architecture: AArch64\n"); + seq_printf(m, "CPU architecture: %s\n", +#if IS_ENABLED(CONFIG_ARMV7_COMPAT_CPUINFO) + is_compat_task() ? "8" : +#endif + "AArch64"); seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15); seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff); seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index ac7e237d0bda..9b43b410d039 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -26,7 +26,7 @@ #include <asm/fpsimd.h> #include <asm/signal32.h> #include <asm/uaccess.h> -#include <asm/unistd32.h> +#include <asm/unistd.h> struct compat_sigcontext { /* We always set these two fields to 0 */ @@ -183,6 +183,14 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr); break; +#ifdef __ARCH_SIGSYS + case __SI_SYS: + err |= __put_user((compat_uptr_t)(unsigned long) + from->si_call_addr, &to->si_call_addr); + err |= __put_user(from->si_syscall, &to->si_syscall); + err |= __put_user(from->si_arch, &to->si_arch); + break; +#endif default: /* this is just in case for now ... */ err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); diff --git a/arch/arm64/kernel/swp_emulate.c b/arch/arm64/kernel/swp_emulate.c new file mode 100644 index 000000000000..508fd2edb8ab --- /dev/null +++ b/arch/arm64/kernel/swp_emulate.c @@ -0,0 +1,223 @@ +/* + * Derived from from linux/arch/arm/kernel/swp_emulate.c + * + * Copyright (C) 2009 ARM Limited + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * + * 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 + * published by the Free Software Foundation. + * + * Implements emulation of the SWP/SWPB instructions using load-exclusive and + * store-exclusive for processors that have them disabled (or future ones that + * might not implement them). + * + * Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>] + * Where: Rt = destination + * Rt2 = source + * Rn = address + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/sched.h> +#include <linux/syscalls.h> +#include <linux/perf_event.h> + +#include <asm/opcodes.h> +#include <asm/traps.h> +#include <asm/uaccess.h> +#include <asm/system_misc.h> +#include <linux/debugfs.h> + +/* + * Error-checking SWP macros implemented using ldrex{b}/strex{b} + */ + +static int swpb(u8 in, u8 *out, u8 *addr) +{ + u8 _out; + int res; + int err; + + do { + __asm__ __volatile__( + "0: ldxrb %w1, %4\n" + "1: stxrb %w0, %w3, %4\n" + " mov %w2, #0\n" + "2:\n" + " .section .fixup,\"ax\"\n" + " .align 2\n" + "3: mov %w2, %5\n" + " b 2b\n" + " .previous\n" + " .section __ex_table,\"a\"\n" + " .align 3\n" + " .quad 0b, 3b\n" + " .quad 1b, 3b\n" + " .previous" + : "=&r" (res), "=r" (_out), "=r" (err) + : "r" (in), "Q" (*addr), "i" (-EFAULT) + : "cc", "memory"); + } while (err == 0 && res != 0); + + if (err == 0) + *out = _out; + return err; +} + +static int swp(u32 in, u32 *out, u32 *addr) +{ + u32 _out; + int res; + int err = 0; + + do { + __asm__ __volatile__( + "0: ldxr %w1, %4\n" + "1: stxr %w0, %w3, %4\n" + " mov %w2, #0\n" + "2:\n" + " .section .fixup,\"ax\"\n" + " .align 2\n" + "3: mov %w2, %5\n" + " b 2b\n" + " .previous\n" + " .section __ex_table,\"a\"\n" + " .align 3\n" + " .quad 0b, 3b\n" + " .quad 1b, 3b\n" + " .previous" + : "=&r" (res), "=r" (_out), "=r" (err) + : "r" (in), "Q" (*addr), "i" (-EFAULT) + : "cc", "memory"); + } while (err == 0 && res != 0); + + if (err == 0) + *out = _out; + return err; +} +/* + * Macros/defines for extracting register numbers from instruction. + */ +#define EXTRACT_REG_NUM(instruction, offset) \ + (((instruction) & (0xf << (offset))) >> (offset)) +#define RN_OFFSET 16 +#define RT_OFFSET 12 +#define RT2_OFFSET 0 +/* + * Bit 22 of the instruction encoding distinguishes between + * the SWP and SWPB variants (bit set means SWPB). + */ +#define TYPE_SWPB (1 << 22) + +static pid_t previous_pid; + +u64 swpb_count = 0; +u64 swp_count = 0; + +/* + * swp_handler logs the id of calling process, dissects the instruction, sanity + * checks the memory location, calls emulate_swpX for the actual operation and + * deals with fixup/error handling before returning + */ +static int swp_handler(struct pt_regs *regs, unsigned int instr) +{ + u32 destreg, data, type; + uintptr_t address; + unsigned int res = 0; + int err; + u32 temp32; + u8 temp8; + + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); + + res = arm_check_condition(instr, regs->pstate); + switch (res) { + case ARM_OPCODE_CONDTEST_PASS: + break; + case ARM_OPCODE_CONDTEST_FAIL: + /* Condition failed - return to next instruction */ + regs->pc += 4; + return 0; + case ARM_OPCODE_CONDTEST_UNCOND: + /* If unconditional encoding - not a SWP, undef */ + return -EFAULT; + default: + return -EINVAL; + } + + if (current->pid != previous_pid) { + pr_warn("\"%s\" (%ld) uses obsolete SWP{B} instruction\n", + current->comm, (unsigned long)current->pid); + previous_pid = current->pid; + } + + address = regs->regs[EXTRACT_REG_NUM(instr, RN_OFFSET)] & 0xffffffff; + data = regs->regs[EXTRACT_REG_NUM(instr, RT2_OFFSET)]; + destreg = EXTRACT_REG_NUM(instr, RT_OFFSET); + + type = instr & TYPE_SWPB; + + /* Check access in reasonable access range for both SWP and SWPB */ + if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { + pr_debug("SWP{B} emulation: access to %p not allowed!\n", + (void *)address); + res = -EFAULT; + } + if (type == TYPE_SWPB) { + err = swpb((u8) data, &temp8, (u8 *) address); + if (err) + return err; + regs->regs[destreg] = temp8; + regs->pc += 4; + swpb_count++; + } else if (address & 0x3) { + /* SWP to unaligned address not permitted */ + pr_debug("SWP instruction on unaligned pointer!\n"); + return -EFAULT; + } else { + err = swp((u32) data, &temp32, (u32 *) address); + if (err) + return err; + regs->regs[destreg] = temp32; + regs->pc += 4; + swp_count++; + } + + return 0; +} + +/* + * Only emulate SWP/SWPB executed in ARM state/User mode. + * The kernel must be SWP free and SWP{B} does not exist in Thumb/ThumbEE. + */ +static struct undef_hook swp_hook = { + .instr_mask = 0x0fb00ff0, + .instr_val = 0x01000090, + .pstate_mask = COMPAT_PSR_MODE_MASK | COMPAT_PSR_T_BIT, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = swp_handler +}; + +/* + * Register handler and create status file in /proc/cpu + * Invoked as late_initcall, since not needed before init spawned. + */ +static int __init swp_emulation_init(void) +{ + struct dentry *dir; + dir = debugfs_create_dir("swp_emulate", NULL); + debugfs_create_u64("swp_count", S_IRUGO | S_IWUSR, dir, &swp_count); + debugfs_create_u64("swpb_count", S_IRUGO | S_IWUSR, dir, &swpb_count); + + pr_notice("Registering SWP/SWPB emulation handler\n"); + register_undef_hook(&swp_hook); + + + return 0; +} + +late_initcall(swp_emulation_init); diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c index 78039927c807..dc47e53e9e28 100644 --- a/arch/arm64/kernel/sys_compat.c +++ b/arch/arm64/kernel/sys_compat.c @@ -26,7 +26,7 @@ #include <linux/uaccess.h> #include <asm/cacheflush.h> -#include <asm/unistd32.h> +#include <asm/unistd.h> static inline void do_compat_cache_op(unsigned long start, unsigned long end, int flags) diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 7ffadddb645d..0da47699510b 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -3,6 +3,7 @@ * * Copyright (C) 1995-2009 Russell King * Copyright (C) 2012 ARM Ltd. + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. * * 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 @@ -257,15 +258,58 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, die(str, regs, err); } +static LIST_HEAD(undef_hook); + +void register_undef_hook(struct undef_hook *hook) +{ + list_add(&hook->node, &undef_hook); +} + +static int call_undef_hook(struct pt_regs *regs, unsigned int instr) +{ + struct undef_hook *hook; + int (*fn)(struct pt_regs *regs, unsigned int instr) = NULL; + + list_for_each_entry(hook, &undef_hook, node) + if ((instr & hook->instr_mask) == hook->instr_val && + (regs->pstate & hook->pstate_mask) == hook->pstate_val) + fn = hook->fn; + + return fn ? fn(regs, instr) : 1; +} + asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { + u32 instr; siginfo_t info; void __user *pc = (void __user *)instruction_pointer(regs); /* check for AArch32 breakpoint instructions */ if (!aarch32_break_handler(regs)) return; + if (user_mode(regs)) { + if (compat_thumb_mode(regs)) { + if (get_user(instr, (u16 __user *)pc)) + goto die_sig; + if (is_wide_instruction(instr)) { + u32 instr2; + if (get_user(instr2, (u16 __user *)pc+1)) + goto die_sig; + instr <<= 16; + instr |= instr2; + } + } else if (get_user(instr, (u32 __user *)pc)) { + goto die_sig; + } + } else { + /* kernel mode */ + instr = *((u32 *)pc); + } + + if (call_undef_hook(regs, instr) == 0) + return; +die_sig: if (show_unhandled_signals && unhandled_signal(current, SIGILL) && printk_ratelimit()) { pr_info("%s[%d]: undefined instruction: pc=%p\n", diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index cc3339d0a276..aa44a7bc9ae9 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -102,9 +102,11 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max) } #ifdef CONFIG_HAVE_ARCH_PFN_VALID +#define PFN_MASK ((1UL << (64 - PAGE_SHIFT)) - 1) + int pfn_valid(unsigned long pfn) { - return memblock_is_memory(pfn << PAGE_SHIFT); + return (pfn & PFN_MASK) == pfn && memblock_is_memory(pfn << PAGE_SHIFT); } EXPORT_SYMBOL(pfn_valid); #endif diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index e085ee6ef4e2..e83249401615 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -225,6 +225,20 @@ ENTRY(__cpu_setup) ret // return to head.S ENDPROC(__cpu_setup) +#ifdef CONFIG_ARMV7_COMPAT + /* + * n n T + * U E WT T UD US IHBS + * CE0 XWHW CZ ME TEEA S + * .... .IEE .... NEAI TE.I ..AD DEN0 ACAM + * 0011 0... 1101 ..0. ..0. 10.. .... .... < hardware reserved + * .... .100 .... 01.1 11.1 ..01 0011 1101 < software settings + */ + .type crval, #object +crval: + .word 0x030802e2 // clear + .word 0x0405d03d // set +#else /* * n n T * U E WT T UD US IHBS @@ -237,3 +251,4 @@ ENDPROC(__cpu_setup) crval: .word 0x000802e2 // clear .word 0x0405d11d // set +#endif diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index cd29d2f4e4f3..bebc0bd8abc2 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h @@ -89,11 +89,10 @@ static inline void syscall_set_arguments(struct task_struct *task, regs->orig_gpr2 = args[0]; } -static inline int syscall_get_arch(struct task_struct *task, - struct pt_regs *regs) +static inline int syscall_get_arch(void) { #ifdef CONFIG_COMPAT - if (test_tsk_thread_flag(task, TIF_31BIT)) + if (test_tsk_thread_flag(current, TIF_31BIT)) return AUDIT_ARCH_S390; #endif return sizeof(long) == 8 ? AUDIT_ARCH_S390X : AUDIT_ARCH_S390; diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index aea284b41312..7e6d0c49ecab 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h @@ -91,8 +91,7 @@ static inline void syscall_set_arguments(struct task_struct *task, memcpy(®s->bx + i, args, n * sizeof(args[0])); } -static inline int syscall_get_arch(struct task_struct *task, - struct pt_regs *regs) +static inline int syscall_get_arch(void) { return AUDIT_ARCH_I386; } @@ -221,8 +220,7 @@ static inline void syscall_set_arguments(struct task_struct *task, } } -static inline int syscall_get_arch(struct task_struct *task, - struct pt_regs *regs) +static inline int syscall_get_arch(void) { #ifdef CONFIG_IA32_EMULATION /* @@ -234,7 +232,7 @@ static inline int syscall_get_arch(struct task_struct *task, * * x32 tasks should be considered AUDIT_ARCH_X86_64. */ - if (task_thread_info(task)->status & TS_COMPAT) + if (task_thread_info(current)->status & TS_COMPAT) return AUDIT_ARCH_I386; #endif /* Both x32 and x86_64 are considered "64-bit". */ diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl index 96bc506ac6de..7527eac24122 100644 --- a/arch/x86/syscalls/syscall_32.tbl +++ b/arch/x86/syscalls/syscall_32.tbl @@ -359,3 +359,5 @@ 350 i386 finit_module sys_finit_module 351 i386 sched_setattr sys_sched_setattr 352 i386 sched_getattr sys_sched_getattr +353 i386 renameat2 sys_renameat2 +354 i386 seccomp sys_seccomp diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index 7f517ca19d32..16272a6c12b7 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl @@ -322,6 +322,8 @@ 313 common finit_module sys_finit_module 314 common sched_setattr sys_sched_setattr 315 common sched_getattr sys_sched_getattr +316 common renameat2 sys_renameat2 +317 common seccomp sys_seccomp # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/crypto/Kconfig b/crypto/Kconfig index 7bcb70d216e1..7a5f79e8d894 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -547,6 +547,17 @@ config CRYPTO_SHA1_PPC This is the powerpc hardware accelerated implementation of the SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). +config CRYPTO_SHA1_ARM_NEON + tristate "SHA1 digest algorithm (ARM NEON)" + depends on ARM && KERNEL_MODE_NEON && !CPU_BIG_ENDIAN + select CRYPTO_SHA1_ARM + select CRYPTO_SHA1 + select CRYPTO_HASH + help + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented + using optimized ARM NEON assembly, when NEON instructions are + available. + config CRYPTO_SHA256 tristate "SHA224 and SHA256 digest algorithm" select CRYPTO_HASH @@ -580,6 +591,21 @@ config CRYPTO_SHA512 This code also includes SHA-384, a 384 bit hash with 192 bits of security against collision attacks. +config CRYPTO_SHA512_ARM_NEON + tristate "SHA384 and SHA512 digest algorithm (ARM NEON)" + depends on ARM && KERNEL_MODE_NEON && !CPU_BIG_ENDIAN + select CRYPTO_SHA512 + select CRYPTO_HASH + help + SHA-512 secure hash standard (DFIPS 180-2) implemented + using ARM NEON instructions, when available. + + This version of SHA implements a 512 bit hash with 256 bits of + security against collision attacks. + + This code also includes SHA-384, a 384 bit hash with 192 bits + of security against collision attacks. + config CRYPTO_SHA512_SPARC64 tristate "SHA384 and SHA512 digest algorithm (SPARC64)" depends on SPARC64 diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 8a38bf8c792f..335e9efc7872 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -346,7 +346,7 @@ int register_cpu(struct cpu *cpu, int num) cpu->dev.offline_disabled = !cpu->hotpluggable; cpu->dev.offline = !cpu_online(num); cpu->dev.of_node = of_get_cpu_node(num, NULL); -#ifdef CONFIG_HAVE_CPU_AUTOPROBE +#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE cpu->dev.bus->uevent = cpu_uevent; #endif cpu->dev.groups = common_cpu_attr_groups; diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 9fe35277c0f2..e8fbc58b12e4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -31,6 +31,7 @@ #include <trace/events/power.h> #include <linux/cpuidle.h> #include <linux/timer.h> +#include <linux/wakeup_reason.h> #include "../base.h" #include "power.h" @@ -983,6 +984,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) static int dpm_suspend_noirq(pm_message_t state) { ktime_t starttime = ktime_get(); + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; int error = 0; cpuidle_pause(); @@ -1010,6 +1012,9 @@ static int dpm_suspend_noirq(pm_message_t state) put_device(dev); if (pm_wakeup_pending()) { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); error = -EBUSY; break; } @@ -1068,6 +1073,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state) static int dpm_suspend_late(pm_message_t state) { ktime_t starttime = ktime_get(); + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; int error = 0; mutex_lock(&dpm_list_mtx); @@ -1093,6 +1099,9 @@ static int dpm_suspend_late(pm_message_t state) put_device(dev); if (pm_wakeup_pending()) { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); error = -EBUSY; break; } @@ -1163,6 +1172,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) struct timer_list timer; struct dpm_drv_wd_data data; DECLARE_DPM_WATCHDOG_ON_STACK(wd); + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; dpm_wait_for_children(dev, async); @@ -1179,6 +1189,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) pm_wakeup_event(dev, 0); if (pm_wakeup_pending()) { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); async_error = -EBUSY; goto Complete; } diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 2d56f4113ae7..066d15837e15 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -659,6 +659,22 @@ void pm_wakeup_event(struct device *dev, unsigned int msec) } EXPORT_SYMBOL_GPL(pm_wakeup_event); +void pm_get_active_wakeup_sources(char *pending_wakeup_source, size_t max) +{ + struct wakeup_source *ws; + int len = 0; + rcu_read_lock(); + len += snprintf(pending_wakeup_source, max, "Pending Wakeup Sources: "); + list_for_each_entry_rcu(ws, &wakeup_sources, entry) { + if (ws->active) { + len += snprintf(pending_wakeup_source + len, max, + "%s ", ws->name); + } + } + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(pm_get_active_wakeup_sources); + void pm_print_active_wakeup_sources(void) { struct wakeup_source *ws; diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index e8d11b6630ee..0ab546558c4e 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -10,6 +10,7 @@ #include <linux/mutex.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/wakeup_reason.h> static LIST_HEAD(syscore_ops_list); static DEFINE_MUTEX(syscore_ops_lock); @@ -73,6 +74,8 @@ int syscore_suspend(void) return 0; err_out: + log_suspend_abort_reason("System core suspend callback %pF failed", + ops->suspend); pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend); list_for_each_entry_continue(ops, &syscore_ops_list, node) diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index ff77b300df88..24fe0ce88e77 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -44,8 +44,10 @@ struct cpufreq_interactive_cpuinfo { u64 cputime_speedadj_timestamp; struct cpufreq_policy *policy; struct cpufreq_frequency_table *freq_table; + spinlock_t target_freq_lock; /*protects target freq */ unsigned int target_freq; unsigned int floor_freq; + unsigned int max_freq; u64 floor_validate_time; u64 hispeed_validate_time; struct rw_semaphore enable_sem; @@ -103,6 +105,7 @@ struct cpufreq_interactive_tunables { int boostpulse_duration_val; /* End time of boost pulse in ktime converted to usecs */ u64 boostpulse_endtime; + bool boosted; /* * Max additional time to wait in idle, beyond timer_rate, at speeds * above minimum before wakeup to reduce speed, or -1 if unnecessary. @@ -113,7 +116,7 @@ struct cpufreq_interactive_tunables { }; /* For cases where we have single governor instance for system */ -struct cpufreq_interactive_tunables *common_tunables; +static struct cpufreq_interactive_tunables *common_tunables; static struct attribute_group *get_sysfs_attr(void); @@ -342,7 +345,6 @@ static void cpufreq_interactive_timer(unsigned long data) unsigned int loadadjfreq; unsigned int index; unsigned long flags; - bool boosted; if (!down_read_trylock(&pcpu->enable_sem)) return; @@ -358,12 +360,13 @@ static void cpufreq_interactive_timer(unsigned long data) if (WARN_ON_ONCE(!delta_time)) goto rearm; + spin_lock_irqsave(&pcpu->target_freq_lock, flags); do_div(cputime_speedadj, delta_time); loadadjfreq = (unsigned int)cputime_speedadj * 100; cpu_load = loadadjfreq / pcpu->target_freq; - boosted = tunables->boost_val || now < tunables->boostpulse_endtime; + tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime; - if (cpu_load >= tunables->go_hispeed_load || boosted) { + if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) { if (pcpu->target_freq < tunables->hispeed_freq) { new_freq = tunables->hispeed_freq; } else { @@ -374,6 +377,9 @@ static void cpufreq_interactive_timer(unsigned long data) } } else { new_freq = choose_freq(pcpu, loadadjfreq); + if (new_freq > tunables->hispeed_freq && + pcpu->target_freq < tunables->hispeed_freq) + new_freq = tunables->hispeed_freq; } if (pcpu->target_freq >= tunables->hispeed_freq && @@ -383,6 +389,7 @@ static void cpufreq_interactive_timer(unsigned long data) trace_cpufreq_interactive_notyet( data, cpu_load, pcpu->target_freq, pcpu->policy->cur, new_freq); + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); goto rearm; } @@ -390,8 +397,10 @@ static void cpufreq_interactive_timer(unsigned long data) if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table, new_freq, CPUFREQ_RELATION_L, - &index)) + &index)) { + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); goto rearm; + } new_freq = pcpu->freq_table[index].frequency; @@ -405,6 +414,7 @@ static void cpufreq_interactive_timer(unsigned long data) trace_cpufreq_interactive_notyet( data, cpu_load, pcpu->target_freq, pcpu->policy->cur, new_freq); + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); goto rearm; } } @@ -417,15 +427,17 @@ static void cpufreq_interactive_timer(unsigned long data) * (or the indefinite boost is turned off). */ - if (!boosted || new_freq > tunables->hispeed_freq) { + if (!tunables->boosted || new_freq > tunables->hispeed_freq) { pcpu->floor_freq = new_freq; pcpu->floor_validate_time = now; } - if (pcpu->target_freq == new_freq) { + if (pcpu->target_freq == new_freq && + pcpu->target_freq <= pcpu->policy->cur) { trace_cpufreq_interactive_already( data, cpu_load, pcpu->target_freq, pcpu->policy->cur, new_freq); + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); goto rearm_if_notmax; } @@ -433,6 +445,7 @@ static void cpufreq_interactive_timer(unsigned long data) pcpu->policy->cur, new_freq); pcpu->target_freq = new_freq; + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); spin_lock_irqsave(&speedchange_cpumask_lock, flags); cpumask_set_cpu(data, &speedchange_cpumask); spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); @@ -572,20 +585,23 @@ static int cpufreq_interactive_speedchange_task(void *data) return 0; } -static void cpufreq_interactive_boost(void) +static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunables) { int i; int anyboost = 0; - unsigned long flags; + unsigned long flags[2]; struct cpufreq_interactive_cpuinfo *pcpu; - struct cpufreq_interactive_tunables *tunables; - spin_lock_irqsave(&speedchange_cpumask_lock, flags); + tunables->boosted = true; + + spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]); for_each_online_cpu(i) { pcpu = &per_cpu(cpuinfo, i); - tunables = pcpu->policy->governor_data; + if (tunables != pcpu->policy->governor_data) + continue; + spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]); if (pcpu->target_freq < tunables->hispeed_freq) { pcpu->target_freq = tunables->hispeed_freq; cpumask_set_cpu(i, &speedchange_cpumask); @@ -601,9 +617,10 @@ static void cpufreq_interactive_boost(void) pcpu->floor_freq = tunables->hispeed_freq; pcpu->floor_validate_time = ktime_to_us(ktime_get()); + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]); } - spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); + spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]); if (anyboost) wake_up_process(speedchange_task); @@ -895,8 +912,10 @@ static ssize_t store_boost(struct cpufreq_interactive_tunables *tunables, if (tunables->boost_val) { trace_cpufreq_interactive_boost("on"); - cpufreq_interactive_boost(); + if (!tunables->boosted) + cpufreq_interactive_boost(tunables); } else { + tunables->boostpulse_endtime = ktime_to_us(ktime_get()); trace_cpufreq_interactive_unboost("off"); } @@ -916,7 +935,8 @@ static ssize_t store_boostpulse(struct cpufreq_interactive_tunables *tunables, tunables->boostpulse_endtime = ktime_to_us(ktime_get()) + tunables->boostpulse_duration_val; trace_cpufreq_interactive_boost("pulse"); - cpufreq_interactive_boost(); + if (!tunables->boosted) + cpufreq_interactive_boost(tunables); return count; } @@ -1114,6 +1134,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, struct cpufreq_interactive_cpuinfo *pcpu; struct cpufreq_frequency_table *freq_table; struct cpufreq_interactive_tunables *tunables; + unsigned long flags; if (have_governor_per_policy()) tunables = policy->governor_data; @@ -1154,8 +1175,10 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, spin_lock_init(&tunables->above_hispeed_delay_lock); policy->governor_data = tunables; - if (!have_governor_per_policy()) + if (!have_governor_per_policy()) { common_tunables = tunables; + WARN_ON(cpufreq_get_global_kobject()); + } rc = sysfs_create_group(get_governor_parent_kobj(policy), get_sysfs_attr()); @@ -1185,6 +1208,10 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, sysfs_remove_group(get_governor_parent_kobj(policy), get_sysfs_attr()); + + if (!have_governor_per_policy()) + cpufreq_put_global_kobject(); + kfree(tunables); common_tunables = NULL; } @@ -1209,6 +1236,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, ktime_to_us(ktime_get()); pcpu->hispeed_validate_time = pcpu->floor_validate_time; + pcpu->max_freq = policy->max; down_write(&pcpu->enable_sem); del_timer_sync(&pcpu->cpu_timer); del_timer_sync(&pcpu->cpu_slack_timer); @@ -1244,29 +1272,37 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, for_each_cpu(j, policy->cpus) { pcpu = &per_cpu(cpuinfo, j); - /* hold write semaphore to avoid race */ - down_write(&pcpu->enable_sem); + down_read(&pcpu->enable_sem); if (pcpu->governor_enabled == 0) { - up_write(&pcpu->enable_sem); + up_read(&pcpu->enable_sem); continue; } - /* update target_freq firstly */ + spin_lock_irqsave(&pcpu->target_freq_lock, flags); if (policy->max < pcpu->target_freq) pcpu->target_freq = policy->max; else if (policy->min > pcpu->target_freq) pcpu->target_freq = policy->min; - /* Reschedule timer. + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags); + up_read(&pcpu->enable_sem); + + /* Reschedule timer only if policy->max is raised. * Delete the timers, else the timer callback may * return without re-arm the timer when failed * acquire the semaphore. This race may cause timer * stopped unexpectedly. */ - del_timer_sync(&pcpu->cpu_timer); - del_timer_sync(&pcpu->cpu_slack_timer); - cpufreq_interactive_timer_start(tunables, j); - up_write(&pcpu->enable_sem); + + if (policy->max > pcpu->max_freq) { + down_write(&pcpu->enable_sem); + del_timer_sync(&pcpu->cpu_timer); + del_timer_sync(&pcpu->cpu_slack_timer); + cpufreq_interactive_timer_start(tunables, j); + up_write(&pcpu->enable_sem); + } + + pcpu->max_freq = policy->max; } break; } @@ -1302,6 +1338,7 @@ static int __init cpufreq_interactive_init(void) init_timer(&pcpu->cpu_slack_timer); pcpu->cpu_slack_timer.function = cpufreq_interactive_nop_timer; spin_lock_init(&pcpu->load_lock); + spin_lock_init(&pcpu->target_freq_lock); init_rwsem(&pcpu->enable_sem); } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 5793e1447fb1..d3eafcb25b59 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -13,6 +13,7 @@ #include <linux/cpufreq.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/sort.h> #include <asm/cputime.h> static spinlock_t cpufreq_stats_lock; @@ -31,6 +32,20 @@ struct cpufreq_stats { #endif }; +struct all_cpufreq_stats { + unsigned int state_num; + cputime64_t *time_in_state; + unsigned int *freq_table; +}; + +struct all_freq_table { + unsigned int *freq_table; + unsigned int table_size; +}; + +static struct all_freq_table *all_freq_table; + +static DEFINE_PER_CPU(struct all_cpufreq_stats *, all_cpufreq_stats); static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); struct cpufreq_stats_attribute { @@ -41,14 +56,24 @@ struct cpufreq_stats_attribute { static int cpufreq_stats_update(unsigned int cpu) { struct cpufreq_stats *stat; + struct all_cpufreq_stats *all_stat; unsigned long long cur_time; cur_time = get_jiffies_64(); spin_lock(&cpufreq_stats_lock); stat = per_cpu(cpufreq_stats_table, cpu); - if (stat->time_in_state) + all_stat = per_cpu(all_cpufreq_stats, cpu); + if (!stat) { + spin_unlock(&cpufreq_stats_lock); + return 0; + } + if (stat->time_in_state) { stat->time_in_state[stat->last_index] += cur_time - stat->last_time; + if (all_stat) + all_stat->time_in_state[stat->last_index] += + cur_time - stat->last_time; + } stat->last_time = cur_time; spin_unlock(&cpufreq_stats_lock); return 0; @@ -79,6 +104,62 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) return len; } +static int get_index_all_cpufreq_stat(struct all_cpufreq_stats *all_stat, + unsigned int freq) +{ + int i; + if (!all_stat) + return -1; + for (i = 0; i < all_stat->state_num; i++) { + if (all_stat->freq_table[i] == freq) + return i; + } + return -1; +} + +static ssize_t show_all_time_in_state(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + ssize_t len = 0; + unsigned int i, cpu, freq, index; + struct all_cpufreq_stats *all_stat; + struct cpufreq_policy *policy; + + len += scnprintf(buf + len, PAGE_SIZE - len, "freq\t\t"); + for_each_possible_cpu(cpu) { + len += scnprintf(buf + len, PAGE_SIZE - len, "cpu%d\t\t", cpu); + if (cpu_online(cpu)) + cpufreq_stats_update(cpu); + } + + if (!all_freq_table) + goto out; + for (i = 0; i < all_freq_table->table_size; i++) { + freq = all_freq_table->freq_table[i]; + len += scnprintf(buf + len, PAGE_SIZE - len, "\n%u\t\t", freq); + for_each_possible_cpu(cpu) { + policy = cpufreq_cpu_get(cpu); + if (policy == NULL) + continue; + all_stat = per_cpu(all_cpufreq_stats, policy->cpu); + index = get_index_all_cpufreq_stat(all_stat, freq); + if (index != -1) { + len += scnprintf(buf + len, PAGE_SIZE - len, + "%llu\t\t", (unsigned long long) + cputime64_to_clock_t(all_stat->time_in_state[index])); + } else { + len += scnprintf(buf + len, PAGE_SIZE - len, + "N/A\t\t"); + } + cpufreq_cpu_put(policy); + } + } + +out: + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} + #ifdef CONFIG_CPU_FREQ_STAT_DETAILS static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) { @@ -142,6 +223,9 @@ static struct attribute_group stats_attr_group = { .name = "stats" }; +static struct kobj_attribute _attr_all_time_in_state = __ATTR(all_time_in_state, + 0444, show_all_time_in_state, NULL); + static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) { int index; @@ -180,6 +264,29 @@ static void cpufreq_stats_free_table(unsigned int cpu) cpufreq_cpu_put(policy); } +static void cpufreq_allstats_free(void) +{ + int cpu; + struct all_cpufreq_stats *all_stat; + + sysfs_remove_file(cpufreq_global_kobject, + &_attr_all_time_in_state.attr); + + for_each_possible_cpu(cpu) { + all_stat = per_cpu(all_cpufreq_stats, cpu); + if (!all_stat) + continue; + kfree(all_stat->time_in_state); + kfree(all_stat); + per_cpu(all_cpufreq_stats, cpu) = NULL; + } + if (all_freq_table) { + kfree(all_freq_table->freq_table); + kfree(all_freq_table); + all_freq_table = NULL; + } +} + static int __cpufreq_stats_create_table(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { @@ -286,6 +393,106 @@ static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) stat->cpu = policy->cpu; } +static int compare_for_sort(const void *lhs_ptr, const void *rhs_ptr) +{ + unsigned int lhs = *(const unsigned int *)(lhs_ptr); + unsigned int rhs = *(const unsigned int *)(rhs_ptr); + if (lhs < rhs) + return -1; + if (lhs > rhs) + return 1; + return 0; +} + +static bool check_all_freq_table(unsigned int freq) +{ + int i; + for (i = 0; i < all_freq_table->table_size; i++) { + if (freq == all_freq_table->freq_table[i]) + return true; + } + return false; +} + +static void create_all_freq_table(void) +{ + all_freq_table = kzalloc(sizeof(struct all_freq_table), + GFP_KERNEL); + if (!all_freq_table) + pr_warn("could not allocate memory for all_freq_table\n"); + return; +} + +static void add_all_freq_table(unsigned int freq) +{ + unsigned int size; + size = sizeof(unsigned int) * (all_freq_table->table_size + 1); + all_freq_table->freq_table = krealloc(all_freq_table->freq_table, + size, GFP_ATOMIC); + if (IS_ERR(all_freq_table->freq_table)) { + pr_warn("Could not reallocate memory for freq_table\n"); + all_freq_table->freq_table = NULL; + return; + } + all_freq_table->freq_table[all_freq_table->table_size++] = freq; +} + +static void cpufreq_allstats_create(unsigned int cpu) +{ + int i , j = 0; + unsigned int alloc_size, count = 0; + struct cpufreq_frequency_table *table = cpufreq_frequency_get_table(cpu); + struct all_cpufreq_stats *all_stat; + bool sort_needed = false; + + if (!table) + return; + + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + unsigned int freq = table[i].frequency; + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + count++; + } + + all_stat = kzalloc(sizeof(struct all_cpufreq_stats), + GFP_KERNEL); + if (!all_stat) { + pr_warn("Cannot allocate memory for cpufreq stats\n"); + return; + } + + /*Allocate memory for freq table per cpu as well as clockticks per freq*/ + alloc_size = count * sizeof(int) + count * sizeof(cputime64_t); + all_stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL); + if (!all_stat->time_in_state) { + pr_warn("Cannot allocate memory for cpufreq time_in_state\n"); + kfree(all_stat); + all_stat = NULL; + return; + } + all_stat->freq_table = (unsigned int *) + (all_stat->time_in_state + count); + + spin_lock(&cpufreq_stats_lock); + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + unsigned int freq = table[i].frequency; + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + all_stat->freq_table[j++] = freq; + if (all_freq_table && !check_all_freq_table(freq)) { + add_all_freq_table(freq); + sort_needed = true; + } + } + if (sort_needed) + sort(all_freq_table->freq_table, all_freq_table->table_size, + sizeof(unsigned int), &compare_for_sort, NULL); + all_stat->state_num = j; + per_cpu(all_cpufreq_stats, cpu) = all_stat; + spin_unlock(&cpufreq_stats_lock); +} + static int cpufreq_stat_notifier_policy(struct notifier_block *nb, unsigned long val, void *data) { @@ -303,6 +510,9 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, if (!table) return 0; + if (!per_cpu(all_cpufreq_stats, cpu)) + cpufreq_allstats_create(cpu); + if (val == CPUFREQ_CREATE_POLICY) ret = __cpufreq_stats_create_table(policy, table); else if (val == CPUFREQ_REMOVE_POLICY) @@ -379,6 +589,13 @@ static int __init cpufreq_stats_init(void) return ret; } + create_all_freq_table(); + WARN_ON(cpufreq_get_global_kobject()); + ret = sysfs_create_file(cpufreq_global_kobject, + &_attr_all_time_in_state.attr); + if (ret) + pr_warn("Error creating sysfs file for cpufreq stats\n"); + return 0; } static void __exit cpufreq_stats_exit(void) @@ -391,6 +608,8 @@ static void __exit cpufreq_stats_exit(void) CPUFREQ_TRANSITION_NOTIFIER); for_each_online_cpu(cpu) cpufreq_stats_free_table(cpu); + cpufreq_allstats_free(); + cpufreq_put_global_kobject(); } MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>"); diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 53b771d5683c..941ab3c287ec 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -855,6 +855,16 @@ static const char *keys[KEY_MAX + 1] = { [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", [KEY_KBDILLUMUP] = "KbdIlluminationUp", [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", + [KEY_BUTTONCONFIG] = "ButtonConfig", + [KEY_TASKMANAGER] = "TaskManager", + [KEY_JOURNAL] = "Journal", + [KEY_CONTROLPANEL] = "ControlPanel", + [KEY_APPSELECT] = "AppSelect", + [KEY_SCREENSAVER] = "ScreenSaver", + [KEY_VOICECOMMAND] = "VoiceCommand", + [KEY_BRIGHTNESS_MIN] = "BrightnessMin", + [KEY_BRIGHTNESS_MAX] = "BrightnessMax", + [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto", }; static const char *relatives[REL_MAX + 1] = { diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index edf215490b6c..679abc0d2dfa 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -724,6 +724,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x06c: map_key_clear(KEY_YELLOW); break; case 0x06d: map_key_clear(KEY_ZOOM); break; + case 0x06f: map_key_clear(KEY_BRIGHTNESSUP); break; + case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN); break; + case 0x072: map_key_clear(KEY_BRIGHTNESS_TOGGLE); break; + case 0x073: map_key_clear(KEY_BRIGHTNESS_MIN); break; + case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX); break; + case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO); break; + case 0x082: map_key_clear(KEY_VIDEO_NEXT); break; case 0x083: map_key_clear(KEY_LAST); break; case 0x084: map_key_clear(KEY_ENTER); break; @@ -764,6 +771,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0bf: map_key_clear(KEY_SLOW); break; case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; + case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break; case 0x0e0: map_abs_clear(ABS_VOLUME); break; case 0x0e2: map_key_clear(KEY_MUTE); break; case 0x0e5: map_key_clear(KEY_BASSBOOST); break; @@ -771,6 +779,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; case 0x0f5: map_key_clear(KEY_SLOW); break; + case 0x181: map_key_clear(KEY_BUTTONCONFIG); break; case 0x182: map_key_clear(KEY_BOOKMARKS); break; case 0x183: map_key_clear(KEY_CONFIG); break; case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; @@ -784,6 +793,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x18c: map_key_clear(KEY_VOICEMAIL); break; case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break; case 0x18e: map_key_clear(KEY_CALENDAR); break; + case 0x18f: map_key_clear(KEY_TASKMANAGER); break; + case 0x190: map_key_clear(KEY_JOURNAL); break; case 0x191: map_key_clear(KEY_FINANCE); break; case 0x192: map_key_clear(KEY_CALC); break; case 0x193: map_key_clear(KEY_PLAYER); break; @@ -792,10 +803,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x199: map_key_clear(KEY_CHAT); break; case 0x19c: map_key_clear(KEY_LOGOFF); break; case 0x19e: map_key_clear(KEY_COFFEE); break; + case 0x19f: map_key_clear(KEY_CONTROLPANEL); break; + case 0x1a2: map_key_clear(KEY_APPSELECT); break; + case 0x1a3: map_key_clear(KEY_NEXT); break; + case 0x1a4: map_key_clear(KEY_PREVIOUS); break; case 0x1a6: map_key_clear(KEY_HELP); break; case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; case 0x1ae: map_key_clear(KEY_KEYBOARD); break; + case 0x1b1: map_key_clear(KEY_SCREENSAVER); break; + case 0x1b4: map_key_clear(KEY_FILE); break; case 0x1b6: map_key_clear(KEY_IMAGES); break; case 0x1b7: map_key_clear(KEY_AUDIO); break; case 0x1b8: map_key_clear(KEY_VIDEO); break; diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c index 29f328f411fb..8060650dcfe5 100644 --- a/drivers/hid/hid-steelseries.c +++ b/drivers/hid/hid-steelseries.c @@ -254,6 +254,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev, goto err_free; } + if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) { + ret = -ENODEV; + goto err_free; + } + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { hid_err(hdev, "hw start failed\n"); diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 9c13b63ef915..518efa2a9f52 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -177,12 +177,22 @@ config INPUT_APMPOWER config INPUT_KEYRESET tristate "Reset key" depends on INPUT + select INPUT_KEYCOMBO ---help--- Say Y here if you want to reboot when some keys are pressed; To compile this driver as a module, choose M here: the module will be called keyreset. +config INPUT_KEYCOMBO + tristate "Key combo" + depends on INPUT + ---help--- + Say Y here if you want to take action when some keys are pressed; + + To compile this driver as a module, choose M here: the + module will be called keycombo. + comment "Input Device Drivers" source "drivers/input/keyboard/Kconfig" diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 191ea43d0800..ee4c06520bb4 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -26,3 +26,5 @@ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o +obj-$(CONFIG_INPUT_KEYCOMBO) += keycombo.o + diff --git a/drivers/input/keycombo.c b/drivers/input/keycombo.c new file mode 100644 index 000000000000..2fba451b91d5 --- /dev/null +++ b/drivers/input/keycombo.c @@ -0,0 +1,261 @@ +/* drivers/input/keycombo.c + * + * Copyright (C) 2014 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/input.h> +#include <linux/keycombo.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/sched.h> +#include <linux/slab.h> + +struct keycombo_state { + struct input_handler input_handler; + unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; + spinlock_t lock; + struct workqueue_struct *wq; + int key_down_target; + int key_down; + int key_up; + struct delayed_work key_down_work; + int delay; + struct work_struct key_up_work; + void (*key_up_fn)(void *); + void (*key_down_fn)(void *); + void *priv; + int key_is_down; + struct wakeup_source combo_held_wake_source; + struct wakeup_source combo_up_wake_source; +}; + +static void do_key_down(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work, struct delayed_work, + work); + struct keycombo_state *state = container_of(dwork, + struct keycombo_state, key_down_work); + if (state->key_down_fn) + state->key_down_fn(state->priv); +} + +static void do_key_up(struct work_struct *work) +{ + struct keycombo_state *state = container_of(work, struct keycombo_state, + key_up_work); + if (state->key_up_fn) + state->key_up_fn(state->priv); + __pm_relax(&state->combo_up_wake_source); +} + +static void keycombo_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + unsigned long flags; + struct keycombo_state *state = handle->private; + + if (type != EV_KEY) + return; + + if (code >= KEY_MAX) + return; + + if (!test_bit(code, state->keybit)) + return; + + spin_lock_irqsave(&state->lock, flags); + if (!test_bit(code, state->key) == !value) + goto done; + __change_bit(code, state->key); + if (test_bit(code, state->upbit)) { + if (value) + state->key_up++; + else + state->key_up--; + } else { + if (value) + state->key_down++; + else + state->key_down--; + } + if (state->key_down == state->key_down_target && state->key_up == 0) { + __pm_stay_awake(&state->combo_held_wake_source); + state->key_is_down = 1; + if (queue_delayed_work(state->wq, &state->key_down_work, + state->delay)) + pr_debug("Key down work already queued!"); + } else if (state->key_is_down) { + if (!cancel_delayed_work(&state->key_down_work)) { + __pm_stay_awake(&state->combo_up_wake_source); + queue_work(state->wq, &state->key_up_work); + } + __pm_relax(&state->combo_held_wake_source); + state->key_is_down = 0; + } +done: + spin_unlock_irqrestore(&state->lock, flags); +} + +static int keycombo_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) +{ + int i; + int ret; + struct input_handle *handle; + struct keycombo_state *state = + container_of(handler, struct keycombo_state, input_handler); + for (i = 0; i < KEY_MAX; i++) { + if (test_bit(i, state->keybit) && test_bit(i, dev->keybit)) + break; + } + if (i == KEY_MAX) + return -ENODEV; + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = KEYCOMBO_NAME; + handle->private = state; + + ret = input_register_handle(handle); + if (ret) + goto err_input_register_handle; + + ret = input_open_device(handle); + if (ret) + goto err_input_open_device; + + return 0; + +err_input_open_device: + input_unregister_handle(handle); +err_input_register_handle: + kfree(handle); + return ret; +} + +static void keycombo_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id keycombo_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, + { }, +}; +MODULE_DEVICE_TABLE(input, keycombo_ids); + +static int keycombo_probe(struct platform_device *pdev) +{ + int ret; + int key, *keyp; + struct keycombo_state *state; + struct keycombo_platform_data *pdata = pdev->dev.platform_data; + + if (!pdata) + return -EINVAL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + spin_lock_init(&state->lock); + keyp = pdata->keys_down; + while ((key = *keyp++)) { + if (key >= KEY_MAX) + continue; + state->key_down_target++; + __set_bit(key, state->keybit); + } + if (pdata->keys_up) { + keyp = pdata->keys_up; + while ((key = *keyp++)) { + if (key >= KEY_MAX) + continue; + __set_bit(key, state->keybit); + __set_bit(key, state->upbit); + } + } + + state->wq = alloc_ordered_workqueue("keycombo", 0); + if (!state->wq) + return -ENOMEM; + + state->priv = pdata->priv; + + if (pdata->key_down_fn) + state->key_down_fn = pdata->key_down_fn; + INIT_DELAYED_WORK(&state->key_down_work, do_key_down); + + if (pdata->key_up_fn) + state->key_up_fn = pdata->key_up_fn; + INIT_WORK(&state->key_up_work, do_key_up); + + wakeup_source_init(&state->combo_held_wake_source, "key combo"); + wakeup_source_init(&state->combo_up_wake_source, "key combo up"); + state->delay = msecs_to_jiffies(pdata->key_down_delay); + + state->input_handler.event = keycombo_event; + state->input_handler.connect = keycombo_connect; + state->input_handler.disconnect = keycombo_disconnect; + state->input_handler.name = KEYCOMBO_NAME; + state->input_handler.id_table = keycombo_ids; + ret = input_register_handler(&state->input_handler); + if (ret) { + kfree(state); + return ret; + } + platform_set_drvdata(pdev, state); + return 0; +} + +int keycombo_remove(struct platform_device *pdev) +{ + struct keycombo_state *state = platform_get_drvdata(pdev); + input_unregister_handler(&state->input_handler); + destroy_workqueue(state->wq); + kfree(state); + return 0; +} + + +struct platform_driver keycombo_driver = { + .driver.name = KEYCOMBO_NAME, + .probe = keycombo_probe, + .remove = keycombo_remove, +}; + +static int __init keycombo_init(void) +{ + return platform_driver_register(&keycombo_driver); +} + +static void __exit keycombo_exit(void) +{ + return platform_driver_unregister(&keycombo_driver); +} + +module_init(keycombo_init); +module_exit(keycombo_exit); diff --git a/drivers/input/keyreset.c b/drivers/input/keyreset.c index 36208fe0baae..7fbf7247e65f 100644 --- a/drivers/input/keyreset.c +++ b/drivers/input/keyreset.c @@ -1,6 +1,6 @@ /* drivers/input/keyreset.c * - * Copyright (C) 2008 Google, Inc. + * Copyright (C) 2014 Google, Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -21,200 +21,106 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/syscalls.h> - +#include <linux/keycombo.h> struct keyreset_state { - struct input_handler input_handler; - unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; - unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; - unsigned long key[BITS_TO_LONGS(KEY_CNT)]; - spinlock_t lock; - int key_down_target; - int key_down; - int key_up; - int restart_disabled; + int restart_requested; int (*reset_fn)(void); + struct platform_device *pdev_child; + struct work_struct restart_work; }; -int restart_requested; -static void deferred_restart(struct work_struct *dummy) +static void do_restart(struct work_struct *unused) { - restart_requested = 2; sys_sync(); - restart_requested = 3; kernel_restart(NULL); } -static DECLARE_WORK(restart_work, deferred_restart); -static void keyreset_event(struct input_handle *handle, unsigned int type, - unsigned int code, int value) +static void do_reset_fn(void *priv) { - unsigned long flags; - struct keyreset_state *state = handle->private; - - if (type != EV_KEY) - return; - - if (code >= KEY_MAX) - return; - - if (!test_bit(code, state->keybit)) - return; - - spin_lock_irqsave(&state->lock, flags); - if (!test_bit(code, state->key) == !value) - goto done; - __change_bit(code, state->key); - if (test_bit(code, state->upbit)) { - if (value) { - state->restart_disabled = 1; - state->key_up++; - } else - state->key_up--; + struct keyreset_state *state = priv; + if (state->restart_requested) + panic("keyboard reset failed, %d", state->restart_requested); + if (state->reset_fn) { + state->restart_requested = state->reset_fn(); } else { - if (value) - state->key_down++; - else - state->key_down--; + pr_info("keyboard reset\n"); + schedule_work(&state->restart_work); + state->restart_requested = 1; } - if (state->key_down == 0 && state->key_up == 0) - state->restart_disabled = 0; - - pr_debug("reset key changed %d %d new state %d-%d-%d\n", code, value, - state->key_down, state->key_up, state->restart_disabled); - - if (value && !state->restart_disabled && - state->key_down == state->key_down_target) { - state->restart_disabled = 1; - if (restart_requested) - panic("keyboard reset failed, %d", restart_requested); - if (state->reset_fn) { - restart_requested = state->reset_fn(); - } else { - pr_info("keyboard reset\n"); - schedule_work(&restart_work); - restart_requested = 1; - } - } -done: - spin_unlock_irqrestore(&state->lock, flags); } -static int keyreset_connect(struct input_handler *handler, - struct input_dev *dev, - const struct input_device_id *id) -{ - int i; - int ret; - struct input_handle *handle; - struct keyreset_state *state = - container_of(handler, struct keyreset_state, input_handler); - - for (i = 0; i < KEY_MAX; i++) { - if (test_bit(i, state->keybit) && test_bit(i, dev->keybit)) - break; - } - if (i == KEY_MAX) - return -ENODEV; - - handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; - - handle->dev = dev; - handle->handler = handler; - handle->name = "keyreset"; - handle->private = state; - - ret = input_register_handle(handle); - if (ret) - goto err_input_register_handle; - - ret = input_open_device(handle); - if (ret) - goto err_input_open_device; - - pr_info("using input dev %s for key reset\n", dev->name); - - return 0; - -err_input_open_device: - input_unregister_handle(handle); -err_input_register_handle: - kfree(handle); - return ret; -} - -static void keyreset_disconnect(struct input_handle *handle) -{ - input_close_device(handle); - input_unregister_handle(handle); - kfree(handle); -} - -static const struct input_device_id keyreset_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_KEY) }, - }, - { }, -}; -MODULE_DEVICE_TABLE(input, keyreset_ids); - static int keyreset_probe(struct platform_device *pdev) { - int ret; + int ret = -ENOMEM; + struct keycombo_platform_data *pdata_child; + struct keyreset_platform_data *pdata = pdev->dev.platform_data; + int up_size = 0, down_size = 0, size; int key, *keyp; struct keyreset_state *state; - struct keyreset_platform_data *pdata = pdev->dev.platform_data; if (!pdata) return -EINVAL; - - state = kzalloc(sizeof(*state), GFP_KERNEL); + state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; - spin_lock_init(&state->lock); + state->pdev_child = platform_device_alloc(KEYCOMBO_NAME, + PLATFORM_DEVID_AUTO); + if (!state->pdev_child) + return -ENOMEM; + state->pdev_child->dev.parent = &pdev->dev; + INIT_WORK(&state->restart_work, do_restart); + keyp = pdata->keys_down; while ((key = *keyp++)) { if (key >= KEY_MAX) continue; - state->key_down_target++; - __set_bit(key, state->keybit); + down_size++; } if (pdata->keys_up) { keyp = pdata->keys_up; while ((key = *keyp++)) { if (key >= KEY_MAX) continue; - __set_bit(key, state->keybit); - __set_bit(key, state->upbit); + up_size++; } } - - if (pdata->reset_fn) - state->reset_fn = pdata->reset_fn; - - state->input_handler.event = keyreset_event; - state->input_handler.connect = keyreset_connect; - state->input_handler.disconnect = keyreset_disconnect; - state->input_handler.name = KEYRESET_NAME; - state->input_handler.id_table = keyreset_ids; - ret = input_register_handler(&state->input_handler); - if (ret) { - kfree(state); - return ret; + size = sizeof(struct keycombo_platform_data) + + sizeof(int) * (down_size + 1); + pdata_child = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!pdata_child) + goto error; + memcpy(pdata_child->keys_down, pdata->keys_down, + sizeof(int) * down_size); + if (up_size > 0) { + pdata_child->keys_up = devm_kzalloc(&pdev->dev, up_size + 1, + GFP_KERNEL); + if (!pdata_child->keys_up) + goto error; + memcpy(pdata_child->keys_up, pdata->keys_up, + sizeof(int) * up_size); + if (!pdata_child->keys_up) + goto error; } + state->reset_fn = pdata->reset_fn; + pdata_child->key_down_fn = do_reset_fn; + pdata_child->priv = state; + pdata_child->key_down_delay = pdata->key_down_delay; + ret = platform_device_add_data(state->pdev_child, pdata_child, size); + if (ret) + goto error; platform_set_drvdata(pdev, state); - return 0; + return platform_device_add(state->pdev_child); +error: + platform_device_put(state->pdev_child); + return ret; } int keyreset_remove(struct platform_device *pdev) { struct keyreset_state *state = platform_get_drvdata(pdev); - input_unregister_handler(&state->input_handler); - kfree(state); + platform_device_put(state->pdev_child); return 0; } diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 024b8f99d480..29a45ac2786d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -763,36 +763,66 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, return 0; } +/* + * Convert configs to something easy to use in C code + */ +#if defined(CONFIG_CMDLINE_FORCE) +static const int overwrite_incoming_cmdline = 1; +static const int read_dt_cmdline; +static const int concat_cmdline; +#elif defined(CONFIG_CMDLINE_EXTEND) +static const int overwrite_incoming_cmdline; +static const int read_dt_cmdline = 1; +static const int concat_cmdline = 1; +#else /* CMDLINE_FROM_BOOTLOADER */ +static const int overwrite_incoming_cmdline; +static const int read_dt_cmdline = 1; +static const int concat_cmdline; +#endif + +#ifdef CONFIG_CMDLINE +static const char *config_cmdline = CONFIG_CMDLINE; +#else +static const char *config_cmdline = ""; +#endif + int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { - int l; - const char *p; + int l = 0; + char *p = NULL; + char *cmdline = data; pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); - if (depth != 1 || !data || + if (depth != 1 || !cmdline || (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) return 0; early_init_dt_check_for_initrd(node); - /* Retrieve command line */ - p = of_get_flat_dt_prop(node, "bootargs", &l); - if (p != NULL && l > 0) - strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); - - /* - * CONFIG_CMDLINE is meant to be a default in case nothing else - * managed to set the command line, unless CONFIG_CMDLINE_FORCE - * is set in which case we override whatever was found earlier. - */ -#ifdef CONFIG_CMDLINE -#ifndef CONFIG_CMDLINE_FORCE - if (!((char *)data)[0]) -#endif - strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); -#endif /* CONFIG_CMDLINE */ + /* Put CONFIG_CMDLINE in if forced or if data had nothing in it to start */ + if (overwrite_incoming_cmdline || !cmdline[0]) + strlcpy(cmdline, config_cmdline, COMMAND_LINE_SIZE); + + /* Retrieve command line unless forcing */ + if (read_dt_cmdline) + p = of_get_flat_dt_prop(node, "bootargs", &l); + + if (p != NULL && l > 0) { + if (concat_cmdline) { + int cmdline_len; + int copy_len; + strlcat(cmdline, " ", COMMAND_LINE_SIZE); + cmdline_len = strlen(cmdline); + copy_len = COMMAND_LINE_SIZE - cmdline_len - 1; + copy_len = min((int)l, copy_len); + strncpy(cmdline + cmdline_len, p, copy_len); + cmdline[cmdline_len + copy_len] = '\0'; + } else { + strlcpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE)); + } + } pr_debug("Command line is: %s\n", (char*)data); diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 7566e15701e5..6650f8fe548c 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -105,7 +105,10 @@ static ssize_t power_supply_show_property(struct device *dev, else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) return sprintf(buf, "%s\n", value.strval); - return sprintf(buf, "%d\n", value.intval); + if (off == POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT) + return sprintf(buf, "%lld\n", value.int64val); + else + return sprintf(buf, "%d\n", value.intval); } static ssize_t power_supply_store_property(struct device *dev, @@ -193,6 +196,8 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(usb_hc), POWER_SUPPLY_ATTR(usb_otg), POWER_SUPPLY_ATTR(charge_enabled), + /* Local extensions of type int64_t */ + POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ POWER_SUPPLY_ATTR(model_name), POWER_SUPPLY_ATTR(manufacturer), diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 511883e1789b..b7a71ad325af 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -119,6 +119,8 @@ config SW_SYNC_USER source "drivers/staging/android/ion/Kconfig" +source "drivers/staging/android/fiq_debugger/Kconfig" + endif # if ANDROID endmenu diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 0a01e1914905..907b62f56203 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -1,6 +1,7 @@ ccflags-y += -I$(src) # needed for trace events obj-y += ion/ +obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger/ obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o obj-$(CONFIG_ASHMEM) += ashmem.o diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 5a26e7c5ab5e..5465fa7cdaad 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -433,7 +433,9 @@ ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) if (!(sc->gfp_mask & __GFP_FS)) return SHRINK_STOP; - mutex_lock(&ashmem_mutex); + if (!mutex_trylock(&ashmem_mutex)) + return -1; + list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) { loff_t start = range->pgstart * PAGE_SIZE; loff_t end = (range->pgend + 1) * PAGE_SIZE; diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index f66abb0c8943..6f116e48b6ef 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -26,6 +26,7 @@ #include <linux/miscdevice.h> #include <linux/mm.h> #include <linux/module.h> +#include <linux/rtmutex.h> #include <linux/mutex.h> #include <linux/nsproxy.h> #include <linux/poll.h> @@ -42,7 +43,7 @@ #include "binder.h" #include "binder_trace.h" -static DEFINE_MUTEX(binder_main_lock); +static DEFINE_RT_MUTEX(binder_main_lock); static DEFINE_MUTEX(binder_deferred_lock); static DEFINE_MUTEX(binder_mmap_lock); @@ -420,14 +421,14 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) static inline void binder_lock(const char *tag) { trace_binder_lock(tag); - mutex_lock(&binder_main_lock); + rt_mutex_lock(&binder_main_lock); trace_binder_locked(tag); } static inline void binder_unlock(const char *tag) { trace_binder_unlock(tag); - mutex_unlock(&binder_main_lock); + rt_mutex_unlock(&binder_main_lock); } static void binder_set_nice(long nice) diff --git a/drivers/staging/android/fiq_debugger/Kconfig b/drivers/staging/android/fiq_debugger/Kconfig new file mode 100644 index 000000000000..56f7f999377e --- /dev/null +++ b/drivers/staging/android/fiq_debugger/Kconfig @@ -0,0 +1,49 @@ +config FIQ_DEBUGGER + bool "FIQ Mode Serial Debugger" + default n + depends on ARM || ARM64 + help + The FIQ serial debugger can accept commands even when the + kernel is unresponsive due to being stuck with interrupts + disabled. + +config FIQ_DEBUGGER_NO_SLEEP + bool "Keep serial debugger active" + depends on FIQ_DEBUGGER + default n + help + Enables the serial debugger at boot. Passing + fiq_debugger.no_sleep on the kernel commandline will + override this config option. + +config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON + bool "Don't disable wakeup IRQ when debugger is active" + depends on FIQ_DEBUGGER + default n + help + Don't disable the wakeup irq when enabling the uart clock. This will + cause extra interrupts, but it makes the serial debugger usable with + on some MSM radio builds that ignore the uart clock request in power + collapse. + +config FIQ_DEBUGGER_CONSOLE + bool "Console on FIQ Serial Debugger port" + depends on FIQ_DEBUGGER + default n + help + Enables a console so that printk messages are displayed on + the debugger serial port as the occur. + +config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE + bool "Put the FIQ debugger into console mode by default" + depends on FIQ_DEBUGGER_CONSOLE + default n + help + If enabled, this puts the fiq debugger into console mode by default. + Otherwise, the fiq debugger will start out in debug mode. + +config FIQ_WATCHDOG + bool + select FIQ_DEBUGGER + select PSTORE_RAM + default n diff --git a/drivers/staging/android/fiq_debugger/Makefile b/drivers/staging/android/fiq_debugger/Makefile new file mode 100644 index 000000000000..a7ca4871cad3 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/Makefile @@ -0,0 +1,4 @@ +obj-y += fiq_debugger.o +obj-$(CONFIG_ARM) += fiq_debugger_arm.o +obj-$(CONFIG_ARM64) += fiq_debugger_arm64.o +obj-$(CONFIG_FIQ_WATCHDOG) += fiq_watchdog.o diff --git a/arch/arm/common/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c index 65b943c76300..7d6b4ae8a2cd 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c @@ -1,5 +1,5 @@ /* - * arch/arm/common/fiq_debugger.c + * drivers/staging/android/fiq_debugger.c * * Serial Debugger Interface accessed through an FIQ interrupt. * @@ -35,12 +35,14 @@ #include <linux/tty_flip.h> #include <linux/wakelock.h> -#include <asm/fiq_debugger.h> +#ifdef CONFIG_FIQ_GLUE #include <asm/fiq_glue.h> -#include <asm/stacktrace.h> +#endif #include <linux/uaccess.h> +#include "fiq_debugger.h" +#include "fiq_debugger_priv.h" #include "fiq_debugger_ringbuf.h" #define DEBUG_MAX 64 @@ -48,11 +50,11 @@ #define MAX_FIQ_DEBUGGER_PORTS 4 -#define THREAD_INFO(sp) ((struct thread_info *) \ - ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) - struct fiq_debugger_state { +#ifdef CONFIG_FIQ_GLUE struct fiq_glue_handler handler; +#endif + struct fiq_debugger_output output; int fiq; int uart_irq; @@ -124,10 +126,13 @@ module_param_named(console_enable, initial_console_enable, bool, 0644); module_param_named(kgdb_enable, fiq_kgdb_enable, bool, 0644); #ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON -static inline void enable_wakeup_irq(struct fiq_debugger_state *state) {} -static inline void disable_wakeup_irq(struct fiq_debugger_state *state) {} +static inline +void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state) {} +static inline +void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state) {} #else -static inline void enable_wakeup_irq(struct fiq_debugger_state *state) +static inline +void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state) { if (state->wakeup_irq < 0) return; @@ -135,7 +140,8 @@ static inline void enable_wakeup_irq(struct fiq_debugger_state *state) if (!state->wakeup_irq_no_set_wake) enable_irq_wake(state->wakeup_irq); } -static inline void disable_wakeup_irq(struct fiq_debugger_state *state) +static inline +void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state) { if (state->wakeup_irq < 0) return; @@ -145,16 +151,17 @@ static inline void disable_wakeup_irq(struct fiq_debugger_state *state) } #endif -static bool inline debug_have_fiq(struct fiq_debugger_state *state) +static inline bool fiq_debugger_have_fiq(struct fiq_debugger_state *state) { return (state->fiq >= 0); } -static void debug_force_irq(struct fiq_debugger_state *state) +#ifdef CONFIG_FIQ_GLUE +static void fiq_debugger_force_irq(struct fiq_debugger_state *state) { unsigned int irq = state->signal_irq; - if (WARN_ON(!debug_have_fiq(state))) + if (WARN_ON(!fiq_debugger_have_fiq(state))) return; if (state->pdata->force_irq) { state->pdata->force_irq(state->pdev, irq); @@ -164,8 +171,9 @@ static void debug_force_irq(struct fiq_debugger_state *state) chip->irq_retrigger(irq_get_irq_data(irq)); } } +#endif -static void debug_uart_enable(struct fiq_debugger_state *state) +static void fiq_debugger_uart_enable(struct fiq_debugger_state *state) { if (state->clk) clk_enable(state->clk); @@ -173,7 +181,7 @@ static void debug_uart_enable(struct fiq_debugger_state *state) state->pdata->uart_enable(state->pdev); } -static void debug_uart_disable(struct fiq_debugger_state *state) +static void fiq_debugger_uart_disable(struct fiq_debugger_state *state) { if (state->pdata->uart_disable) state->pdata->uart_disable(state->pdev); @@ -181,33 +189,33 @@ static void debug_uart_disable(struct fiq_debugger_state *state) clk_disable(state->clk); } -static void debug_uart_flush(struct fiq_debugger_state *state) +static void fiq_debugger_uart_flush(struct fiq_debugger_state *state) { if (state->pdata->uart_flush) state->pdata->uart_flush(state->pdev); } -static void debug_putc(struct fiq_debugger_state *state, char c) +static void fiq_debugger_putc(struct fiq_debugger_state *state, char c) { state->pdata->uart_putc(state->pdev, c); } -static void debug_puts(struct fiq_debugger_state *state, char *s) +static void fiq_debugger_puts(struct fiq_debugger_state *state, char *s) { unsigned c; while ((c = *s++)) { if (c == '\n') - debug_putc(state, '\r'); - debug_putc(state, c); + fiq_debugger_putc(state, '\r'); + fiq_debugger_putc(state, c); } } -static void debug_prompt(struct fiq_debugger_state *state) +static void fiq_debugger_prompt(struct fiq_debugger_state *state) { - debug_puts(state, "debug> "); + fiq_debugger_puts(state, "debug> "); } -static void dump_kernel_log(struct fiq_debugger_state *state) +static void fiq_debugger_dump_kernel_log(struct fiq_debugger_state *state) { char buf[512]; size_t len; @@ -218,40 +226,27 @@ static void dump_kernel_log(struct fiq_debugger_state *state) while (kmsg_dump_get_line_nolock(&dumper, true, buf, sizeof(buf) - 1, &len)) { buf[len] = 0; - debug_puts(state, buf); + fiq_debugger_puts(state, buf); } } -static char *mode_name(unsigned cpsr) +static void fiq_debugger_printf(struct fiq_debugger_output *output, + const char *fmt, ...) { - switch (cpsr & MODE_MASK) { - case USR_MODE: return "USR"; - case FIQ_MODE: return "FIQ"; - case IRQ_MODE: return "IRQ"; - case SVC_MODE: return "SVC"; - case ABT_MODE: return "ABT"; - case UND_MODE: return "UND"; - case SYSTEM_MODE: return "SYS"; - default: return "???"; - } -} - -static int debug_printf(void *cookie, const char *fmt, ...) -{ - struct fiq_debugger_state *state = cookie; + struct fiq_debugger_state *state; char buf[256]; va_list ap; + state = container_of(output, struct fiq_debugger_state, output); va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - debug_puts(state, buf); - return state->debug_abort; + fiq_debugger_puts(state, buf); } /* Safe outside fiq context */ -static int debug_printf_nfiq(void *cookie, const char *fmt, ...) +static int fiq_debugger_printf_nfiq(void *cookie, const char *fmt, ...) { struct fiq_debugger_state *state = cookie; char buf[256]; @@ -263,115 +258,24 @@ static int debug_printf_nfiq(void *cookie, const char *fmt, ...) va_end(ap); local_irq_save(irq_flags); - debug_puts(state, buf); - debug_uart_flush(state); + fiq_debugger_puts(state, buf); + fiq_debugger_uart_flush(state); local_irq_restore(irq_flags); return state->debug_abort; } -static void dump_regs(struct fiq_debugger_state *state, unsigned *regs) -{ - debug_printf(state, " r0 %08x r1 %08x r2 %08x r3 %08x\n", - regs[0], regs[1], regs[2], regs[3]); - debug_printf(state, " r4 %08x r5 %08x r6 %08x r7 %08x\n", - regs[4], regs[5], regs[6], regs[7]); - debug_printf(state, " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", - regs[8], regs[9], regs[10], regs[11], - mode_name(regs[16])); - if ((regs[16] & MODE_MASK) == USR_MODE) - debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " - "cpsr %08x\n", regs[12], regs[13], regs[14], - regs[15], regs[16]); - else - debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " - "cpsr %08x spsr %08x\n", regs[12], regs[13], - regs[14], regs[15], regs[16], regs[17]); -} - -struct mode_regs { - unsigned long sp_svc; - unsigned long lr_svc; - unsigned long spsr_svc; - - unsigned long sp_abt; - unsigned long lr_abt; - unsigned long spsr_abt; - - unsigned long sp_und; - unsigned long lr_und; - unsigned long spsr_und; - - unsigned long sp_irq; - unsigned long lr_irq; - unsigned long spsr_irq; - - unsigned long r8_fiq; - unsigned long r9_fiq; - unsigned long r10_fiq; - unsigned long r11_fiq; - unsigned long r12_fiq; - unsigned long sp_fiq; - unsigned long lr_fiq; - unsigned long spsr_fiq; -}; - -void __naked get_mode_regs(struct mode_regs *regs) -{ - asm volatile ( - "mrs r1, cpsr\n" - "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r8 - r14}\n" - "mrs r2, spsr\n" - "stmia r0!, {r2}\n" - "msr cpsr_c, r1\n" - "bx lr\n"); -} - - -static void dump_allregs(struct fiq_debugger_state *state, unsigned *regs) -{ - struct mode_regs mode_regs; - dump_regs(state, regs); - get_mode_regs(&mode_regs); - debug_printf(state, " svc: sp %08x lr %08x spsr %08x\n", - mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); - debug_printf(state, " abt: sp %08x lr %08x spsr %08x\n", - mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); - debug_printf(state, " und: sp %08x lr %08x spsr %08x\n", - mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); - debug_printf(state, " irq: sp %08x lr %08x spsr %08x\n", - mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); - debug_printf(state, " fiq: r8 %08x r9 %08x r10 %08x r11 %08x " - "r12 %08x\n", - mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, - mode_regs.r11_fiq, mode_regs.r12_fiq); - debug_printf(state, " fiq: sp %08x lr %08x spsr %08x\n", - mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); -} - -static void dump_irqs(struct fiq_debugger_state *state) +static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state) { int n; struct irq_desc *desc; - debug_printf(state, "irqnr total since-last status name\n"); + fiq_debugger_printf(&state->output, + "irqnr total since-last status name\n"); for_each_irq_desc(n, desc) { struct irqaction *act = desc->action; if (!act && !kstat_irqs(n)) continue; - debug_printf(state, "%5d: %10u %11u %8x %s\n", n, + fiq_debugger_printf(&state->output, "%5d: %10u %11u %8x %s\n", n, kstat_irqs(n), kstat_irqs(n) - state->last_irqs[n], desc->status_use_accessors, @@ -380,175 +284,86 @@ static void dump_irqs(struct fiq_debugger_state *state) } } -struct stacktrace_state { - struct fiq_debugger_state *state; - unsigned int depth; -}; - -static int report_trace(struct stackframe *frame, void *d) -{ - struct stacktrace_state *sts = d; - - if (sts->depth) { - debug_printf(sts->state, - " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", - frame->pc, frame->pc, frame->lr, frame->lr, - frame->sp, frame->fp); - sts->depth--; - return 0; - } - debug_printf(sts->state, " ...\n"); - - return sts->depth == 0; -} - -struct frame_tail { - struct frame_tail *fp; - unsigned long sp; - unsigned long lr; -} __attribute__((packed)); - -static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, - struct frame_tail *tail) -{ - struct frame_tail buftail[2]; - - /* Also check accessibility of one struct frame_tail beyond */ - if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { - debug_printf(state, " invalid frame pointer %p\n", tail); - return NULL; - } - if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { - debug_printf(state, - " failed to copy frame pointer %p\n", tail); - return NULL; - } - - debug_printf(state, " %p\n", buftail[0].lr); - - /* frame pointers should strictly progress back up the stack - * (towards higher addresses) */ - if (tail >= buftail[0].fp) - return NULL; - - return buftail[0].fp-1; -} - -void dump_stacktrace(struct fiq_debugger_state *state, - struct pt_regs * const regs, unsigned int depth, void *ssp) -{ - struct frame_tail *tail; - struct thread_info *real_thread_info = THREAD_INFO(ssp); - struct stacktrace_state sts; - - sts.depth = depth; - sts.state = state; - *current_thread_info() = *real_thread_info; - - if (!current) - debug_printf(state, "current NULL\n"); - else - debug_printf(state, "pid: %d comm: %s\n", - current->pid, current->comm); - dump_regs(state, (unsigned *)regs); - - if (!user_mode(regs)) { - struct stackframe frame; - frame.fp = regs->ARM_fp; - frame.sp = regs->ARM_sp; - frame.lr = regs->ARM_lr; - frame.pc = regs->ARM_pc; - debug_printf(state, - " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", - regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, - regs->ARM_sp, regs->ARM_fp); - walk_stackframe(&frame, report_trace, &sts); - return; - } - - tail = ((struct frame_tail *) regs->ARM_fp) - 1; - while (depth-- && tail && !((unsigned long) tail & 3)) - tail = user_backtrace(state, tail); -} - -static void do_ps(struct fiq_debugger_state *state) +static void fiq_debugger_do_ps(struct fiq_debugger_state *state) { struct task_struct *g; struct task_struct *p; unsigned task_state; static const char stat_nam[] = "RSDTtZX"; - debug_printf(state, "pid ppid prio task pc\n"); + fiq_debugger_printf(&state->output, "pid ppid prio task pc\n"); read_lock(&tasklist_lock); do_each_thread(g, p) { task_state = p->state ? __ffs(p->state) + 1 : 0; - debug_printf(state, + fiq_debugger_printf(&state->output, "%5d %5d %4d ", p->pid, p->parent->pid, p->prio); - debug_printf(state, "%-13.13s %c", p->comm, + fiq_debugger_printf(&state->output, "%-13.13s %c", p->comm, task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]); if (task_state == TASK_RUNNING) - debug_printf(state, " running\n"); + fiq_debugger_printf(&state->output, " running\n"); else - debug_printf(state, " %08lx\n", thread_saved_pc(p)); + fiq_debugger_printf(&state->output, " %08lx\n", + thread_saved_pc(p)); } while_each_thread(g, p); read_unlock(&tasklist_lock); } #ifdef CONFIG_FIQ_DEBUGGER_CONSOLE -static void begin_syslog_dump(struct fiq_debugger_state *state) +static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state) { state->syslog_dumping = true; } -static void end_syslog_dump(struct fiq_debugger_state *state) +static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state) { state->syslog_dumping = false; } #else extern int do_syslog(int type, char __user *bug, int count); -static void begin_syslog_dump(struct fiq_debugger_state *state) +static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state) { do_syslog(5 /* clear */, NULL, 0); } -static void end_syslog_dump(struct fiq_debugger_state *state) +static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state) { - dump_kernel_log(state); + fiq_debugger_dump_kernel_log(state); } #endif -static void do_sysrq(struct fiq_debugger_state *state, char rq) +static void fiq_debugger_do_sysrq(struct fiq_debugger_state *state, char rq) { if ((rq == 'g' || rq == 'G') && !fiq_kgdb_enable) { - debug_printf(state, "sysrq-g blocked\n"); + fiq_debugger_printf(&state->output, "sysrq-g blocked\n"); return; } - begin_syslog_dump(state); + fiq_debugger_begin_syslog_dump(state); handle_sysrq(rq); - end_syslog_dump(state); + fiq_debugger_end_syslog_dump(state); } #ifdef CONFIG_KGDB -static void do_kgdb(struct fiq_debugger_state *state) +static void fiq_debugger_do_kgdb(struct fiq_debugger_state *state) { if (!fiq_kgdb_enable) { - debug_printf(state, "kgdb through fiq debugger not enabled\n"); + fiq_debugger_printf(&state->output, "kgdb through fiq debugger not enabled\n"); return; } - debug_printf(state, "enabling console and triggering kgdb\n"); + fiq_debugger_printf(&state->output, "enabling console and triggering kgdb\n"); state->console_enable = true; handle_sysrq('g'); } #endif -static void debug_schedule_work(struct fiq_debugger_state *state, char *cmd) +static void fiq_debugger_schedule_work(struct fiq_debugger_state *state, + char *cmd) { unsigned long flags; spin_lock_irqsave(&state->work_lock, flags); if (state->work_cmd[0] != '\0') { - debug_printf(state, "work command processor busy\n"); + fiq_debugger_printf(&state->output, "work command processor busy\n"); spin_unlock_irqrestore(&state->work_lock, flags); return; } @@ -559,7 +374,7 @@ static void debug_schedule_work(struct fiq_debugger_state *state, char *cmd) schedule_work(&state->work); } -static void debug_work(struct work_struct *work) +static void fiq_debugger_work(struct work_struct *work) { struct fiq_debugger_state *state; char work_cmd[DEBUG_MAX]; @@ -585,30 +400,32 @@ static void debug_work(struct work_struct *work) else kernel_restart(NULL); } else { - debug_printf(state, "unknown work command '%s'\n", work_cmd); + fiq_debugger_printf(&state->output, "unknown work command '%s'\n", + work_cmd); } } /* This function CANNOT be called in FIQ context */ -static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd) +static void fiq_debugger_irq_exec(struct fiq_debugger_state *state, char *cmd) { if (!strcmp(cmd, "ps")) - do_ps(state); + fiq_debugger_do_ps(state); if (!strcmp(cmd, "sysrq")) - do_sysrq(state, 'h'); + fiq_debugger_do_sysrq(state, 'h'); if (!strncmp(cmd, "sysrq ", 6)) - do_sysrq(state, cmd[6]); + fiq_debugger_do_sysrq(state, cmd[6]); #ifdef CONFIG_KGDB if (!strcmp(cmd, "kgdb")) - do_kgdb(state); + fiq_debugger_do_kgdb(state); #endif if (!strncmp(cmd, "reboot", 6)) - debug_schedule_work(state, cmd); + fiq_debugger_schedule_work(state, cmd); } -static void debug_help(struct fiq_debugger_state *state) +static void fiq_debugger_help(struct fiq_debugger_state *state) { - debug_printf(state, "FIQ Debugger commands:\n" + fiq_debugger_printf(&state->output, + "FIQ Debugger commands:\n" " pc PC status\n" " regs Register dump\n" " allregs Extended Register dump\n" @@ -618,20 +435,23 @@ static void debug_help(struct fiq_debugger_state *state) " irqs Interupt status\n" " kmsg Kernel log\n" " version Kernel version\n"); - debug_printf(state, " sleep Allow sleep while in FIQ\n" + fiq_debugger_printf(&state->output, + " sleep Allow sleep while in FIQ\n" " nosleep Disable sleep while in FIQ\n" " console Switch terminal to console\n" " cpu Current CPU\n" " cpu <number> Switch to CPU<number>\n"); - debug_printf(state, " ps Process list\n" + fiq_debugger_printf(&state->output, + " ps Process list\n" " sysrq sysrq options\n" " sysrq <param> Execute sysrq with <param>\n"); #ifdef CONFIG_KGDB - debug_printf(state, " kgdb Enter kernel debugger\n"); + fiq_debugger_printf(&state->output, + " kgdb Enter kernel debugger\n"); #endif } -static void take_affinity(void *info) +static void fiq_debugger_take_affinity(void *info) { struct fiq_debugger_state *state = info; struct cpumask cpumask; @@ -642,29 +462,30 @@ static void take_affinity(void *info) irq_set_affinity(state->uart_irq, &cpumask); } -static void switch_cpu(struct fiq_debugger_state *state, int cpu) +static void fiq_debugger_switch_cpu(struct fiq_debugger_state *state, int cpu) { - if (!debug_have_fiq(state)) - smp_call_function_single(cpu, take_affinity, state, false); + if (!fiq_debugger_have_fiq(state)) + smp_call_function_single(cpu, fiq_debugger_take_affinity, state, + false); state->current_cpu = cpu; } -static bool debug_fiq_exec(struct fiq_debugger_state *state, - const char *cmd, unsigned *regs, void *svc_sp) +static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, + const char *cmd, const struct pt_regs *regs, + void *svc_sp) { bool signal_helper = false; if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { - debug_help(state); + fiq_debugger_help(state); } else if (!strcmp(cmd, "pc")) { - debug_printf(state, " pc %08x cpsr %08x mode %s\n", - regs[15], regs[16], mode_name(regs[16])); + fiq_debugger_dump_pc(&state->output, regs); } else if (!strcmp(cmd, "regs")) { - dump_regs(state, regs); + fiq_debugger_dump_regs(&state->output, regs); } else if (!strcmp(cmd, "allregs")) { - dump_allregs(state, regs); + fiq_debugger_dump_allregs(&state->output, regs); } else if (!strcmp(cmd, "bt")) { - dump_stacktrace(state, (struct pt_regs *)regs, 100, svc_sp); + fiq_debugger_dump_stacktrace(&state->output, regs, 100, svc_sp); } else if (!strncmp(cmd, "reset", 5)) { cmd += 5; while (*cmd == ' ') @@ -677,33 +498,33 @@ static bool debug_fiq_exec(struct fiq_debugger_state *state, machine_restart(NULL); } } else if (!strcmp(cmd, "irqs")) { - dump_irqs(state); + fiq_debugger_dump_irqs(state); } else if (!strcmp(cmd, "kmsg")) { - dump_kernel_log(state); + fiq_debugger_dump_kernel_log(state); } else if (!strcmp(cmd, "version")) { - debug_printf(state, "%s\n", linux_banner); + fiq_debugger_printf(&state->output, "%s\n", linux_banner); } else if (!strcmp(cmd, "sleep")) { state->no_sleep = false; - debug_printf(state, "enabling sleep\n"); + fiq_debugger_printf(&state->output, "enabling sleep\n"); } else if (!strcmp(cmd, "nosleep")) { state->no_sleep = true; - debug_printf(state, "disabling sleep\n"); + fiq_debugger_printf(&state->output, "disabling sleep\n"); } else if (!strcmp(cmd, "console")) { - debug_printf(state, "console mode\n"); - debug_uart_flush(state); + fiq_debugger_printf(&state->output, "console mode\n"); + fiq_debugger_uart_flush(state); state->console_enable = true; } else if (!strcmp(cmd, "cpu")) { - debug_printf(state, "cpu %d\n", state->current_cpu); + fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); } else if (!strncmp(cmd, "cpu ", 4)) { unsigned long cpu = 0; if (strict_strtoul(cmd + 4, 10, &cpu) == 0) - switch_cpu(state, cpu); + fiq_debugger_switch_cpu(state, cpu); else - debug_printf(state, "invalid cpu\n"); - debug_printf(state, "cpu %d\n", state->current_cpu); + fiq_debugger_printf(&state->output, "invalid cpu\n"); + fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); } else { if (state->debug_busy) { - debug_printf(state, + fiq_debugger_printf(&state->output, "command processor busy. trying to abort.\n"); state->debug_abort = -1; } else { @@ -714,12 +535,12 @@ static bool debug_fiq_exec(struct fiq_debugger_state *state, return true; } if (!state->console_enable) - debug_prompt(state); + fiq_debugger_prompt(state); return signal_helper; } -static void sleep_timer_expired(unsigned long data) +static void fiq_debugger_sleep_timer_expired(unsigned long data) { struct fiq_debugger_state *state = (struct fiq_debugger_state *)data; unsigned long flags; @@ -728,18 +549,19 @@ static void sleep_timer_expired(unsigned long data) if (state->uart_enabled && !state->no_sleep) { if (state->debug_enable && !state->console_enable) { state->debug_enable = false; - debug_printf_nfiq(state, "suspending fiq debugger\n"); + fiq_debugger_printf_nfiq(state, + "suspending fiq debugger\n"); } state->ignore_next_wakeup_irq = true; - debug_uart_disable(state); + fiq_debugger_uart_disable(state); state->uart_enabled = false; - enable_wakeup_irq(state); + fiq_debugger_enable_wakeup_irq(state); } wake_unlock(&state->debugger_wake_lock); spin_unlock_irqrestore(&state->sleep_timer_lock, flags); } -static void handle_wakeup(struct fiq_debugger_state *state) +static void fiq_debugger_handle_wakeup(struct fiq_debugger_state *state) { unsigned long flags; @@ -748,26 +570,27 @@ static void handle_wakeup(struct fiq_debugger_state *state) state->ignore_next_wakeup_irq = false; } else if (!state->uart_enabled) { wake_lock(&state->debugger_wake_lock); - debug_uart_enable(state); + fiq_debugger_uart_enable(state); state->uart_enabled = true; - disable_wakeup_irq(state); + fiq_debugger_disable_wakeup_irq(state); mod_timer(&state->sleep_timer, jiffies + HZ / 2); } spin_unlock_irqrestore(&state->sleep_timer_lock, flags); } -static irqreturn_t wakeup_irq_handler(int irq, void *dev) +static irqreturn_t fiq_debugger_wakeup_irq_handler(int irq, void *dev) { struct fiq_debugger_state *state = dev; if (!state->no_sleep) - debug_puts(state, "WAKEUP\n"); - handle_wakeup(state); + fiq_debugger_puts(state, "WAKEUP\n"); + fiq_debugger_handle_wakeup(state); return IRQ_HANDLED; } -static void debug_handle_console_irq_context(struct fiq_debugger_state *state) +static +void fiq_debugger_handle_console_irq_context(struct fiq_debugger_state *state) { #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) if (state->tty_port.ops) { @@ -784,7 +607,7 @@ static void debug_handle_console_irq_context(struct fiq_debugger_state *state) #endif } -static void debug_handle_irq_context(struct fiq_debugger_state *state) +static void fiq_debugger_handle_irq_context(struct fiq_debugger_state *state) { if (!state->no_sleep) { unsigned long flags; @@ -794,22 +617,22 @@ static void debug_handle_irq_context(struct fiq_debugger_state *state) mod_timer(&state->sleep_timer, jiffies + HZ * 5); spin_unlock_irqrestore(&state->sleep_timer_lock, flags); } - debug_handle_console_irq_context(state); + fiq_debugger_handle_console_irq_context(state); if (state->debug_busy) { - debug_irq_exec(state, state->debug_cmd); + fiq_debugger_irq_exec(state, state->debug_cmd); if (!state->console_enable) - debug_prompt(state); + fiq_debugger_prompt(state); state->debug_busy = 0; } } -static int debug_getc(struct fiq_debugger_state *state) +static int fiq_debugger_getc(struct fiq_debugger_state *state) { return state->pdata->uart_getc(state->pdev); } -static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, - int this_cpu, void *regs, void *svc_sp) +static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state, + int this_cpu, const struct pt_regs *regs, void *svc_sp) { int c; static int last_c; @@ -824,30 +647,31 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, MAX_UNHANDLED_FIQ_COUNT) return false; - debug_printf(state, "fiq_debugger: cpu %d not responding, " + fiq_debugger_printf(&state->output, + "fiq_debugger: cpu %d not responding, " "reverting to cpu %d\n", state->current_cpu, this_cpu); atomic_set(&state->unhandled_fiq_count, 0); - switch_cpu(state, this_cpu); + fiq_debugger_switch_cpu(state, this_cpu); return false; } state->in_fiq = true; - while ((c = debug_getc(state)) != FIQ_DEBUGGER_NO_CHAR) { + while ((c = fiq_debugger_getc(state)) != FIQ_DEBUGGER_NO_CHAR) { count++; if (!state->debug_enable) { if ((c == 13) || (c == 10)) { state->debug_enable = true; state->debug_count = 0; - debug_prompt(state); + fiq_debugger_prompt(state); } } else if (c == FIQ_DEBUGGER_BREAK) { state->console_enable = false; - debug_puts(state, "fiq debugger mode\n"); + fiq_debugger_puts(state, "fiq debugger mode\n"); state->debug_count = 0; - debug_prompt(state); + fiq_debugger_prompt(state); #ifdef CONFIG_FIQ_DEBUGGER_CONSOLE } else if (state->console_enable && state->tty_rbuf) { fiq_debugger_ringbuf_push(state->tty_rbuf, c); @@ -856,34 +680,35 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, } else if ((c >= ' ') && (c < 127)) { if (state->debug_count < (DEBUG_MAX - 1)) { state->debug_buf[state->debug_count++] = c; - debug_putc(state, c); + fiq_debugger_putc(state, c); } } else if ((c == 8) || (c == 127)) { if (state->debug_count > 0) { state->debug_count--; - debug_putc(state, 8); - debug_putc(state, ' '); - debug_putc(state, 8); + fiq_debugger_putc(state, 8); + fiq_debugger_putc(state, ' '); + fiq_debugger_putc(state, 8); } } else if ((c == 13) || (c == 10)) { if (c == '\r' || (c == '\n' && last_c != '\r')) { - debug_putc(state, '\r'); - debug_putc(state, '\n'); + fiq_debugger_putc(state, '\r'); + fiq_debugger_putc(state, '\n'); } if (state->debug_count) { state->debug_buf[state->debug_count] = 0; state->debug_count = 0; signal_helper |= - debug_fiq_exec(state, state->debug_buf, - regs, svc_sp); + fiq_debugger_fiq_exec(state, + state->debug_buf, + regs, svc_sp); } else { - debug_prompt(state); + fiq_debugger_prompt(state); } } last_c = c; } if (!state->console_enable) - debug_uart_flush(state); + fiq_debugger_uart_flush(state); if (state->pdata->fiq_ack) state->pdata->fiq_ack(state->pdev, state->fiq); @@ -897,36 +722,40 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, return signal_helper; } -static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) +#ifdef CONFIG_FIQ_GLUE +static void fiq_debugger_fiq(struct fiq_glue_handler *h, + const struct pt_regs *regs, void *svc_sp) { struct fiq_debugger_state *state = container_of(h, struct fiq_debugger_state, handler); unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu; bool need_irq; - need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp); + need_irq = fiq_debugger_handle_uart_interrupt(state, this_cpu, regs, + svc_sp); if (need_irq) - debug_force_irq(state); + fiq_debugger_force_irq(state); } +#endif /* * When not using FIQs, we only use this single interrupt as an entry point. * This just effectively takes over the UART interrupt and does all the work * in this context. */ -static irqreturn_t debug_uart_irq(int irq, void *dev) +static irqreturn_t fiq_debugger_uart_irq(int irq, void *dev) { struct fiq_debugger_state *state = dev; bool not_done; - handle_wakeup(state); + fiq_debugger_handle_wakeup(state); /* handle the debugger irq in regular context */ - not_done = debug_handle_uart_interrupt(state, smp_processor_id(), + not_done = fiq_debugger_handle_uart_interrupt(state, smp_processor_id(), get_irq_regs(), current_thread_info()); if (not_done) - debug_handle_irq_context(state); + fiq_debugger_handle_irq_context(state); return IRQ_HANDLED; } @@ -936,34 +765,36 @@ static irqreturn_t debug_uart_irq(int irq, void *dev) * FIQ handler does what it can and then signals this interrupt to finish the * job in irq context. */ -static irqreturn_t debug_signal_irq(int irq, void *dev) +static irqreturn_t fiq_debugger_signal_irq(int irq, void *dev) { struct fiq_debugger_state *state = dev; if (state->pdata->force_irq_ack) state->pdata->force_irq_ack(state->pdev, state->signal_irq); - debug_handle_irq_context(state); + fiq_debugger_handle_irq_context(state); return IRQ_HANDLED; } -static void debug_resume(struct fiq_glue_handler *h) +#ifdef CONFIG_FIQ_GLUE +static void fiq_debugger_resume(struct fiq_glue_handler *h) { struct fiq_debugger_state *state = container_of(h, struct fiq_debugger_state, handler); if (state->pdata->uart_resume) state->pdata->uart_resume(state->pdev); } +#endif #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) -struct tty_driver *debug_console_device(struct console *co, int *index) +struct tty_driver *fiq_debugger_console_device(struct console *co, int *index) { *index = co->index; return fiq_tty_driver; } -static void debug_console_write(struct console *co, +static void fiq_debugger_console_write(struct console *co, const char *s, unsigned int count) { struct fiq_debugger_state *state; @@ -974,22 +805,22 @@ static void debug_console_write(struct console *co, if (!state->console_enable && !state->syslog_dumping) return; - debug_uart_enable(state); + fiq_debugger_uart_enable(state); spin_lock_irqsave(&state->console_lock, flags); while (count--) { if (*s == '\n') - debug_putc(state, '\r'); - debug_putc(state, *s++); + fiq_debugger_putc(state, '\r'); + fiq_debugger_putc(state, *s++); } - debug_uart_flush(state); + fiq_debugger_uart_flush(state); spin_unlock_irqrestore(&state->console_lock, flags); - debug_uart_disable(state); + fiq_debugger_uart_disable(state); } static struct console fiq_debugger_console = { .name = "ttyFIQ", - .device = debug_console_device, - .write = debug_console_write, + .device = fiq_debugger_console_device, + .write = fiq_debugger_console_write, .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, }; @@ -1017,12 +848,12 @@ int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) if (!state->console_enable) return count; - debug_uart_enable(state); + fiq_debugger_uart_enable(state); spin_lock_irq(&state->console_lock); for (i = 0; i < count; i++) - debug_putc(state, *buf++); + fiq_debugger_putc(state, *buf++); spin_unlock_irq(&state->console_lock); - debug_uart_disable(state); + fiq_debugger_uart_disable(state); return count; } @@ -1044,19 +875,19 @@ static int fiq_tty_poll_get_char(struct tty_driver *driver, int line) struct fiq_debugger_state *state = states[line]; int c = NO_POLL_CHAR; - debug_uart_enable(state); - if (debug_have_fiq(state)) { + fiq_debugger_uart_enable(state); + if (fiq_debugger_have_fiq(state)) { int count = fiq_debugger_ringbuf_level(state->tty_rbuf); if (count > 0) { c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0); fiq_debugger_ringbuf_consume(state->tty_rbuf, 1); } } else { - c = debug_getc(state); + c = fiq_debugger_getc(state); if (c == FIQ_DEBUGGER_NO_CHAR) c = NO_POLL_CHAR; } - debug_uart_disable(state); + fiq_debugger_uart_disable(state); return c; } @@ -1065,9 +896,9 @@ static void fiq_tty_poll_put_char(struct tty_driver *driver, int line, char ch) { struct fiq_debugger_state **states = driver->driver_state; struct fiq_debugger_state *state = states[line]; - debug_uart_enable(state); - debug_putc(state, ch); - debug_uart_disable(state); + fiq_debugger_uart_enable(state); + fiq_debugger_putc(state, ch); + fiq_debugger_uart_disable(state); } #endif @@ -1224,7 +1055,8 @@ static int fiq_debugger_probe(struct platform_device *pdev) return -EINVAL; state = kzalloc(sizeof(*state), GFP_KERNEL); - setup_timer(&state->sleep_timer, sleep_timer_expired, + state->output.printf = fiq_debugger_printf; + setup_timer(&state->sleep_timer, fiq_debugger_sleep_timer_expired, (unsigned long)state); state->pdata = pdata; state->pdev = pdev; @@ -1237,14 +1069,14 @@ static int fiq_debugger_probe(struct platform_device *pdev) state->signal_irq = platform_get_irq_byname(pdev, "signal"); state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup"); - INIT_WORK(&state->work, debug_work); + INIT_WORK(&state->work, fiq_debugger_work); spin_lock_init(&state->work_lock); platform_set_drvdata(pdev, state); spin_lock_init(&state->sleep_timer_lock); - if (state->wakeup_irq < 0 && debug_have_fiq(state)) + if (state->wakeup_irq < 0 && fiq_debugger_have_fiq(state)) state->no_sleep = true; state->ignore_next_wakeup_irq = !state->no_sleep; @@ -1268,21 +1100,25 @@ static int fiq_debugger_probe(struct platform_device *pdev) goto err_uart_init; } - debug_printf_nfiq(state, "<hit enter %sto activate fiq debugger>\n", + fiq_debugger_printf_nfiq(state, + "<hit enter %sto activate fiq debugger>\n", state->no_sleep ? "" : "twice "); - if (debug_have_fiq(state)) { - state->handler.fiq = debug_fiq; - state->handler.resume = debug_resume; +#ifdef CONFIG_FIQ_GLUE + if (fiq_debugger_have_fiq(state)) { + state->handler.fiq = fiq_debugger_fiq; + state->handler.resume = fiq_debugger_resume; ret = fiq_glue_register_handler(&state->handler); if (ret) { pr_err("%s: could not install fiq handler\n", __func__); - goto err_register_fiq; + goto err_register_irq; } pdata->fiq_enable(pdev, state->fiq, 1); - } else { - ret = request_irq(state->uart_irq, debug_uart_irq, + } else +#endif + { + ret = request_irq(state->uart_irq, fiq_debugger_uart_irq, IRQF_NO_SUSPEND, "debug", state); if (ret) { pr_err("%s: could not install irq handler\n", __func__); @@ -1299,14 +1135,15 @@ static int fiq_debugger_probe(struct platform_device *pdev) clk_disable(state->clk); if (state->signal_irq >= 0) { - ret = request_irq(state->signal_irq, debug_signal_irq, + ret = request_irq(state->signal_irq, fiq_debugger_signal_irq, IRQF_TRIGGER_RISING, "debug-signal", state); if (ret) pr_err("serial_debugger: could not install signal_irq"); } if (state->wakeup_irq >= 0) { - ret = request_irq(state->wakeup_irq, wakeup_irq_handler, + ret = request_irq(state->wakeup_irq, + fiq_debugger_wakeup_irq_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, "debug-wakeup", state); if (ret) { @@ -1323,7 +1160,7 @@ static int fiq_debugger_probe(struct platform_device *pdev) } } if (state->no_sleep) - handle_wakeup(state); + fiq_debugger_handle_wakeup(state); #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) spin_lock_init(&state->console_lock); @@ -1338,7 +1175,6 @@ static int fiq_debugger_probe(struct platform_device *pdev) return 0; err_register_irq: -err_register_fiq: if (pdata->uart_free) pdata->uart_free(pdev); err_uart_init: diff --git a/arch/arm/include/asm/fiq_debugger.h b/drivers/staging/android/fiq_debugger/fiq_debugger.h index 4d274883ba6a..c9ec4f8db086 100644 --- a/arch/arm/include/asm/fiq_debugger.h +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.h @@ -1,5 +1,5 @@ /* - * arch/arm/include/asm/fiq_debugger.h + * drivers/staging/android/fiq_debugger/fiq_debugger.h * * Copyright (C) 2010 Google, Inc. * Author: Colin Cross <ccross@android.com> diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c new file mode 100644 index 000000000000..8b3e0137be1a --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2014 Google, Inc. + * Author: Colin Cross <ccross@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/ptrace.h> +#include <linux/uaccess.h> + +#include <asm/stacktrace.h> + +#include "fiq_debugger_priv.h" + +static char *mode_name(unsigned cpsr) +{ + switch (cpsr & MODE_MASK) { + case USR_MODE: return "USR"; + case FIQ_MODE: return "FIQ"; + case IRQ_MODE: return "IRQ"; + case SVC_MODE: return "SVC"; + case ABT_MODE: return "ABT"; + case UND_MODE: return "UND"; + case SYSTEM_MODE: return "SYS"; + default: return "???"; + } +} + +void fiq_debugger_dump_pc(struct fiq_debugger_output *output, + const struct pt_regs *regs) +{ + output->printf(output, " pc %08x cpsr %08x mode %s\n", + regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr)); +} + +void fiq_debugger_dump_regs(struct fiq_debugger_output *output, + const struct pt_regs *regs) +{ + output->printf(output, + " r0 %08x r1 %08x r2 %08x r3 %08x\n", + regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); + output->printf(output, + " r4 %08x r5 %08x r6 %08x r7 %08x\n", + regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7); + output->printf(output, + " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", + regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp, + mode_name(regs->ARM_cpsr)); + output->printf(output, + " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", + regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc, + regs->ARM_cpsr); +} + +struct mode_regs { + unsigned long sp_svc; + unsigned long lr_svc; + unsigned long spsr_svc; + + unsigned long sp_abt; + unsigned long lr_abt; + unsigned long spsr_abt; + + unsigned long sp_und; + unsigned long lr_und; + unsigned long spsr_und; + + unsigned long sp_irq; + unsigned long lr_irq; + unsigned long spsr_irq; + + unsigned long r8_fiq; + unsigned long r9_fiq; + unsigned long r10_fiq; + unsigned long r11_fiq; + unsigned long r12_fiq; + unsigned long sp_fiq; + unsigned long lr_fiq; + unsigned long spsr_fiq; +}; + +static void __naked get_mode_regs(struct mode_regs *regs) +{ + asm volatile ( + "mrs r1, cpsr\n" + "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r8 - r14}\n" + "mrs r2, spsr\n" + "stmia r0!, {r2}\n" + "msr cpsr_c, r1\n" + "bx lr\n"); +} + + +void fiq_debugger_dump_allregs(struct fiq_debugger_output *output, + const struct pt_regs *regs) +{ + struct mode_regs mode_regs; + unsigned long mode = regs->ARM_cpsr & MODE_MASK; + + fiq_debugger_dump_regs(output, regs); + get_mode_regs(&mode_regs); + + output->printf(output, + "%csvc: sp %08x lr %08x spsr %08x\n", + mode == SVC_MODE ? '*' : ' ', + mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); + output->printf(output, + "%cabt: sp %08x lr %08x spsr %08x\n", + mode == ABT_MODE ? '*' : ' ', + mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); + output->printf(output, + "%cund: sp %08x lr %08x spsr %08x\n", + mode == UND_MODE ? '*' : ' ', + mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); + output->printf(output, + "%cirq: sp %08x lr %08x spsr %08x\n", + mode == IRQ_MODE ? '*' : ' ', + mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); + output->printf(output, + "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", + mode == FIQ_MODE ? '*' : ' ', + mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, + mode_regs.r11_fiq, mode_regs.r12_fiq); + output->printf(output, + " fiq: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); +} + +struct stacktrace_state { + struct fiq_debugger_output *output; + unsigned int depth; +}; + +static int report_trace(struct stackframe *frame, void *d) +{ + struct stacktrace_state *sts = d; + + if (sts->depth) { + sts->output->printf(sts->output, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + frame->pc, frame->pc, frame->lr, frame->lr, + frame->sp, frame->fp); + sts->depth--; + return 0; + } + sts->output->printf(sts->output, " ...\n"); + + return sts->depth == 0; +} + +struct frame_tail { + struct frame_tail *fp; + unsigned long sp; + unsigned long lr; +} __attribute__((packed)); + +static struct frame_tail *user_backtrace(struct fiq_debugger_output *output, + struct frame_tail *tail) +{ + struct frame_tail buftail[2]; + + /* Also check accessibility of one struct frame_tail beyond */ + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { + output->printf(output, " invalid frame pointer %p\n", + tail); + return NULL; + } + if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { + output->printf(output, + " failed to copy frame pointer %p\n", tail); + return NULL; + } + + output->printf(output, " %p\n", buftail[0].lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (tail >= buftail[0].fp) + return NULL; + + return buftail[0].fp-1; +} + +void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output, + const struct pt_regs *regs, unsigned int depth, void *ssp) +{ + struct frame_tail *tail; + struct thread_info *real_thread_info = THREAD_INFO(ssp); + struct stacktrace_state sts; + + sts.depth = depth; + sts.output = output; + *current_thread_info() = *real_thread_info; + + if (!current) + output->printf(output, "current NULL\n"); + else + output->printf(output, "pid: %d comm: %s\n", + current->pid, current->comm); + fiq_debugger_dump_regs(output, regs); + + if (!user_mode(regs)) { + struct stackframe frame; + frame.fp = regs->ARM_fp; + frame.sp = regs->ARM_sp; + frame.lr = regs->ARM_lr; + frame.pc = regs->ARM_pc; + output->printf(output, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, + regs->ARM_sp, regs->ARM_fp); + walk_stackframe(&frame, report_trace, &sts); + return; + } + + tail = ((struct frame_tail *) regs->ARM_fp) - 1; + while (depth-- && tail && !((unsigned long) tail & 3)) + tail = user_backtrace(output, tail); +} diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c new file mode 100644 index 000000000000..99c6584fcfa5 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2014 Google, Inc. + * Author: Colin Cross <ccross@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/ptrace.h> +#include <asm/stacktrace.h> + +#include "fiq_debugger_priv.h" + +static char *mode_name(const struct pt_regs *regs) +{ + if (compat_user_mode(regs)) { + return "USR"; + } else { + switch (processor_mode(regs)) { + case PSR_MODE_EL0t: return "EL0t"; + case PSR_MODE_EL1t: return "EL1t"; + case PSR_MODE_EL1h: return "EL1h"; + case PSR_MODE_EL2t: return "EL2t"; + case PSR_MODE_EL2h: return "EL2h"; + default: return "???"; + } + } +} + +void fiq_debugger_dump_pc(struct fiq_debugger_output *output, + const struct pt_regs *regs) +{ + output->printf(output, " pc %016lx cpsr %08lx mode %s\n", + regs->pc, regs->pstate, mode_name(regs)); +} + +void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_output *output, + const struct pt_regs *regs) +{ + output->printf(output, " r0 %08x r1 %08x r2 %08x r3 %08x\n", + regs->compat_usr(0), regs->compat_usr(1), + regs->compat_usr(2), regs->compat_usr(3)); + output->printf(output, " r4 %08x r5 %08x r6 %08x r7 %08x\n", + regs->compat_usr(4), regs->compat_usr(5), + regs->compat_usr(6), regs->compat_usr(7)); + output->printf(output, " r8 %08x r9 %08x r10 %08x r11 %08x\n", + regs->compat_usr(8), regs->compat_usr(9), + regs->compat_usr(10), regs->compat_usr(11)); + output->printf(output, " ip %08x sp %08x lr %08x pc %08x\n", + regs->compat_usr(12), regs->compat_sp, + regs->compat_lr, regs->pc); + output->printf(output, " cpsr %08x (%s)\n", + regs->pstate, mode_name(regs)); +} + +void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_output *output, + const struct pt_regs *regs) +{ + + output->printf(output, " x0 %016lx x1 %016lx\n", + regs->regs[0], regs->regs[1]); + output->printf(output, " x2 %016lx x3 %016lx\n", + regs->regs[2], regs->regs[3]); + output->printf(output, " x4 %016lx x5 %016lx\n", + regs->regs[4], regs->regs[5]); + output->printf(output, " x6 %016lx x7 %016lx\n", + regs->regs[6], regs->regs[7]); + output->printf(output, " x8 %016lx x9 %016lx\n", + regs->regs[8], regs->regs[9]); + output->printf(output, " x10 %016lx x11 %016lx\n", + regs->regs[10], regs->regs[11]); + output->printf(output, " x12 %016lx x13 %016lx\n", + regs->regs[12], regs->regs[13]); + output->printf(output, " x14 %016lx x15 %016lx\n", + regs->regs[14], regs->regs[15]); + output->printf(output, " x16 %016lx x17 %016lx\n", + regs->regs[16], regs->regs[17]); + output->printf(output, " x18 %016lx x19 %016lx\n", + regs->regs[18], regs->regs[19]); + output->printf(output, " x20 %016lx x21 %016lx\n", + regs->regs[20], regs->regs[21]); + output->printf(output, " x22 %016lx x23 %016lx\n", + regs->regs[22], regs->regs[23]); + output->printf(output, " x24 %016lx x25 %016lx\n", + regs->regs[24], regs->regs[25]); + output->printf(output, " x26 %016lx x27 %016lx\n", + regs->regs[26], regs->regs[27]); + output->printf(output, " x28 %016lx x29 %016lx\n", + regs->regs[28], regs->regs[29]); + output->printf(output, " x30 %016lx sp %016lx\n", + regs->regs[30], regs->sp); + output->printf(output, " pc %016lx cpsr %08x (%s)\n", + regs->pc, regs->pstate, mode_name(regs)); +} + +void fiq_debugger_dump_regs(struct fiq_debugger_output *output, + const struct pt_regs *regs) +{ + if (compat_user_mode(regs)) + fiq_debugger_dump_regs_aarch32(output, regs); + else + fiq_debugger_dump_regs_aarch64(output, regs); +} + +#define READ_SPECIAL_REG(x) ({ \ + u64 val; \ + asm volatile ("mrs %0, " # x : "=r"(val)); \ + val; \ +}) + +void fiq_debugger_dump_allregs(struct fiq_debugger_output *output, + const struct pt_regs *regs) +{ + u32 pstate = READ_SPECIAL_REG(CurrentEl); + bool in_el2 = (pstate & PSR_MODE_MASK) >= PSR_MODE_EL2t; + + fiq_debugger_dump_regs(output, regs); + + output->printf(output, " sp_el0 %016lx\n", + READ_SPECIAL_REG(sp_el0)); + + if (in_el2) + output->printf(output, " sp_el1 %016lx\n", + READ_SPECIAL_REG(sp_el1)); + + output->printf(output, " elr_el1 %016lx\n", + READ_SPECIAL_REG(elr_el1)); + + output->printf(output, " spsr_el1 %08lx\n", + READ_SPECIAL_REG(spsr_el1)); + + if (in_el2) { + output->printf(output, " spsr_irq %08lx\n", + READ_SPECIAL_REG(spsr_irq)); + output->printf(output, " spsr_abt %08lx\n", + READ_SPECIAL_REG(spsr_abt)); + output->printf(output, " spsr_und %08lx\n", + READ_SPECIAL_REG(spsr_und)); + output->printf(output, " spsr_fiq %08lx\n", + READ_SPECIAL_REG(spsr_fiq)); + output->printf(output, " spsr_el2 %08lx\n", + READ_SPECIAL_REG(elr_el2)); + output->printf(output, " spsr_el2 %08lx\n", + READ_SPECIAL_REG(spsr_el2)); + } +} + +struct stacktrace_state { + struct fiq_debugger_output *output; + unsigned int depth; +}; + +static int report_trace(struct stackframe *frame, void *d) +{ + struct stacktrace_state *sts = d; + + if (sts->depth) { + sts->output->printf(sts->output, "%pF:\n", frame->pc); + sts->output->printf(sts->output, + " pc %016lx sp %016lx fp %016lx\n", + frame->pc, frame->sp, frame->fp); + sts->depth--; + return 0; + } + sts->output->printf(sts->output, " ...\n"); + + return sts->depth == 0; +} + +void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output, + const struct pt_regs *regs, unsigned int depth, void *ssp) +{ + struct thread_info *real_thread_info = THREAD_INFO(ssp); + struct stacktrace_state sts; + + sts.depth = depth; + sts.output = output; + *current_thread_info() = *real_thread_info; + + if (!current) + output->printf(output, "current NULL\n"); + else + output->printf(output, "pid: %d comm: %s\n", + current->pid, current->comm); + fiq_debugger_dump_regs(output, regs); + + if (!user_mode(regs)) { + struct stackframe frame; + frame.fp = regs->regs[29]; + frame.sp = regs->sp; + frame.pc = regs->pc; + output->printf(output, "\n"); + walk_stackframe(&frame, report_trace, &sts); + } +} diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h new file mode 100644 index 000000000000..d5d051f727a8 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 Google, Inc. + * Author: Colin Cross <ccross@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _FIQ_DEBUGGER_PRIV_H_ +#define _FIQ_DEBUGGER_PRIV_H_ + +#define THREAD_INFO(sp) ((struct thread_info *) \ + ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) + +struct fiq_debugger_output { + void (*printf)(struct fiq_debugger_output *output, const char *fmt, ...); +}; + +struct pt_regs; + +void fiq_debugger_dump_pc(struct fiq_debugger_output *output, + const struct pt_regs *regs); +void fiq_debugger_dump_regs(struct fiq_debugger_output *output, + const struct pt_regs *regs); +void fiq_debugger_dump_allregs(struct fiq_debugger_output *output, + const struct pt_regs *regs); +void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output, + const struct pt_regs *regs, unsigned int depth, void *ssp); + +#endif diff --git a/arch/arm/common/fiq_debugger_ringbuf.h b/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h index 2649b5581088..10c3c5d09098 100644 --- a/arch/arm/common/fiq_debugger_ringbuf.h +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h @@ -1,5 +1,5 @@ /* - * arch/arm/common/fiq_debugger_ringbuf.c + * drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h * * simple lockless ringbuffer * diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.c b/drivers/staging/android/fiq_debugger/fiq_watchdog.c new file mode 100644 index 000000000000..194b54138417 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_watchdog.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/pstore_ram.h> + +#include "fiq_watchdog.h" +#include "fiq_debugger_priv.h" + +static DEFINE_RAW_SPINLOCK(fiq_watchdog_lock); + +static void fiq_watchdog_printf(struct fiq_debugger_output *output, + const char *fmt, ...) +{ + char buf[256]; + va_list ap; + int len; + + va_start(ap, fmt); + len = vscnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + ramoops_console_write_buf(buf, len); +} + +struct fiq_debugger_output fiq_watchdog_output = { + .printf = fiq_watchdog_printf, +}; + +void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp) +{ + char msg[24]; + int len; + + raw_spin_lock(&fiq_watchdog_lock); + + len = scnprintf(msg, sizeof(msg), "watchdog fiq cpu %d\n", + THREAD_INFO(svc_sp)->cpu); + ramoops_console_write_buf(msg, len); + + fiq_debugger_dump_stacktrace(&fiq_watchdog_output, regs, 100, svc_sp); + + raw_spin_unlock(&fiq_watchdog_lock); +} diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.h b/drivers/staging/android/fiq_debugger/fiq_watchdog.h new file mode 100644 index 000000000000..c6b507f8d976 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_watchdog.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2014 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _FIQ_WATCHDOG_H_ +#define _FIQ_WATCHDOG_H_ + +void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp); + +#endif diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c index 53e50b5e8612..c0397f1116ac 100644 --- a/drivers/usb/gadget/f_accessory.c +++ b/drivers/usb/gadget/f_accessory.c @@ -662,10 +662,17 @@ static ssize_t acc_write(struct file *fp, const char __user *buf, break; } - if (count > BULK_BUFFER_SIZE) + if (count > BULK_BUFFER_SIZE) { xfer = BULK_BUFFER_SIZE; - else + /* ZLP, They will be more TX requests so not yet. */ + req->zero = 0; + } else { xfer = count; + /* If the data length is a multple of the + * maxpacket size then send a zero length packet(ZLP). + */ + req->zero = ((xfer % dev->ep_in->maxpacket) == 0); + } if (copy_from_user(req->buf, buf, xfer)) { r = -EFAULT; break; @@ -1193,7 +1200,8 @@ err: static void acc_disconnect(void) { /* unregister all HID devices if USB is disconnected */ - kill_all_hid_devices(_acc_dev); + if (_acc_dev) + kill_all_hid_devices(_acc_dev); } static void acc_cleanup(void) diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c index 56dcf217cfe5..21ced13c83d8 100644 --- a/drivers/usb/gadget/f_audio_source.c +++ b/drivers/usb/gadget/f_audio_source.c @@ -24,7 +24,7 @@ #define SAMPLE_RATE 44100 #define FRAMES_PER_MSEC (SAMPLE_RATE / 1000) -#define IN_EP_MAX_PACKET_SIZE 384 +#define IN_EP_MAX_PACKET_SIZE 256 /* Number of requests to allocate */ #define IN_EP_REQ_COUNT 4 @@ -580,12 +580,18 @@ audio_bind(struct usb_configuration *c, struct usb_function *f) goto fail; ac_interface_desc.bInterfaceNumber = status; + /* AUDIO_AC_INTERFACE */ + ac_header_desc.baInterfaceNr[0] = status; + status = usb_interface_id(c, f); if (status < 0) goto fail; as_interface_alt_0_desc.bInterfaceNumber = status; as_interface_alt_1_desc.bInterfaceNumber = status; + /* AUDIO_AS_INTERFACE */ + ac_header_desc.baInterfaceNr[1] = status; + status = -ENODEV; /* allocate our endpoint */ diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index a3a220890b58..416551f0dd8e 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -69,6 +69,16 @@ * - MS-Windows drivers sometimes emit undocumented requests. */ +static unsigned int rndis_dl_max_pkt_per_xfer = 3; +module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer, + "Maximum packets per transfer for DL aggregation"); + +static unsigned int rndis_ul_max_pkt_per_xfer = 3; +module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer, + "Maximum packets per transfer for UL aggregation"); + struct f_rndis { struct gether port; u8 ctrl_id, data_id; @@ -450,6 +460,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) { struct f_rndis *rndis = req->context; int status; + rndis_init_msg_type *buf; /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ // spin_lock(&dev->lock); @@ -457,6 +468,21 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) if (status < 0) pr_err("RNDIS command error %d, %d/%d\n", status, req->actual, req->length); + + buf = (rndis_init_msg_type *)req->buf; + + if (buf->MessageType == RNDIS_MSG_INIT) { + if (buf->MaxTransferSize > 2048) + rndis->port.multi_pkt_xfer = 1; + else + rndis->port.multi_pkt_xfer = 0; + pr_info("%s: MaxTransferSize: %d : Multi_pkt_txr: %s\n", + __func__, buf->MaxTransferSize, + rndis->port.multi_pkt_xfer ? "enabled" : + "disabled"); + if (rndis_dl_max_pkt_per_xfer <= 1) + rndis->port.multi_pkt_xfer = 0; + } // spin_unlock(&dev->lock); } @@ -783,6 +809,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->config, rndis->ethaddr); + rndis_set_max_pkt_xfer(rndis->config, rndis_ul_max_pkt_per_xfer); if (rndis->manufacturer && rndis->vendorID && rndis_set_param_vendor(rndis->config, rndis->vendorID, @@ -1015,6 +1042,8 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) rndis->port.header_len = sizeof(struct rndis_packet_msg_type); rndis->port.wrap = rndis_add_header; rndis->port.unwrap = rndis_rm_hdr; + rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer; + rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer; rndis->port.func.name = "rndis"; /* descriptors are per-instance copies */ diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index d822d822efb3..3a0d2f51a78d 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -58,6 +58,16 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging"); #define RNDIS_MAX_CONFIGS 1 +int rndis_ul_max_pkt_per_xfer_rcvd; +module_param(rndis_ul_max_pkt_per_xfer_rcvd, int, S_IRUGO); +MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer_rcvd, + "Max num of REMOTE_NDIS_PACKET_MSGs received in a single transfer"); + +int rndis_ul_max_xfer_size_rcvd; +module_param(rndis_ul_max_xfer_size_rcvd, int, S_IRUGO); +MODULE_PARM_DESC(rndis_ul_max_xfer_size_rcvd, + "Max size of bus transfer received"); + static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS]; @@ -584,12 +594,12 @@ static int rndis_init_response(int configNr, rndis_init_msg_type *buf) resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION); resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS); resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3); - resp->MaxPacketsPerTransfer = cpu_to_le32(1); - resp->MaxTransferSize = cpu_to_le32( - params->dev->mtu + resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer); + resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer * + (params->dev->mtu + sizeof(struct ethhdr) + sizeof(struct rndis_packet_msg_type) - + 22); + + 22)); resp->PacketAlignmentFactor = cpu_to_le32(0); resp->AFListOffset = cpu_to_le32(0); resp->AFListSize = cpu_to_le32(0); @@ -685,6 +695,12 @@ static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf) rndis_reset_cmplt_type *resp; rndis_resp_t *r; struct rndis_params *params = rndis_per_dev_params + configNr; + u32 length; + u8 *xbuf; + + /* drain the response queue */ + while ((xbuf = rndis_get_next_response(configNr, &length))) + rndis_free_response(configNr, xbuf); r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type)); if (!r) @@ -916,6 +932,8 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) rndis_per_dev_params[configNr].dev = dev; rndis_per_dev_params[configNr].filter = cdc_filter; + rndis_ul_max_xfer_size_rcvd = 0; + rndis_ul_max_pkt_per_xfer_rcvd = 0; return 0; } EXPORT_SYMBOL(rndis_set_param_dev); @@ -945,6 +963,13 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) } EXPORT_SYMBOL(rndis_set_param_medium); +void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer) +{ + pr_debug("%s:\n", __func__); + + rndis_per_dev_params[configNr].max_pkt_per_xfer = max_pkt_per_xfer; +} + void rndis_add_hdr(struct sk_buff *skb) { struct rndis_packet_msg_type *header; @@ -1020,23 +1045,73 @@ int rndis_rm_hdr(struct gether *port, struct sk_buff *skb, struct sk_buff_head *list) { - /* tmp points to a struct rndis_packet_msg_type */ - __le32 *tmp = (void *)skb->data; + int num_pkts = 1; - /* MessageType, MessageLength */ - if (cpu_to_le32(RNDIS_MSG_PACKET) - != get_unaligned(tmp++)) { - dev_kfree_skb_any(skb); - return -EINVAL; - } - tmp++; + if (skb->len > rndis_ul_max_xfer_size_rcvd) + rndis_ul_max_xfer_size_rcvd = skb->len; + + while (skb->len) { + struct rndis_packet_msg_type *hdr; + struct sk_buff *skb2; + u32 msg_len, data_offset, data_len; + + /* some rndis hosts send extra byte to avoid zlp, ignore it */ + if (skb->len == 1) { + dev_kfree_skb_any(skb); + return 0; + } + + if (skb->len < sizeof *hdr) { + pr_err("invalid rndis pkt: skblen:%u hdr_len:%u", + skb->len, sizeof *hdr); + dev_kfree_skb_any(skb); + return -EINVAL; + } + + hdr = (void *)skb->data; + msg_len = le32_to_cpu(hdr->MessageLength); + data_offset = le32_to_cpu(hdr->DataOffset); + data_len = le32_to_cpu(hdr->DataLength); + + if (skb->len < msg_len || + ((data_offset + data_len + 8) > msg_len)) { + pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n", + le32_to_cpu(hdr->MessageType), + msg_len, data_offset, data_len, skb->len); + dev_kfree_skb_any(skb); + return -EOVERFLOW; + } + if (le32_to_cpu(hdr->MessageType) != RNDIS_MSG_PACKET) { + pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n", + le32_to_cpu(hdr->MessageType), + msg_len, data_offset, data_len, skb->len); + dev_kfree_skb_any(skb); + return -EINVAL; + } + + skb_pull(skb, data_offset + 8); - /* DataOffset, DataLength */ - if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) { - dev_kfree_skb_any(skb); - return -EOVERFLOW; + if (msg_len == skb->len) { + skb_trim(skb, data_len); + break; + } + + skb2 = skb_clone(skb, GFP_ATOMIC); + if (!skb2) { + pr_err("%s:skb clone failed\n", __func__); + dev_kfree_skb_any(skb); + return -ENOMEM; + } + + skb_pull(skb, msg_len - sizeof *hdr); + skb_trim(skb2, data_len); + skb_queue_tail(list, skb2); + + num_pkts++; } - skb_trim(skb, get_unaligned_le32(tmp++)); + + if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd) + rndis_ul_max_pkt_per_xfer_rcvd = num_pkts; skb_queue_tail(list, skb); return 0; diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h index 0f4abb4c3775..145f01b18190 100644 --- a/drivers/usb/gadget/rndis.h +++ b/drivers/usb/gadget/rndis.h @@ -190,6 +190,7 @@ typedef struct rndis_params struct net_device *dev; u32 vendorID; + u8 max_pkt_per_xfer; const char *vendorDescr; void (*resp_avail)(void *v); void *v; @@ -205,6 +206,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev, int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr); int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); +void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer); void rndis_add_hdr (struct sk_buff *skb); int rndis_rm_hdr(struct gether *port, struct sk_buff *skb, struct sk_buff_head *list); diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index b7d4f82872b7..28b291a4e0e5 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -48,6 +48,8 @@ #define UETH__VERSION "29-May-2008" +static struct workqueue_struct *uether_wq; + struct eth_dev { /* lock is held while accessing port_usb */ @@ -59,19 +61,27 @@ struct eth_dev { spinlock_t req_lock; /* guard {rx,tx}_reqs */ struct list_head tx_reqs, rx_reqs; - atomic_t tx_qlen; + unsigned tx_qlen; +/* Minimum number of TX USB request queued to UDC */ +#define TX_REQ_THRESHOLD 5 + int no_tx_req_used; + int tx_skb_hold_count; + u32 tx_req_bufsize; struct sk_buff_head rx_frames; unsigned qmult; unsigned header_len; + unsigned ul_max_pkts_per_xfer; + unsigned dl_max_pkts_per_xfer; struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb); int (*unwrap)(struct gether *, struct sk_buff *skb, struct sk_buff_head *list); struct work_struct work; + struct work_struct rx_work; unsigned long todo; #define WORK_RX_MEMORY 0 @@ -225,9 +235,13 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) size += out->maxpacket - 1; size -= size % out->maxpacket; + if (dev->ul_max_pkts_per_xfer) + size *= dev->ul_max_pkts_per_xfer; + if (dev->port_usb->is_fixed) size = max_t(size_t, size, dev->port_usb->fixed_out_len); + DBG(dev, "%s: size: %d\n", __func__, size); skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags); if (skb == NULL) { DBG(dev, "no rx skb\n"); @@ -253,18 +267,16 @@ enomem: DBG(dev, "rx submit --> %d\n", retval); if (skb) dev_kfree_skb_any(skb); - spin_lock_irqsave(&dev->req_lock, flags); - list_add(&req->list, &dev->rx_reqs); - spin_unlock_irqrestore(&dev->req_lock, flags); } return retval; } static void rx_complete(struct usb_ep *ep, struct usb_request *req) { - struct sk_buff *skb = req->context, *skb2; + struct sk_buff *skb = req->context; struct eth_dev *dev = ep->driver_data; int status = req->status; + bool queue = 0; switch (status) { @@ -280,6 +292,10 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) status = dev->unwrap(dev->port_usb, skb, &dev->rx_frames); + if (status == -EINVAL) + dev->net->stats.rx_errors++; + else if (status == -EOVERFLOW) + dev->net->stats.rx_over_errors++; } else { dev_kfree_skb_any(skb); status = -ENOTCONN; @@ -288,30 +304,9 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) } else { skb_queue_tail(&dev->rx_frames, skb); } - skb = NULL; - - skb2 = skb_dequeue(&dev->rx_frames); - while (skb2) { - if (status < 0 - || ETH_HLEN > skb2->len - || skb2->len > VLAN_ETH_FRAME_LEN) { - dev->net->stats.rx_errors++; - dev->net->stats.rx_length_errors++; - DBG(dev, "rx length %d\n", skb2->len); - dev_kfree_skb_any(skb2); - goto next_frame; - } - skb2->protocol = eth_type_trans(skb2, dev->net); - dev->net->stats.rx_packets++; - dev->net->stats.rx_bytes += skb2->len; - /* no buffer copies needed, unless hardware can't - * use skb buffers. - */ - status = netif_rx(skb2); -next_frame: - skb2 = skb_dequeue(&dev->rx_frames); - } + if (!status) + queue = 1; break; /* software-driven interface shutdown */ @@ -334,22 +329,20 @@ quiesce: /* FALLTHROUGH */ default: + queue = 1; + dev_kfree_skb_any(skb); dev->net->stats.rx_errors++; DBG(dev, "rx status %d\n", status); break; } - if (skb) - dev_kfree_skb_any(skb); - if (!netif_running(dev->net)) { clean: - spin_lock(&dev->req_lock); - list_add(&req->list, &dev->rx_reqs); - spin_unlock(&dev->req_lock); - req = NULL; - } - if (req) - rx_submit(dev, req, GFP_ATOMIC); + spin_lock(&dev->req_lock); + list_add(&req->list, &dev->rx_reqs); + spin_unlock(&dev->req_lock); + + if (queue) + queue_work(uether_wq, &dev->rx_work); } static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) @@ -414,16 +407,24 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) { struct usb_request *req; unsigned long flags; + int req_cnt = 0; /* fill unused rxq slots with some skb */ spin_lock_irqsave(&dev->req_lock, flags); while (!list_empty(&dev->rx_reqs)) { + /* break the nexus of continuous completion and re-submission*/ + if (++req_cnt > qlen(dev->gadget, dev->qmult)) + break; + req = container_of(dev->rx_reqs.next, struct usb_request, list); list_del_init(&req->list); spin_unlock_irqrestore(&dev->req_lock, flags); if (rx_submit(dev, req, gfp_flags) < 0) { + spin_lock_irqsave(&dev->req_lock, flags); + list_add(&req->list, &dev->rx_reqs); + spin_unlock_irqrestore(&dev->req_lock, flags); defer_kevent(dev, WORK_RX_MEMORY); return; } @@ -433,6 +434,36 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) spin_unlock_irqrestore(&dev->req_lock, flags); } +static void process_rx_w(struct work_struct *work) +{ + struct eth_dev *dev = container_of(work, struct eth_dev, rx_work); + struct sk_buff *skb; + int status = 0; + + if (!dev->port_usb) + return; + + while ((skb = skb_dequeue(&dev->rx_frames))) { + if (status < 0 + || ETH_HLEN > skb->len + || skb->len > ETH_FRAME_LEN) { + dev->net->stats.rx_errors++; + dev->net->stats.rx_length_errors++; + DBG(dev, "rx length %d\n", skb->len); + dev_kfree_skb_any(skb); + continue; + } + skb->protocol = eth_type_trans(skb, dev->net); + dev->net->stats.rx_packets++; + dev->net->stats.rx_bytes += skb->len; + + status = netif_rx_ni(skb); + } + + if (netif_running(dev->net)) + rx_fill(dev, GFP_KERNEL); +} + static void eth_work(struct work_struct *work) { struct eth_dev *dev = container_of(work, struct eth_dev, work); @@ -450,6 +481,11 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) { struct sk_buff *skb = req->context; struct eth_dev *dev = ep->driver_data; + struct net_device *net = dev->net; + struct usb_request *new_req; + struct usb_ep *in; + int length; + int retval; switch (req->status) { default: @@ -460,16 +496,74 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) case -ESHUTDOWN: /* disconnect etc */ break; case 0: - dev->net->stats.tx_bytes += skb->len; + if (!req->zero) + dev->net->stats.tx_bytes += req->length-1; + else + dev->net->stats.tx_bytes += req->length; } dev->net->stats.tx_packets++; spin_lock(&dev->req_lock); - list_add(&req->list, &dev->tx_reqs); - spin_unlock(&dev->req_lock); - dev_kfree_skb_any(skb); + list_add_tail(&req->list, &dev->tx_reqs); + + if (dev->port_usb->multi_pkt_xfer) { + dev->no_tx_req_used--; + req->length = 0; + in = dev->port_usb->in_ep; + + if (!list_empty(&dev->tx_reqs)) { + new_req = container_of(dev->tx_reqs.next, + struct usb_request, list); + list_del(&new_req->list); + spin_unlock(&dev->req_lock); + if (new_req->length > 0) { + length = new_req->length; + + /* NCM requires no zlp if transfer is + * dwNtbInMaxSize */ + if (dev->port_usb->is_fixed && + length == dev->port_usb->fixed_in_len && + (length % in->maxpacket) == 0) + new_req->zero = 0; + else + new_req->zero = 1; + + /* use zlp framing on tx for strict CDC-Ether + * conformance, though any robust network rx + * path ignores extra padding. and some hardware + * doesn't like to write zlps. + */ + if (new_req->zero && !dev->zlp && + (length % in->maxpacket) == 0) { + new_req->zero = 0; + length++; + } + + new_req->length = length; + retval = usb_ep_queue(in, new_req, GFP_ATOMIC); + switch (retval) { + default: + DBG(dev, "tx queue err %d\n", retval); + break; + case 0: + spin_lock(&dev->req_lock); + dev->no_tx_req_used++; + spin_unlock(&dev->req_lock); + net->trans_start = jiffies; + } + } else { + spin_lock(&dev->req_lock); + list_add(&new_req->list, &dev->tx_reqs); + spin_unlock(&dev->req_lock); + } + } else { + spin_unlock(&dev->req_lock); + } + } else { + spin_unlock(&dev->req_lock); + dev_kfree_skb_any(skb); + } - atomic_dec(&dev->tx_qlen); if (netif_carrier_ok(dev->net)) netif_wake_queue(dev->net); } @@ -479,6 +573,26 @@ static inline int is_promisc(u16 cdc_filter) return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; } +static void alloc_tx_buffer(struct eth_dev *dev) +{ + struct list_head *act; + struct usb_request *req; + + dev->tx_req_bufsize = (dev->dl_max_pkts_per_xfer * + (dev->net->mtu + + sizeof(struct ethhdr) + /* size of rndis_packet_msg_type */ + + 44 + + 22)); + + list_for_each(act, &dev->tx_reqs) { + req = container_of(act, struct usb_request, list); + if (!req->buf) + req->buf = kmalloc(dev->tx_req_bufsize, + GFP_ATOMIC); + } +} + static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct net_device *net) { @@ -505,6 +619,10 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } + /* Allocate memory for tx_reqs to support multi packet transfer */ + if (dev->port_usb->multi_pkt_xfer && !dev->tx_req_bufsize) + alloc_tx_buffer(dev); + /* apply outgoing CDC or RNDIS filters */ if (!is_promisc(cdc_filter)) { u8 *dest = skb->data; @@ -559,11 +677,39 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, spin_unlock_irqrestore(&dev->lock, flags); if (!skb) goto drop; + } + spin_lock_irqsave(&dev->req_lock, flags); + dev->tx_skb_hold_count++; + spin_unlock_irqrestore(&dev->req_lock, flags); + + if (dev->port_usb->multi_pkt_xfer) { + memcpy(req->buf + req->length, skb->data, skb->len); + req->length = req->length + skb->len; + length = req->length; + dev_kfree_skb_any(skb); + + spin_lock_irqsave(&dev->req_lock, flags); + if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) { + if (dev->no_tx_req_used > TX_REQ_THRESHOLD) { + list_add(&req->list, &dev->tx_reqs); + spin_unlock_irqrestore(&dev->req_lock, flags); + goto success; + } + } + + dev->no_tx_req_used++; + spin_unlock_irqrestore(&dev->req_lock, flags); + + spin_lock_irqsave(&dev->lock, flags); + dev->tx_skb_hold_count = 0; + spin_unlock_irqrestore(&dev->lock, flags); + } else { length = skb->len; + req->buf = skb->data; + req->context = skb; } - req->buf = skb->data; - req->context = skb; + req->complete = tx_complete; /* NCM requires no zlp if transfer is dwNtbInMaxSize */ @@ -578,17 +724,26 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, * though any robust network rx path ignores extra padding. * and some hardware doesn't like to write zlps. */ - if (req->zero && !dev->zlp && (length % in->maxpacket) == 0) + if (req->zero && !dev->zlp && (length % in->maxpacket) == 0) { + req->zero = 0; length++; + } req->length = length; - /* throttle high/super speed IRQ rate back slightly */ - if (gadget_is_dualspeed(dev->gadget)) - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH || - dev->gadget->speed == USB_SPEED_SUPER) - ? ((atomic_read(&dev->tx_qlen) % dev->qmult) != 0) - : 0; + /* throttle highspeed IRQ rate back slightly */ + if (gadget_is_dualspeed(dev->gadget) && + (dev->gadget->speed == USB_SPEED_HIGH)) { + dev->tx_qlen++; + if (dev->tx_qlen == (dev->qmult/2)) { + req->no_interrupt = 0; + dev->tx_qlen = 0; + } else { + req->no_interrupt = 1; + } + } else { + req->no_interrupt = 0; + } retval = usb_ep_queue(in, req, GFP_ATOMIC); switch (retval) { @@ -597,11 +752,11 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, break; case 0: net->trans_start = jiffies; - atomic_inc(&dev->tx_qlen); } if (retval) { - dev_kfree_skb_any(skb); + if (!dev->port_usb->multi_pkt_xfer) + dev_kfree_skb_any(skb); drop: dev->net->stats.tx_dropped++; spin_lock_irqsave(&dev->req_lock, flags); @@ -610,6 +765,7 @@ drop: list_add(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } +success: return NETDEV_TX_OK; } @@ -623,7 +779,7 @@ static void eth_start(struct eth_dev *dev, gfp_t gfp_flags) rx_fill(dev, gfp_flags); /* and open the tx floodgates */ - atomic_set(&dev->tx_qlen, 0); + dev->tx_qlen = 0; netif_wake_queue(dev->net); } @@ -696,6 +852,8 @@ static int eth_stop(struct net_device *net) /*-------------------------------------------------------------------------*/ +static u8 host_ethaddr[ETH_ALEN]; + static int get_ether_addr(const char *str, u8 *dev_addr) { if (str) { @@ -728,6 +886,17 @@ static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len) return 18; } +static int get_host_ether_addr(u8 *str, u8 *dev_addr) +{ + memcpy(dev_addr, str, ETH_ALEN); + if (is_valid_ether_addr(dev_addr)) + return 0; + + random_ether_addr(dev_addr); + memcpy(str, dev_addr, ETH_ALEN); + return 1; +} + static const struct net_device_ops eth_netdev_ops = { .ndo_open = eth_open, .ndo_stop = eth_stop, @@ -771,6 +940,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, spin_lock_init(&dev->lock); spin_lock_init(&dev->req_lock); INIT_WORK(&dev->work, eth_work); + INIT_WORK(&dev->rx_work, process_rx_w); INIT_LIST_HEAD(&dev->tx_reqs); INIT_LIST_HEAD(&dev->rx_reqs); @@ -784,9 +954,11 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&g->dev, "using random %s ethernet address\n", "self"); - if (get_ether_addr(host_addr, dev->host_mac)) - dev_warn(&g->dev, - "using random %s ethernet address\n", "host"); + + if (get_host_ether_addr(host_ethaddr, dev->host_mac)) + dev_warn(&g->dev, "using random %s ethernet address\n", "host"); + else + dev_warn(&g->dev, "using previous %s ethernet address\n", "host"); if (ethaddr) memcpy(ethaddr, dev->host_mac, ETH_ALEN); @@ -1067,8 +1239,13 @@ struct net_device *gether_connect(struct gether *link) dev->header_len = link->header_len; dev->unwrap = link->unwrap; dev->wrap = link->wrap; + dev->ul_max_pkts_per_xfer = link->ul_max_pkts_per_xfer; + dev->dl_max_pkts_per_xfer = link->dl_max_pkts_per_xfer; spin_lock(&dev->lock); + dev->tx_skb_hold_count = 0; + dev->no_tx_req_used = 0; + dev->tx_req_bufsize = 0; dev->port_usb = link; if (netif_running(dev->net)) { if (link->open) @@ -1113,6 +1290,7 @@ void gether_disconnect(struct gether *link) { struct eth_dev *dev = link->ioport; struct usb_request *req; + struct sk_buff *skb; WARN_ON(!dev); if (!dev) @@ -1135,6 +1313,8 @@ void gether_disconnect(struct gether *link) list_del(&req->list); spin_unlock(&dev->req_lock); + if (link->multi_pkt_xfer) + kfree(req->buf); usb_ep_free_request(link->in_ep, req); spin_lock(&dev->req_lock); } @@ -1154,6 +1334,12 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); + + spin_lock(&dev->rx_frames.lock); + while ((skb = __skb_dequeue(&dev->rx_frames))) + dev_kfree_skb_any(skb); + spin_unlock(&dev->rx_frames.lock); + link->out_ep->driver_data = NULL; link->out_ep->desc = NULL; @@ -1168,5 +1354,23 @@ void gether_disconnect(struct gether *link) } EXPORT_SYMBOL(gether_disconnect); -MODULE_LICENSE("GPL"); +static int __init gether_init(void) +{ + uether_wq = create_singlethread_workqueue("uether"); + if (!uether_wq) { + pr_err("%s: Unable to create workqueue: uether\n", __func__); + return -ENOMEM; + } + return 0; +} +module_init(gether_init); + +static void __exit gether_exit(void) +{ + destroy_workqueue(uether_wq); + +} +module_exit(gether_exit); MODULE_AUTHOR("David Brownell"); +MODULE_DESCRIPTION("ethernet over USB driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index 0f0290acea7e..e971b8a9a042 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -74,6 +74,9 @@ struct gether { bool is_fixed; u32 fixed_out_len; u32 fixed_in_len; + unsigned ul_max_pkts_per_xfer; + unsigned dl_max_pkts_per_xfer; + bool multi_pkt_xfer; struct sk_buff *(*wrap)(struct gether *port, struct sk_buff *skb); int (*unwrap)(struct gether *port, diff --git a/drivers/video/adf/adf.c b/drivers/video/adf/adf.c index 2d20024fd251..42c30c05826a 100644 --- a/drivers/video/adf/adf.c +++ b/drivers/video/adf/adf.c @@ -2,6 +2,8 @@ * Copyright (C) 2013 Google, Inc. * adf_modeinfo_{set_name,set_vrefresh} modified from * drivers/gpu/drm/drm_modes.c + * adf_format_validate_yuv modified from framebuffer_check in + * drivers/gpu/drm/drm_crtc.c * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -492,6 +494,7 @@ static void adf_obj_destroy(struct adf_obj *obj, struct idr *idr) struct adf_event_refcount *refcount = container_of(node, struct adf_event_refcount, node); + rb_erase(&refcount->node, &obj->event_refcount); kfree(refcount); node = rb_first(&obj->event_refcount); } @@ -610,6 +613,10 @@ void adf_device_destroy(struct adf_device *dev) } mutex_destroy(&dev->post_lock); mutex_destroy(&dev->client_lock); + + if (dev->timeline) + sync_timeline_destroy(&dev->timeline->obj); + adf_obj_destroy(&dev->base, &adf_devices); } EXPORT_SYMBOL(adf_device_destroy); @@ -1071,6 +1078,7 @@ int adf_format_validate_yuv(struct adf_device *dev, struct adf_buffer *buf, u32 width = buf->w / (i != 0 ? hsub : 1); u32 height = buf->h / (i != 0 ? vsub : 1); u8 cpp = adf_format_plane_cpp(buf->format, i); + u32 last_line_size; if (buf->pitch[i] < (u64) width * cpp) { dev_err(&dev->base.dev, "plane %u pitch is shorter than buffer width (pitch = %u, width = %u, bpp = %u)\n", @@ -1078,8 +1086,21 @@ int adf_format_validate_yuv(struct adf_device *dev, struct adf_buffer *buf, return -EINVAL; } - if ((u64) height * buf->pitch[i] + buf->offset[i] > - buf->dma_bufs[i]->size) { + switch (dev->ops->quirks.buffer_padding) { + case ADF_BUFFER_PADDED_TO_PITCH: + last_line_size = buf->pitch[i]; + break; + + case ADF_BUFFER_UNPADDED: + last_line_size = width * cpp; + break; + + default: + BUG(); + } + + if ((u64) (height - 1) * buf->pitch[i] + last_line_size + + buf->offset[i] > buf->dma_bufs[i]->size) { dev_err(&dev->base.dev, "plane %u buffer too small (height = %u, pitch = %u, offset = %u, size = %zu)\n", i, height, buf->pitch[i], buf->offset[i], buf->dma_bufs[i]->size); diff --git a/drivers/video/adf/adf_fbdev.c b/drivers/video/adf/adf_fbdev.c index cac34d14cbc2..a5b53bc08c3f 100644 --- a/drivers/video/adf/adf_fbdev.c +++ b/drivers/video/adf/adf_fbdev.c @@ -136,13 +136,13 @@ void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode, vmode->vsync_len = mode->vsync_end - mode->vsync_start; vmode->sync = 0; - if (mode->flags | DRM_MODE_FLAG_PHSYNC) + if (mode->flags & DRM_MODE_FLAG_PHSYNC) vmode->sync |= FB_SYNC_HOR_HIGH_ACT; - if (mode->flags | DRM_MODE_FLAG_PVSYNC) + if (mode->flags & DRM_MODE_FLAG_PVSYNC) vmode->sync |= FB_SYNC_VERT_HIGH_ACT; - if (mode->flags | DRM_MODE_FLAG_PCSYNC) + if (mode->flags & DRM_MODE_FLAG_PCSYNC) vmode->sync |= FB_SYNC_COMP_HIGH_ACT; - if (mode->flags | DRM_MODE_FLAG_BCAST) + if (mode->flags & DRM_MODE_FLAG_BCAST) vmode->sync |= FB_SYNC_BROADCAST; vmode->vmode = 0; @@ -356,18 +356,25 @@ int adf_fbdev_open(struct fb_info *info, int user) struct adf_fbdev *fbdev = info->par; int ret; - if (!fbdev->open) { + mutex_lock(&fbdev->refcount_lock); + + if (unlikely(fbdev->refcount == UINT_MAX)) { + ret = -EMFILE; + goto done; + } + + if (!fbdev->refcount) { struct drm_mode_modeinfo mode; struct fb_videomode fbmode; struct adf_device *dev = adf_interface_parent(fbdev->intf); ret = adf_device_attach(dev, fbdev->eng, fbdev->intf); if (ret < 0 && ret != -EALREADY) - return ret; + goto done; ret = adf_fb_alloc(fbdev); if (ret < 0) - return ret; + goto done; adf_interface_current_mode(fbdev->intf, &mode); adf_modeinfo_to_fb_videomode(&mode, &fbmode); @@ -379,13 +386,15 @@ int adf_fbdev_open(struct fb_info *info, int user) ret = adf_fbdev_post(fbdev); if (ret < 0) { - if (!fbdev->open) + if (!fbdev->refcount) adf_fb_destroy(fbdev); - return ret; + goto done; } - fbdev->open = true; - return 0; + fbdev->refcount++; +done: + mutex_unlock(&fbdev->refcount_lock); + return ret; } EXPORT_SYMBOL(adf_fbdev_open); @@ -395,8 +404,12 @@ EXPORT_SYMBOL(adf_fbdev_open); int adf_fbdev_release(struct fb_info *info, int user) { struct adf_fbdev *fbdev = info->par; - adf_fb_destroy(fbdev); - fbdev->open = false; + mutex_lock(&fbdev->refcount_lock); + BUG_ON(!fbdev->refcount); + fbdev->refcount--; + if (!fbdev->refcount) + adf_fb_destroy(fbdev); + mutex_unlock(&fbdev->refcount_lock); return 0; } EXPORT_SYMBOL(adf_fbdev_release); @@ -601,6 +614,7 @@ int adf_fbdev_init(struct adf_fbdev *fbdev, struct adf_interface *interface, dev_err(dev, "allocating framebuffer device failed\n"); return -ENOMEM; } + mutex_init(&fbdev->refcount_lock); fbdev->default_xres_virtual = xres_virtual; fbdev->default_yres_virtual = yres_virtual; fbdev->default_format = format; @@ -644,8 +658,8 @@ EXPORT_SYMBOL(adf_fbdev_init); void adf_fbdev_destroy(struct adf_fbdev *fbdev) { unregister_framebuffer(fbdev->info); - if (WARN_ON(fbdev->open)) - adf_fb_destroy(fbdev); + BUG_ON(fbdev->refcount); + mutex_destroy(&fbdev->refcount_lock); framebuffer_release(fbdev->info); } EXPORT_SYMBOL(adf_fbdev_destroy); diff --git a/drivers/video/adf/adf_fops.c b/drivers/video/adf/adf_fops.c index abec58ea2ed8..7fbf33e1cb39 100644 --- a/drivers/video/adf/adf_fops.c +++ b/drivers/video/adf/adf_fops.c @@ -187,7 +187,7 @@ static int adf_buffer_import(struct adf_device *dev, buf->dma_bufs[i] = dma_buf_get(user_buf.fd[i]); if (IS_ERR(buf->dma_bufs[i])) { ret = PTR_ERR(buf->dma_bufs[i]); - dev_err(&dev->base.dev, "importing dma_buf fd %llu failed: %d\n", + dev_err(&dev->base.dev, "importing dma_buf fd %d failed: %d\n", user_buf.fd[i], ret); buf->dma_bufs[i] = NULL; goto done; @@ -200,7 +200,7 @@ static int adf_buffer_import(struct adf_device *dev, if (user_buf.acquire_fence >= 0) { buf->acquire_fence = sync_fence_fdget(user_buf.acquire_fence); if (!buf->acquire_fence) { - dev_err(&dev->base.dev, "getting fence fd %lld failed\n", + dev_err(&dev->base.dev, "getting fence fd %d failed\n", user_buf.acquire_fence); ret = -EINVAL; goto done; diff --git a/drivers/video/adf/adf_fops32.h b/drivers/video/adf/adf_fops32.h index 53d43f010208..64034ce33a6b 100644 --- a/drivers/video/adf/adf_fops32.h +++ b/drivers/video/adf/adf_fops32.h @@ -25,7 +25,7 @@ struct adf_post_config32 { compat_size_t custom_data_size; compat_uptr_t custom_data; - __s64 complete_fence; + __s32 complete_fence; }; struct adf_device_data32 { diff --git a/drivers/video/adf/adf_memblock.c b/drivers/video/adf/adf_memblock.c index 3c99f27388db..e73a7d59f1e6 100644 --- a/drivers/video/adf/adf_memblock.c +++ b/drivers/video/adf/adf_memblock.c @@ -28,7 +28,7 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach, unsigned long pfn = PFN_DOWN(pdata->base); struct page *page = pfn_to_page(pfn); struct sg_table *table; - int ret; + int nents, ret; table = kzalloc(sizeof(*table), GFP_KERNEL); if (!table) @@ -36,12 +36,21 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach, ret = sg_alloc_table(table, 1, GFP_KERNEL); if (ret < 0) - goto err; + goto err_alloc; sg_set_page(table->sgl, page, attach->dmabuf->size, 0); + + nents = dma_map_sg(attach->dev, table->sgl, 1, direction); + if (!nents) { + ret = -EINVAL; + goto err_map; + } + return table; -err: +err_map: + sg_free_table(table); +err_alloc: kfree(table); return ERR_PTR(ret); } @@ -49,6 +58,7 @@ err: static void adf_memblock_unmap(struct dma_buf_attachment *attach, struct sg_table *table, enum dma_data_direction direction) { + dma_unmap_sg(attach->dev, table->sgl, 1, direction); sg_free_table(table); } @@ -147,3 +157,4 @@ struct dma_buf *adf_memblock_export(phys_addr_t base, size_t size, int flags) return buf; } +EXPORT_SYMBOL(adf_memblock_export); diff --git a/fs/exec.c b/fs/exec.c index ea4449d0536a..327f5cefcda2 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1230,7 +1230,7 @@ EXPORT_SYMBOL(install_exec_creds); /* * determine how safe it is to execute the proposed program * - the caller must hold ->cred_guard_mutex to protect against - * PTRACE_ATTACH + * PTRACE_ATTACH or seccomp thread-sync */ static void check_unsafe_exec(struct linux_binprm *bprm) { @@ -1248,7 +1248,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm) * This isn't strictly necessary, but it makes it harder for LSMs to * mess up. */ - if (current->no_new_privs) + if (task_no_new_privs(current)) bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS; t = p; @@ -1286,7 +1286,7 @@ int prepare_binprm(struct linux_binprm *bprm) bprm->cred->egid = current_egid(); if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) && - !current->no_new_privs && + !task_no_new_privs(current) && kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) && kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) { /* Set-uid? */ diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 2a6830a7af33..5d00bd5fc00e 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2084,7 +2084,8 @@ extern int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t i, struct ext4_group_desc *desc); extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, ext4_fsblk_t block, unsigned long count); -extern int ext4_trim_fs(struct super_block *, struct fstrim_range *); +extern int ext4_trim_fs(struct super_block *, struct fstrim_range *, + unsigned long blkdev_flags); /* inode.c */ struct buffer_head *ext4_getblk(handle_t *, struct inode *, diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index dfe982dee0b3..06b705fe1d8e 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -599,11 +599,13 @@ resizefs_out: return err; } + case FIDTRIM: case FITRIM: { struct request_queue *q = bdev_get_queue(sb->s_bdev); struct fstrim_range range; int ret = 0; + int flags = cmd == FIDTRIM ? BLKDEV_DISCARD_SECURE : 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -611,13 +613,15 @@ resizefs_out: if (!blk_queue_discard(q)) return -EOPNOTSUPP; + if ((flags & BLKDEV_DISCARD_SECURE) && !blk_queue_secdiscard(q)) + return -EOPNOTSUPP; if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range))) return -EFAULT; range.minlen = max((unsigned int)range.minlen, q->limits.discard_granularity); - ret = ext4_trim_fs(sb, &range); + ret = ext4_trim_fs(sb, &range, flags); if (ret < 0) return ret; diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 242226a87be7..17728b7b6428 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2726,7 +2726,8 @@ int ext4_mb_release(struct super_block *sb) } static inline int ext4_issue_discard(struct super_block *sb, - ext4_group_t block_group, ext4_grpblk_t cluster, int count) + ext4_group_t block_group, ext4_grpblk_t cluster, int count, + unsigned long flags) { ext4_fsblk_t discard_block; @@ -2735,7 +2736,7 @@ static inline int ext4_issue_discard(struct super_block *sb, count = EXT4_C2B(EXT4_SB(sb), count); trace_ext4_discard_blocks(sb, (unsigned long long) discard_block, count); - return sb_issue_discard(sb, discard_block, count, GFP_NOFS, 0); + return sb_issue_discard(sb, discard_block, count, GFP_NOFS, flags); } /* @@ -2757,7 +2758,7 @@ static void ext4_free_data_callback(struct super_block *sb, if (test_opt(sb, DISCARD)) { err = ext4_issue_discard(sb, entry->efd_group, entry->efd_start_cluster, - entry->efd_count); + entry->efd_count, 0); if (err && err != -EOPNOTSUPP) ext4_msg(sb, KERN_WARNING, "discard request in" " group:%d block:%d count:%d failed" @@ -4817,7 +4818,8 @@ do_more: * them with group lock_held */ if (test_opt(sb, DISCARD)) { - err = ext4_issue_discard(sb, block_group, bit, count); + err = ext4_issue_discard(sb, block_group, bit, count, + 0); if (err && err != -EOPNOTSUPP) ext4_msg(sb, KERN_WARNING, "discard request in" " group:%d block:%d count:%lu failed" @@ -5024,13 +5026,15 @@ error_return: * @count: number of blocks to TRIM * @group: alloc. group we are working with * @e4b: ext4 buddy for the group + * @blkdev_flags: flags for the block device * * Trim "count" blocks starting at "start" in the "group". To assure that no * one will allocate those blocks, mark it as used in buddy bitmap. This must * be called with under the group lock. */ static int ext4_trim_extent(struct super_block *sb, int start, int count, - ext4_group_t group, struct ext4_buddy *e4b) + ext4_group_t group, struct ext4_buddy *e4b, + unsigned long blkdev_flags) { struct ext4_free_extent ex; int ret = 0; @@ -5049,7 +5053,7 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count, */ mb_mark_used(e4b, &ex); ext4_unlock_group(sb, group); - ret = ext4_issue_discard(sb, group, start, count); + ret = ext4_issue_discard(sb, group, start, count, blkdev_flags); ext4_lock_group(sb, group); mb_free_blocks(NULL, e4b, start, ex.fe_len); return ret; @@ -5062,6 +5066,7 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count, * @start: first group block to examine * @max: last group block to examine * @minblocks: minimum extent block count + * @blkdev_flags: flags for the block device * * ext4_trim_all_free walks through group's buddy bitmap searching for free * extents. When the free block is found, ext4_trim_extent is called to TRIM @@ -5076,7 +5081,7 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count, static ext4_grpblk_t ext4_trim_all_free(struct super_block *sb, ext4_group_t group, ext4_grpblk_t start, ext4_grpblk_t max, - ext4_grpblk_t minblocks) + ext4_grpblk_t minblocks, unsigned long blkdev_flags) { void *bitmap; ext4_grpblk_t next, count = 0, free_count = 0; @@ -5109,7 +5114,8 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, if ((next - start) >= minblocks) { ret = ext4_trim_extent(sb, start, - next - start, group, &e4b); + next - start, group, &e4b, + blkdev_flags); if (ret && ret != -EOPNOTSUPP) break; ret = 0; @@ -5151,6 +5157,7 @@ out: * ext4_trim_fs() -- trim ioctl handle function * @sb: superblock for filesystem * @range: fstrim_range structure + * @blkdev_flags: flags for the block device * * start: First Byte to trim * len: number of Bytes to trim from start @@ -5159,7 +5166,8 @@ out: * start to start+len. For each such a group ext4_trim_all_free function * is invoked to trim all free space. */ -int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) +int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range, + unsigned long blkdev_flags) { struct ext4_group_info *grp; ext4_group_t group, first_group, last_group; @@ -5215,7 +5223,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) if (grp->bb_free >= minlen) { cnt = ext4_trim_all_free(sb, group, first_cluster, - end, minlen); + end, minlen, blkdev_flags); if (cnt < 0) { ret = cnt; break; diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 983d9510becc..916b8e23d968 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -21,6 +21,16 @@ config PSTORE_CONSOLE When the option is enabled, pstore will log all kernel messages, even if no oops or panic happened. +config PSTORE_PMSG + bool "Log user space messages" + depends on PSTORE + help + When the option is enabled, pstore will export a character + interface /dev/pmsg0 to log user space messages. On reboot + data can be retrieved from /sys/fs/pstore/pmsg-ramoops-[ID]. + + If unsure, say N. + config PSTORE_FTRACE bool "Persistent function tracer" depends on PSTORE diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile index 4c9095c2781e..e647d8e81712 100644 --- a/fs/pstore/Makefile +++ b/fs/pstore/Makefile @@ -7,5 +7,7 @@ obj-y += pstore.o pstore-objs += inode.o platform.o obj-$(CONFIG_PSTORE_FTRACE) += ftrace.o +obj-$(CONFIG_PSTORE_PMSG) += pmsg.o + ramoops-objs += ram.o ram_core.o obj-$(CONFIG_PSTORE_RAM) += ramoops.o diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 14120a3c6195..c6e2faae7822 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -315,32 +315,38 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, switch (type) { case PSTORE_TYPE_DMESG: - sprintf(name, "dmesg-%s-%lld%s", psname, id, - compressed ? ".enc.z" : ""); + scnprintf(name, sizeof(name), "dmesg-%s-%lld%s", + psname, id, compressed ? ".enc.z" : ""); break; case PSTORE_TYPE_CONSOLE: - sprintf(name, "console-%s-%lld", psname, id); + scnprintf(name, sizeof(name), "console-%s", psname); break; case PSTORE_TYPE_FTRACE: - sprintf(name, "ftrace-%s-%lld", psname, id); + scnprintf(name, sizeof(name), "ftrace-%s", psname); break; case PSTORE_TYPE_MCE: - sprintf(name, "mce-%s-%lld", psname, id); + scnprintf(name, sizeof(name), "mce-%s-%lld", psname, id); break; case PSTORE_TYPE_PPC_RTAS: - sprintf(name, "rtas-%s-%lld", psname, id); + scnprintf(name, sizeof(name), "rtas-%s-%lld", psname, id); break; case PSTORE_TYPE_PPC_OF: - sprintf(name, "powerpc-ofw-%s-%lld", psname, id); + scnprintf(name, sizeof(name), "powerpc-ofw-%s-%lld", + psname, id); break; case PSTORE_TYPE_PPC_COMMON: - sprintf(name, "powerpc-common-%s-%lld", psname, id); + scnprintf(name, sizeof(name), "powerpc-common-%s-%lld", + psname, id); + break; + case PSTORE_TYPE_PMSG: + scnprintf(name, sizeof(name), "pmsg-%s-%lld", psname, id); break; case PSTORE_TYPE_UNKNOWN: - sprintf(name, "unknown-%s-%lld", psname, id); + scnprintf(name, sizeof(name), "unknown-%s-%lld", psname, id); break; default: - sprintf(name, "type%d-%s-%lld", type, psname, id); + scnprintf(name, sizeof(name), "type%d-%s-%lld", + type, psname, id); break; } diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h index 3b3d305277c4..c36ba2cd0b5d 100644 --- a/fs/pstore/internal.h +++ b/fs/pstore/internal.h @@ -45,6 +45,12 @@ extern void pstore_register_ftrace(void); static inline void pstore_register_ftrace(void) {} #endif +#ifdef CONFIG_PSTORE_PMSG +extern void pstore_register_pmsg(void); +#else +static inline void pstore_register_pmsg(void) {} +#endif + extern struct pstore_info *psinfo; extern void pstore_set_kmsg_bytes(int); diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 78c3c2097787..b2741b2e6c5b 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -447,6 +447,7 @@ int pstore_register(struct pstore_info *psi) if ((psi->flags & PSTORE_FLAGS_FRAGILE) == 0) { pstore_register_console(); pstore_register_ftrace(); + pstore_register_pmsg(); } if (pstore_update_ms >= 0) { diff --git a/fs/pstore/pmsg.c b/fs/pstore/pmsg.c new file mode 100644 index 000000000000..feb5dd2948b4 --- /dev/null +++ b/fs/pstore/pmsg.c @@ -0,0 +1,114 @@ +/* + * Copyright 2014 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/vmalloc.h> +#include "internal.h" + +static DEFINE_MUTEX(pmsg_lock); +#define PMSG_MAX_BOUNCE_BUFFER_SIZE (2*PAGE_SIZE) + +static ssize_t write_pmsg(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + size_t i, buffer_size; + char *buffer; + + if (!count) + return 0; + + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + + buffer_size = count; + if (buffer_size > PMSG_MAX_BOUNCE_BUFFER_SIZE) + buffer_size = PMSG_MAX_BOUNCE_BUFFER_SIZE; + buffer = vmalloc(buffer_size); + + mutex_lock(&pmsg_lock); + for (i = 0; i < count; ) { + size_t c = min(count - i, buffer_size); + u64 id; + long ret; + + ret = __copy_from_user(buffer, buf + i, c); + if (unlikely(ret != 0)) { + mutex_unlock(&pmsg_lock); + vfree(buffer); + return -EFAULT; + } + psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id, 0, buffer, 0, c, + psinfo); + + i += c; + } + + mutex_unlock(&pmsg_lock); + vfree(buffer); + return count; +} + +static const struct file_operations pmsg_fops = { + .owner = THIS_MODULE, + .llseek = noop_llseek, + .write = write_pmsg, +}; + +static struct class *pmsg_class; +static int pmsg_major; +#define PMSG_NAME "pmsg" +#undef pr_fmt +#define pr_fmt(fmt) PMSG_NAME ": " fmt + +static char *pmsg_devnode(struct device *dev, umode_t *mode) +{ + if (mode) + *mode = 0220; + return NULL; +} + +void pstore_register_pmsg(void) +{ + struct device *pmsg_device; + + pmsg_major = register_chrdev(0, PMSG_NAME, &pmsg_fops); + if (pmsg_major < 0) { + pr_err("register_chrdev failed\n"); + goto err; + } + + pmsg_class = class_create(THIS_MODULE, PMSG_NAME); + if (IS_ERR(pmsg_class)) { + pr_err("device class file already in use\n"); + goto err_class; + } + pmsg_class->devnode = pmsg_devnode; + + pmsg_device = device_create(pmsg_class, NULL, MKDEV(pmsg_major, 0), + NULL, "%s%d", PMSG_NAME, 0); + if (IS_ERR(pmsg_device)) { + pr_err("failed to create device\n"); + goto err_device; + } + return; + +err_device: + class_destroy(pmsg_class); +err_class: + unregister_chrdev(pmsg_major, PMSG_NAME); +err: + return; +} diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index e7d95f959333..e1c7a3faae38 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -51,6 +51,10 @@ static ulong ramoops_ftrace_size = MIN_MEM_SIZE; module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400); MODULE_PARM_DESC(ftrace_size, "size of ftrace log"); +static ulong ramoops_pmsg_size = MIN_MEM_SIZE; +module_param_named(pmsg_size, ramoops_pmsg_size, ulong, 0400); +MODULE_PARM_DESC(pmsg_size, "size of user space message log"); + static ulong mem_address; module_param(mem_address, ulong, 0400); MODULE_PARM_DESC(mem_address, @@ -82,19 +86,23 @@ struct ramoops_context { struct persistent_ram_zone **przs; struct persistent_ram_zone *cprz; struct persistent_ram_zone *fprz; + struct persistent_ram_zone *mprz; phys_addr_t phys_addr; unsigned long size; unsigned int memtype; size_t record_size; size_t console_size; size_t ftrace_size; + size_t pmsg_size; int dump_oops; struct persistent_ram_ecc_info ecc_info; unsigned int max_dump_cnt; unsigned int dump_write_cnt; + /* _read_cnt need clear on ramoops_pstore_open */ unsigned int dump_read_cnt; unsigned int console_read_cnt; unsigned int ftrace_read_cnt; + unsigned int pmsg_read_cnt; struct pstore_info pstore; }; @@ -107,6 +115,8 @@ static int ramoops_pstore_open(struct pstore_info *psi) cxt->dump_read_cnt = 0; cxt->console_read_cnt = 0; + cxt->ftrace_read_cnt = 0; + cxt->pmsg_read_cnt = 0; return 0; } @@ -158,6 +168,12 @@ static void ramoops_read_kmsg_hdr(char *buffer, struct timespec *time, } } +static bool prz_ok(struct persistent_ram_zone *prz) +{ + return !!prz && !!(persistent_ram_old_size(prz) + + persistent_ram_ecc_string(prz, NULL, 0)); +} + static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, bool *compressed, @@ -171,13 +187,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt, cxt->max_dump_cnt, id, type, PSTORE_TYPE_DMESG, 1); - if (!prz) + if (!prz_ok(prz)) prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt, 1, id, type, PSTORE_TYPE_CONSOLE, 0); - if (!prz) + if (!prz_ok(prz)) prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt, 1, id, type, PSTORE_TYPE_FTRACE, 0); - if (!prz) + if (!prz_ok(prz)) + prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt, + 1, id, type, PSTORE_TYPE_PMSG, 0); + if (!prz_ok(prz)) return 0; size = persistent_ram_old_size(prz); @@ -240,6 +259,11 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, return -ENOMEM; persistent_ram_write(cxt->fprz, buf, size); return 0; + } else if (type == PSTORE_TYPE_PMSG) { + if (!cxt->mprz) + return -ENOMEM; + persistent_ram_write(cxt->mprz, buf, size); + return 0; } if (type != PSTORE_TYPE_DMESG) @@ -297,6 +321,9 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count, case PSTORE_TYPE_FTRACE: prz = cxt->fprz; break; + case PSTORE_TYPE_PMSG: + prz = cxt->mprz; + break; default: return -EINVAL; } @@ -406,6 +433,12 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, return 0; } +void notrace ramoops_console_write_buf(const char *buf, size_t size) +{ + struct ramoops_context *cxt = &oops_cxt; + persistent_ram_write(cxt->cprz, buf, size); +} + static int ramoops_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -422,7 +455,7 @@ static int ramoops_probe(struct platform_device *pdev) goto fail_out; if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && - !pdata->ftrace_size)) { + !pdata->ftrace_size && !pdata->pmsg_size)) { pr_err("The memory size and the record/console size must be " "non-zero\n"); goto fail_out; @@ -434,20 +467,23 @@ static int ramoops_probe(struct platform_device *pdev) pdata->console_size = rounddown_pow_of_two(pdata->console_size); if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size)) pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); + if (pdata->pmsg_size && !is_power_of_2(pdata->pmsg_size)) + pdata->pmsg_size = rounddown_pow_of_two(pdata->pmsg_size); - cxt->dump_read_cnt = 0; cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; cxt->memtype = pdata->mem_type; cxt->record_size = pdata->record_size; cxt->console_size = pdata->console_size; cxt->ftrace_size = pdata->ftrace_size; + cxt->pmsg_size = pdata->pmsg_size; cxt->dump_oops = pdata->dump_oops; cxt->ecc_info = pdata->ecc_info; paddr = cxt->phys_addr; - dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size; + dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size + - cxt->pmsg_size; err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); if (err) goto fail_out; @@ -462,13 +498,9 @@ static int ramoops_probe(struct platform_device *pdev) if (err) goto fail_init_fprz; - if (!cxt->przs && !cxt->cprz && !cxt->fprz) { - pr_err("memory size too small, minimum is %zu\n", - cxt->console_size + cxt->record_size + - cxt->ftrace_size); - err = -EINVAL; - goto fail_cnt; - } + err = ramoops_init_prz(dev, cxt, &cxt->mprz, &paddr, cxt->pmsg_size, 0); + if (err) + goto fail_init_mprz; cxt->pstore.data = cxt; /* @@ -514,7 +546,8 @@ fail_buf: fail_clear: cxt->pstore.bufsize = 0; cxt->max_dump_cnt = 0; -fail_cnt: + kfree(cxt->mprz); +fail_init_mprz: kfree(cxt->fprz); fail_init_fprz: kfree(cxt->cprz); @@ -573,6 +606,7 @@ static void ramoops_register_dummy(void) dummy_data->record_size = record_size; dummy_data->console_size = ramoops_console_size; dummy_data->ftrace_size = ramoops_ftrace_size; + dummy_data->pmsg_size = ramoops_pmsg_size; dummy_data->dump_oops = dump_oops; /* * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC diff --git a/fs/seq_file.c b/fs/seq_file.c index 1d641bb108d2..3857b720cb1b 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -8,8 +8,10 @@ #include <linux/fs.h> #include <linux/export.h> #include <linux/seq_file.h> +#include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/cred.h> +#include <linux/mm.h> #include <asm/uaccess.h> #include <asm/page.h> @@ -30,6 +32,16 @@ static void seq_set_overflow(struct seq_file *m) m->count = m->size; } +static void *seq_buf_alloc(unsigned long size) +{ + void *buf; + + buf = kmalloc(size, GFP_KERNEL | __GFP_NOWARN); + if (!buf && size > PAGE_SIZE) + buf = vmalloc(size); + return buf; +} + /** * seq_open - initialize sequential file * @file: file we initialize @@ -96,7 +108,7 @@ static int traverse(struct seq_file *m, loff_t offset) return 0; } if (!m->buf) { - m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); + m->buf = seq_buf_alloc(m->size = PAGE_SIZE); if (!m->buf) return -ENOMEM; } @@ -135,9 +147,9 @@ static int traverse(struct seq_file *m, loff_t offset) Eoverflow: m->op->stop(m, p); - kfree(m->buf); + kvfree(m->buf); m->count = 0; - m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); + m->buf = seq_buf_alloc(m->size <<= 1); return !m->buf ? -ENOMEM : -EAGAIN; } @@ -192,7 +204,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) /* grab buffer if we didn't have one */ if (!m->buf) { - m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); + m->buf = seq_buf_alloc(m->size = PAGE_SIZE); if (!m->buf) goto Enomem; } @@ -232,9 +244,9 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) if (m->count < m->size) goto Fill; m->op->stop(m, p); - kfree(m->buf); + kvfree(m->buf); m->count = 0; - m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); + m->buf = seq_buf_alloc(m->size <<= 1); if (!m->buf) goto Enomem; m->version = 0; @@ -350,7 +362,7 @@ EXPORT_SYMBOL(seq_lseek); int seq_release(struct inode *inode, struct file *file) { struct seq_file *m = file->private_data; - kfree(m->buf); + kvfree(m->buf); kfree(m); return 0; } @@ -605,13 +617,13 @@ EXPORT_SYMBOL(single_open); int single_open_size(struct file *file, int (*show)(struct seq_file *, void *), void *data, size_t size) { - char *buf = kmalloc(size, GFP_KERNEL); + char *buf = seq_buf_alloc(size); int ret; if (!buf) return -ENOMEM; ret = single_open(file, show, data); if (ret) { - kfree(buf); + kvfree(buf); return ret; } ((struct seq_file *)file->private_data)->buf = buf; diff --git a/include/asm-generic/seccomp.h b/include/asm-generic/seccomp.h new file mode 100644 index 000000000000..663ac3dc02ea --- /dev/null +++ b/include/asm-generic/seccomp.h @@ -0,0 +1,29 @@ +/* + * include/asm-generic/seccomp.h + * + * Copyright (C) 2014 Linaro Limited + * Author: AKASHI Takahiro <takahiro.akashi <at> linaro.org> + * + * 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 + * published by the Free Software Foundation. + */ +#ifndef _ASM_GENERIC_SECCOMP_H +#define _ASM_GENERIC_SECCOMP_H + +#include <asm-generic/unistd.h> + +#if defined(CONFIG_COMPAT) && !defined(__NR_seccomp_read_32) +#define __NR_seccomp_read_32 __NR_read +#define __NR_seccomp_write_32 __NR_write +#define __NR_seccomp_exit_32 __NR_exit +#define __NR_seccomp_sigreturn_32 __NR_rt_sigreturn +#endif /* CONFIG_COMPAT && ! already defined */ + +#define __NR_seccomp_read __NR_read +#define __NR_seccomp_write __NR_write +#define __NR_seccomp_exit __NR_exit +#define __NR_seccomp_sigreturn __NR_rt_sigreturn + +#endif /* _ASM_GENERIC_SECCOMP_H */ + diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h index 5b09392db673..d401e5463fb0 100644 --- a/include/asm-generic/syscall.h +++ b/include/asm-generic/syscall.h @@ -144,8 +144,6 @@ void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, /** * syscall_get_arch - return the AUDIT_ARCH for the current system call - * @task: task of interest, must be in system call entry tracing - * @regs: task_pt_regs() of @task * * Returns the AUDIT_ARCH_* based on the system call convention in use. * @@ -155,5 +153,5 @@ void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, * Architectures which permit CONFIG_HAVE_ARCH_SECCOMP_FILTER must * provide an implementation of this. */ -int syscall_get_arch(struct task_struct *task, struct pt_regs *regs); +int syscall_get_arch(void); #endif /* _ASM_SYSCALL_H */ diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index bbda8c015591..1edbda9e0773 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -850,6 +850,17 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from); struct cgroup_subsys_state *css_from_dir(struct dentry *dentry, struct cgroup_subsys *ss); +/* + * Default Android check for whether the current process is allowed to move a + * task across cgroups, either because CAP_SYS_NICE is set or because the uid + * of the calling process is the same as the moved task or because we are + * running as root. + * Returns 0 if this is allowed, or -EACCES otherwise. + */ +int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css, + struct cgroup_taskset *tset); + + #else /* !CONFIG_CGROUPS */ static inline int cgroup_init_early(void) { return 0; } @@ -871,6 +882,11 @@ static inline int cgroup_attach_task_all(struct task_struct *from, return 0; } +static inline int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css, + void *tset) +{ + return 0; +} #endif /* !CONFIG_CGROUPS */ #endif /* _LINUX_CGROUP_H */ diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 2faef339d8f2..61ca9614f43b 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -37,10 +37,12 @@ struct ipv6_devconf { __s32 accept_ra_rt_info_max_plen; #endif #endif + __s32 accept_ra_rt_table; __s32 proxy_ndp; __s32 accept_source_route; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD __s32 optimistic_dad; + __s32 use_optimistic; #endif #ifdef CONFIG_IPV6_MROUTE __s32 mc_forwarding; diff --git a/include/linux/keycombo.h b/include/linux/keycombo.h new file mode 100644 index 000000000000..c6db2626b0d3 --- /dev/null +++ b/include/linux/keycombo.h @@ -0,0 +1,36 @@ +/* + * include/linux/keycombo.h - platform data structure for keycombo driver + * + * Copyright (C) 2014 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _LINUX_KEYCOMBO_H +#define _LINUX_KEYCOMBO_H + +#define KEYCOMBO_NAME "keycombo" + +/* + * if key_down_fn and key_up_fn are both present, you are guaranteed that + * key_down_fn will return before key_up_fn is called, and that key_up_fn + * is called iff key_down_fn is called. + */ +struct keycombo_platform_data { + void (*key_down_fn)(void *); + void (*key_up_fn)(void *); + void *priv; + int key_down_delay; /* Time in ms */ + int *keys_up; + int keys_down[]; /* 0 terminated */ +}; + +#endif /* _LINUX_KEYCOMBO_H */ diff --git a/include/linux/keyreset.h b/include/linux/keyreset.h index a2ac49e5b684..2e34afab65e4 100644 --- a/include/linux/keyreset.h +++ b/include/linux/keyreset.h @@ -1,7 +1,7 @@ /* * include/linux/keyreset.h - platform data structure for resetkeys driver * - * Copyright (C) 2008 Google, Inc. + * Copyright (C) 2014 Google, Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -21,6 +21,7 @@ struct keyreset_platform_data { int (*reset_fn)(void); + int key_down_delay; int *keys_up; int keys_down[]; /* 0 terminated */ }; diff --git a/include/linux/mm.h b/include/linux/mm.h index d362d81eb953..6047a2a7f0c6 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -362,6 +362,8 @@ static inline int is_vmalloc_or_module_addr(const void *x) } #endif +extern void kvfree(const void *addr); + static inline void compound_lock(struct page *page) { #ifdef CONFIG_TRANSPARENT_HUGEPAGE diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 5f5b83461a81..19dd1d437306 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -90,6 +90,27 @@ extern int of_flat_dt_is_compatible(unsigned long node, const char *name); extern int of_flat_dt_match(unsigned long node, const char *const *matches); extern unsigned long of_get_flat_dt_root(void); +/* + * early_init_dt_scan_chosen - scan the device tree for ramdisk and bootargs + * + * The boot arguments will be placed into the memory pointed to by @data. + * That memory should be COMMAND_LINE_SIZE big and initialized to be a valid + * (possibly empty) string. Logic for what will be in @data after this + * function finishes: + * + * - CONFIG_CMDLINE_FORCE=true + * CONFIG_CMDLINE + * - CONFIG_CMDLINE_EXTEND=true, @data is non-empty string + * @data + dt bootargs (even if dt bootargs are empty) + * - CONFIG_CMDLINE_EXTEND=true, @data is empty string + * CONFIG_CMDLINE + dt bootargs (even if dt bootargs are empty) + * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=non-empty: + * dt bootargs + * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is non-empty string + * @data is left unchanged + * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is empty string + * CONFIG_CMDLINE (or "" if that's not defined) + */ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data); extern int early_init_dt_scan_memory(unsigned long node, const char *uname, diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 62c2e9f48e1b..21c98bad7808 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -17,6 +17,7 @@ #include <linux/leds.h> #include <linux/spinlock.h> #include <linux/notifier.h> +#include <linux/types.h> struct device; @@ -146,6 +147,8 @@ enum power_supply_property { POWER_SUPPLY_PROP_USB_HC, POWER_SUPPLY_PROP_USB_OTG, POWER_SUPPLY_PROP_CHARGE_ENABLED, + /* Local extensions of type int64_t */ + POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, @@ -170,6 +173,7 @@ enum power_supply_notifier_events { union power_supply_propval { int intval; const char *strval; + int64_t int64val; }; struct device_node; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index ece0c6bbfcc5..8884f6e507f7 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -39,6 +39,7 @@ enum pstore_type_id { PSTORE_TYPE_PPC_RTAS = 4, PSTORE_TYPE_PPC_OF = 5, PSTORE_TYPE_PPC_COMMON = 6, + PSTORE_TYPE_PMSG = 7, PSTORE_TYPE_UNKNOWN = 255 }; diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 4af3fdc85b01..712757f320a4 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -68,6 +68,8 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz); ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, char *str, size_t len); +void ramoops_console_write_buf(const char *buf, size_t size); + /* * Ramoops platform data * @mem_size memory size for ramoops @@ -81,6 +83,7 @@ struct ramoops_platform_data { unsigned long record_size; unsigned long console_size; unsigned long ftrace_size; + unsigned long pmsg_size; int dump_oops; struct persistent_ram_ecc_info ecc_info; }; diff --git a/include/linux/sched.h b/include/linux/sched.h index 5d16d14032da..22913f78b829 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1251,13 +1251,12 @@ struct task_struct { * execve */ unsigned in_iowait:1; - /* task may not gain privileges */ - unsigned no_new_privs:1; - /* Revert to default priority/policy when forking */ unsigned sched_reset_on_fork:1; unsigned sched_contributes_to_load:1; + unsigned long atomic_flags; /* Flags needing atomic access. */ + pid_t pid; pid_t tgid; @@ -1901,6 +1900,19 @@ static inline void memalloc_noio_restore(unsigned int flags) current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags; } +/* Per-process atomic flags. */ +#define PFA_NO_NEW_PRIVS 0x00000001 /* May not gain new privileges. */ + +static inline bool task_no_new_privs(struct task_struct *p) +{ + return test_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags); +} + +static inline void task_set_no_new_privs(struct task_struct *p) +{ + set_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags); +} + /* * task->jobctl flags */ diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 6f19cfd1840e..9687691799ff 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -3,6 +3,8 @@ #include <uapi/linux/seccomp.h> +#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC) + #ifdef CONFIG_SECCOMP #include <linux/thread_info.h> @@ -14,11 +16,11 @@ struct seccomp_filter; * * @mode: indicates one of the valid values above for controlled * system calls available to a process. - * @filter: The metadata and ruleset for determining what system calls - * are allowed for a task. + * @filter: must always point to a valid seccomp-filter or NULL as it is + * accessed without locking during system call entry. * * @filter must only be accessed from the context of current as there - * is no locking. + * is no read locking. */ struct seccomp { int mode; diff --git a/include/linux/suspend.h b/include/linux/suspend.h index f73cabf59012..d6e568f5007b 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -364,6 +364,7 @@ extern bool pm_get_wakeup_count(unsigned int *count, bool block); extern bool pm_save_wakeup_count(unsigned int count); extern void pm_wakep_autosleep_enabled(bool set); extern void pm_print_active_wakeup_sources(void); +extern void pm_get_active_wakeup_sources(char *pending_sources, size_t max); static inline void lock_system_sleep(void) { diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index a747a77ea584..029b012aa075 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -855,4 +855,6 @@ asmlinkage long sys_process_vm_writev(pid_t pid, asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2); asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); +asmlinkage long sys_seccomp(unsigned int op, unsigned int flags, + const char __user *uargs); #endif diff --git a/include/linux/wakeup_reason.h b/include/linux/wakeup_reason.h index 7ce50f0debc4..ad8b76936c7f 100644 --- a/include/linux/wakeup_reason.h +++ b/include/linux/wakeup_reason.h @@ -18,6 +18,10 @@ #ifndef _LINUX_WAKEUP_REASON_H #define _LINUX_WAKEUP_REASON_H +#define MAX_SUSPEND_ABORT_LEN 256 + void log_wakeup_reason(int irq); +void log_suspend_abort_reason(const char *fmt, ...); +int check_wakeup_reason(int irq); #endif /* _LINUX_WAKEUP_REASON_H */ diff --git a/include/linux/wlan_plat.h b/include/linux/wlan_plat.h index 40ec3482d1ef..8e8b06f1ba4a 100644 --- a/include/linux/wlan_plat.h +++ b/include/linux/wlan_plat.h @@ -15,13 +15,16 @@ #ifndef _LINUX_WLAN_PLAT_H_ #define _LINUX_WLAN_PLAT_H_ +#define WLAN_PLAT_NODFS_FLAG 0x01 + struct wifi_platform_data { int (*set_power)(int val); int (*set_reset)(int val); int (*set_carddetect)(int val); void *(*mem_prealloc)(int section, unsigned long size); int (*get_mac_addr)(unsigned char *buf); - void *(*get_country_code)(char *ccode); + int (*get_wake_irq)(void); + void *(*get_country_code)(char *ccode, u32 flags); }; #endif diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 50e39a8822b4..b811775a4e62 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -193,6 +193,8 @@ static inline bool ipv6_is_mld(struct sk_buff *skb, int nexthdr, int offset) void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao); +u32 addrconf_rt_table(const struct net_device *dev, u32 default_table); + /* * anycast prototypes (anycast.c) */ diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index e584de16e4c3..c10c06f8e59d 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -28,6 +28,8 @@ struct fib_rule { int suppress_prefixlen; char iifname[IFNAMSIZ]; char oifname[IFNAMSIZ]; + kuid_t uid_start; + kuid_t uid_end; struct rcu_head rcu; }; @@ -86,9 +88,13 @@ struct fib_rules_ops { [FRA_FWMARK] = { .type = NLA_U32 }, \ [FRA_FWMASK] = { .type = NLA_U32 }, \ [FRA_TABLE] = { .type = NLA_U32 }, \ + [FRA_GOTO] = { .type = NLA_U32 }, \ + [FRA_UID_START] = { .type = NLA_U32 }, \ + [FRA_UID_END] = { .type = NLA_U32 }, \ [FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \ [FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \ [FRA_GOTO] = { .type = NLA_U32 } + static inline void fib_rule_get(struct fib_rule *rule) { diff --git a/include/net/flow.h b/include/net/flow.h index d23e7fa2042e..4f109deacf64 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -10,6 +10,7 @@ #include <linux/socket.h> #include <linux/in6.h> #include <linux/atomic.h> +#include <linux/uidgid.h> struct flowi_common { int flowic_oif; @@ -22,6 +23,7 @@ struct flowi_common { #define FLOWI_FLAG_ANYSRC 0x01 #define FLOWI_FLAG_KNOWN_NH 0x02 __u32 flowic_secid; + kuid_t flowic_uid; }; union flowi_uli { @@ -58,6 +60,7 @@ struct flowi4 { #define flowi4_proto __fl_common.flowic_proto #define flowi4_flags __fl_common.flowic_flags #define flowi4_secid __fl_common.flowic_secid +#define flowi4_uid __fl_common.flowic_uid /* (saddr,daddr) must be grouped, same order as in IP header */ __be32 saddr; @@ -77,7 +80,8 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, __u32 mark, __u8 tos, __u8 scope, __u8 proto, __u8 flags, __be32 daddr, __be32 saddr, - __be16 dport, __be16 sport) + __be16 dport, __be16 sport, + kuid_t uid) { fl4->flowi4_oif = oif; fl4->flowi4_iif = 0; @@ -87,6 +91,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, fl4->flowi4_proto = proto; fl4->flowi4_flags = flags; fl4->flowi4_secid = 0; + fl4->flowi4_uid = uid; fl4->daddr = daddr; fl4->saddr = saddr; fl4->fl4_dport = dport; @@ -114,6 +119,7 @@ struct flowi6 { #define flowi6_proto __fl_common.flowic_proto #define flowi6_flags __fl_common.flowic_flags #define flowi6_secid __fl_common.flowic_secid +#define flowi6_uid __fl_common.flowic_uid struct in6_addr daddr; struct in6_addr saddr; __be32 flowlabel; @@ -157,6 +163,7 @@ struct flowi { #define flowi_proto u.__fl_common.flowic_proto #define flowi_flags u.__fl_common.flowic_flags #define flowi_secid u.__fl_common.flowic_secid +#define flowi_uid u.__fl_common.flowic_uid } __attribute__((__aligned__(BITS_PER_LONG/8))); static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 1833c3f389ee..adb0fbeea5be 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -88,6 +88,7 @@ struct inet_request_sock { acked : 1, no_srccheck: 1; kmemcheck_bitfield_end(flags); + u32 ir_mark; struct ip_options_rcu *opt; struct sk_buff *pktopts; }; @@ -97,6 +98,14 @@ static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk) return (struct inet_request_sock *)sk; } +static inline u32 inet_request_mark(struct sock *sk, struct sk_buff *skb) +{ + if (!sk->sk_mark && sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept) + return skb->mark; + + return sk->sk_mark; +} + struct inet_cork { unsigned int flags; __be32 addr; diff --git a/include/net/ip.h b/include/net/ip.h index 937f19681426..0c6a80944e71 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -165,6 +165,7 @@ struct ip_reply_arg { /* -1 if not needed */ int bound_dev_if; u8 tos; + kuid_t uid; }; #define IP_REPLY_ARG_NOSRCCHECK 1 @@ -237,6 +238,9 @@ void ipfrag_init(void); void ip_static_sysctl_init(void); +#define IP4_REPLY_MARK(net, mark) \ + ((net)->ipv4.sysctl_fwmark_reflect ? (mark) : 0) + static inline bool ip_is_fragment(const struct iphdr *iph) { return (iph->frag_off & htons(IP_MF | IP_OFFSET)) != 0; diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 2e74c6cfa612..0377a392b629 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -103,7 +103,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, const struct in6_addr *gwaddr); void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, int oif, - u32 mark); + u32 mark, kuid_t uid); void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu); void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark); void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, diff --git a/include/net/ipv6.h b/include/net/ipv6.h index a60948d7bcea..944f3b2bdbb4 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -113,6 +113,9 @@ struct frag_hdr { #define IP6_MF 0x0001 #define IP6_OFFSET 0xFFF8 +#define IP6_REPLY_MARK(net, mark) \ + ((net)->ipv6.sysctl.fwmark_reflect ? (mark) : 0) + #include <net/sock.h> /* sysctls */ diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 80f500a29498..c701843f4195 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -72,6 +72,9 @@ struct netns_ipv4 { int sysctl_ip_no_pmtu_disc; int sysctl_ip_fwd_use_pmtu; + int sysctl_fwmark_reflect; + int sysctl_tcp_fwmark_accept; + kgid_t sysctl_ping_group_range[2]; atomic_t dev_addr_genid; diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 21edaf1f7916..19d3446e59d2 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -30,6 +30,7 @@ struct netns_sysctl_ipv6 { int flowlabel_consistency; int icmpv6_time; int anycast_src_echo_reply; + int fwmark_reflect; }; struct netns_ipv6 { diff --git a/include/net/route.h b/include/net/route.h index 9d1f423d5944..9b1ea0e9f3c6 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -140,7 +140,7 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos, RT_SCOPE_UNIVERSE, proto, sk ? inet_sk_flowi_flags(sk) : 0, - daddr, saddr, dport, sport); + daddr, saddr, dport, sport, sk ? sock_i_uid(sk) : KUIDT_INIT(0)); if (sk) security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); return ip_route_output_flow(net, fl4, sk); @@ -250,7 +250,8 @@ static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 flow_flags |= FLOWI_FLAG_ANYSRC; flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, - protocol, flow_flags, dst, src, dport, sport); + protocol, flow_flags, dst, src, dport, sport, + sock_i_uid(sk)); } static inline struct rtable *ip_route_connect(struct flowi4 *fl4, diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index dde8041f40d2..f2011a9b37d7 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -697,8 +697,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr) #define __NR_sched_getattr 275 __SYSCALL(__NR_sched_getattr, sys_sched_getattr) +#define __NR_seccomp 277 +__SYSCALL(__NR_seccomp, sys_seccomp) + #undef __NR_syscalls -#define __NR_syscalls 276 +#define __NR_syscalls 278 /* * All syscalls below here should go away really, diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 2d48fe1274ca..619b6589344c 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -333,6 +333,8 @@ enum { /* distinguish syscall tables */ #define __AUDIT_ARCH_64BIT 0x80000000 #define __AUDIT_ARCH_LE 0x40000000 + +#define AUDIT_ARCH_AARCH64 (EM_AARCH64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) #define AUDIT_ARCH_ALPHA (EM_ALPHA|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) #define AUDIT_ARCH_ARM (EM_ARM|__AUDIT_ARCH_LE) #define AUDIT_ARCH_ARMEB (EM_ARM) diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h index 2b82d7e30974..743e3008df60 100644 --- a/include/uapi/linux/fib_rules.h +++ b/include/uapi/linux/fib_rules.h @@ -49,6 +49,8 @@ enum { FRA_TABLE, /* Extended table id */ FRA_FWMASK, /* mask for netfilter mark */ FRA_OIFNAME, + FRA_UID_START, /* UID range */ + FRA_UID_END, __FRA_MAX }; diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 6c28b61bb690..a1048181e4a9 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -154,6 +154,8 @@ struct inodes_stat_t { #define FITHAW _IOWR('X', 120, int) /* Thaw */ #define FITRIM _IOWR('X', 121, struct fstrim_range) /* Trim */ +#define FIDTRIM _IOWR('f', 128, struct fstrim_range) /* Deep discard trim */ + #define FS_IOC_GETFLAGS _IOR('f', 1, long) #define FS_IOC_SETFLAGS _IOW('f', 2, long) #define FS_IOC_GETVERSION _IOR('v', 1, long) diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index a99f7bc41bbb..a24fb643fe8e 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -467,7 +467,10 @@ struct input_keymap_entry { #define KEY_VIDEO_NEXT 241 /* drive next video source */ #define KEY_VIDEO_PREV 242 /* drive previous video source */ #define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ -#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */ +#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual + brightness control is off, + rely on ambient */ +#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO #define KEY_DISPLAY_OFF 245 /* display device to off state */ #define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ @@ -637,6 +640,7 @@ struct input_keymap_entry { #define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ #define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ #define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ +#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE #define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ #define KEY_LOGOFF 0x1b1 /* AL Logoff */ @@ -728,6 +732,17 @@ struct input_keymap_entry { #define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ +#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ +#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ +#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */ +#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */ +#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ +#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ +#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ + +#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ +#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ + #define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY2 0x2c1 diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h index 593b0e32d956..d28c98fe8730 100644 --- a/include/uapi/linux/ipv6.h +++ b/include/uapi/linux/ipv6.h @@ -160,9 +160,11 @@ enum { DEVCONF_ACCEPT_DAD, DEVCONF_FORCE_TLLAO, DEVCONF_NDISC_NOTIFY, + DEVCONF_ACCEPT_RA_RT_TABLE, DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL, DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL, DEVCONF_SUPPRESS_FRAG_NDISC, + DEVCONF_USE_OPTIMISTIC, DEVCONF_MAX }; diff --git a/include/uapi/linux/netfilter/xt_socket.h b/include/uapi/linux/netfilter/xt_socket.h index 55076a32bdfd..c9b247c0bfa6 100644 --- a/include/uapi/linux/netfilter/xt_socket.h +++ b/include/uapi/linux/netfilter/xt_socket.h @@ -18,6 +18,7 @@ struct xt_socket_mtinfo2 { }; #define XT_SOCKET_FLAGS_V2 (XT_SOCKET_TRANSPARENT | XT_SOCKET_NOWILDCARD) +void xt_socket_put_sk(struct sock *sk); struct sock *xt_socket_get4_sk(const struct sk_buff *skb, struct xt_action_param *par); struct sock *xt_socket_get6_sk(const struct sk_buff *skb, diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 253856a2a8ad..28bb0b3a08bf 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -149,6 +149,12 @@ #define PR_GET_TID_ADDRESS 40 +/* Sets the timerslack for arbitrary threads + * arg2 slack value, 0 means "use default" + * arg3 pid of the thread whose timer slack needs to be set + */ +#define PR_SET_TIMERSLACK_PID 41 + #define PR_SET_VMA 0x53564d41 # define PR_SET_VMA_ANON_NAME 0 diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index eb0f1a554d7b..01757b79db64 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -297,6 +297,7 @@ enum rtattr_type_t { RTA_TABLE, RTA_MARK, RTA_MFC_STATS, + RTA_UID, __RTA_MAX }; diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h index ac2dc9f72973..0f238a43ff1e 100644 --- a/include/uapi/linux/seccomp.h +++ b/include/uapi/linux/seccomp.h @@ -10,6 +10,13 @@ #define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ #define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ +/* Valid operations for seccomp syscall. */ +#define SECCOMP_SET_MODE_STRICT 0 +#define SECCOMP_SET_MODE_FILTER 1 + +/* Valid flags for SECCOMP_SET_MODE_FILTER */ +#define SECCOMP_FILTER_FLAG_TSYNC 1 + /* * All BPF programs must return a 32-bit value. * The bottom 16-bits are for optional return data. diff --git a/include/uapi/video/adf.h b/include/uapi/video/adf.h index b703bf9e9a66..c5d2e62cdb9b 100644 --- a/include/uapi/video/adf.h +++ b/include/uapi/video/adf.h @@ -83,7 +83,7 @@ struct adf_event { */ struct adf_vsync_event { struct adf_event base; - __u64 timestamp; + __aligned_u64 timestamp; }; /** @@ -119,12 +119,12 @@ struct adf_buffer_config { __u32 h; __u32 format; - __s64 fd[ADF_MAX_PLANES]; + __s32 fd[ADF_MAX_PLANES]; __u32 offset[ADF_MAX_PLANES]; __u32 pitch[ADF_MAX_PLANES]; __u8 n_planes; - __s64 acquire_fence; + __s32 acquire_fence; }; #define ADF_MAX_BUFFERS (4096 / sizeof(struct adf_buffer_config)) @@ -150,7 +150,7 @@ struct adf_post_config { size_t custom_data_size; void __user *custom_data; - __s64 complete_fence; + __s32 complete_fence; }; #define ADF_MAX_INTERFACES (4096 / sizeof(__u32)) @@ -180,7 +180,7 @@ struct adf_simple_buffer_alloc { __u16 h; __u32 format; - __s64 fd; + __s32 fd; __u32 offset; __u32 pitch; }; @@ -195,7 +195,7 @@ struct adf_simple_buffer_alloc { */ struct adf_simple_post_config { struct adf_buffer_config buf; - __s64 complete_fence; + __s32 complete_fence; }; /** diff --git a/include/video/adf.h b/include/video/adf.h index 2b742ab463dd..34f10e538f9e 100644 --- a/include/video/adf.h +++ b/include/video/adf.h @@ -193,10 +193,26 @@ struct adf_obj { }; /** + * struct adf_device_quirks - common display device quirks + * + * @buffer_padding: whether the last scanline of a buffer extends to the + * buffer's pitch (@ADF_BUFFER_PADDED_TO_PITCH) or just to the visible + * width (@ADF_BUFFER_UNPADDED) + */ +struct adf_device_quirks { + /* optional, defaults to ADF_BUFFER_PADDED_TO_PITCH */ + enum { + ADF_BUFFER_PADDED_TO_PITCH = 0, + ADF_BUFFER_UNPADDED = 1, + } buffer_padding; +}; + +/** * struct adf_device_ops - display device implementation ops * * @owner: device's module * @base: common operations (see &struct adf_obj_ops) + * @quirks: device's quirks (see &struct adf_device_quirks) * * @attach: attach overlay engine @eng to interface @intf. Return 0 on success * or error code (<0) on failure. @@ -228,6 +244,8 @@ struct adf_device_ops { /* required */ struct module *owner; const struct adf_obj_ops base; + /* optional */ + const struct adf_device_quirks quirks; /* optional */ int (*attach)(struct adf_device *dev, struct adf_overlay_engine *eng, diff --git a/include/video/adf_fbdev.h b/include/video/adf_fbdev.h index 9c349144b5cd..b722c6b3ab02 100644 --- a/include/video/adf_fbdev.h +++ b/include/video/adf_fbdev.h @@ -16,6 +16,7 @@ #define _VIDEO_ADF_FBDEV_H_ #include <linux/fb.h> +#include <linux/mutex.h> #include <video/adf.h> struct adf_fbdev { @@ -24,7 +25,8 @@ struct adf_fbdev { struct fb_info *info; u32 pseudo_palette[16]; - bool open; + unsigned int refcount; + struct mutex refcount_lock; struct dma_buf *dma_buf; u32 offset; @@ -37,6 +39,7 @@ struct adf_fbdev { u32 default_format; }; +#if IS_ENABLED(CONFIG_ADF_FBDEV) void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode, struct fb_videomode *vmode); void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode, @@ -55,5 +58,67 @@ int adf_fbdev_set_par(struct fb_info *info); int adf_fbdev_blank(int blank, struct fb_info *info); int adf_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); int adf_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma); +#else +static inline void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode, + struct fb_videomode *vmode) +{ + WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__); +} + +static inline void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode, + struct drm_mode_modeinfo *mode) +{ + WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__); +} + +static inline int adf_fbdev_init(struct adf_fbdev *fbdev, + struct adf_interface *interface, + struct adf_overlay_engine *eng, + u16 xres_virtual, u16 yres_virtual, u32 format, + struct fb_ops *fbops, const char *fmt, ...) +{ + return -ENODEV; +} + +static inline void adf_fbdev_destroy(struct adf_fbdev *fbdev) { } + +static inline int adf_fbdev_open(struct fb_info *info, int user) +{ + return -ENODEV; +} + +static inline int adf_fbdev_release(struct fb_info *info, int user) +{ + return -ENODEV; +} + +static inline int adf_fbdev_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + return -ENODEV; +} + +static inline int adf_fbdev_set_par(struct fb_info *info) +{ + return -ENODEV; +} + +static inline int adf_fbdev_blank(int blank, struct fb_info *info) +{ + return -ENODEV; +} + +static inline int adf_fbdev_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + return -ENODEV; +} + +static inline int adf_fbdev_mmap(struct fb_info *info, + struct vm_area_struct *vma) +{ + return -ENODEV; +} +#endif #endif /* _VIDEO_ADF_FBDEV_H_ */ diff --git a/kernel/cgroup.c b/kernel/cgroup.c index b00a0f10726c..984ae7fa063f 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2129,6 +2129,25 @@ static int cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) return 0; } +int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css, struct cgroup_taskset *tset) +{ + const struct cred *cred = current_cred(), *tcred; + struct task_struct *task; + + if (capable(CAP_SYS_NICE)) + return 0; + + cgroup_taskset_for_each(task, css, tset) { + tcred = __task_cred(task); + + if (current != task && !uid_eq(cred->euid, tcred->uid) && + !uid_eq(cred->euid, tcred->suid)) + return -EACCES; + } + + return 0; +} + /* * Find the task_struct of the task to attach by vpid and pass it along to the * function to attach either it or all tasks in its threadgroup. Will lock diff --git a/kernel/fork.c b/kernel/fork.c index ca4471518ba8..20eaa23152eb 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -329,6 +329,15 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) goto free_ti; tsk->stack = ti; +#ifdef CONFIG_SECCOMP + /* + * We must handle setting up seccomp filters once we're under + * the sighand lock in case orig has changed between now and + * then. Until then, filter must be NULL to avoid messing up + * the usage counts on the error path calling free_task. + */ + tsk->seccomp.filter = NULL; +#endif setup_thread_stack(tsk, orig); clear_user_return_notifier(tsk); @@ -1100,6 +1109,39 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p) p->flags = new_flags; } +static void copy_seccomp(struct task_struct *p) +{ +#ifdef CONFIG_SECCOMP + /* + * Must be called with sighand->lock held, which is common to + * all threads in the group. Holding cred_guard_mutex is not + * needed because this new task is not yet running and cannot + * be racing exec. + */ + assert_spin_locked(¤t->sighand->siglock); + + /* Ref-count the new filter user, and assign it. */ + get_seccomp_filter(current); + p->seccomp = current->seccomp; + + /* + * Explicitly enable no_new_privs here in case it got set + * between the task_struct being duplicated and holding the + * sighand lock. The seccomp state and nnp must be in sync. + */ + if (task_no_new_privs(current)) + task_set_no_new_privs(p); + + /* + * If the parent gained a seccomp mode after copying thread + * flags and between before we held the sighand lock, we have + * to manually enable the seccomp thread flag here. + */ + if (p->seccomp.mode != SECCOMP_MODE_DISABLED) + set_tsk_thread_flag(p, TIF_SECCOMP); +#endif +} + SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) { current->clear_child_tid = tidptr; @@ -1215,7 +1257,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, goto fork_out; ftrace_graph_init_task(p); - get_seccomp_filter(p); rt_mutex_init_task(p); @@ -1456,6 +1497,12 @@ static struct task_struct *copy_process(unsigned long clone_flags, spin_lock(¤t->sighand->siglock); /* + * Copy seccomp details explicitly here, in case they were changed + * before holding sighand lock. + */ + copy_seccomp(p); + + /* * Process group and session signals need to be delivered to just the * parent before the fork or both the parent and the child after the * fork. Restart if a signal comes in before we add the new process to diff --git a/kernel/futex.c b/kernel/futex.c index fda2950f2ce4..f42621958272 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1566,6 +1566,15 @@ retry: goto out_put_keys; } + /* + * The check above which compares uaddrs is not sufficient for + * shared futexes. We need to compare the keys: + */ + if (requeue_pi && match_futex(&key1, &key2)) { + ret = -EINVAL; + goto out_put_keys; + } + hb1 = hash_futex(&key1); hb2 = hash_futex(&key2); diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index c72b7a43beb9..da5f2ffa7106 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -10,7 +10,7 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/syscore_ops.h> - +#include <linux/wakeup_reason.h> #include "internals.h" /** @@ -105,6 +105,10 @@ int check_wakeup_irqs(void) for_each_irq_desc(irq, desc) { if (irqd_is_wakeup_set(&desc->irq_data)) { if (desc->istate & IRQS_PENDING) { + log_suspend_abort_reason("Wakeup IRQ %d %s pending", + irq, + desc->action && desc->action->name ? + desc->action->name : ""); pr_info("Wakeup IRQ %d %s pending, suspend aborted\n", irq, desc->action && desc->action->name ? diff --git a/kernel/power/process.c b/kernel/power/process.c index f1fe7ec110bb..78915a30b4a7 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -17,7 +17,7 @@ #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/kmod.h> - +#include <linux/wakeup_reason.h> /* * Timeout for stopping processes */ @@ -34,6 +34,9 @@ static int try_to_freeze_tasks(bool user_only) unsigned int elapsed_msecs; bool wakeup = false; int sleep_usecs = USEC_PER_MSEC; +#ifdef CONFIG_PM_SLEEP + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; +#endif do_gettimeofday(&start); @@ -63,6 +66,11 @@ static int try_to_freeze_tasks(bool user_only) break; if (pm_wakeup_pending()) { +#ifdef CONFIG_PM_SLEEP + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); +#endif wakeup = true; break; } @@ -82,23 +90,24 @@ static int try_to_freeze_tasks(bool user_only) do_div(elapsed_msecs64, NSEC_PER_MSEC); elapsed_msecs = elapsed_msecs64; - if (todo) { + if (wakeup) { + printk("\n"); + printk(KERN_ERR "Freezing of tasks aborted after %d.%03d seconds", + elapsed_msecs / 1000, elapsed_msecs % 1000); + } else if (todo) { printk("\n"); - printk(KERN_ERR "Freezing of tasks %s after %d.%03d seconds " - "(%d tasks refusing to freeze, wq_busy=%d):\n", - wakeup ? "aborted" : "failed", + printk(KERN_ERR "Freezing of tasks failed after %d.%03d seconds" + " (%d tasks refusing to freeze, wq_busy=%d):\n", elapsed_msecs / 1000, elapsed_msecs % 1000, todo - wq_busy, wq_busy); - if (!wakeup) { - read_lock(&tasklist_lock); - do_each_thread(g, p) { - if (p != current && !freezer_should_skip(p) - && freezing(p) && !frozen(p)) - sched_show_task(p); - } while_each_thread(g, p); - read_unlock(&tasklist_lock); - } + read_lock(&tasklist_lock); + do_each_thread(g, p) { + if (p != current && !freezer_should_skip(p) + && freezing(p) && !frozen(p)) + sched_show_task(p); + } while_each_thread(g, p); + read_unlock(&tasklist_lock); } else { printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000, elapsed_msecs % 1000); diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 8c911a25705d..2d98d52a8700 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -27,6 +27,7 @@ #include <linux/ftrace.h> #include <linux/rtc.h> #include <trace/events/power.h> +#include <linux/wakeup_reason.h> #include "power.h" @@ -139,7 +140,7 @@ static int suspend_prepare(suspend_state_t state) error = suspend_freeze_processes(); if (!error) return 0; - + log_suspend_abort_reason("One or more tasks refusing to freeze"); suspend_stats.failed_freeze++; dpm_save_failed_step(SUSPEND_FREEZE); Finish: @@ -169,7 +170,8 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) */ static int suspend_enter(suspend_state_t state, bool *wakeup) { - int error; + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; + int error, last_dev; if (need_suspend_ops(state) && suspend_ops->prepare) { error = suspend_ops->prepare(); @@ -179,7 +181,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) error = dpm_suspend_end(PMSG_SUSPEND); if (error) { + last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; + last_dev %= REC_FAILED_NUM; printk(KERN_ERR "PM: Some devices failed to power down\n"); + log_suspend_abort_reason("%s device failed to power down", + suspend_stats.failed_devs[last_dev]); goto Platform_finish; } @@ -205,8 +211,10 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) ftrace_stop(); error = disable_nonboot_cpus(); - if (error || suspend_test(TEST_CPUS)) + if (error || suspend_test(TEST_CPUS)) { + log_suspend_abort_reason("Disabling non-boot cpus failed"); goto Enable_cpus; + } arch_suspend_disable_irqs(); BUG_ON(!irqs_disabled()); @@ -217,6 +225,10 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) if (!(suspend_test(TEST_CORE) || *wakeup)) { error = suspend_ops->enter(state); events_check_enabled = false; + } else { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); } syscore_resume(); } @@ -264,6 +276,7 @@ int suspend_devices_and_enter(suspend_state_t state) error = dpm_suspend_start(PMSG_SUSPEND); if (error) { pr_err("PM: Some devices failed to suspend, or early wake event detected\n"); + log_suspend_abort_reason("Some devices failed to suspend, or early wake event detected"); goto Recover_platform; } suspend_test_finish("suspend devices"); diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 188a6bfacf5a..085c99edca06 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -31,30 +31,35 @@ #define MAX_WAKEUP_REASON_IRQS 32 static int irq_list[MAX_WAKEUP_REASON_IRQS]; static int irqcount; +static bool suspend_abort; +static char abort_reason[MAX_SUSPEND_ABORT_LEN]; static struct kobject *wakeup_reason; -static spinlock_t resume_reason_lock; +static DEFINE_SPINLOCK(resume_reason_lock); -static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, +static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int irq_no, buf_offset = 0; struct irq_desc *desc; spin_lock(&resume_reason_lock); - for (irq_no = 0; irq_no < irqcount; irq_no++) { - desc = irq_to_desc(irq_list[irq_no]); - if (desc && desc->action && desc->action->name) - buf_offset += sprintf(buf + buf_offset, "%d %s\n", - irq_list[irq_no], desc->action->name); - else - buf_offset += sprintf(buf + buf_offset, "%d\n", - irq_list[irq_no]); + if (suspend_abort) { + buf_offset = sprintf(buf, "Abort: %s", abort_reason); + } else { + for (irq_no = 0; irq_no < irqcount; irq_no++) { + desc = irq_to_desc(irq_list[irq_no]); + if (desc && desc->action && desc->action->name) + buf_offset += sprintf(buf + buf_offset, "%d %s\n", + irq_list[irq_no], desc->action->name); + else + buf_offset += sprintf(buf + buf_offset, "%d\n", + irq_list[irq_no]); + } } spin_unlock(&resume_reason_lock); return buf_offset; } -static struct kobj_attribute resume_reason = __ATTR(last_resume_reason, 0666, - reason_show, NULL); +static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason); static struct attribute *attrs[] = { &resume_reason.attr, @@ -90,6 +95,40 @@ void log_wakeup_reason(int irq) spin_unlock(&resume_reason_lock); } +int check_wakeup_reason(int irq) +{ + int irq_no; + int ret = false; + + spin_lock(&resume_reason_lock); + for (irq_no = 0; irq_no < irqcount; irq_no++) + if (irq_list[irq_no] == irq) { + ret = true; + break; + } + spin_unlock(&resume_reason_lock); + return ret; +} + +void log_suspend_abort_reason(const char *fmt, ...) +{ + va_list args; + + spin_lock(&resume_reason_lock); + + //Suspend abort reason has already been logged. + if (suspend_abort) { + spin_unlock(&resume_reason_lock); + return; + } + + suspend_abort = true; + va_start(args, fmt); + snprintf(abort_reason, MAX_SUSPEND_ABORT_LEN, fmt, args); + va_end(args); + spin_unlock(&resume_reason_lock); +} + /* Detects a suspend and clears all the previous wake up reasons*/ static int wakeup_reason_pm_event(struct notifier_block *notifier, unsigned long pm_event, void *unused) @@ -98,6 +137,7 @@ static int wakeup_reason_pm_event(struct notifier_block *notifier, case PM_SUSPEND_PREPARE: spin_lock(&resume_reason_lock); irqcount = 0; + suspend_abort = false; spin_unlock(&resume_reason_lock); break; default: @@ -116,7 +156,7 @@ static struct notifier_block wakeup_reason_pm_notifier_block = { int __init wakeup_reason_init(void) { int retval; - spin_lock_init(&resume_reason_lock); + retval = register_pm_notifier(&wakeup_reason_pm_notifier_block); if (retval) printk(KERN_WARNING "[%s] failed to register PM notifier %d\n", diff --git a/kernel/sched/core.c b/kernel/sched/core.c index e0c852d4778e..092886c47c1e 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7654,24 +7654,6 @@ static void cpu_cgroup_css_offline(struct cgroup_subsys_state *css) sched_offline_group(tg); } -static int cpu_cgroup_allow_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) -{ - const struct cred *cred = current_cred(), *tcred; - struct task_struct *task; - - cgroup_taskset_for_each(task, css, tset) { - tcred = __task_cred(task); - - if ((current != task) && !capable(CAP_SYS_NICE) && - !uid_eq(cred->euid, tcred->uid) && - !uid_eq(cred->euid, tcred->suid)) - return -EACCES; - } - - return 0; -} - static int cpu_cgroup_can_attach(struct cgroup_subsys_state *css, struct cgroup_taskset *tset) { @@ -8042,7 +8024,7 @@ struct cgroup_subsys cpu_cgroup_subsys = { .css_offline = cpu_cgroup_css_offline, .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, - .allow_attach = cpu_cgroup_allow_attach, + .allow_attach = subsys_cgroup_allow_attach, .exit = cpu_cgroup_exit, .subsys_id = cpu_cgroup_subsys_id, .base_cftypes = cpu_files, diff --git a/kernel/seccomp.c b/kernel/seccomp.c index b7a10048a32c..1fbb1a2bc459 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -18,15 +18,17 @@ #include <linux/compat.h> #include <linux/sched.h> #include <linux/seccomp.h> +#include <linux/slab.h> +#include <linux/syscalls.h> /* #define SECCOMP_DEBUG 1 */ #ifdef CONFIG_SECCOMP_FILTER #include <asm/syscall.h> #include <linux/filter.h> +#include <linux/pid.h> #include <linux/ptrace.h> #include <linux/security.h> -#include <linux/slab.h> #include <linux/tracehook.h> #include <linux/uaccess.h> @@ -95,7 +97,7 @@ u32 seccomp_bpf_load(int off) if (off == BPF_DATA(nr)) return syscall_get_nr(current, regs); if (off == BPF_DATA(arch)) - return syscall_get_arch(current, regs); + return syscall_get_arch(); if (off >= BPF_DATA(args[0]) && off < BPF_DATA(args[6])) { unsigned long value; int arg = (off - BPF_DATA(args[0])) / sizeof(u64); @@ -201,32 +203,170 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) */ static u32 seccomp_run_filters(int syscall) { - struct seccomp_filter *f; + struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter); u32 ret = SECCOMP_RET_ALLOW; /* Ensure unexpected behavior doesn't result in failing open. */ - if (WARN_ON(current->seccomp.filter == NULL)) + if (unlikely(WARN_ON(f == NULL))) return SECCOMP_RET_KILL; + /* Make sure cross-thread synced filter points somewhere sane. */ + smp_read_barrier_depends(); + /* * All filters in the list are evaluated and the lowest BPF return * value always takes priority (ignoring the DATA). */ - for (f = current->seccomp.filter; f; f = f->prev) { + for (; f; f = f->prev) { u32 cur_ret = sk_run_filter(NULL, f->insns); + if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) ret = cur_ret; } return ret; } +#endif /* CONFIG_SECCOMP_FILTER */ + +static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode) +{ + assert_spin_locked(¤t->sighand->siglock); + + if (current->seccomp.mode && current->seccomp.mode != seccomp_mode) + return false; + + return true; +} + +static inline void seccomp_assign_mode(struct task_struct *task, + unsigned long seccomp_mode) +{ + assert_spin_locked(&task->sighand->siglock); + + task->seccomp.mode = seccomp_mode; + /* + * Make sure TIF_SECCOMP cannot be set before the mode (and + * filter) is set. + */ + smp_mb(); + set_tsk_thread_flag(task, TIF_SECCOMP); +} + +#ifdef CONFIG_SECCOMP_FILTER +/* Returns 1 if the parent is an ancestor of the child. */ +static int is_ancestor(struct seccomp_filter *parent, + struct seccomp_filter *child) +{ + /* NULL is the root ancestor. */ + if (parent == NULL) + return 1; + for (; child; child = child->prev) + if (child == parent) + return 1; + return 0; +} /** - * seccomp_attach_filter: Attaches a seccomp filter to current. + * seccomp_can_sync_threads: checks if all threads can be synchronized + * + * Expects sighand and cred_guard_mutex locks to be held. + * + * Returns 0 on success, -ve on error, or the pid of a thread which was + * either not in the correct seccomp mode or it did not have an ancestral + * seccomp filter. + */ +static inline pid_t seccomp_can_sync_threads(void) +{ + struct task_struct *thread, *caller; + + BUG_ON(!mutex_is_locked(¤t->signal->cred_guard_mutex)); + assert_spin_locked(¤t->sighand->siglock); + + /* Validate all threads being eligible for synchronization. */ + caller = current; + for_each_thread(caller, thread) { + pid_t failed; + + /* Skip current, since it is initiating the sync. */ + if (thread == caller) + continue; + + if (thread->seccomp.mode == SECCOMP_MODE_DISABLED || + (thread->seccomp.mode == SECCOMP_MODE_FILTER && + is_ancestor(thread->seccomp.filter, + caller->seccomp.filter))) + continue; + + /* Return the first thread that cannot be synchronized. */ + failed = task_pid_vnr(thread); + /* If the pid cannot be resolved, then return -ESRCH */ + if (unlikely(WARN_ON(failed == 0))) + failed = -ESRCH; + return failed; + } + + return 0; +} + +/** + * seccomp_sync_threads: sets all threads to use current's filter + * + * Expects sighand and cred_guard_mutex locks to be held, and for + * seccomp_can_sync_threads() to have returned success already + * without dropping the locks. + * + */ +static inline void seccomp_sync_threads(void) +{ + struct task_struct *thread, *caller; + + BUG_ON(!mutex_is_locked(¤t->signal->cred_guard_mutex)); + assert_spin_locked(¤t->sighand->siglock); + + /* Synchronize all threads. */ + caller = current; + for_each_thread(caller, thread) { + /* Skip current, since it needs no changes. */ + if (thread == caller) + continue; + + /* Get a task reference for the new leaf node. */ + get_seccomp_filter(caller); + /* + * Drop the task reference to the shared ancestor since + * current's path will hold a reference. (This also + * allows a put before the assignment.) + */ + put_seccomp_filter(thread); + smp_store_release(&thread->seccomp.filter, + caller->seccomp.filter); + /* + * Opt the other thread into seccomp if needed. + * As threads are considered to be trust-realm + * equivalent (see ptrace_may_access), it is safe to + * allow one thread to transition the other. + */ + if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) { + /* + * Don't let an unprivileged task work around + * the no_new_privs restriction by creating + * a thread that sets it up, enters seccomp, + * then dies. + */ + if (task_no_new_privs(caller)) + task_set_no_new_privs(thread); + + seccomp_assign_mode(thread, SECCOMP_MODE_FILTER); + } + } +} + +/** + * seccomp_prepare_filter: Prepares a seccomp filter for use. * @fprog: BPF program to install * - * Returns 0 on success or an errno on failure. + * Returns filter on success or an ERR_PTR on failure. */ -static long seccomp_attach_filter(struct sock_fprog *fprog) +static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) { struct seccomp_filter *filter; unsigned long fp_size = fprog->len * sizeof(struct sock_filter); @@ -234,12 +374,13 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) long ret; if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) - return -EINVAL; + return ERR_PTR(-EINVAL); + BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter)); for (filter = current->seccomp.filter; filter; filter = filter->prev) total_insns += filter->len + 4; /* include a 4 instr penalty */ if (total_insns > MAX_INSNS_PER_PATH) - return -ENOMEM; + return ERR_PTR(-ENOMEM); /* * Installing a seccomp filter requires that the task have @@ -247,16 +388,16 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) * This avoids scenarios where unprivileged tasks can affect the * behavior of privileged children. */ - if (!current->no_new_privs && + if (!task_no_new_privs(current) && security_capable_noaudit(current_cred(), current_user_ns(), CAP_SYS_ADMIN) != 0) - return -EACCES; + return ERR_PTR(-EACCES); /* Allocate a new seccomp_filter */ filter = kzalloc(sizeof(struct seccomp_filter) + fp_size, GFP_KERNEL|__GFP_NOWARN); if (!filter) - return -ENOMEM; + return ERR_PTR(-ENOMEM);; atomic_set(&filter->usage, 1); filter->len = fprog->len; @@ -275,28 +416,24 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) if (ret) goto fail; - /* - * If there is an existing filter, make it the prev and don't drop its - * task reference. - */ - filter->prev = current->seccomp.filter; - current->seccomp.filter = filter; - return 0; + return filter; + fail: kfree(filter); - return ret; + return ERR_PTR(ret); } /** - * seccomp_attach_user_filter - attaches a user-supplied sock_fprog + * seccomp_prepare_user_filter - prepares a user-supplied sock_fprog * @user_filter: pointer to the user data containing a sock_fprog. * * Returns 0 on success and non-zero otherwise. */ -long seccomp_attach_user_filter(char __user *user_filter) +static struct seccomp_filter * +seccomp_prepare_user_filter(const char __user *user_filter) { struct sock_fprog fprog; - long ret = -EFAULT; + struct seccomp_filter *filter = ERR_PTR(-EFAULT); #ifdef CONFIG_COMPAT if (is_compat_task()) { @@ -309,9 +446,56 @@ long seccomp_attach_user_filter(char __user *user_filter) #endif if (copy_from_user(&fprog, user_filter, sizeof(fprog))) goto out; - ret = seccomp_attach_filter(&fprog); + filter = seccomp_prepare_filter(&fprog); out: - return ret; + return filter; +} + +/** + * seccomp_attach_filter: validate and attach filter + * @flags: flags to change filter behavior + * @filter: seccomp filter to add to the current process + * + * Caller must be holding current->sighand->siglock lock. + * + * Returns 0 on success, -ve on error. + */ +static long seccomp_attach_filter(unsigned int flags, + struct seccomp_filter *filter) +{ + unsigned long total_insns; + struct seccomp_filter *walker; + + assert_spin_locked(¤t->sighand->siglock); + + /* Validate resulting filter length. */ + total_insns = filter->len; + for (walker = current->seccomp.filter; walker; walker = walker->prev) + total_insns += walker->len + 4; /* 4 instr penalty */ + if (total_insns > MAX_INSNS_PER_PATH) + return -ENOMEM; + + /* If thread sync has been requested, check that it is possible. */ + if (flags & SECCOMP_FILTER_FLAG_TSYNC) { + int ret; + + ret = seccomp_can_sync_threads(); + if (ret) + return ret; + } + + /* + * If there is an existing filter, make it the prev and don't drop its + * task reference. + */ + filter->prev = current->seccomp.filter; + current->seccomp.filter = filter; + + /* Now that the new filter is in place, synchronize to all threads. */ + if (flags & SECCOMP_FILTER_FLAG_TSYNC) + seccomp_sync_threads(); + + return 0; } /* get_seccomp_filter - increments the reference count of the filter on @tsk */ @@ -324,6 +508,13 @@ void get_seccomp_filter(struct task_struct *tsk) atomic_inc(&orig->usage); } +static inline void seccomp_filter_free(struct seccomp_filter *filter) +{ + if (filter) { + kfree(filter); + } +} + /* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */ void put_seccomp_filter(struct task_struct *tsk) { @@ -332,7 +523,7 @@ void put_seccomp_filter(struct task_struct *tsk) while (orig && atomic_dec_and_test(&orig->usage)) { struct seccomp_filter *freeme = orig; orig = orig->prev; - kfree(freeme); + seccomp_filter_free(freeme); } } @@ -351,7 +542,7 @@ static void seccomp_send_sigsys(int syscall, int reason) info.si_code = SYS_SECCOMP; info.si_call_addr = (void __user *)KSTK_EIP(current); info.si_errno = reason; - info.si_arch = syscall_get_arch(current, task_pt_regs(current)); + info.si_arch = syscall_get_arch(); info.si_syscall = syscall; force_sig_info(SIGSYS, &info, current); } @@ -376,12 +567,17 @@ static int mode1_syscalls_32[] = { int __secure_computing(int this_syscall) { - int mode = current->seccomp.mode; int exit_sig = 0; int *syscall; u32 ret; - switch (mode) { + /* + * Make sure that any changes to mode from another thread have + * been seen after TIF_SECCOMP was seen. + */ + rmb(); + + switch (current->seccomp.mode) { case SECCOMP_MODE_STRICT: syscall = mode1_syscalls; #ifdef CONFIG_COMPAT @@ -467,47 +663,152 @@ long prctl_get_seccomp(void) } /** - * prctl_set_seccomp: configures current->seccomp.mode - * @seccomp_mode: requested mode to use - * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER + * seccomp_set_mode_strict: internal function for setting strict seccomp + * + * Once current->seccomp.mode is non-zero, it may not be changed. + * + * Returns 0 on success or -EINVAL on failure. + */ +static long seccomp_set_mode_strict(void) +{ + const unsigned long seccomp_mode = SECCOMP_MODE_STRICT; + long ret = -EINVAL; + + spin_lock_irq(¤t->sighand->siglock); + + if (!seccomp_may_assign_mode(seccomp_mode)) + goto out; + +#ifdef TIF_NOTSC + disable_TSC(); +#endif + seccomp_assign_mode(current, seccomp_mode); + ret = 0; + +out: + spin_unlock_irq(¤t->sighand->siglock); + + return ret; +} + +#ifdef CONFIG_SECCOMP_FILTER +/** + * seccomp_set_mode_filter: internal function for setting seccomp filter + * @flags: flags to change filter behavior + * @filter: struct sock_fprog containing filter * - * This function may be called repeatedly with a @seccomp_mode of - * SECCOMP_MODE_FILTER to install additional filters. Every filter - * successfully installed will be evaluated (in reverse order) for each system - * call the task makes. + * This function may be called repeatedly to install additional filters. + * Every filter successfully installed will be evaluated (in reverse order) + * for each system call the task makes. * * Once current->seccomp.mode is non-zero, it may not be changed. * * Returns 0 on success or -EINVAL on failure. */ -long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) +static long seccomp_set_mode_filter(unsigned int flags, + const char __user *filter) { + const unsigned long seccomp_mode = SECCOMP_MODE_FILTER; + struct seccomp_filter *prepared = NULL; long ret = -EINVAL; - if (current->seccomp.mode && - current->seccomp.mode != seccomp_mode) + /* Validate flags. */ + if (flags & ~SECCOMP_FILTER_FLAG_MASK) + return -EINVAL; + + /* Prepare the new filter before holding any locks. */ + prepared = seccomp_prepare_user_filter(filter); + if (IS_ERR(prepared)) + return PTR_ERR(prepared); + + /* + * Make sure we cannot change seccomp or nnp state via TSYNC + * while another thread is in the middle of calling exec. + */ + if (flags & SECCOMP_FILTER_FLAG_TSYNC && + mutex_lock_killable(¤t->signal->cred_guard_mutex)) + goto out_free; + + spin_lock_irq(¤t->sighand->siglock); + + if (!seccomp_may_assign_mode(seccomp_mode)) + goto out; + + ret = seccomp_attach_filter(flags, prepared); + if (ret) goto out; + /* Do not free the successfully attached filter. */ + prepared = NULL; + + seccomp_assign_mode(current, seccomp_mode); +out: + spin_unlock_irq(¤t->sighand->siglock); + if (flags & SECCOMP_FILTER_FLAG_TSYNC) + mutex_unlock(¤t->signal->cred_guard_mutex); +out_free: + seccomp_filter_free(prepared); + return ret; +} +#else +static inline long seccomp_set_mode_filter(unsigned int flags, + const char __user *filter) +{ + return -EINVAL; +} +#endif + +/* Common entry point for both prctl and syscall. */ +static long do_seccomp(unsigned int op, unsigned int flags, + const char __user *uargs) +{ + switch (op) { + case SECCOMP_SET_MODE_STRICT: + if (flags != 0 || uargs != NULL) + return -EINVAL; + return seccomp_set_mode_strict(); + case SECCOMP_SET_MODE_FILTER: + return seccomp_set_mode_filter(flags, uargs); + default: + return -EINVAL; + } +} + +SYSCALL_DEFINE3(seccomp, unsigned int, op, unsigned int, flags, + const char __user *, uargs) +{ + return do_seccomp(op, flags, uargs); +} + +/** + * prctl_set_seccomp: configures current->seccomp.mode + * @seccomp_mode: requested mode to use + * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER + * + * Returns 0 on success or -EINVAL on failure. + */ +long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) +{ + unsigned int op; + char __user *uargs; switch (seccomp_mode) { case SECCOMP_MODE_STRICT: - ret = 0; -#ifdef TIF_NOTSC - disable_TSC(); -#endif + op = SECCOMP_SET_MODE_STRICT; + /* + * Setting strict mode through prctl always ignored filter, + * so make sure it is always NULL here to pass the internal + * check in do_seccomp(). + */ + uargs = NULL; break; -#ifdef CONFIG_SECCOMP_FILTER case SECCOMP_MODE_FILTER: - ret = seccomp_attach_user_filter(filter); - if (ret) - goto out; + op = SECCOMP_SET_MODE_FILTER; + uargs = filter; break; -#endif default: - goto out; + return -EINVAL; } - current->seccomp.mode = seccomp_mode; - set_thread_flag(TIF_SECCOMP); -out: - return ret; + /* prctl interface doesn't have flags, so they are always zero. */ + return do_seccomp(op, 0, uargs); } diff --git a/kernel/sys.c b/kernel/sys.c index d0e9efaea8e3..4bf3cb0f337c 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -43,6 +43,7 @@ #include <linux/ctype.h> #include <linux/mm.h> #include <linux/mempolicy.h> +#include <linux/sched.h> #include <linux/compat.h> #include <linux/syscalls.h> @@ -1920,7 +1921,7 @@ static int prctl_set_vma_anon_name(unsigned long start, unsigned long end, tmp = end; /* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */ - error = prctl_update_vma_anon_name(vma, &prev, start, end, + error = prctl_update_vma_anon_name(vma, &prev, start, tmp, (const char __user *)arg); if (error) return error; @@ -1986,6 +1987,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5) { struct task_struct *me = current; + struct task_struct *tsk; unsigned char comm[sizeof(me->comm)]; long error; @@ -2128,6 +2130,26 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, case PR_GET_TID_ADDRESS: error = prctl_get_tid_address(me, (int __user **)arg2); break; + case PR_SET_TIMERSLACK_PID: + if (task_pid_vnr(current) != (pid_t)arg3 && + !capable(CAP_SYS_NICE)) + return -EPERM; + rcu_read_lock(); + tsk = find_task_by_vpid((pid_t)arg3); + if (tsk == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + get_task_struct(tsk); + rcu_read_unlock(); + if (arg2 <= 0) + tsk->timer_slack_ns = + tsk->default_timer_slack_ns; + else + tsk->timer_slack_ns = arg2; + put_task_struct(tsk); + error = 0; + break; case PR_SET_CHILD_SUBREAPER: me->signal->is_child_subreaper = !!arg2; break; @@ -2139,12 +2161,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, if (arg2 != 1 || arg3 || arg4 || arg5) return -EINVAL; - current->no_new_privs = 1; + task_set_no_new_privs(current); break; case PR_GET_NO_NEW_PRIVS: if (arg2 || arg3 || arg4 || arg5) return -EINVAL; - return current->no_new_privs ? 1 : 0; + return task_no_new_privs(current) ? 1 : 0; case PR_SET_VMA: error = prctl_set_vma(arg2, arg3, arg4, arg5); break; diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 7078052284fd..7e7fc0a082c4 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -209,3 +209,6 @@ cond_syscall(compat_sys_open_by_handle_at); /* compare kernel pointers */ cond_syscall(sys_kcmp); + +/* operate on Secure Computing state */ +cond_syscall(sys_seccomp); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index b58d4fbe6c48..7979c90bc8c3 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -7110,6 +7110,12 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css, return ret; } +static int mem_cgroup_allow_attach(struct cgroup_subsys_state *css, + struct cgroup_taskset *tset) +{ + return subsys_cgroup_allow_attach(css->cgroup, tset); +} + static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css, struct cgroup_taskset *tset) { @@ -7278,6 +7284,11 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css, { return 0; } +static int mem_cgroup_allow_attach(struct cgroup_subsys_state *css, + struct cgroup_taskset *tset) +{ + return 0; +} static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css, struct cgroup_taskset *tset) { @@ -7313,6 +7324,7 @@ struct cgroup_subsys mem_cgroup_subsys = { .can_attach = mem_cgroup_can_attach, .cancel_attach = mem_cgroup_cancel_attach, .attach = mem_cgroup_move_task, + .allow_attach = mem_cgroup_allow_attach, .bind = mem_cgroup_bind, .base_cftypes = mem_cgroup_files, .early_init = 0, diff --git a/mm/util.c b/mm/util.c index c1010cb7ca0c..8f5cb5bd066f 100644 --- a/mm/util.c +++ b/mm/util.c @@ -9,7 +9,7 @@ #include <linux/swapops.h> #include <linux/mman.h> #include <linux/hugetlb.h> - +#include <linux/vmalloc.h> #include <asm/uaccess.h> #include "internal.h" @@ -383,6 +383,15 @@ unsigned long vm_mmap(struct file *file, unsigned long addr, } EXPORT_SYMBOL(vm_mmap); +void kvfree(const void *addr) +{ + if (is_vmalloc_addr(addr)) + vfree(addr); + else + kfree(addr); +} +EXPORT_SYMBOL(kvfree); + struct address_space *page_mapping(struct page *page) { struct address_space *mapping = page->mapping; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index bdac619de122..7e3f5f1db79c 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -49,15 +49,15 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) skb_reset_mac_header(skb); skb_pull(skb, ETH_HLEN); + if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid)) + goto out; + u64_stats_update_begin(&brstats->syncp); brstats->tx_packets++; /* Exclude ETH_HLEN from byte stats for consistency with Rx chain */ brstats->tx_bytes += skb->len; u64_stats_update_end(&brstats->syncp); - if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid)) - goto out; - if (is_broadcast_ether_addr(dest)) br_flood_deliver(br, skb, false); else if (is_multicast_ether_addr(dest)) { diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 185c341fafbd..5cbcdfd89f38 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -31,6 +31,8 @@ int fib_default_rule_add(struct fib_rules_ops *ops, r->pref = pref; r->table = table; r->flags = flags; + r->uid_start = INVALID_UID; + r->uid_end = INVALID_UID; r->fr_net = hold_net(ops->fro_net); r->suppress_prefixlen = -1; @@ -182,6 +184,23 @@ void fib_rules_unregister(struct fib_rules_ops *ops) } EXPORT_SYMBOL_GPL(fib_rules_unregister); +static inline kuid_t fib_nl_uid(struct nlattr *nla) +{ + return make_kuid(current_user_ns(), nla_get_u32(nla)); +} + +static int nla_put_uid(struct sk_buff *skb, int idx, kuid_t uid) +{ + return nla_put_u32(skb, idx, from_kuid_munged(current_user_ns(), uid)); +} + +static int fib_uid_range_match(struct flowi *fl, struct fib_rule *rule) +{ + return (!uid_valid(rule->uid_start) && !uid_valid(rule->uid_end)) || + (uid_gte(fl->flowi_uid, rule->uid_start) && + uid_lte(fl->flowi_uid, rule->uid_end)); +} + static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, struct flowi *fl, int flags) { @@ -196,6 +215,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask) goto out; + if (!fib_uid_range_match(fl, rule)) + goto out; + ret = ops->match(rule, fl, flags); out: return (rule->flags & FIB_RULE_INVERT) ? !ret : ret; @@ -378,6 +400,19 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) } else if (rule->action == FR_ACT_GOTO) goto errout_free; + /* UID start and end must either both be valid or both unspecified. */ + rule->uid_start = rule->uid_end = INVALID_UID; + if (tb[FRA_UID_START] || tb[FRA_UID_END]) { + if (tb[FRA_UID_START] && tb[FRA_UID_END]) { + rule->uid_start = fib_nl_uid(tb[FRA_UID_START]); + rule->uid_end = fib_nl_uid(tb[FRA_UID_END]); + } + if (!uid_valid(rule->uid_start) || + !uid_valid(rule->uid_end) || + !uid_lte(rule->uid_start, rule->uid_end)) + goto errout_free; + } + err = ops->configure(rule, skb, frh, tb); if (err < 0) goto errout_free; @@ -484,6 +519,14 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK]))) continue; + if (tb[FRA_UID_START] && + !uid_eq(rule->uid_start, fib_nl_uid(tb[FRA_UID_START]))) + continue; + + if (tb[FRA_UID_END] && + !uid_eq(rule->uid_end, fib_nl_uid(tb[FRA_UID_END]))) + continue; + if (!ops->compare(rule, frh, tb)) continue; @@ -542,7 +585,9 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, + nla_total_size(4) /* FRA_SUPPRESS_PREFIXLEN */ + nla_total_size(4) /* FRA_SUPPRESS_IFGROUP */ + nla_total_size(4) /* FRA_FWMARK */ - + nla_total_size(4); /* FRA_FWMASK */ + + nla_total_size(4) /* FRA_FWMASK */ + + nla_total_size(4) /* FRA_UID_START */ + + nla_total_size(4); /* FRA_UID_END */ if (ops->nlmsg_payload) payload += ops->nlmsg_payload(rule); @@ -598,7 +643,11 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, ((rule->mark_mask || rule->mark) && nla_put_u32(skb, FRA_FWMASK, rule->mark_mask)) || (rule->target && - nla_put_u32(skb, FRA_GOTO, rule->target))) + nla_put_u32(skb, FRA_GOTO, rule->target)) || + (uid_valid(rule->uid_start) && + nla_put_uid(skb, FRA_UID_START, rule->uid_start)) || + (uid_valid(rule->uid_end) && + nla_put_uid(skb, FRA_UID_END, rule->uid_end))) goto nla_put_failure; if (rule->suppress_ifgroup != -1) { diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index c7539e22868b..d73a3da45c49 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -531,6 +531,7 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = { [RTA_METRICS] = { .type = NLA_NESTED }, [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, [RTA_FLOW] = { .type = NLA_U32 }, + [RTA_UID] = { .type = NLA_U32 }, }; static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 1e4aa8354f93..724967cf4a7e 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -337,6 +337,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) struct sock *sk; struct inet_sock *inet; __be32 daddr, saddr; + u32 mark = IP4_REPLY_MARK(net, skb->mark); if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb)) return; @@ -349,6 +350,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) icmp_param->data.icmph.checksum = 0; inet->tos = ip_hdr(skb)->tos; + sk->sk_mark = mark; daddr = ipc.addr = ip_hdr(skb)->saddr; saddr = fib_compute_spec_dst(skb); ipc.opt = NULL; @@ -364,6 +366,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) memset(&fl4, 0, sizeof(fl4)); fl4.daddr = daddr; fl4.saddr = saddr; + fl4.flowi4_mark = mark; fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); fl4.flowi4_proto = IPPROTO_ICMP; security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); @@ -382,7 +385,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, struct sk_buff *skb_in, const struct iphdr *iph, - __be32 saddr, u8 tos, + __be32 saddr, u8 tos, u32 mark, int type, int code, struct icmp_bxm *param) { @@ -394,6 +397,7 @@ static struct rtable *icmp_route_lookup(struct net *net, fl4->daddr = (param->replyopts.opt.opt.srr ? param->replyopts.opt.opt.faddr : iph->saddr); fl4->saddr = saddr; + fl4->flowi4_mark = mark; fl4->flowi4_tos = RT_TOS(tos); fl4->flowi4_proto = IPPROTO_ICMP; fl4->fl4_icmp_type = type; @@ -491,6 +495,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct flowi4 fl4; __be32 saddr; u8 tos; + u32 mark; struct net *net; struct sock *sk; @@ -592,6 +597,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL) : iph->tos; + mark = IP4_REPLY_MARK(net, skb_in->mark); if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb_in)) goto out_unlock; @@ -608,13 +614,14 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) icmp_param->skb = skb_in; icmp_param->offset = skb_network_offset(skb_in); inet_sk(sk)->tos = tos; + sk->sk_mark = mark; ipc.addr = iph->saddr; ipc.opt = &icmp_param->replyopts.opt; ipc.tx_flags = 0; ipc.ttl = 0; ipc.tos = -1; - rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, + rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, mark, type, code, icmp_param); if (IS_ERR(rt)) goto out_unlock; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 0d1e2cb877ec..530503a73835 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -408,12 +408,13 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, struct net *net = sock_net(sk); int flags = inet_sk_flowi_flags(sk); - flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, + flowi4_init_output(fl4, sk->sk_bound_dev_if, ireq->ir_mark, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, flags, (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, - ireq->ir_loc_addr, ireq->ir_rmt_port, inet_sk(sk)->inet_sport); + ireq->ir_loc_addr, ireq->ir_rmt_port, inet_sk(sk)->inet_sport, + sock_i_uid(sk)); security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) @@ -445,11 +446,12 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk, rcu_read_lock(); opt = rcu_dereference(newinet->inet_opt); - flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, + flowi4_init_output(fl4, sk->sk_bound_dev_if, inet_rsk(req)->ir_mark, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, - ireq->ir_loc_addr, ireq->ir_rmt_port, inet_sk(sk)->inet_sport); + ireq->ir_loc_addr, ireq->ir_rmt_port, inet_sk(sk)->inet_sport, + sock_i_uid(sk)); security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) @@ -680,6 +682,8 @@ struct sock *inet_csk_clone_lock(const struct sock *sk, inet_sk(newsk)->inet_sport = htons(inet_rsk(req)->ir_num); newsk->sk_write_space = sk_stream_write_space; + newsk->sk_mark = inet_rsk(req)->ir_mark; + newicsk->icsk_retransmits = 0; newicsk->icsk_backoff = 0; newicsk->icsk_probes_out = 0; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 844323b6cfb9..e641b15a772e 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1505,12 +1505,14 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr, daddr = replyopts.opt.opt.faddr; } - flowi4_init_output(&fl4, arg->bound_dev_if, 0, + flowi4_init_output(&fl4, arg->bound_dev_if, + IP4_REPLY_MARK(net, skb->mark), RT_TOS(arg->tos), RT_SCOPE_UNIVERSE, ip_hdr(skb)->protocol, ip_reply_arg_flowi_flags(arg), daddr, saddr, - tcp_hdr(skb)->source, tcp_hdr(skb)->dest); + tcp_hdr(skb)->source, tcp_hdr(skb)->dest, + arg->uid); security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 0d33f947a87f..bdf2a257b142 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -780,7 +780,8 @@ static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, - inet_sk_flowi_flags(sk), faddr, saddr, 0, 0); + inet_sk_flowi_flags(sk), faddr, saddr, 0, 0, + sock_i_uid(sk)); security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(net, &fl4, sk); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 11c8d81fdc59..14ee444ef572 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -577,7 +577,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk) | (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), - daddr, saddr, 0, 0); + daddr, saddr, 0, 0, + sock_i_uid(sk)); if (!inet->hdrincl) { err = raw_probe_proto_opt(&fl4, msg); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 487bb6252520..dd01bba729b5 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -505,7 +505,7 @@ void __ip_select_ident(struct iphdr *iph, int segs) } EXPORT_SYMBOL(__ip_select_ident); -static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk, +static void __build_flow_key(struct flowi4 *fl4, struct sock *sk, const struct iphdr *iph, int oif, u8 tos, u8 prot, u32 mark, int flow_flags) @@ -521,11 +521,12 @@ static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk, flowi4_init_output(fl4, oif, mark, tos, RT_SCOPE_UNIVERSE, prot, flow_flags, - iph->daddr, iph->saddr, 0, 0); + iph->daddr, iph->saddr, 0, 0, + sk ? sock_i_uid(sk) : KUIDT_INIT(0)); } static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb, - const struct sock *sk) + struct sock *sk) { const struct iphdr *iph = ip_hdr(skb); int oif = skb->dev->ifindex; @@ -536,7 +537,7 @@ static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb, __build_flow_key(fl4, sk, iph, oif, tos, prot, mark, 0); } -static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk) +static void build_sk_flow_key(struct flowi4 *fl4, struct sock *sk) { const struct inet_sock *inet = inet_sk(sk); const struct ip_options_rcu *inet_opt; @@ -550,11 +551,12 @@ static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk) RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk), - daddr, inet->inet_saddr, 0, 0); + daddr, inet->inet_saddr, 0, 0, + sock_i_uid(sk)); rcu_read_unlock(); } -static void ip_rt_build_flow_key(struct flowi4 *fl4, const struct sock *sk, +static void ip_rt_build_flow_key(struct flowi4 *fl4, struct sock *sk, const struct sk_buff *skb) { if (skb) @@ -1007,6 +1009,9 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, struct flowi4 fl4; struct rtable *rt; + if (!mark) + mark = IP4_REPLY_MARK(net, skb->mark); + __build_flow_key(&fl4, NULL, iph, oif, RT_TOS(iph->tos), protocol, mark, flow_flags); rt = __ip_route_output_key(net, &fl4); @@ -1024,6 +1029,10 @@ static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) struct rtable *rt; __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); + + if (!fl4.flowi4_mark) + fl4.flowi4_mark = IP4_REPLY_MARK(sock_net(sk), skb->mark); + rt = __ip_route_output_key(sock_net(sk), &fl4); if (!IS_ERR(rt)) { __ip_rt_update_pmtu(rt, &fl4, mtu); @@ -2350,6 +2359,11 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, nla_put_u32(skb, RTA_MARK, fl4->flowi4_mark)) goto nla_put_failure; + if (!uid_eq(fl4->flowi4_uid, INVALID_UID) && + nla_put_u32(skb, RTA_UID, + from_kuid_munged(current_user_ns(), fl4->flowi4_uid))) + goto nla_put_failure; + error = rt->dst.error; if (rt_is_input_route(rt)) { @@ -2399,6 +2413,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) int err; int mark; struct sk_buff *skb; + kuid_t uid; err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy); if (err < 0) @@ -2426,6 +2441,10 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) dst = tb[RTA_DST] ? nla_get_be32(tb[RTA_DST]) : 0; iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0; mark = tb[RTA_MARK] ? nla_get_u32(tb[RTA_MARK]) : 0; + if (tb[RTA_UID]) + uid = make_kuid(current_user_ns(), nla_get_u32(tb[RTA_UID])); + else + uid = (iif ? INVALID_UID : current_uid()); memset(&fl4, 0, sizeof(fl4)); fl4.daddr = dst; @@ -2433,6 +2452,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) fl4.flowi4_tos = rtm->rtm_tos; fl4.flowi4_oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0; fl4.flowi4_mark = mark; + fl4.flowi4_uid = uid; if (iif) { struct net_device *dev; diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index f2ed13c2125f..1d6869b17856 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -303,6 +303,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, ireq->ir_rmt_port = th->source; ireq->ir_loc_addr = ip_hdr(skb)->daddr; ireq->ir_rmt_addr = ip_hdr(skb)->saddr; + ireq->ir_mark = inet_request_mark(sk, skb); ireq->ecn_ok = ecn_ok; ireq->snd_wscale = tcp_opt.snd_wscale; ireq->sack_ok = tcp_opt.sack_ok; @@ -339,11 +340,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, * hasn't changed since we received the original syn, but I see * no easy way to do this. */ - flowi4_init_output(&fl4, sk->sk_bound_dev_if, sk->sk_mark, + flowi4_init_output(&fl4, sk->sk_bound_dev_if, ireq->ir_mark, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP, inet_sk_flowi_flags(sk), (opt && opt->srr) ? opt->faddr : ireq->ir_rmt_addr, - ireq->ir_loc_addr, th->source, th->dest); + ireq->ir_loc_addr, th->source, th->dest, + sock_i_uid(sk)); security_req_classify_flow(req, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(sock_net(sk), &fl4); if (IS_ERR(rt)) { diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 187ead8c6a12..07bcc2fcf567 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -860,6 +860,20 @@ static struct ctl_table ipv4_net_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "fwmark_reflect", + .data = &init_net.ipv4.sysctl_fwmark_reflect, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "tcp_fwmark_accept", + .data = &init_net.ipv4.sysctl_tcp_fwmark_accept, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { } }; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index dea50f95d9d8..f605357bcaf7 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3330,3 +3330,4 @@ restart: return 0; } +EXPORT_SYMBOL_GPL(tcp_nuke_addr); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a782d5be132e..80776b764285 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1508,6 +1508,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ireq->ir_rmt_addr = saddr; ireq->no_srccheck = inet_sk(sk)->transparent; ireq->opt = tcp_v4_save_options(skb); + ireq->ir_mark = inet_request_mark(sk, skb); if (security_inet_conn_request(sk, skb, req)) goto drop_and_free; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index b25e852625d8..277d44f9e95a 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -987,7 +987,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), - faddr, saddr, dport, inet->inet_sport); + faddr, saddr, dport, inet->inet_sport, + sock_i_uid(sk)); security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3f0ec063d7f8..f627adf1ed06 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -194,6 +194,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .accept_ra_rt_info_max_plen = 0, #endif #endif + .accept_ra_rt_table = 0, .proxy_ndp = 0, .accept_source_route = 0, /* we do not accept RH0 by default. */ .disable_ipv6 = 0, @@ -230,6 +231,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .accept_ra_rt_info_max_plen = 0, #endif #endif + .accept_ra_rt_table = 0, .proxy_ndp = 0, .accept_source_route = 0, /* we do not accept RH0 by default. */ .disable_ipv6 = 0, @@ -1164,6 +1166,9 @@ enum { IPV6_SADDR_RULE_PRIVACY, IPV6_SADDR_RULE_ORCHID, IPV6_SADDR_RULE_PREFIX, +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + IPV6_SADDR_RULE_NOT_OPTIMISTIC, +#endif IPV6_SADDR_RULE_MAX }; @@ -1191,6 +1196,15 @@ static inline int ipv6_saddr_preferred(int type) return 0; } +static inline bool ipv6_use_optimistic_addr(struct inet6_dev *idev) +{ +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + return idev && idev->cnf.optimistic_dad && idev->cnf.use_optimistic; +#else + return false; +#endif +} + static int ipv6_get_saddr_eval(struct net *net, struct ipv6_saddr_score *score, struct ipv6_saddr_dst *dst, @@ -1251,10 +1265,16 @@ static int ipv6_get_saddr_eval(struct net *net, score->scopedist = ret; break; case IPV6_SADDR_RULE_PREFERRED: + { /* Rule 3: Avoid deprecated and optimistic addresses */ + u8 avoid = IFA_F_DEPRECATED; + + if (!ipv6_use_optimistic_addr(score->ifa->idev)) + avoid |= IFA_F_OPTIMISTIC; ret = ipv6_saddr_preferred(score->addr_type) || - !(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)); + !(score->ifa->flags & avoid); break; + } #ifdef CONFIG_IPV6_MIP6 case IPV6_SADDR_RULE_HOA: { @@ -1300,6 +1320,14 @@ static int ipv6_get_saddr_eval(struct net *net, ret = score->ifa->prefix_len; score->matchlen = ret; break; +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + case IPV6_SADDR_RULE_NOT_OPTIMISTIC: + /* Optimistic addresses still have lower precedence than other + * preferred addresses. + */ + ret = !(score->ifa->flags & IFA_F_OPTIMISTIC); + break; +#endif default: ret = 0; } @@ -1497,7 +1525,9 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, if (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_equal(&ifp->addr, addr) && - !(ifp->flags&IFA_F_TENTATIVE) && + (!(ifp->flags&IFA_F_TENTATIVE) || + (ipv6_use_optimistic_addr(ifp->idev) && + ifp->flags&IFA_F_OPTIMISTIC)) && (dev == NULL || ifp->idev->dev == dev || !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { rcu_read_unlock_bh(); @@ -1960,6 +1990,31 @@ static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmp __ipv6_regen_rndid(idev); } +u32 addrconf_rt_table(const struct net_device *dev, u32 default_table) { + /* Determines into what table to put autoconf PIO/RIO/default routes + * learned on this device. + * + * - If 0, use the same table for every device. This puts routes into + * one of RT_TABLE_{PREFIX,INFO,DFLT} depending on the type of route + * (but note that these three are currently all equal to + * RT6_TABLE_MAIN). + * - If > 0, use the specified table. + * - If < 0, put routes into table dev->ifindex + (-rt_table). + */ + struct inet6_dev *idev = in6_dev_get(dev); + u32 table; + int sysctl = idev->cnf.accept_ra_rt_table; + if (sysctl == 0) { + table = default_table; + } else if (sysctl > 0) { + table = (u32) sysctl; + } else { + table = (unsigned) dev->ifindex + (-sysctl); + } + in6_dev_put(idev); + return table; +} + /* * Add prefix route. */ @@ -1969,7 +2024,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, unsigned long expires, u32 flags) { struct fib6_config cfg = { - .fc_table = RT6_TABLE_PREFIX, + .fc_table = addrconf_rt_table(dev, RT6_TABLE_PREFIX), .fc_metric = IP6_RT_PRIO_ADDRCONF, .fc_ifindex = dev->ifindex, .fc_expires = expires, @@ -2003,7 +2058,8 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, struct rt6_info *rt = NULL; struct fib6_table *table; - table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX); + table = fib6_get_table(dev_net(dev), + addrconf_rt_table(dev, RT6_TABLE_PREFIX)); if (table == NULL) return NULL; @@ -3211,8 +3267,15 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp) * Optimistic nodes can start receiving * Frames right away */ - if (ifp->flags & IFA_F_OPTIMISTIC) + if (ifp->flags & IFA_F_OPTIMISTIC) { ip6_ins_rt(ifp->rt); + if (ipv6_use_optimistic_addr(idev)) { + /* Because optimistic nodes can use this address, + * notify listeners. If DAD fails, RTM_DELADDR is sent. + */ + ipv6_ifa_notify(RTM_NEWADDR, ifp); + } + } addrconf_dad_kick(ifp); out: @@ -4308,10 +4371,12 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; #endif #endif + array[DEVCONF_ACCEPT_RA_RT_TABLE] = cnf->accept_ra_rt_table; array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; + array[DEVCONF_USE_OPTIMISTIC] = cnf->use_optimistic; #endif #ifdef CONFIG_IPV6_MROUTE array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; @@ -5100,6 +5165,13 @@ static struct addrconf_sysctl_table #endif #endif { + .procname = "accept_ra_rt_table", + .data = &ipv6_devconf.accept_ra_rt_table, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { .procname = "proxy_ndp", .data = &ipv6_devconf.proxy_ndp, .maxlen = sizeof(int), @@ -5122,6 +5194,14 @@ static struct addrconf_sysctl_table .proc_handler = proc_dointvec, }, + { + .procname = "use_optimistic", + .data = &ipv6_devconf.use_optimistic, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + + }, #endif #ifdef CONFIG_IPV6_MROUTE { diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index db23fbdf357c..8652ad15edbc 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -690,6 +690,7 @@ int inet6_sk_rebuild_header(struct sock *sk) fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet->inet_dport; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); final_p = fl6_update_dst(&fl6, np->opt, &final); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 81e496a2e008..37312d1e0e5c 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -628,7 +628,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (type == NDISC_REDIRECT) ip6_redirect(skb, net, skb->dev->ifindex, 0); else - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, INVALID_UID); xfrm_state_put(x); } diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index c3bf2d2e519e..f88dc999298d 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -161,6 +161,7 @@ ipv4_connected: fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet->inet_dport; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); if (!fl6.flowi6_oif && (addr_type&IPV6_ADDR_MULTICAST)) fl6.flowi6_oif = np->mcast_oif; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 6eef8a7e35f2..a617b0389875 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -441,7 +441,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (type == NDISC_REDIRECT) ip6_redirect(skb, net, skb->dev->ifindex, 0); else - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, INVALID_UID); xfrm_state_put(x); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 7b326529e6a2..d78f3bd945d7 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -91,7 +91,7 @@ static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct net *net = dev_net(skb->dev); if (type == ICMPV6_PKT_TOOBIG) - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, INVALID_UID); else if (type == NDISC_REDIRECT) ip6_redirect(skb, net, skb->dev->ifindex, 0); @@ -400,6 +400,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) int len; int hlimit; int err = 0; + u32 mark = IP6_REPLY_MARK(net, skb->mark); if ((u8 *)hdr < skb->head || (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) @@ -466,6 +467,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) fl6.daddr = hdr->saddr; if (saddr) fl6.saddr = *saddr; + fl6.flowi6_mark = mark; fl6.flowi6_oif = iif; fl6.fl6_icmp_type = type; fl6.fl6_icmp_code = code; @@ -474,6 +476,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) sk = icmpv6_xmit_lock(net); if (sk == NULL) return; + sk->sk_mark = mark; np = inet6_sk(sk); if (!icmpv6_xrlim_allow(sk, type, &fl6)) @@ -556,6 +559,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) int err = 0; int hlimit; u8 tclass; + u32 mark = IP6_REPLY_MARK(net, skb->mark); saddr = &ipv6_hdr(skb)->daddr; @@ -574,11 +578,13 @@ static void icmpv6_echo_reply(struct sk_buff *skb) fl6.saddr = *saddr; fl6.flowi6_oif = skb->dev->ifindex; fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; + fl6.flowi6_mark = mark; security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); sk = icmpv6_xmit_lock(net); if (sk == NULL) return; + sk->sk_mark = mark; np = inet6_sk(sk); if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index c9138189415a..5aefd263dcf3 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -81,9 +81,10 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk, final_p = fl6_update_dst(fl6, np->opt, &final); fl6->saddr = ireq->ir_v6_loc_addr; fl6->flowi6_oif = ireq->ir_iif; - fl6->flowi6_mark = sk->sk_mark; + fl6->flowi6_mark = inet_rsk(req)->ir_mark; fl6->fl6_dport = ireq->ir_rmt_port; fl6->fl6_sport = htons(ireq->ir_num); + fl6->flowi6_uid = sock_i_uid(sk); security_req_classify_flow(req, flowi6_to_flowi(fl6)); dst = ip6_dst_lookup_flow(sk, fl6, final_p); @@ -210,6 +211,7 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk, fl6->flowi6_mark = sk->sk_mark; fl6->fl6_sport = inet->inet_sport; fl6->fl6_dport = inet->inet_dport; + fl6->flowi6_uid = sock_i_uid(sk); security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); final_p = fl6_update_dst(fl6, np->opt, &final); diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index da9becb42e81..8964a1004aad 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -76,7 +76,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (type == NDISC_REDIRECT) ip6_redirect(skb, net, skb->dev->ifindex, 0); else - ip6_update_pmtu(skb, net, info, 0, 0); + ip6_update_pmtu(skb, net, info, 0, 0, INVALID_UID); xfrm_state_put(x); } diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index bda74291c3e0..f0db1dfc6cc7 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -136,6 +136,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, fl6.saddr = np->saddr; fl6.daddr = *daddr; fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sock_i_uid(sk); fl6.fl6_icmp_type = user_icmph.icmp6_type; fl6.fl6_icmp_code = user_icmph.icmp6_code; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 1f29996e368a..5d8dd9a03e70 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -770,6 +770,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sock_i_uid(sk); if (sin6) { if (addr_len < SIN6_LEN_RFC2133) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7cc1102e298c..d4ee85294a66 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -95,13 +95,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, static int rt6_score_route(struct rt6_info *rt, int oif, int strict); #ifdef CONFIG_IPV6_ROUTE_INFO -static struct rt6_info *rt6_add_route_info(struct net *net, +static struct rt6_info *rt6_add_route_info(struct net_device *dev, const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, int ifindex, - unsigned int pref); -static struct rt6_info *rt6_get_route_info(struct net *net, + const struct in6_addr *gwaddr, unsigned int pref); +static struct rt6_info *rt6_get_route_info(struct net_device *dev, const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, int ifindex); + const struct in6_addr *gwaddr); #endif static void rt6_bind_peer(struct rt6_info *rt, int create) @@ -706,7 +705,6 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, const struct in6_addr *gwaddr) { - struct net *net = dev_net(dev); struct route_info *rinfo = (struct route_info *) opt; struct in6_addr prefix_buf, *prefix; unsigned int pref; @@ -751,8 +749,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, if (rinfo->prefix_len == 0) rt = rt6_get_dflt_router(gwaddr, dev); else - rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, - gwaddr, dev->ifindex); + rt = rt6_get_route_info(dev, prefix, rinfo->prefix_len, gwaddr); if (rt && !lifetime) { ip6_del_rt(rt); @@ -760,8 +757,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, } if (!rt && lifetime) - rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex, - pref); + rt = rt6_add_route_info(dev, prefix, rinfo->prefix_len, gwaddr, pref); else if (rt) rt->rt6i_flags = RTF_ROUTEINFO | (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); @@ -1172,7 +1168,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, } void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, - int oif, u32 mark) + int oif, u32 mark, kuid_t uid) { const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; struct dst_entry *dst; @@ -1180,10 +1176,11 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_oif = oif; - fl6.flowi6_mark = mark; + fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark); fl6.daddr = iph->daddr; fl6.saddr = iph->saddr; fl6.flowlabel = ip6_flowinfo(iph); + fl6.flowi6_uid = uid; dst = ip6_route_output(net, NULL, &fl6); if (!dst->error) @@ -1195,7 +1192,7 @@ EXPORT_SYMBOL_GPL(ip6_update_pmtu); void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu) { ip6_update_pmtu(skb, sock_net(sk), mtu, - sk->sk_bound_dev_if, sk->sk_mark); + sk->sk_bound_dev_if, sk->sk_mark, sock_i_uid(sk)); } EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu); @@ -1937,15 +1934,16 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort, } #ifdef CONFIG_IPV6_ROUTE_INFO -static struct rt6_info *rt6_get_route_info(struct net *net, +static struct rt6_info *rt6_get_route_info(struct net_device *dev, const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, int ifindex) + const struct in6_addr *gwaddr) { struct fib6_node *fn; struct rt6_info *rt = NULL; struct fib6_table *table; - table = fib6_get_table(net, RT6_TABLE_INFO); + table = fib6_get_table(dev_net(dev), + addrconf_rt_table(dev, RT6_TABLE_INFO)); if (!table) return NULL; @@ -1955,7 +1953,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net, goto out; for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { - if (rt->dst.dev->ifindex != ifindex) + if (rt->dst.dev->ifindex != dev->ifindex) continue; if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) continue; @@ -1969,21 +1967,20 @@ out: return rt; } -static struct rt6_info *rt6_add_route_info(struct net *net, +static struct rt6_info *rt6_add_route_info(struct net_device *dev, const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, int ifindex, - unsigned int pref) + const struct in6_addr *gwaddr, unsigned int pref) { struct fib6_config cfg = { - .fc_table = RT6_TABLE_INFO, + .fc_table = addrconf_rt_table(dev, RT6_TABLE_INFO), .fc_metric = IP6_RT_PRIO_USER, - .fc_ifindex = ifindex, + .fc_ifindex = dev->ifindex, .fc_dst_len = prefixlen, .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref), .fc_nlinfo.portid = 0, .fc_nlinfo.nlh = NULL, - .fc_nlinfo.nl_net = net, + .fc_nlinfo.nl_net = dev_net(dev), }; cfg.fc_dst = *prefix; @@ -1995,7 +1992,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net, ip6_route_add(&cfg); - return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex); + return rt6_get_route_info(dev, prefix, prefixlen, gwaddr); } #endif @@ -2004,7 +2001,8 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev struct rt6_info *rt; struct fib6_table *table; - table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT); + table = fib6_get_table(dev_net(dev), + addrconf_rt_table(dev, RT6_TABLE_MAIN)); if (!table) return NULL; @@ -2026,7 +2024,7 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, unsigned int pref) { struct fib6_config cfg = { - .fc_table = RT6_TABLE_DFLT, + .fc_table = addrconf_rt_table(dev, RT6_TABLE_DFLT), .fc_metric = IP6_RT_PRIO_USER, .fc_ifindex = dev->ifindex, .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | @@ -2043,28 +2041,17 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, return rt6_get_dflt_router(gwaddr, dev); } -void rt6_purge_dflt_routers(struct net *net) -{ - struct rt6_info *rt; - struct fib6_table *table; - /* NOTE: Keep consistent with rt6_get_dflt_router */ - table = fib6_get_table(net, RT6_TABLE_DFLT); - if (!table) - return; +int rt6_addrconf_purge(struct rt6_info *rt, void *arg) { + if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) && + (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) + return -1; + return 0; +} -restart: - read_lock_bh(&table->tb6_lock); - for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) { - if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) && - (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) { - dst_hold(&rt->dst); - read_unlock_bh(&table->tb6_lock); - ip6_del_rt(rt); - goto restart; - } - } - read_unlock_bh(&table->tb6_lock); +void rt6_purge_dflt_routers(struct net *net) +{ + fib6_clean_all(net, rt6_addrconf_purge, NULL); } static void rtmsg_to_fib6_config(struct net *net, @@ -2349,6 +2336,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { [RTA_PRIORITY] = { .type = NLA_U32 }, [RTA_METRICS] = { .type = NLA_NESTED }, [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, + [RTA_UID] = { .type = NLA_U32 }, }; static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -2735,6 +2723,12 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh) if (tb[RTA_OIF]) oif = nla_get_u32(tb[RTA_OIF]); + if (tb[RTA_UID]) + fl6.flowi6_uid = make_kuid(current_user_ns(), + nla_get_u32(tb[RTA_UID])); + else + fl6.flowi6_uid = iif ? INVALID_UID : current_uid(); + if (iif) { struct net_device *dev; int flags = 0; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index bb53a5e73c1a..38541fcbcb2b 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -216,6 +216,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) ireq->ir_iif = inet6_iif(skb); + ireq->ir_mark = inet_request_mark(sk, skb); + req->expires = 0UL; req->num_retrans = 0; ireq->ecn_ok = ecn_ok; @@ -242,9 +244,10 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) final_p = fl6_update_dst(&fl6, np->opt, &final); fl6.saddr = ireq->ir_v6_loc_addr; fl6.flowi6_oif = sk->sk_bound_dev_if; - fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_mark = ireq->ir_mark; fl6.fl6_dport = ireq->ir_rmt_port; fl6.fl6_sport = inet_sk(sk)->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); security_req_classify_flow(req, flowi6_to_flowi(&fl6)); dst = ip6_dst_lookup_flow(sk, &fl6, final_p); diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 7f405a168822..8d08a1b0d47a 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -38,6 +38,15 @@ static struct ctl_table ipv6_table_template[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "flowlabel_consistency", + .data = &init_net.ipv6.sysctl.flowlabel_consistency, + .procname = "fwmark_reflect", + .data = &init_net.ipv6.sysctl.fwmark_reflect, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { } }; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a4f890dd223a..3291857694b1 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -252,6 +252,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = usin->sin6_port; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); final_p = fl6_update_dst(&fl6, np->opt, &final); @@ -800,6 +801,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, fl6.flowi6_proto = IPPROTO_TCP; if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL) fl6.flowi6_oif = inet6_iif(skb); + fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark); fl6.fl6_dport = t1->dest; fl6.fl6_sport = t1->source; security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); @@ -1012,6 +1014,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) TCP_ECN_create_request(req, skb, sock_net(sk)); ireq->ir_iif = sk->sk_bound_dev_if; + inet_rsk(req)->ir_mark = inet_request_mark(sk, skb); /* So that link locals have meaning */ if (!sk->sk_bound_dev_if && diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 20b63d2ab70f..2b5d6d1c2ada 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1177,6 +1177,7 @@ do_udp_sendmsg: fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex; fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sock_i_uid(sk); if (msg->msg_controllen) { opt = &opt_space; diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index df91e26f55f2..f6562ba97a97 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -42,6 +42,11 @@ #include <linux/skbuff.h> #include <linux/workqueue.h> #include <linux/sysfs.h> +#include <linux/rtc.h> +#include <linux/time.h> +#include <linux/math64.h> +#include <linux/suspend.h> +#include <linux/notifier.h> #include <net/net_namespace.h> struct idletimer_tg_attr { @@ -58,22 +63,65 @@ struct idletimer_tg { struct kobject *kobj; struct idletimer_tg_attr attr; + struct timespec delayed_timer_trigger; + struct timespec last_modified_timer; + struct timespec last_suspend_time; + struct notifier_block pm_nb; + + int timeout; unsigned int refcnt; + bool work_pending; bool send_nl_msg; bool active; }; static LIST_HEAD(idletimer_tg_list); static DEFINE_MUTEX(list_mutex); +static DEFINE_SPINLOCK(timestamp_lock); static struct kobject *idletimer_tg_kobj; +static bool check_for_delayed_trigger(struct idletimer_tg *timer, + struct timespec *ts) +{ + bool state; + struct timespec temp; + spin_lock_bh(×tamp_lock); + timer->work_pending = false; + if ((ts->tv_sec - timer->last_modified_timer.tv_sec) > timer->timeout || + timer->delayed_timer_trigger.tv_sec != 0) { + state = false; + temp.tv_sec = timer->timeout; + temp.tv_nsec = 0; + if (timer->delayed_timer_trigger.tv_sec != 0) { + temp = timespec_add(timer->delayed_timer_trigger, temp); + ts->tv_sec = temp.tv_sec; + ts->tv_nsec = temp.tv_nsec; + timer->delayed_timer_trigger.tv_sec = 0; + timer->work_pending = true; + schedule_work(&timer->work); + } else { + temp = timespec_add(timer->last_modified_timer, temp); + ts->tv_sec = temp.tv_sec; + ts->tv_nsec = temp.tv_nsec; + } + } else { + state = timer->active; + } + spin_unlock_bh(×tamp_lock); + return state; +} + static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer) { char iface_msg[NLMSG_MAX_SIZE]; char state_msg[NLMSG_MAX_SIZE]; - char *envp[] = { iface_msg, state_msg, NULL }; + char timestamp_msg[NLMSG_MAX_SIZE]; + char *envp[] = { iface_msg, state_msg, timestamp_msg, NULL }; int res; + struct timespec ts; + uint64_t time_ns; + bool state; res = snprintf(iface_msg, NLMSG_MAX_SIZE, "INTERFACE=%s", iface); @@ -81,12 +129,24 @@ static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer) pr_err("message too long (%d)", res); return; } + + get_monotonic_boottime(&ts); + state = check_for_delayed_trigger(timer, &ts); res = snprintf(state_msg, NLMSG_MAX_SIZE, "STATE=%s", - timer->active ? "active" : "inactive"); + state ? "active" : "inactive"); + if (NLMSG_MAX_SIZE <= res) { pr_err("message too long (%d)", res); return; } + + time_ns = timespec_to_ns(&ts); + res = snprintf(timestamp_msg, NLMSG_MAX_SIZE, "TIME_NS=%llu", time_ns); + if (NLMSG_MAX_SIZE <= res) { + timestamp_msg[0] = '\0'; + pr_err("message too long (%d)", res); + } + pr_debug("putting nlmsg: <%s> <%s>\n", iface_msg, state_msg); kobject_uevent_env(idletimer_tg_kobj, KOBJ_CHANGE, envp); return; @@ -151,9 +211,55 @@ static void idletimer_tg_expired(unsigned long data) struct idletimer_tg *timer = (struct idletimer_tg *) data; pr_debug("timer %s expired\n", timer->attr.attr.name); - + spin_lock_bh(×tamp_lock); timer->active = false; + timer->work_pending = true; schedule_work(&timer->work); + spin_unlock_bh(×tamp_lock); +} + +static int idletimer_resume(struct notifier_block *notifier, + unsigned long pm_event, void *unused) +{ + struct timespec ts; + unsigned long time_diff, now = jiffies; + struct idletimer_tg *timer = container_of(notifier, + struct idletimer_tg, pm_nb); + if (!timer) + return NOTIFY_DONE; + switch (pm_event) { + case PM_SUSPEND_PREPARE: + get_monotonic_boottime(&timer->last_suspend_time); + break; + case PM_POST_SUSPEND: + spin_lock_bh(×tamp_lock); + if (!timer->active) { + spin_unlock_bh(×tamp_lock); + break; + } + /* since jiffies are not updated when suspended now represents + * the time it would have suspended */ + if (time_after(timer->timer.expires, now)) { + get_monotonic_boottime(&ts); + ts = timespec_sub(ts, timer->last_suspend_time); + time_diff = timespec_to_jiffies(&ts); + if (timer->timer.expires > (time_diff + now)) { + mod_timer_pending(&timer->timer, + (timer->timer.expires - time_diff)); + } else { + del_timer(&timer->timer); + timer->timer.expires = 0; + timer->active = false; + timer->work_pending = true; + schedule_work(&timer->work); + } + } + spin_unlock_bh(×tamp_lock); + break; + default: + break; + } + return NOTIFY_DONE; } static int idletimer_tg_create(struct idletimer_tg_info *info) @@ -187,6 +293,18 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) info->timer->refcnt = 1; info->timer->send_nl_msg = (info->send_nl_msg == 0) ? false : true; info->timer->active = true; + info->timer->timeout = info->timeout; + + info->timer->delayed_timer_trigger.tv_sec = 0; + info->timer->delayed_timer_trigger.tv_nsec = 0; + info->timer->work_pending = false; + get_monotonic_boottime(&info->timer->last_modified_timer); + + info->timer->pm_nb.notifier_call = idletimer_resume; + ret = register_pm_notifier(&info->timer->pm_nb); + if (ret) + printk(KERN_WARNING "[%s] Failed to register pm notifier %d\n", + __func__, ret); mod_timer(&info->timer->timer, msecs_to_jiffies(info->timeout * 1000) + jiffies); @@ -203,6 +321,34 @@ out: return ret; } +static void reset_timer(const struct idletimer_tg_info *info) +{ + unsigned long now = jiffies; + struct idletimer_tg *timer = info->timer; + bool timer_prev; + + spin_lock_bh(×tamp_lock); + timer_prev = timer->active; + timer->active = true; + /* timer_prev is used to guard overflow problem in time_before*/ + if (!timer_prev || time_before(timer->timer.expires, now)) { + pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n", + timer->timer.expires, now); + /* checks if there is a pending inactive notification*/ + if (timer->work_pending) + timer->delayed_timer_trigger = timer->last_modified_timer; + else { + timer->work_pending = true; + schedule_work(&timer->work); + } + } + + get_monotonic_boottime(&timer->last_modified_timer); + mod_timer(&timer->timer, + msecs_to_jiffies(info->timeout * 1000) + now); + spin_unlock_bh(×tamp_lock); +} + /* * The actual xt_tables plugin. */ @@ -226,9 +372,7 @@ static unsigned int idletimer_tg_target(struct sk_buff *skb, } /* TODO: Avoid modifying timers on each packet */ - mod_timer(&info->timer->timer, - msecs_to_jiffies(info->timeout * 1000) + now); - + reset_timer(info); return XT_CONTINUE; } @@ -236,7 +380,6 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) { struct idletimer_tg_info *info = par->targinfo; int ret; - unsigned long now = jiffies; pr_debug("checkentry targinfo %s\n", info->label); @@ -257,17 +400,7 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) info->timer = __idletimer_tg_find_by_label(info->label); if (info->timer) { info->timer->refcnt++; - info->timer->active = true; - - if (time_before(info->timer->timer.expires, now)) { - schedule_work(&info->timer->work); - pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n", - info->timer->timer.expires, now); - } - - mod_timer(&info->timer->timer, - msecs_to_jiffies(info->timeout * 1000) + now); - + reset_timer(info); pr_debug("increased refcnt of timer %s to %u\n", info->label, info->timer->refcnt); } else { @@ -298,6 +431,7 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par) list_del(&info->timer->entry); del_timer_sync(&info->timer->timer); sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr); + unregister_pm_notifier(&info->timer->pm_nb); kfree(info->timer->attr.attr.name); kfree(info->timer); } else { diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index f0a670aa9864..084967225f2e 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -145,7 +145,7 @@ static bool can_manipulate_uids(void) { /* root pwnd */ return in_egroup_p(xt_qtaguid_ctrl_file->gid) - || unlikely(!from_kuid(&init_user_ns,current_fsuid())) || unlikely(!proc_ctrl_write_limited) + || unlikely(!from_kuid(&init_user_ns, current_fsuid())) || unlikely(!proc_ctrl_write_limited) || unlikely(uid_eq(current_fsuid(), xt_qtaguid_ctrl_file->uid)); } @@ -158,7 +158,7 @@ static bool can_read_other_uid_stats(kuid_t uid) { /* root pwnd */ return in_egroup_p(xt_qtaguid_stats_file->gid) - || unlikely(!from_kuid(&init_user_ns,current_fsuid())) || uid_eq(uid, current_fsuid()) + || unlikely(!from_kuid(&init_user_ns, current_fsuid())) || uid_eq(uid, current_fsuid()) || unlikely(!proc_stats_readall_limited) || unlikely(uid_eq(current_fsuid(), xt_qtaguid_ctrl_file->uid)); } @@ -542,7 +542,7 @@ static void put_utd_entry(struct uid_tag_data *utd_entry) "erase utd_entry=%p uid=%u " "by pid=%u tgid=%u uid=%u\n", __func__, utd_entry, utd_entry->uid, - current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); BUG_ON(utd_entry->num_active_tags); rb_erase(&utd_entry->node, &uid_tag_data_tree); kfree(utd_entry); @@ -744,7 +744,7 @@ static int iface_stat_fmt_proc_show(struct seq_file *m, void *v) CT_DEBUG("qtaguid:proc iface_stat_fmt pid=%u tgid=%u uid=%u\n", - current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); iface_entry = list_entry(v, struct iface_stat, list); @@ -1927,7 +1927,7 @@ static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v) long f_count; CT_DEBUG("qtaguid: proc ctrl pid=%u tgid=%u uid=%u\n", - current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); if (sock_tag_entry != SEQ_START_TOKEN) { uid = get_uid_from_tag(sock_tag_entry->tag); @@ -1958,18 +1958,18 @@ static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v) "match_found_no_sk_in_ct=%llu " "match_no_sk=%llu " "match_no_sk_file=%llu\n", - atomic64_read(&qtu_events.sockets_tagged), - atomic64_read(&qtu_events.sockets_untagged), - atomic64_read(&qtu_events.counter_set_changes), - atomic64_read(&qtu_events.delete_cmds), - atomic64_read(&qtu_events.iface_events), - atomic64_read(&qtu_events.match_calls), - atomic64_read(&qtu_events.match_calls_prepost), - atomic64_read(&qtu_events.match_found_sk), - atomic64_read(&qtu_events.match_found_sk_in_ct), - atomic64_read(&qtu_events.match_found_no_sk_in_ct), - atomic64_read(&qtu_events.match_no_sk), - atomic64_read(&qtu_events.match_no_sk_file)); + (u64)atomic64_read(&qtu_events.sockets_tagged), + (u64)atomic64_read(&qtu_events.sockets_untagged), + (u64)atomic64_read(&qtu_events.counter_set_changes), + (u64)atomic64_read(&qtu_events.delete_cmds), + (u64)atomic64_read(&qtu_events.iface_events), + (u64)atomic64_read(&qtu_events.match_calls), + (u64)atomic64_read(&qtu_events.match_calls_prepost), + (u64)atomic64_read(&qtu_events.match_found_sk), + (u64)atomic64_read(&qtu_events.match_found_sk_in_ct), + (u64)atomic64_read(&qtu_events.match_found_no_sk_in_ct), + (u64)atomic64_read(&qtu_events.match_no_sk), + (u64)atomic64_read(&qtu_events.match_no_sk_file)); /* Count the following as part of the last item_index */ prdebug_full_state(0, "proc ctrl"); @@ -2001,7 +2001,7 @@ static int ctrl_cmd_delete(const char *input) struct uid_tag_data *utd_entry; argc = sscanf(input, "%c %llu %u", &cmd, &acct_tag, &uid_int); - uid = KUIDT_INIT(uid_int); + uid = make_kuid(&init_user_ns, uid_int); CT_DEBUG("qtaguid: ctrl_delete(%s): argc=%d cmd=%c " "user_tag=0x%llx uid=%u\n", input, argc, cmd, acct_tag, uid_int); @@ -2016,18 +2016,19 @@ static int ctrl_cmd_delete(const char *input) } if (argc < 3) { uid = current_fsuid(); + uid_int = from_kuid(&init_user_ns, uid); } else if (!can_impersonate_uid(uid)) { pr_info("qtaguid: ctrl_delete(%s): " "insufficient priv from pid=%u tgid=%u uid=%u\n", - input, current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); res = -EPERM; goto err; } - tag = combine_atag_with_uid(acct_tag, from_kuid(&init_user_ns,uid)); + tag = combine_atag_with_uid(acct_tag, uid_int); CT_DEBUG("qtaguid: ctrl_delete(%s): " "looking for tag=0x%llx (uid=%u)\n", - input, tag, from_kuid(&init_user_ns, uid)); + input, tag, uid_int); /* Delete socket tags */ spin_lock_bh(&sock_tag_list_lock); @@ -2036,7 +2037,7 @@ static int ctrl_cmd_delete(const char *input) st_entry = rb_entry(node, struct sock_tag, sock_node); entry_uid = get_uid_from_tag(st_entry->tag); node = rb_next(node); - if (!uid_eq(make_kuid(&init_user_ns,entry_uid), uid)) + if (entry_uid != uid_int) continue; CT_DEBUG("qtaguid: ctrl_delete(%s): st tag=0x%llx (uid=%u)\n", @@ -2097,7 +2098,7 @@ static int ctrl_cmd_delete(const char *input) "ts tag=0x%llx (uid=%u)\n", input, ts_entry->tn.tag, entry_uid); - if (!uid_eq(make_kuid(&init_user_ns,entry_uid), uid)) + if (entry_uid != uid_int) continue; if (!acct_tag || ts_entry->tn.tag == tag) { CT_DEBUG("qtaguid: ctrl_delete(%s): " @@ -2126,7 +2127,7 @@ static int ctrl_cmd_delete(const char *input) "utd uid=%u\n", input, entry_uid); - if (!uid_eq(make_kuid(&init_user_ns,entry_uid), uid)) + if (entry_uid != uid_int) continue; /* * Go over the tag_refs, and those that don't have @@ -2170,7 +2171,7 @@ static int ctrl_cmd_counter_set(const char *input) if (!can_manipulate_uids()) { pr_info("qtaguid: ctrl_counterset(%s): " "insufficient priv from pid=%u tgid=%u uid=%u\n", - input, current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); res = -EPERM; goto err; } @@ -2208,7 +2209,7 @@ static int ctrl_cmd_tag(const char *input) char cmd; int sock_fd = 0; kuid_t uid; - unsigned int uid_int; + unsigned int uid_int = 0; tag_t acct_tag = make_atag_from_value(0); tag_t full_tag; struct socket *el_socket; @@ -2220,7 +2221,7 @@ static int ctrl_cmd_tag(const char *input) /* Unassigned args will get defaulted later. */ argc = sscanf(input, "%c %d %llu %u", &cmd, &sock_fd, &acct_tag, &uid_int); - uid = KUIDT_INIT(uid_int); + uid = make_kuid(&init_user_ns, uid_int); CT_DEBUG("qtaguid: ctrl_tag(%s): argc=%d cmd=%c sock_fd=%d " "acct_tag=0x%llx uid=%u\n", input, argc, cmd, sock_fd, acct_tag, uid_int); @@ -2233,7 +2234,7 @@ static int ctrl_cmd_tag(const char *input) pr_info("qtaguid: ctrl_tag(%s): failed to lookup" " sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n", input, sock_fd, res, current->pid, current->tgid, - from_kuid(&init_user_ns,current_fsuid())); + from_kuid(&init_user_ns, current_fsuid())); goto err; } CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%ld ->sk=%p\n", @@ -2253,19 +2254,20 @@ static int ctrl_cmd_tag(const char *input) from_kuid(&init_user_ns, current_uid()), from_kuid(&init_user_ns, current_euid()), from_kuid(&init_user_ns, current_fsuid()), - from_kgid(&init_user_ns,xt_qtaguid_ctrl_file->gid), + from_kgid(&init_user_ns, xt_qtaguid_ctrl_file->gid), in_group_p(xt_qtaguid_ctrl_file->gid), in_egroup_p(xt_qtaguid_ctrl_file->gid)); if (argc < 4) { uid = current_fsuid(); + uid_int = from_kuid(&init_user_ns, uid); } else if (!can_impersonate_uid(uid)) { pr_info("qtaguid: ctrl_tag(%s): " "insufficient priv from pid=%u tgid=%u uid=%u\n", - input, current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); res = -EPERM; goto err_put; } - full_tag = combine_atag_with_uid(acct_tag, from_kuid(&init_user_ns,uid)); + full_tag = combine_atag_with_uid(acct_tag, uid_int); spin_lock_bh(&sock_tag_list_lock); sock_tag_entry = get_sock_stat_nl(el_socket->sk); @@ -2312,8 +2314,7 @@ static int ctrl_cmd_tag(const char *input) sock_tag_entry->sk = el_socket->sk; sock_tag_entry->socket = el_socket; sock_tag_entry->pid = current->tgid; - sock_tag_entry->tag = combine_atag_with_uid(acct_tag, - from_kuid(&init_user_ns,uid)); + sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid_int); spin_lock_bh(&uid_tag_data_tree_lock); pqd_entry = proc_qtu_data_tree_search( &proc_qtu_data_tree, current->tgid); @@ -2328,7 +2329,7 @@ static int ctrl_cmd_tag(const char *input) "User space forgot to open /dev/xt_qtaguid? " "pid=%u tgid=%u uid=%u\n", __func__, current->pid, current->tgid, - from_kuid(&init_user_ns,current_fsuid())); + from_kuid(&init_user_ns, current_fsuid())); else list_add(&sock_tag_entry->list, &pqd_entry->sock_tag_list); @@ -2383,7 +2384,7 @@ static int ctrl_cmd_untag(const char *input) pr_info("qtaguid: ctrl_untag(%s): failed to lookup" " sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n", input, sock_fd, res, current->pid, current->tgid, - from_kuid(&init_user_ns,current_fsuid())); + from_kuid(&init_user_ns, current_fsuid())); goto err; } CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%ld ->sk=%p\n", @@ -2417,7 +2418,7 @@ static int ctrl_cmd_untag(const char *input) pr_warn_once("qtaguid: %s(): " "User space forgot to open /dev/xt_qtaguid? " "pid=%u tgid=%u uid=%u\n", __func__, - current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); else list_del(&sock_tag_entry->list); spin_unlock_bh(&uid_tag_data_tree_lock); @@ -2460,7 +2461,7 @@ static ssize_t qtaguid_ctrl_parse(const char *input, size_t count) ssize_t res; CT_DEBUG("qtaguid: ctrl(%s): pid=%u tgid=%u uid=%u\n", - input, current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); cmd = input[0]; /* Collect params for commands */ @@ -2549,7 +2550,7 @@ static int pp_stats_line(struct seq_file *m, struct tag_stat *ts_entry, "from pid=%u tgid=%u uid=%u stats.gid=%u\n", ppi->iface_entry->ifname, get_atag_from_tag(tag), stat_uid, - current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid()), + current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()), from_kgid(&init_user_ns,xt_qtaguid_stats_file->gid)); return 0; } @@ -2752,12 +2753,12 @@ static int qtudev_open(struct inode *inode, struct file *file) return 0; DR_DEBUG("qtaguid: qtudev_open(): pid=%u tgid=%u uid=%u\n", - current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); spin_lock_bh(&uid_tag_data_tree_lock); /* Look for existing uid data, or alloc one. */ - utd_entry = get_uid_data(from_kuid(&init_user_ns,current_fsuid()), &utd_entry_found); + utd_entry = get_uid_data(from_kuid(&init_user_ns, current_fsuid()), &utd_entry_found); if (IS_ERR_OR_NULL(utd_entry)) { res = PTR_ERR(utd_entry); goto err_unlock; @@ -2769,7 +2770,7 @@ static int qtudev_open(struct inode *inode, struct file *file) if (pqd_entry) { pr_err("qtaguid: qtudev_open(): %u/%u %u " "%s already opened\n", - current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid()), + current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()), QTU_DEV_NAME); res = -EBUSY; goto err_unlock_free_utd; @@ -2779,7 +2780,7 @@ static int qtudev_open(struct inode *inode, struct file *file) if (!new_pqd_entry) { pr_err("qtaguid: qtudev_open(): %u/%u %u: " "proc data alloc failed\n", - current->pid, current->tgid, from_kuid(&init_user_ns,current_fsuid())); + current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); res = -ENOMEM; goto err_unlock_free_utd; } @@ -2793,7 +2794,7 @@ static int qtudev_open(struct inode *inode, struct file *file) spin_unlock_bh(&uid_tag_data_tree_lock); DR_DEBUG("qtaguid: tracking data for uid=%u in pqd=%p\n", - from_kuid(&init_user_ns,current_fsuid()), new_pqd_entry); + from_kuid(&init_user_ns, current_fsuid()), new_pqd_entry); file->private_data = new_pqd_entry; return 0; diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c index 00cc65b10298..99592ae56d9b 100644 --- a/net/netfilter/xt_quota2.c +++ b/net/netfilter/xt_quota2.c @@ -52,14 +52,9 @@ static DEFINE_SPINLOCK(counter_list_lock); static struct proc_dir_entry *proc_xt_quota; static unsigned int quota_list_perms = S_IRUGO | S_IWUSR; -static kuid_t quota_list_uid; -static kgid_t quota_list_gid; -static unsigned int quota_list_uid_param; -static unsigned int quota_list_gid_param; +static kuid_t quota_list_uid = KUIDT_INIT(0); +static kgid_t quota_list_gid = KGIDT_INIT(0); module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR); -module_param_named(uid, quota_list_uid_param, uint, S_IRUGO | S_IWUSR); -module_param_named(gid, quota_list_gid_param, uint, S_IRUGO | S_IWUSR); - #ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG static void quota2_log(unsigned int hooknum, @@ -354,10 +349,6 @@ static int __init quota_mt2_init(void) int ret; pr_debug("xt_quota2: init()"); - quota_list_uid = KUIDT_INIT(quota_list_uid_param); - quota_list_gid = KGIDT_INIT(quota_list_gid_param); - - #ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL); if (!nflognl) diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 7eb9d7d534d6..c2d565bdb484 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -35,6 +35,16 @@ #include <net/netfilter/nf_conntrack.h> #endif +void +xt_socket_put_sk(struct sock *sk) +{ + if (sk->sk_state == TCP_TIME_WAIT) + inet_twsk_put(inet_twsk(sk)); + else + sock_put(sk); +} +EXPORT_SYMBOL(xt_socket_put_sk); + static int extract_icmp4_fields(const struct sk_buff *skb, u8 *protocol, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index b2b57ebe2e76..26c66241d68c 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -55,7 +55,7 @@ * also linked into the probe response struct. */ -#define IEEE80211_SCAN_RESULT_EXPIRE (3 * HZ) +#define IEEE80211_SCAN_RESULT_EXPIRE (7 * HZ) static void bss_free(struct cfg80211_internal_bss *bss) { diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 452567d3a08e..d97cba3e3849 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) * There is no exception for unconfined as change_hat is not * available. */ - if (current->no_new_privs) + if (task_no_new_privs(current)) return -EPERM; /* released below */ @@ -776,7 +776,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, * no_new_privs is set because this aways results in a reduction * of permissions. */ - if (current->no_new_privs && !unconfined(profile)) { + if (task_no_new_privs(current) && !unconfined(profile)) { put_cred(cred); return -EPERM; } diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 8fb1488a3cd4..97130f88838b 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -66,7 +66,6 @@ extern int apparmor_initialized __initdata; char *aa_split_fqname(char *args, char **ns_name); void aa_info_message(const char *str); void *__aa_kvmalloc(size_t size, gfp_t flags); -void kvfree(void *buffer); static inline void *kvmalloc(size_t size) { diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 69689922c491..c1827e068454 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -104,17 +104,3 @@ void *__aa_kvmalloc(size_t size, gfp_t flags) } return buffer; } - -/** - * kvfree - free an allocation do by kvmalloc - * @buffer: buffer to free (MAYBE_NULL) - * - * Free a buffer allocated by kvmalloc - */ -void kvfree(void *buffer) -{ - if (is_vmalloc_addr(buffer)) - vfree(buffer); - else - kfree(buffer); -} diff --git a/security/selinux/avc.c b/security/selinux/avc.c index fc3e6628a864..a18f1fa6440b 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -444,11 +444,15 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) avc_dump_query(ab, ad->selinux_audit_data->ssid, ad->selinux_audit_data->tsid, ad->selinux_audit_data->tclass); + if (ad->selinux_audit_data->denied) { + audit_log_format(ab, " permissive=%u", + ad->selinux_audit_data->result ? 0 : 1); + } } /* This is the slow part of avc audit with big stack footprint */ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, - u32 requested, u32 audited, u32 denied, + u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a, unsigned flags) { @@ -477,6 +481,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, sad.tsid = tsid; sad.audited = audited; sad.denied = denied; + sad.result = result; a->selinux_audit_data = &sad; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index cefb65c9b9de..7c9a452b2d92 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -392,23 +392,14 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) { struct superblock_security_struct *sbsec = sb->s_security; - if (sbsec->behavior == SECURITY_FS_USE_XATTR || - sbsec->behavior == SECURITY_FS_USE_TRANS || - sbsec->behavior == SECURITY_FS_USE_TASK) - return 1; - - /* Special handling for sysfs. Is genfs but also has setxattr handler*/ - if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) - return 1; - - /* - * Special handling for rootfs. Is genfs but supports - * setting SELinux context on in-core inodes. - */ - if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0) - return 1; - - return 0; + return sbsec->behavior == SECURITY_FS_USE_XATTR || + sbsec->behavior == SECURITY_FS_USE_TRANS || + sbsec->behavior == SECURITY_FS_USE_TASK || + /* Special handling. Genfs but also in-core setxattr handler */ + !strcmp(sb->s_type->name, "sysfs") || + !strcmp(sb->s_type->name, "pstore") || + !strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "rootfs"); } static int sb_finish_set_opts(struct super_block *sb) @@ -2831,6 +2822,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na static noinline int audit_inode_permission(struct inode *inode, u32 perms, u32 audited, u32 denied, + int result, unsigned flags) { struct common_audit_data ad; @@ -2841,7 +2833,7 @@ static noinline int audit_inode_permission(struct inode *inode, ad.u.inode = inode; rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms, - audited, denied, &ad, flags); + audited, denied, result, &ad, flags); if (rc) return rc; return 0; @@ -2883,7 +2875,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) if (likely(!audited)) return rc; - rc2 = audit_inode_permission(inode, perms, audited, denied, flags); + rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags); if (rc2) return rc2; return rc; diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index f53ee3c58d0f..ddf8eec03f21 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -102,7 +102,7 @@ static inline u32 avc_audit_required(u32 requested, } int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, - u32 requested, u32 audited, u32 denied, + u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a, unsigned flags); @@ -137,7 +137,7 @@ static inline int avc_audit(u32 ssid, u32 tsid, if (likely(!audited)) return 0; return slow_avc_audit(ssid, tsid, tclass, - requested, audited, denied, + requested, audited, denied, result, a, 0); } |