From eeb8a2dda8269e00a279815210ae7870bc5f153d Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 22 Jan 2016 05:20:26 +0000 Subject: [PATCH 001/266] UPSTREAM: MIPS: math-emu: Correctly handle NOP emulation Fix an issue introduced with commit 9ab4471c9f1b ("MIPS: math-emu: Correct delay-slot exception propagation") where the emulation of a NOP instruction signals the need to terminate the emulation loop. This in turn, if the PC has not changed from the entry to the loop, will cause the kernel to terminate the program with SIGILL. Consider this program: static double div(double d) { do d /= 2.0; while (d > .5); return d; } int main(int argc, char **argv) { return div(argc); } which gets compiled to the following binary code: 00400490
: 400490: 44840000 mtc1 a0,$f0 400494: 3c020040 lui v0,0x40 400498: d44207f8 ldc1 $f2,2040(v0) 40049c: 46800021 cvt.d.w $f0,$f0 4004a0: 46220002 mul.d $f0,$f0,$f2 4004a4: 4620103c c.lt.d $f2,$f0 4004a8: 4501fffd bc1t 4004a0 4004ac: 00000000 nop 4004b0: 4620000d trunc.w.d $f0,$f0 4004b4: 03e00008 jr ra 4004b8: 44020000 mfc1 v0,$f0 4004bc: 00000000 nop Where the FPU emulator is used, depending on the number of command-line arguments this code will either run to completion or terminate with SIGILL. If no arguments are specified, then BC1T will not be taken, NOP will not be emulated and code will complete successfully. If one argument is specified, then BC1T will be taken once and NOP will be emulated. At this point the entry PC value will be 0x400498 and the new PC value, set by `mips_dsemul' will be 0x4004a0, the target of BC1T. The emulation loop will terminate, but SIGILL will not be issued, because the PC has changed. The FPU emulator will be entered again and on the second execution BC1T will not be taken, NOP will not be emulated and code will complete successfully. If two or more arguments are specified, then the first execution of BC1T will proceed as above. Upon reentering the FPU emulator the emulation loop will continue to BC1T, at which point the branch will be taken and NOP emulated again. At this point however the entry PC value will be 0x4004a0, the same as the target of BC1T. This will make the emulator conclude that execution has not advanced and therefore an unsupported FPU instruction has been encountered, and SIGILL will be sent to the process. Fix the problem by extending the internal API of `mips_dsemul', making it return -1 if no delay slot emulation frame has been made, the instruction has been handled and execution of the emulation loop needs to continue as if nothing happened. Remove code from `mips_dsemul' to reproduce steps made by the emulation loop at the conclusion of each iteration, as those will be reached normally now. Adjust call sites accordingly. Document the API. Signed-off-by: Maciej W. Rozycki Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12172/ Signed-off-by: Ralf Baechle (cherry picked from commit e4553573b37c3f72533683cb5f3a1ad300b18d37) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 4 ++++ arch/mips/math-emu/dsemul.c | 14 ++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 89d05de8040a..b8941063a56e 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1268,6 +1268,8 @@ branch_common: */ sig = mips_dsemul(xcp, ir, contpc); + if (sig < 0) + break; if (sig) xcp->cp0_epc = bcpc; /* @@ -1321,6 +1323,8 @@ branch_common: * instruction in the dslot */ sig = mips_dsemul(xcp, ir, contpc); + if (sig < 0) + break; if (sig) xcp->cp0_epc = bcpc; /* SIGILL forces out of the emulation loop. */ diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index cbb36c14b155..70e4824c64dc 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -31,18 +31,20 @@ struct emuframe { unsigned long epc; }; +/* + * Set up an emulation frame for instruction IR, from a delay slot of + * a branch jumping to CPC. Return 0 if successful, -1 if no emulation + * required, otherwise a signal number causing a frame setup failure. + */ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) { struct emuframe __user *fr; int err; + /* NOP is easy */ if ((get_isa16_mode(regs->cp0_epc) && ((ir >> 16) == MM_NOP16)) || - (ir == 0)) { - /* NOP is easy */ - regs->cp0_epc = cpc; - clear_delay_slot(regs); - return 0; - } + (ir == 0)) + return -1; pr_debug("dsemul %lx %lx\n", regs->cp0_epc, cpc); From 0aa09660cfef273fe72a27b445323247997292e7 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 22 Jan 2016 05:20:37 +0000 Subject: [PATCH 002/266] UPSTREAM: MIPS: math-emu: dsemul: Fix ill formatting of microMIPS part Correct formatting breakage introduced with commit 102cedc32a6e ("MIPS: microMIPS: Floating point support."), so that further changes to this code can be consistent. Signed-off-by: Maciej W. Rozycki Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12173/ Signed-off-by: Ralf Baechle (cherry picked from commit a87265cfedce49fa362030ae3e6ef047e08bc12c) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dsemul.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 70e4824c64dc..4e30bfc3cdd5 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -75,10 +75,14 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) return SIGBUS; if (get_isa16_mode(regs->cp0_epc)) { - err = __put_user(ir >> 16, (u16 __user *)(&fr->emul)); - err |= __put_user(ir & 0xffff, (u16 __user *)((long)(&fr->emul) + 2)); - err |= __put_user(BREAK_MATH >> 16, (u16 __user *)(&fr->badinst)); - err |= __put_user(BREAK_MATH & 0xffff, (u16 __user *)((long)(&fr->badinst) + 2)); + err = __put_user(ir >> 16, + (u16 __user *)(&fr->emul)); + err |= __put_user(ir & 0xffff, + (u16 __user *)((long)(&fr->emul) + 2)); + err |= __put_user(BREAK_MATH >> 16, + (u16 __user *)(&fr->badinst)); + err |= __put_user(BREAK_MATH & 0xffff, + (u16 __user *)((long)(&fr->badinst) + 2)); } else { err = __put_user(ir, &fr->emul); err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst); @@ -125,8 +129,10 @@ int do_dsemulret(struct pt_regs *xcp) * - Is the following memory word the BD_COOKIE? */ if (get_isa16_mode(xcp->cp0_epc)) { - err = __get_user(instr[0], (u16 __user *)(&fr->badinst)); - err |= __get_user(instr[1], (u16 __user *)((long)(&fr->badinst) + 2)); + err = __get_user(instr[0], + (u16 __user *)(&fr->badinst)); + err |= __get_user(instr[1], + (u16 __user *)((long)(&fr->badinst) + 2)); insn = (instr[0] << 16) | instr[1]; } else { err = __get_user(insn, &fr->badinst); From e415d7547a282c4d020235778fff15e1b3612820 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 22 Jan 2016 05:20:46 +0000 Subject: [PATCH 003/266] UPSTREAM: MIPS: math-emu: Make microMIPS branch delay slot emulation work Complement commit 102cedc32a6e ("MIPS: microMIPS: Floating point support.") which introduced microMIPS FPU emulation, but did not adjust the encoding of the BREAK instruction used to terminate the branch delay slot emulation frame. Consequently the execution of any such frame is indeterminate and, depending on CPU configuration, will result in random code execution or an offending program being terminated with SIGILL. This is because the regular MIPS BREAK instruction is encoded with the 0 major and the 0xd minor opcode, however in the microMIPS instruction set this major/minor opcode pair denotes an encoding reserved for the DSP ASE. Instead the microMIPS BREAK instruction is encoded with the 0 major and the 0x7 minor opcode. Use the correct BREAK encoding for microMIPS FPU emulation then. Signed-off-by: Maciej W. Rozycki Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12174/ Signed-off-by: Ralf Baechle (cherry picked from commit 733b8bc183f491e8263009edf8ef184fb44a6882) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/fpu_emulator.h | 2 +- arch/mips/include/asm/mips-r2-to-r6-emul.h | 2 +- arch/mips/math-emu/dsemul.c | 11 +++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h index 2f021cdfba4f..3225c3c0724b 100644 --- a/arch/mips/include/asm/fpu_emulator.h +++ b/arch/mips/include/asm/fpu_emulator.h @@ -79,7 +79,7 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, /* * Break instruction with special math emu break code set */ -#define BREAK_MATH (0x0000000d | (BRK_MEMU << 16)) +#define BREAK_MATH(micromips) (((micromips) ? 0x7 : 0xd) | (BRK_MEMU << 16)) #define SIGNALLING_NAN 0x7ff800007ff80000LL diff --git a/arch/mips/include/asm/mips-r2-to-r6-emul.h b/arch/mips/include/asm/mips-r2-to-r6-emul.h index 4b89f28047f7..1f6ea8352ca9 100644 --- a/arch/mips/include/asm/mips-r2-to-r6-emul.h +++ b/arch/mips/include/asm/mips-r2-to-r6-emul.h @@ -52,7 +52,7 @@ do { \ __this_cpu_inc(mipsr2emustats.M); \ err = __get_user(nir, (u32 __user *)regs->cp0_epc); \ if (!err) { \ - if (nir == BREAK_MATH) \ + if (nir == BREAK_MATH(0)) \ __this_cpu_inc(mipsr2bdemustats.M); \ } \ preempt_enable(); \ diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 4e30bfc3cdd5..32ec5d7e1728 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -38,6 +38,7 @@ struct emuframe { */ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) { + mips_instruction break_math; struct emuframe __user *fr; int err; @@ -65,6 +66,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) * branches, but gives us a cleaner interface to the exception * handler (single entry point). */ + break_math = BREAK_MATH(get_isa16_mode(regs->cp0_epc)); /* Ensure that the two instructions are in the same cache line */ fr = (struct emuframe __user *) @@ -79,13 +81,13 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) (u16 __user *)(&fr->emul)); err |= __put_user(ir & 0xffff, (u16 __user *)((long)(&fr->emul) + 2)); - err |= __put_user(BREAK_MATH >> 16, + err |= __put_user(break_math >> 16, (u16 __user *)(&fr->badinst)); - err |= __put_user(BREAK_MATH & 0xffff, + err |= __put_user(break_math & 0xffff, (u16 __user *)((long)(&fr->badinst) + 2)); } else { err = __put_user(ir, &fr->emul); - err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst); + err |= __put_user(break_math, &fr->badinst); } err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie); @@ -139,7 +141,8 @@ int do_dsemulret(struct pt_regs *xcp) } err |= __get_user(cookie, &fr->cookie); - if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) { + if (unlikely(err || insn != BREAK_MATH(get_isa16_mode(xcp->cp0_epc)) || + cookie != BD_COOKIE)) { MIPS_FPU_EMU_INC_STATS(errors); return 0; } From a589481cd80332e8b0895a48ddc75e0997acd7ef Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 22 Jan 2016 05:21:00 +0000 Subject: [PATCH 004/266] UPSTREAM: MIPS: math-emu: Correct the emulation of microMIPS ADDIUPC instruction Emulate the microMIPS ADDIUPC instruction directly in `mips_dsemul'. If executed in the emulation frame, this instruction produces an incorrect result, because the value of the PC there is not the same as where the instruction originated. Reshape code so as to handle all microMIPS cases together. Signed-off-by: Maciej W. Rozycki Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12175/ Signed-off-by: Ralf Baechle (cherry picked from commit 69a1e6cbdf1f40d5dcae84c5a538d390b6d2c307) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/uapi/asm/inst.h | 8 ++++++++ arch/mips/math-emu/dsemul.c | 24 ++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index 9b44d5a816fa..b145749c743f 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -799,6 +799,13 @@ struct mm_x_format { /* Scaled indexed load format (microMIPS) */ ;))))) }; +struct mm_a_format { /* ADDIUPC format (microMIPS) */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int rs : 3, + __BITFIELD_FIELD(signed int simmediate : 23, + ;))) +}; + /* * microMIPS instruction formats (16-bit length) */ @@ -940,6 +947,7 @@ union mips_instruction { struct mm_i_format mm_i_format; struct mm_m_format mm_m_format; struct mm_x_format mm_x_format; + struct mm_a_format mm_a_format; struct mm_b0_format mm_b0_format; struct mm_b1_format mm_b1_format; struct mm16_m_format mm16_m_format ; diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 32ec5d7e1728..77a623db3b38 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -43,10 +43,30 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) int err; /* NOP is easy */ - if ((get_isa16_mode(regs->cp0_epc) && ((ir >> 16) == MM_NOP16)) || - (ir == 0)) + if (ir == 0) return -1; + /* microMIPS instructions */ + if (get_isa16_mode(regs->cp0_epc)) { + union mips_instruction insn = { .word = ir }; + + /* NOP16 aka MOVE16 $0, $0 */ + if ((ir >> 16) == MM_NOP16) + return -1; + + /* ADDIUPC */ + if (insn.mm_a_format.opcode == mm_addiupc_op) { + unsigned int rs; + s32 v; + + rs = (((insn.mm_a_format.rs + 0x1e) & 0xf) + 2); + v = regs->cp0_epc & ~3; + v += insn.mm_a_format.simmediate << 2; + regs->regs[rs] = (long)v; + return -1; + } + } + pr_debug("dsemul %lx %lx\n", regs->cp0_epc, cpc); /* From caeae55e45a60a4cd0f049882245ee8ec73a4a60 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 22 Jan 2016 05:21:13 +0000 Subject: [PATCH 005/266] UPSTREAM: MIPS: math-emu: dsemul: Correct description of the emulation frame Remove irrelevant content from the description of the emulation frame in `mips_dsemul', referring to bare-metal configurations. Update the text, reflecting the change made with commit ba3049ed4086 ("MIPS: Switch FPU emulator trap to BREAK instruction."), where we switched from using an address error exception on an unaligned access to the use of a BREAK 514 instruction causing a breakpoint exception instead. Signed-off-by: Maciej W. Rozycki Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12176/ Signed-off-by: Ralf Baechle (cherry picked from commit 6e1715f7c34d00dc94f3cecb2526ae3ff0b0649f) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dsemul.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 77a623db3b38..bca7c4367ca4 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -78,13 +78,8 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) * Algorithmics used a system call instruction, and * borrowed that vector. MIPS/Linux version is a bit * more heavyweight in the interests of portability and - * multiprocessor support. For Linux we generate a - * an unaligned access and force an address error exception. - * - * For embedded systems (stand-alone) we prefer to use a - * non-existing CP1 instruction. This prevents us from emulating - * branches, but gives us a cleaner interface to the exception - * handler (single entry point). + * multiprocessor support. For Linux we use a BREAK 514 + * instruction causing a breakpoint exception. */ break_math = BREAK_MATH(get_isa16_mode(regs->cp0_epc)); From c56de7416556b840463de8a1baa394e938bdcb38 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 22 Jan 2016 05:21:47 +0000 Subject: [PATCH 006/266] UPSTREAM: MIPS: math-emu: dsemul: Reduce `get_isa16_mode' clutter Signed-off-by: Maciej W. Rozycki Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12178/ Signed-off-by: Ralf Baechle (cherry picked from commit 6d7b14151d7510ed434f2e587cdae9eca82fc123) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dsemul.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index bca7c4367ca4..46b964d2b79c 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -38,6 +38,7 @@ struct emuframe { */ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) { + int isa16 = get_isa16_mode(regs->cp0_epc); mips_instruction break_math; struct emuframe __user *fr; int err; @@ -47,7 +48,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) return -1; /* microMIPS instructions */ - if (get_isa16_mode(regs->cp0_epc)) { + if (isa16) { union mips_instruction insn = { .word = ir }; /* NOP16 aka MOVE16 $0, $0 */ @@ -81,7 +82,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) * multiprocessor support. For Linux we use a BREAK 514 * instruction causing a breakpoint exception. */ - break_math = BREAK_MATH(get_isa16_mode(regs->cp0_epc)); + break_math = BREAK_MATH(isa16); /* Ensure that the two instructions are in the same cache line */ fr = (struct emuframe __user *) @@ -91,7 +92,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe)))) return SIGBUS; - if (get_isa16_mode(regs->cp0_epc)) { + if (isa16) { err = __put_user(ir >> 16, (u16 __user *)(&fr->emul)); err |= __put_user(ir & 0xffff, @@ -113,8 +114,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) return SIGBUS; } - regs->cp0_epc = ((unsigned long) &fr->emul) | - get_isa16_mode(regs->cp0_epc); + regs->cp0_epc = (unsigned long)&fr->emul | isa16; flush_cache_sigtramp((unsigned long)&fr->emul); @@ -123,6 +123,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) int do_dsemulret(struct pt_regs *xcp) { + int isa16 = get_isa16_mode(xcp->cp0_epc); struct emuframe __user *fr; unsigned long epc; u32 insn, cookie; @@ -145,7 +146,7 @@ int do_dsemulret(struct pt_regs *xcp) * - Is the instruction pointed to by the EPC an BREAK_MATH? * - Is the following memory word the BD_COOKIE? */ - if (get_isa16_mode(xcp->cp0_epc)) { + if (isa16) { err = __get_user(instr[0], (u16 __user *)(&fr->badinst)); err |= __get_user(instr[1], @@ -156,8 +157,8 @@ int do_dsemulret(struct pt_regs *xcp) } err |= __get_user(cookie, &fr->cookie); - if (unlikely(err || insn != BREAK_MATH(get_isa16_mode(xcp->cp0_epc)) || - cookie != BD_COOKIE)) { + if (unlikely(err || + insn != BREAK_MATH(isa16) || cookie != BD_COOKIE)) { MIPS_FPU_EMU_INC_STATS(errors); return 0; } From 883f4325f636ec426e82f2ac6f6550a5f2d7340f Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 30 Jan 2016 09:09:43 +0000 Subject: [PATCH 007/266] UPSTREAM: MIPS: math-emu: dsemul: Remove an unused bit in ADDIUPC emulation Avoid a reader's confusion, as the calculation is correct either way. Signed-off-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12283/ Signed-off-by: Ralf Baechle (cherry picked from commit 036aff91c30a6f15d5bf25f22827abc26b6d06c1) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dsemul.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 46b964d2b79c..d4ceacd4fa12 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -60,7 +60,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) unsigned int rs; s32 v; - rs = (((insn.mm_a_format.rs + 0x1e) & 0xf) + 2); + rs = (((insn.mm_a_format.rs + 0xe) & 0xf) + 2); v = regs->cp0_epc & ~3; v += insn.mm_a_format.simmediate << 2; regs->regs[rs] = (long)v; From afcd2b897895ebff91eed97a84dfb135e86c5c24 Mon Sep 17 00:00:00 2001 From: Andrea Gelmini Date: Sat, 21 May 2016 14:01:51 +0200 Subject: [PATCH 008/266] UPSTREAM: MIPS: math-emu: Fix typo Signed-off-by: Andrea Gelmini Cc: macro@imgtec.com Cc: trivial@kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13333/ Signed-off-by: Ralf Baechle (cherry picked from commit e7e3346cc64fff306694bdc41908283d195339c1) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dsemul.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index d4ceacd4fa12..47074887e64c 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -8,7 +8,7 @@ #include "ieee754.h" /* - * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when + * Emulate the arbitrary instruction ir at xcp->cp0_epc. Required when * we have to emulate the instruction in a COP1 branch delay slot. Do * not change cp0_epc due to the instruction * @@ -88,7 +88,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) fr = (struct emuframe __user *) ((regs->regs[29] - sizeof(struct emuframe)) & ~0x7); - /* Verify that the stack pointer is not competely insane */ + /* Verify that the stack pointer is not completely insane */ if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe)))) return SIGBUS; From cb7c7f371ea5922f1efea469afe2475c4b039d8f Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 9 Feb 2016 11:00:07 -0800 Subject: [PATCH 009/266] UPSTREAM: MIPS: Select CONFIG_HANDLE_DOMAIN_IRQ and make it work. Per the subject, always select HANDLE_DOMAIN_IRQ, and implement set_irq_regs() so that it actually works. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12496/ Signed-off-by: Ralf Baechle (cherry picked from commit 1d2753a66acbb101a0ec495cd13b9031ac1b171f) Signed-off-by: Greg Kroah-Hartman --- arch/mips/Kconfig | 1 + arch/mips/include/asm/irq_regs.h | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8b0424abc84c..117ac742a063 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -64,6 +64,7 @@ config MIPS select HAVE_IRQ_TIME_ACCOUNTING select GENERIC_TIME_VSYSCALL select ARCH_CLOCKSOURCE_DATA + select HANDLE_DOMAIN_IRQ menu "Machine selection" diff --git a/arch/mips/include/asm/irq_regs.h b/arch/mips/include/asm/irq_regs.h index 33bd2a06de57..8c48d6dd1d78 100644 --- a/arch/mips/include/asm/irq_regs.h +++ b/arch/mips/include/asm/irq_regs.h @@ -18,4 +18,14 @@ static inline struct pt_regs *get_irq_regs(void) return current_thread_info()->regs; } +static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs) +{ + struct pt_regs *old_regs; + + old_regs = get_irq_regs(); + current_thread_info()->regs = new_regs; + + return old_regs; +} + #endif /* __ASM_IRQ_REGS_H */ From 1e9d84070a8c2c3dc4002807611a20a353868267 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 1 Feb 2016 13:50:36 +0000 Subject: [PATCH 010/266] UPSTREAM: MIPS: Properly disable FPU in start_thread() start_thread() (called for execve(2)) clears the TIF_USEDFPU flag without atomically disabling the FPU. With a preemptive kernel, an unfortunately timed preemption after this could result in another task (or KVM guest) being scheduled in with the FPU still enabled, since lose_fpu_inatomic() only turns it off if TIF_USEDFPU is set. Use lose_fpu(0) instead of the separate FPU / MSA management, which should do the right thing (drop FPU properly and atomically without saving state) and will be more future proof. Signed-off-by: James Hogan Reviewed-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/12302/ Signed-off-by: Ralf Baechle (cherry picked from commit 76e5846d3bdf59eb1010d5607003da2dc3910bb1) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/process.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index fcbc4e57d765..25dabde4bdeb 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -64,12 +64,10 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK); status |= KU_USER; regs->cp0_status = status; - clear_used_math(); - clear_fpu_owner(); - init_dsp(); - clear_thread_flag(TIF_USEDMSA); + lose_fpu(0); clear_thread_flag(TIF_MSA_CTX_LIVE); - disable_msa(); + clear_used_math(); + init_dsp(); regs->cp0_epc = pc; regs->regs[29] = sp; } From 5ea4150e17720495e25f57c61416b23562bb6f24 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 27 Mar 2016 00:07:14 +0100 Subject: [PATCH 011/266] UPSTREAM: MIPS: Make flush_thread Avoids function calls to an empty function. Signed-off-by: Ralf Baechle (cherry picked from commit 04cc89d120f94131de89a6e20da27016db4782ce) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/processor.h | 4 ++++ arch/mips/kernel/process.c | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 041153f5cf93..cfa15bad43af 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -355,6 +355,10 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk); */ extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); +static inline void flush_thread(void) +{ +} + unsigned long get_wchan(struct task_struct *p); #define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \ diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 25dabde4bdeb..adb081f513ff 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -76,10 +76,6 @@ void exit_thread(void) { } -void flush_thread(void) -{ -} - int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { /* From 3ebefa784088b9d630f6c3b27666af71f51d342a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 20 May 2016 17:00:16 -0700 Subject: [PATCH 012/266] BACKPORT: exit_thread: remove empty bodies Define HAVE_EXIT_THREAD for archs which want to do something in exit_thread. For others, let's define exit_thread as an empty inline. This is a cleanup before we change the prototype of exit_thread to accept a task parameter. [akpm@linux-foundation.org: fix mips] Signed-off-by: Jiri Slaby Cc: "David S. Miller" Cc: "H. Peter Anvin" Cc: "James E.J. Bottomley" Cc: Aurelien Jacquiot Cc: Benjamin Herrenschmidt Cc: Catalin Marinas Cc: Chen Liqin Cc: Chris Metcalf Cc: Chris Zankel Cc: David Howells Cc: Fenghua Yu Cc: Geert Uytterhoeven Cc: Guan Xuetao Cc: Haavard Skinnemoen Cc: Hans-Christian Egtvedt Cc: Heiko Carstens Cc: Helge Deller Cc: Ingo Molnar Cc: Ivan Kokshaysky Cc: James Hogan Cc: Jeff Dike Cc: Jesper Nilsson Cc: Jiri Slaby Cc: Jonas Bonn Cc: Koichi Yasutake Cc: Lennox Wu Cc: Ley Foon Tan Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Turner Cc: Max Filippov Cc: Michael Ellerman Cc: Michal Simek Cc: Mikael Starvik Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Rich Felker Cc: Richard Henderson Cc: Richard Kuo Cc: Richard Weinberger Cc: Russell King Cc: Steven Miao Cc: Thomas Gleixner Cc: Tony Luck Cc: Vineet Gupta Cc: Will Deacon Cc: Yoshinori Sato Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 5f56a5dfdb9bcb3bca03df59980d4d2f012cbb53) Conflicts: arch/powerpc/kernel/process.c arch/xtensa/Kconfig Signed-off-by: Greg Kroah-Hartman --- arch/Kconfig | 5 +++++ arch/alpha/kernel/process.c | 8 -------- arch/arc/kernel/process.c | 7 ------- arch/arm/Kconfig | 1 + arch/arm64/kernel/process.c | 7 ------- arch/avr32/Kconfig | 1 + arch/blackfin/include/asm/processor.h | 7 ------- arch/c6x/kernel/process.c | 4 ---- arch/cris/Kconfig | 1 + arch/cris/arch-v10/kernel/process.c | 9 --------- arch/frv/include/asm/processor.h | 7 ------- arch/h8300/include/asm/processor.h | 7 ------- arch/hexagon/kernel/process.c | 7 ------- arch/ia64/Kconfig | 1 + arch/m32r/kernel/process.c | 9 --------- arch/m68k/include/asm/processor.h | 7 ------- arch/metag/Kconfig | 1 + arch/metag/include/asm/processor.h | 2 -- arch/microblaze/include/asm/processor.h | 10 ---------- arch/mips/kernel/process.c | 4 ---- arch/mn10300/Kconfig | 1 + arch/nios2/include/asm/processor.h | 5 ----- arch/openrisc/include/asm/processor.h | 9 --------- arch/parisc/kernel/process.c | 7 ------- arch/powerpc/Kconfig | 1 + arch/s390/Kconfig | 1 + arch/score/kernel/process.c | 2 -- arch/sh/Kconfig | 1 + arch/sh/kernel/process_32.c | 7 ------- arch/sparc/Kconfig | 1 + arch/tile/Kconfig | 1 + arch/um/kernel/process.c | 4 ---- arch/unicore32/kernel/process.c | 7 ------- arch/x86/Kconfig | 1 + arch/xtensa/Kconfig | 1 + include/linux/sched.h | 7 +++++++ 36 files changed, 25 insertions(+), 136 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index ed2539c590bf..a29c6098fb98 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -536,6 +536,11 @@ config HAVE_ARCH_MMAP_RND_BITS - ARCH_MMAP_RND_BITS_MIN - ARCH_MMAP_RND_BITS_MAX +config HAVE_EXIT_THREAD + bool + help + An architecture implements exit_thread. + config ARCH_MMAP_RND_BITS_MIN int diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 84d13263ce46..b483156698d5 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -210,14 +210,6 @@ start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) } EXPORT_SYMBOL(start_thread); -/* - * Free current thread data structures etc.. - */ -void -exit_thread(void) -{ -} - void flush_thread(void) { diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index a3f750e76b68..b5db9e7fd649 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -183,13 +183,6 @@ void flush_thread(void) { } -/* - * Free any architecture-specific thread data structures, etc. - */ -void exit_thread(void) -{ -} - int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) { return 0; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 07ac8f7df8bb..b7e2f82247d1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -50,6 +50,7 @@ config ARM select HAVE_DMA_CONTIGUOUS if MMU select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU + select HAVE_EXIT_THREAD select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index dfbabc0e274b..236120fc4dbc 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -270,13 +270,6 @@ void show_regs(struct pt_regs * regs) __show_regs(regs); } -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) -{ -} - static void tls_thread_flush(void) { asm ("msr tpidr_el0, xzr"); diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index b6878eb64884..37d9c02be634 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -4,6 +4,7 @@ config AVR32 # that we usually don't need on AVR32. select EXPERT select HAVE_CLK + select HAVE_EXIT_THREAD select HAVE_OPROFILE select HAVE_KPROBES select VIRT_TO_BUS diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h index 7acd46653df3..0c265aba94ad 100644 --- a/arch/blackfin/include/asm/processor.h +++ b/arch/blackfin/include/asm/processor.h @@ -75,13 +75,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -/* - * Free current thread data structures etc.. - */ -static inline void exit_thread(void) -{ -} - /* * Return saved PC of a blocked thread. */ diff --git a/arch/c6x/kernel/process.c b/arch/c6x/kernel/process.c index 3ae9f5a166a0..0ee7686a78f3 100644 --- a/arch/c6x/kernel/process.c +++ b/arch/c6x/kernel/process.c @@ -82,10 +82,6 @@ void flush_thread(void) { } -void exit_thread(void) -{ -} - /* * Do necessary setup to start up a newly executed thread. */ diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index e086f9e93728..088551086342 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -59,6 +59,7 @@ config CRIS select GENERIC_IOMAP select MODULES_USE_ELF_RELA select CLONE_BACKWARDS2 + select HAVE_EXIT_THREAD if ETRAX_ARCH_V32 select OLD_SIGSUSPEND select OLD_SIGACTION select ARCH_REQUIRE_GPIOLIB diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 02b783457be0..96e5afef6b47 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -35,15 +35,6 @@ void default_idle(void) local_irq_enable(); } -/* - * Free current thread data structures etc.. - */ - -void exit_thread(void) -{ - /* Nothing needs to be done. */ -} - /* if the watchdog is enabled, we can simply disable interrupts and go * into an eternal loop, and the watchdog will reset the CPU after 0.1s * if on the other hand the watchdog wasn't enabled, we just enable it and wait diff --git a/arch/frv/include/asm/processor.h b/arch/frv/include/asm/processor.h index ae8d423e79d9..73f0a79ad8e6 100644 --- a/arch/frv/include/asm/processor.h +++ b/arch/frv/include/asm/processor.h @@ -96,13 +96,6 @@ extern asmlinkage void *restore_user_regs(const struct user_context *target, ... #define release_segments(mm) do { } while (0) #define forget_segments() do { } while (0) -/* - * Free current thread data structures etc.. - */ -static inline void exit_thread(void) -{ -} - /* * Return saved PC of a blocked thread. */ diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h index 54e3fd83c336..111df7397ac7 100644 --- a/arch/h8300/include/asm/processor.h +++ b/arch/h8300/include/asm/processor.h @@ -110,13 +110,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -/* - * Free current thread data structures etc.. - */ -static inline void exit_thread(void) -{ -} - /* * Return saved PC of a blocked thread. */ diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c index a9ebd471823a..d9edfd3fc52a 100644 --- a/arch/hexagon/kernel/process.c +++ b/arch/hexagon/kernel/process.c @@ -136,13 +136,6 @@ void release_thread(struct task_struct *dead_task) { } -/* - * Free any architecture-specific thread data structures, etc. - */ -void exit_thread(void) -{ -} - /* * Some archs flush debug and FPU info here */ diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 7534fd34f79d..a6a72c6e2d03 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -18,6 +18,7 @@ config IA64 select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI select HAVE_UNSTABLE_SCHED_CLOCK + select HAVE_EXIT_THREAD select HAVE_IDE select HAVE_OPROFILE select HAVE_KPROBES diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index e69221d581d5..a88b1f01e91f 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c @@ -101,15 +101,6 @@ void show_regs(struct pt_regs * regs) #endif } -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) -{ - /* Nothing to do. */ - DPRINTK("pid = %d\n", current->pid); -} - void flush_thread(void) { DPRINTK("pid = %d\n", current->pid); diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index 20dda1d4b860..a6ce2ec8d693 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -153,13 +153,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -/* - * Free current thread data structures etc.. - */ -static inline void exit_thread(void) -{ -} - extern unsigned long thread_saved_pc(struct task_struct *tsk); unsigned long get_wchan(struct task_struct *p); diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig index 0b389a81c43a..6fe012a001be 100644 --- a/arch/metag/Kconfig +++ b/arch/metag/Kconfig @@ -11,6 +11,7 @@ config METAG select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_STACKOVERFLOW select HAVE_DYNAMIC_FTRACE + select HAVE_EXIT_THREAD select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FUNCTION_TRACER select HAVE_KERNEL_BZIP2 diff --git a/arch/metag/include/asm/processor.h b/arch/metag/include/asm/processor.h index 0838ca699764..a0333ebcac35 100644 --- a/arch/metag/include/asm/processor.h +++ b/arch/metag/include/asm/processor.h @@ -134,8 +134,6 @@ static inline void release_thread(struct task_struct *dead_task) #define copy_segments(tsk, mm) do { } while (0) #define release_segments(mm) do { } while (0) -extern void exit_thread(void); - /* * Return saved PC of a blocked thread. */ diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h index 497a988d79c2..c38d0dd91134 100644 --- a/arch/microblaze/include/asm/processor.h +++ b/arch/microblaze/include/asm/processor.h @@ -70,11 +70,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -/* Free all resources held by a thread. */ -static inline void exit_thread(void) -{ -} - extern unsigned long thread_saved_pc(struct task_struct *t); extern unsigned long get_wchan(struct task_struct *p); @@ -127,11 +122,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -/* Free current thread data structures etc. */ -static inline void exit_thread(void) -{ -} - /* Return saved (kernel) PC of a blocked thread. */ # define thread_saved_pc(tsk) \ ((tsk)->thread.regs ? (tsk)->thread.regs->r15 : 0) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index adb081f513ff..83153946f389 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -72,10 +72,6 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) regs->regs[29] = sp; } -void exit_thread(void) -{ -} - int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { /* diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index 78ae5552fdb8..e5f4a197a7ea 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig @@ -1,5 +1,6 @@ config MN10300 def_bool y + select HAVE_EXIT_THREAD select HAVE_OPROFILE select HAVE_UID16 select GENERIC_IRQ_SHOW diff --git a/arch/nios2/include/asm/processor.h b/arch/nios2/include/asm/processor.h index c2ba45c159c7..1c953f0cadbf 100644 --- a/arch/nios2/include/asm/processor.h +++ b/arch/nios2/include/asm/processor.h @@ -75,11 +75,6 @@ static inline void release_thread(struct task_struct *dead_task) { } -/* Free current thread data structures etc.. */ -static inline void exit_thread(void) -{ -} - /* Return saved PC of a blocked thread. */ #define thread_saved_pc(tsk) ((tsk)->thread.kregs->ea) diff --git a/arch/openrisc/include/asm/processor.h b/arch/openrisc/include/asm/processor.h index 4d235e3d2534..70334c9f7d24 100644 --- a/arch/openrisc/include/asm/processor.h +++ b/arch/openrisc/include/asm/processor.h @@ -84,15 +84,6 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp); void release_thread(struct task_struct *); unsigned long get_wchan(struct task_struct *p); -/* - * Free current thread data structures etc.. - */ - -extern inline void exit_thread(void) -{ - /* Nothing needs to be done. */ -} - /* * Return saved PC of a blocked thread. For now, this is the "user" PC */ diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 809905a811ed..40639439d8b3 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -144,13 +144,6 @@ void machine_power_off(void) void (*pm_power_off)(void) = machine_power_off; EXPORT_SYMBOL(pm_power_off); -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) -{ -} - void flush_thread(void) { /* Only needs to handle fpu stuff or perf monitors. diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index dfb1ee8c3e06..e55c4fc5d325 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -113,6 +113,7 @@ config PPC select HAVE_MEMBLOCK_NODE_MAP select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG + select HAVE_EXIT_THREAD select HAVE_OPROFILE select HAVE_DEBUG_KMEMLEAK select ARCH_HAS_SG_CHAIN diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 2ee95ece0498..8e82f40a3ae9 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -129,6 +129,7 @@ config S390 select HAVE_DEBUG_KMEMLEAK select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_REGS + select HAVE_EXIT_THREAD select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c index a1519ad3d49d..aae9480706c2 100644 --- a/arch/score/kernel/process.c +++ b/arch/score/kernel/process.c @@ -56,8 +56,6 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) regs->regs[0] = sp; } -void exit_thread(void) {} - /* * When a process does an "exec", machine state like FPU and debug * registers need to be reset. This is a hook function for that. diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index d514df7e04dd..0bc9282d37d2 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -71,6 +71,7 @@ config SUPERH32 config SUPERH64 def_bool ARCH = "sh64" + select HAVE_EXIT_THREAD select KALLSYMS config ARCH_DEFCONFIG diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 2885fc9d9dcd..ee12e9451874 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -76,13 +76,6 @@ void start_thread(struct pt_regs *regs, unsigned long new_pc, } EXPORT_SYMBOL(start_thread); -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) -{ -} - void flush_thread(void) { struct task_struct *tsk = current; diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 94f4ac21761b..b4f7a98acbc5 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -20,6 +20,7 @@ config SPARC select HAVE_OPROFILE select HAVE_ARCH_KGDB if !SMP || SPARC64 select HAVE_ARCH_TRACEHOOK + select HAVE_EXIT_THREAD select SYSCTL_EXCEPTION_TRACE select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 8ec7a4599c08..09d4656f1492 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -3,6 +3,7 @@ config TILE def_bool y + select HAVE_EXIT_THREAD select HAVE_PERF_EVENTS select USE_PMC if PERF_EVENTS select HAVE_DMA_ATTRS diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 48af59aae129..0b04711f1f18 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -103,10 +103,6 @@ void interrupt_end(void) tracehook_notify_resume(regs); } -void exit_thread(void) -{ -} - int get_current_pid(void) { return task_pid_nr(current); diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c index b008e9961465..00299c927852 100644 --- a/arch/unicore32/kernel/process.c +++ b/arch/unicore32/kernel/process.c @@ -201,13 +201,6 @@ void show_regs(struct pt_regs *regs) __backtrace(); } -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) -{ -} - void flush_thread(void) { struct thread_info *thread = current_thread_info(); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 02eb4db5d0b7..93a1b2af3ec3 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -108,6 +108,7 @@ config X86 select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_EFFICIENT_UNALIGNED_ACCESS + select HAVE_EXIT_THREAD select HAVE_FENTRY if X86_64 select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FUNCTION_GRAPH_FP_TEST diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 82044f732323..bdad9be4a729 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -16,6 +16,7 @@ config XTENSA select GENERIC_SCHED_CLOCK select HAVE_DMA_API_DEBUG select HAVE_DMA_ATTRS + select HAVE_EXIT_THREAD select HAVE_FUNCTION_TRACER select HAVE_FUTEX_CMPXCHG if !MMU select HAVE_IRQ_TIME_ACCOUNTING diff --git a/include/linux/sched.h b/include/linux/sched.h index d3dd0d516957..761ccea3eb4a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2816,7 +2816,14 @@ static inline int copy_thread_tls( } #endif extern void flush_thread(void); + +#ifdef CONFIG_HAVE_EXIT_THREAD extern void exit_thread(void); +#else +static inline void exit_thread(void) +{ +} +#endif extern void exit_files(struct task_struct *); extern void __cleanup_sighand(struct sighand_struct *); From cc261c372935629b5414b864205a3bd7e2c69137 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 11 Sep 2017 11:24:23 +0200 Subject: [PATCH 013/266] BACKPORT: s390: get rid of exit_thread() exit_thread() is empty now. Therefore remove it and get rid of a pointless branch. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky (cherry picked from commit 59a19ea9a0b3b0ee69887b6a5015aee3a3c7e527) Conflicts: arch/s390/Kconfig arch/s390/kernel/process.c Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 1 - arch/s390/kernel/process.c | 7 ------- 2 files changed, 8 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 8e82f40a3ae9..2ee95ece0498 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -129,7 +129,6 @@ config S390 select HAVE_DEBUG_KMEMLEAK select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_REGS - select HAVE_EXIT_THREAD select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 7bc4e4c5d5b8..d1653cc64550 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -67,13 +67,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk) extern void kernel_thread_starter(void); -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) -{ -} - void flush_thread(void) { } From c9cd1837ca21b9731f954b7469083482ae5d1e8e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 8 Jul 2016 11:06:19 +0100 Subject: [PATCH 014/266] UPSTREAM: MIPS: Use per-mm page to execute branch delay slot instructions In some cases the kernel needs to execute an instruction from the delay slot of an emulated branch instruction. These cases include: - Emulated floating point branch instructions (bc1[ft]l?) for systems which don't include an FPU, or upon which the kernel is run with the "nofpu" parameter. - MIPSr6 systems running binaries targeting older revisions of the architecture, which may include branch instructions whose encodings are no longer valid in MIPSr6. Executing instructions from such delay slots is done by writing the instruction to memory followed by a trap, as part of an "emuframe", and executing it. This avoids the requirement of an emulator for the entire MIPS instruction set. Prior to this patch such emuframes are written to the user stack and executed from there. This patch moves FP branch delay emuframes off of the user stack and into a per-mm page. Allocating a page per-mm leaves userland with access to only what it had access to previously, and compared to other solutions is relatively simple. When a thread requires a delay slot emulation, it is allocated a frame. A thread may only have one frame allocated at any one time, since it may only ever be executing one instruction at any one time. In order to ensure that we can free up allocated frame later, its index is recorded in struct thread_struct. In the typical case, after executing the delay slot instruction we'll execute a break instruction with the BRK_MEMU code. This traps back to the kernel & leads to a call to do_dsemulret which frees the allocated frame & moves the user PC back to the instruction that would have executed following the emulated branch. In some cases the delay slot instruction may be invalid, such as a branch, or may trigger an exception. In these cases the BRK_MEMU break instruction will not be hit. In order to ensure that frames are freed this patch introduces dsemul_thread_cleanup() and calls it to free any allocated frame upon thread exit. If the instruction generated an exception & leads to a signal being delivered to the thread, or indeed if a signal simply happens to be delivered to the thread whilst it is executing from the struct emuframe, then we need to take care to exit the frame appropriately. This is done by either rolling back the user PC to the branch or advancing it to the continuation PC prior to signal delivery, using dsemul_thread_rollback(). If this were not done then a sigreturn would return to the struct emuframe, and if that frame had meanwhile been used in response to an emulated branch instruction within the signal handler then we would execute the wrong user code. Whilst a user could theoretically place something like a compact branch to self in a delay slot and cause their thread to become stuck in an infinite loop with the frame never being deallocated, this would: - Only affect the users single process. - Be architecturally invalid since there would be a branch in the delay slot, which is forbidden. - Be extremely unlikely to happen by mistake, and provide a program with no more ability to harm the system than a simple infinite loop would. If a thread requires a delay slot emulation & no frame is available to it (ie. the process has enough other threads that all frames are currently in use) then the thread joins a waitqueue. It will sleep until a frame is freed by another thread in the process. Since we now know whether a thread has an allocated frame due to our tracking of its index, the cookie field of struct emuframe is removed as we can be more certain whether we have a valid frame. Since a thread may only ever have a single frame at any given time, the epc field of struct emuframe is also removed & the PC to continue from is instead stored in struct thread_struct. Together these changes simplify & shrink struct emuframe somewhat, allowing twice as many frames to fit into the page allocated for them. The primary benefit of this patch is that we are now free to mark the user stack non-executable where that is possible. Signed-off-by: Paul Burton Cc: Leonid Yegoshin Cc: Maciej Rozycki Cc: Faraz Shahbazker Cc: Raghu Gandham Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13764/ Signed-off-by: Ralf Baechle (cherry picked from commit 432c6bacbd0c16ec210c43da411ccc3855c4c010) Signed-off-by: Greg Kroah-Hartman --- arch/mips/Kconfig | 1 + arch/mips/include/asm/dsemul.h | 92 +++++++ arch/mips/include/asm/fpu_emulator.h | 17 +- arch/mips/include/asm/mmu.h | 9 + arch/mips/include/asm/mmu_context.h | 6 + arch/mips/include/asm/processor.h | 18 +- arch/mips/kernel/mips-r2-to-r6-emul.c | 8 +- arch/mips/kernel/process.c | 14 ++ arch/mips/kernel/signal.c | 8 + arch/mips/kernel/vdso.c | 10 + arch/mips/math-emu/cp1emu.c | 8 +- arch/mips/math-emu/dsemul.c | 333 +++++++++++++++++--------- 12 files changed, 391 insertions(+), 133 deletions(-) create mode 100644 arch/mips/include/asm/dsemul.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 117ac742a063..75e92584013b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -65,6 +65,7 @@ config MIPS select GENERIC_TIME_VSYSCALL select ARCH_CLOCKSOURCE_DATA select HANDLE_DOMAIN_IRQ + select HAVE_EXIT_THREAD menu "Machine selection" diff --git a/arch/mips/include/asm/dsemul.h b/arch/mips/include/asm/dsemul.h new file mode 100644 index 000000000000..a6e067801f23 --- /dev/null +++ b/arch/mips/include/asm/dsemul.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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. + */ + +#ifndef __MIPS_ASM_DSEMUL_H__ +#define __MIPS_ASM_DSEMUL_H__ + +#include +#include + +/* Break instruction with special math emu break code set */ +#define BREAK_MATH(micromips) (((micromips) ? 0x7 : 0xd) | (BRK_MEMU << 16)) + +/* When used as a frame index, indicates the lack of a frame */ +#define BD_EMUFRAME_NONE ((int)BIT(31)) + +struct mm_struct; +struct pt_regs; +struct task_struct; + +/** + * mips_dsemul() - 'Emulate' an instruction from a branch delay slot + * @regs: User thread register context. + * @ir: The instruction to be 'emulated'. + * @branch_pc: The PC of the branch instruction. + * @cont_pc: The PC to continue at following 'emulation'. + * + * Emulate or execute an arbitrary MIPS instruction within the context of + * the current user thread. This is used primarily to handle instructions + * in the delay slots of emulated branch instructions, for example FP + * branch instructions on systems without an FPU. + * + * Return: Zero on success, negative if ir is a NOP, signal number on failure. + */ +extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir, + unsigned long branch_pc, unsigned long cont_pc); + +/** + * do_dsemulret() - Return from a delay slot 'emulation' frame + * @xcp: User thread register context. + * + * Call in response to the BRK_MEMU break instruction used to return to + * the kernel from branch delay slot 'emulation' frames following a call + * to mips_dsemul(). Restores the user thread PC to the value that was + * passed as the cpc parameter to mips_dsemul(). + * + * Return: True if an emulation frame was returned from, else false. + */ +extern bool do_dsemulret(struct pt_regs *xcp); + +/** + * dsemul_thread_cleanup() - Cleanup thread 'emulation' frame + * @tsk: The task structure associated with the thread + * + * If the thread @tsk has a branch delay slot 'emulation' frame + * allocated to it then free that frame. + * + * Return: True if a frame was freed, else false. + */ +extern bool dsemul_thread_cleanup(struct task_struct *tsk); + +/** + * dsemul_thread_rollback() - Rollback from an 'emulation' frame + * @regs: User thread register context. + * + * If the current thread, whose register context is represented by @regs, + * is executing within a delay slot 'emulation' frame then exit that + * frame. The PC will be rolled back to the branch if the instruction + * that was being 'emulated' has not yet executed, or advanced to the + * continuation PC if it has. + * + * Return: True if a frame was exited, else false. + */ +extern bool dsemul_thread_rollback(struct pt_regs *regs); + +/** + * dsemul_mm_cleanup() - Cleanup per-mm delay slot 'emulation' state + * @mm: The struct mm_struct to cleanup state for. + * + * Cleanup state for the given @mm, ensuring that any memory allocated + * for delay slot 'emulation' book-keeping is freed. This is to be called + * before @mm is freed in order to avoid memory leaks. + */ +extern void dsemul_mm_cleanup(struct mm_struct *mm); + +#endif /* __MIPS_ASM_DSEMUL_H__ */ diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h index 3225c3c0724b..355dc25172e7 100644 --- a/arch/mips/include/asm/fpu_emulator.h +++ b/arch/mips/include/asm/fpu_emulator.h @@ -24,7 +24,7 @@ #define _ASM_FPU_EMULATOR_H #include -#include +#include #include #include #include @@ -60,27 +60,16 @@ do { \ #define MIPS_FPU_EMU_INC_STATS(M) do { } while (0) #endif /* CONFIG_DEBUG_FS */ -extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir, - unsigned long cpc); -extern int do_dsemulret(struct pt_regs *xcp); extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, int has_fpu, void *__user *fault_addr); int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31); +int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, + unsigned long *contpc); int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, unsigned long *contpc); -/* - * Instruction inserted following the badinst to further tag the sequence - */ -#define BD_COOKIE 0x0000bd36 /* tne $0, $0 with baggage */ - -/* - * Break instruction with special math emu break code set - */ -#define BREAK_MATH(micromips) (((micromips) ? 0x7 : 0xd) | (BRK_MEMU << 16)) - #define SIGNALLING_NAN 0x7ff800007ff80000LL static inline void fpu_emulator_init_fpu(void) diff --git a/arch/mips/include/asm/mmu.h b/arch/mips/include/asm/mmu.h index 1afa1f986df8..f6ba08d77931 100644 --- a/arch/mips/include/asm/mmu.h +++ b/arch/mips/include/asm/mmu.h @@ -2,11 +2,20 @@ #define __ASM_MMU_H #include +#include +#include typedef struct { unsigned long asid[NR_CPUS]; void *vdso; atomic_t fp_mode_switching; + + /* lock to be held whilst modifying fp_bd_emupage_allocmap */ + spinlock_t bd_emupage_lock; + /* bitmap tracking allocation of fp_bd_emupage */ + unsigned long *bd_emupage_allocmap; + /* wait queue for threads requiring an emuframe */ + wait_queue_head_t bd_emupage_queue; } mm_context_t; #endif /* __ASM_MMU_H */ diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index 45914b59824c..3a7761f88a16 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,10 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) atomic_set(&mm->context.fp_mode_switching, 0); + mm->context.bd_emupage_allocmap = NULL; + spin_lock_init(&mm->context.bd_emupage_lock); + init_waitqueue_head(&mm->context.bd_emupage_queue); + return 0; } @@ -167,6 +172,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, */ static inline void destroy_context(struct mm_struct *mm) { + dsemul_mm_cleanup(mm); } #define deactivate_mm(tsk, mm) do { } while (0) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index cfa15bad43af..25eef1d60f27 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -11,12 +11,14 @@ #ifndef _ASM_PROCESSOR_H #define _ASM_PROCESSOR_H +#include #include #include #include #include #include +#include #include #include @@ -74,7 +76,11 @@ extern unsigned int vced_count, vcei_count; #endif -#define STACK_TOP (TASK_SIZE & PAGE_MASK) +/* + * One page above the stack is used for branch delay slot "emulation". + * See dsemul.c for details. + */ +#define STACK_TOP ((TASK_SIZE & PAGE_MASK) - PAGE_SIZE) /* * This decides where the kernel will search for a free chunk of vm @@ -252,6 +258,12 @@ struct thread_struct { /* Saved fpu/fpu emulator stuff. */ struct mips_fpu_struct fpu FPU_ALIGN; + /* Assigned branch delay slot 'emulation' frame */ + atomic_t bd_emu_frame; + /* PC of the branch from a branch delay slot 'emulation' */ + unsigned long bd_emu_branch_pc; + /* PC to continue from following a branch delay slot 'emulation' */ + unsigned long bd_emu_cont_pc; #ifdef CONFIG_MIPS_MT_FPAFF /* Emulated instruction count */ unsigned long emulated_fp; @@ -319,6 +331,10 @@ struct thread_struct { * FPU affinity state (null if not FPAFF) \ */ \ FPAFF_INIT \ + /* Delay slot emulation */ \ + .bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE), \ + .bd_emu_branch_pc = 0, \ + .bd_emu_cont_pc = 0, \ /* \ * Saved DSP stuff \ */ \ diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index e3384065f5e7..a7a9f7cfb870 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -283,7 +283,7 @@ static int jr_func(struct pt_regs *regs, u32 ir) err = mipsr6_emul(regs, nir); if (err > 0) { regs->cp0_epc = nepc; - err = mips_dsemul(regs, nir, cepc); + err = mips_dsemul(regs, nir, epc, cepc); if (err == SIGILL) err = SIGEMT; MIPS_R2_STATS(dsemul); @@ -1033,7 +1033,7 @@ repeat: if (nir) { err = mipsr6_emul(regs, nir); if (err > 0) { - err = mips_dsemul(regs, nir, cpc); + err = mips_dsemul(regs, nir, epc, cpc); if (err == SIGILL) err = SIGEMT; MIPS_R2_STATS(dsemul); @@ -1082,7 +1082,7 @@ repeat: if (nir) { err = mipsr6_emul(regs, nir); if (err > 0) { - err = mips_dsemul(regs, nir, cpc); + err = mips_dsemul(regs, nir, epc, cpc); if (err == SIGILL) err = SIGEMT; MIPS_R2_STATS(dsemul); @@ -1149,7 +1149,7 @@ repeat: if (nir) { err = mipsr6_emul(regs, nir); if (err > 0) { - err = mips_dsemul(regs, nir, cpc); + err = mips_dsemul(regs, nir, epc, cpc); if (err == SIGILL) err = SIGEMT; MIPS_R2_STATS(dsemul); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 83153946f389..474ce8d1f67d 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -67,11 +68,22 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) lose_fpu(0); clear_thread_flag(TIF_MSA_CTX_LIVE); clear_used_math(); + atomic_set(¤t->thread.bd_emu_frame, BD_EMUFRAME_NONE); init_dsp(); regs->cp0_epc = pc; regs->regs[29] = sp; } +void exit_thread(struct task_struct *tsk) +{ + /* + * User threads may have allocated a delay slot emulation frame. + * If so, clean up that allocation. + */ + if (!(current->flags & PF_KTHREAD)) + dsemul_thread_cleanup(tsk); +} + int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { /* @@ -158,6 +170,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, clear_tsk_thread_flag(p, TIF_FPUBOUND); #endif /* CONFIG_MIPS_MT_FPAFF */ + atomic_set(&p->thread.bd_emu_frame, BD_EMUFRAME_NONE); + if (clone_flags & CLONE_SETTLS) ti->tp_value = regs->regs[7]; diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9e35b6b26aa8..129be9703fe8 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -772,6 +772,14 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) struct mips_abi *abi = current->thread.abi; void *vdso = current->mm->context.vdso; + /* + * If we were emulating a delay slot instruction, exit that frame such + * that addresses in the sigframe are as expected for userland and we + * don't have a problem if we reuse the thread's frame for an + * instruction within the signal handler. + */ + dsemul_thread_rollback(regs); + if (regs->regs[0]) { switch(regs->regs[2]) { case ERESTART_RESTARTBLOCK: diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index 5649a9e429e0..3fcc833b316d 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -106,6 +106,16 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) down_write(&mm->mmap_sem); + /* Map delay slot emulation page */ + base = mmap_region(NULL, STACK_TOP, PAGE_SIZE, + VM_READ|VM_WRITE|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, + 0); + if (IS_ERR_VALUE(base)) { + ret = base; + goto out; + } + /* * Determine total area size. This includes the VDSO data itself, the * data page, and the GIC user page if present. Always create a mapping diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index b8941063a56e..066e0720a7f1 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -434,8 +434,8 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) * a single subroutine should be used across both * modules. */ -static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, - unsigned long *contpc) +int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, + unsigned long *contpc) { union mips_instruction insn = (union mips_instruction)dec_insn.insn; unsigned int fcr31; @@ -1267,7 +1267,7 @@ branch_common: * instruction in the dslot. */ sig = mips_dsemul(xcp, ir, - contpc); + bcpc, contpc); if (sig < 0) break; if (sig) @@ -1322,7 +1322,7 @@ branch_common: * Single step the non-cp1 * instruction in the dslot */ - sig = mips_dsemul(xcp, ir, contpc); + sig = mips_dsemul(xcp, ir, bcpc, contpc); if (sig < 0) break; if (sig) diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 47074887e64c..72a4642eee2c 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -1,3 +1,6 @@ +#include +#include + #include #include #include @@ -5,43 +8,211 @@ #include #include -#include "ieee754.h" - -/* - * Emulate the arbitrary instruction ir at xcp->cp0_epc. Required when - * we have to emulate the instruction in a COP1 branch delay slot. Do - * not change cp0_epc due to the instruction +/** + * struct emuframe - The 'emulation' frame structure + * @emul: The instruction to 'emulate'. + * @badinst: A break instruction to cause a return to the kernel. * - * According to the spec: - * 1) it shouldn't be a branch :-) - * 2) it can be a COP instruction :-( - * 3) if we are tring to run a protected memory space we must take - * special care on memory access instructions :-( + * This structure defines the frames placed within the delay slot emulation + * page in response to a call to mips_dsemul(). Each thread may be allocated + * only one frame at any given time. The kernel stores within it the + * instruction to be 'emulated' followed by a break instruction, then + * executes the frame in user mode. The break causes a trap to the kernel + * which leads to do_dsemulret() being called unless the instruction in + * @emul causes a trap itself, is a branch, or a signal is delivered to + * the thread. In these cases the allocated frame will either be reused by + * a subsequent delay slot 'emulation', or be freed during signal delivery or + * upon thread exit. + * + * This approach is used because: + * + * - Actually emulating all instructions isn't feasible. We would need to + * be able to handle instructions from all revisions of the MIPS ISA, + * all ASEs & all vendor instruction set extensions. This would be a + * whole lot of work & continual maintenance burden as new instructions + * are introduced, and in the case of some vendor extensions may not + * even be possible. Thus we need to take the approach of actually + * executing the instruction. + * + * - We must execute the instruction within user context. If we were to + * execute the instruction in kernel mode then it would have access to + * kernel resources without very careful checks, leaving us with a + * high potential for security or stability issues to arise. + * + * - We used to place the frame on the users stack, but this requires + * that the stack be executable. This is bad for security so the + * per-process page is now used instead. + * + * - The instruction in @emul may be something entirely invalid for a + * delay slot. The user may (intentionally or otherwise) place a branch + * in a delay slot, or a kernel mode instruction, or something else + * which generates an exception. Thus we can't rely upon the break in + * @badinst always being hit. For this reason we track the index of the + * frame allocated to each thread, allowing us to clean it up at later + * points such as signal delivery or thread exit. + * + * - The user may generate a fake struct emuframe if they wish, invoking + * the BRK_MEMU break instruction themselves. We must therefore not + * trust that BRK_MEMU means there's actually a valid frame allocated + * to the thread, and must not allow the user to do anything they + * couldn't already. */ - -/* - * "Trampoline" return routine to catch exception following - * execution of delay-slot instruction execution. - */ - struct emuframe { mips_instruction emul; mips_instruction badinst; - mips_instruction cookie; - unsigned long epc; }; -/* - * Set up an emulation frame for instruction IR, from a delay slot of - * a branch jumping to CPC. Return 0 if successful, -1 if no emulation - * required, otherwise a signal number causing a frame setup failure. - */ -int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) +static const int emupage_frame_count = PAGE_SIZE / sizeof(struct emuframe); + +static inline __user struct emuframe *dsemul_page(void) +{ + return (__user struct emuframe *)STACK_TOP; +} + +static int alloc_emuframe(void) +{ + mm_context_t *mm_ctx = ¤t->mm->context; + int idx; + +retry: + spin_lock(&mm_ctx->bd_emupage_lock); + + /* Ensure we have an allocation bitmap */ + if (!mm_ctx->bd_emupage_allocmap) { + mm_ctx->bd_emupage_allocmap = + kcalloc(BITS_TO_LONGS(emupage_frame_count), + sizeof(unsigned long), + GFP_ATOMIC); + + if (!mm_ctx->bd_emupage_allocmap) { + idx = BD_EMUFRAME_NONE; + goto out_unlock; + } + } + + /* Attempt to allocate a single bit/frame */ + idx = bitmap_find_free_region(mm_ctx->bd_emupage_allocmap, + emupage_frame_count, 0); + if (idx < 0) { + /* + * Failed to allocate a frame. We'll wait until one becomes + * available. We unlock the page so that other threads actually + * get the opportunity to free their frames, which means + * technically the result of bitmap_full may be incorrect. + * However the worst case is that we repeat all this and end up + * back here again. + */ + spin_unlock(&mm_ctx->bd_emupage_lock); + if (!wait_event_killable(mm_ctx->bd_emupage_queue, + !bitmap_full(mm_ctx->bd_emupage_allocmap, + emupage_frame_count))) + goto retry; + + /* Received a fatal signal - just give in */ + return BD_EMUFRAME_NONE; + } + + /* Success! */ + pr_debug("allocate emuframe %d to %d\n", idx, current->pid); +out_unlock: + spin_unlock(&mm_ctx->bd_emupage_lock); + return idx; +} + +static void free_emuframe(int idx, struct mm_struct *mm) +{ + mm_context_t *mm_ctx = &mm->context; + + spin_lock(&mm_ctx->bd_emupage_lock); + + pr_debug("free emuframe %d from %d\n", idx, current->pid); + bitmap_clear(mm_ctx->bd_emupage_allocmap, idx, 1); + + /* If some thread is waiting for a frame, now's its chance */ + wake_up(&mm_ctx->bd_emupage_queue); + + spin_unlock(&mm_ctx->bd_emupage_lock); +} + +static bool within_emuframe(struct pt_regs *regs) +{ + unsigned long base = (unsigned long)dsemul_page(); + + if (regs->cp0_epc < base) + return false; + if (regs->cp0_epc >= (base + PAGE_SIZE)) + return false; + + return true; +} + +bool dsemul_thread_cleanup(struct task_struct *tsk) +{ + int fr_idx; + + /* Clear any allocated frame, retrieving its index */ + fr_idx = atomic_xchg(&tsk->thread.bd_emu_frame, BD_EMUFRAME_NONE); + + /* If no frame was allocated, we're done */ + if (fr_idx == BD_EMUFRAME_NONE) + return false; + + task_lock(tsk); + + /* Free the frame that this thread had allocated */ + if (tsk->mm) + free_emuframe(fr_idx, tsk->mm); + + task_unlock(tsk); + return true; +} + +bool dsemul_thread_rollback(struct pt_regs *regs) +{ + struct emuframe __user *fr; + int fr_idx; + + /* Do nothing if we're not executing from a frame */ + if (!within_emuframe(regs)) + return false; + + /* Find the frame being executed */ + fr_idx = atomic_read(¤t->thread.bd_emu_frame); + if (fr_idx == BD_EMUFRAME_NONE) + return false; + fr = &dsemul_page()[fr_idx]; + + /* + * If the PC is at the emul instruction, roll back to the branch. If + * PC is at the badinst (break) instruction, we've already emulated the + * instruction so progress to the continue PC. If it's anything else + * then something is amiss & the user has branched into some other area + * of the emupage - we'll free the allocated frame anyway. + */ + if (msk_isa16_mode(regs->cp0_epc) == (unsigned long)&fr->emul) + regs->cp0_epc = current->thread.bd_emu_branch_pc; + else if (msk_isa16_mode(regs->cp0_epc) == (unsigned long)&fr->badinst) + regs->cp0_epc = current->thread.bd_emu_cont_pc; + + atomic_set(¤t->thread.bd_emu_frame, BD_EMUFRAME_NONE); + free_emuframe(fr_idx, current->mm); + return true; +} + +void dsemul_mm_cleanup(struct mm_struct *mm) +{ + mm_context_t *mm_ctx = &mm->context; + + kfree(mm_ctx->bd_emupage_allocmap); +} + +int mips_dsemul(struct pt_regs *regs, mips_instruction ir, + unsigned long branch_pc, unsigned long cont_pc) { int isa16 = get_isa16_mode(regs->cp0_epc); mips_instruction break_math; struct emuframe __user *fr; - int err; + int err, fr_idx; /* NOP is easy */ if (ir == 0) @@ -68,30 +239,20 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) } } - pr_debug("dsemul %lx %lx\n", regs->cp0_epc, cpc); + pr_debug("dsemul 0x%08lx cont at 0x%08lx\n", regs->cp0_epc, cont_pc); - /* - * The strategy is to push the instruction onto the user stack - * and put a trap after it which we can catch and jump to - * the required address any alternative apart from full - * instruction emulation!!. - * - * Algorithmics used a system call instruction, and - * borrowed that vector. MIPS/Linux version is a bit - * more heavyweight in the interests of portability and - * multiprocessor support. For Linux we use a BREAK 514 - * instruction causing a breakpoint exception. - */ + /* Allocate a frame if we don't already have one */ + fr_idx = atomic_read(¤t->thread.bd_emu_frame); + if (fr_idx == BD_EMUFRAME_NONE) + fr_idx = alloc_emuframe(); + if (fr_idx == BD_EMUFRAME_NONE) + return SIGBUS; + fr = &dsemul_page()[fr_idx]; + + /* Retrieve the appropriately encoded break instruction */ break_math = BREAK_MATH(isa16); - /* Ensure that the two instructions are in the same cache line */ - fr = (struct emuframe __user *) - ((regs->regs[29] - sizeof(struct emuframe)) & ~0x7); - - /* Verify that the stack pointer is not completely insane */ - if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe)))) - return SIGBUS; - + /* Write the instructions to the frame */ if (isa16) { err = __put_user(ir >> 16, (u16 __user *)(&fr->emul)); @@ -106,84 +267,36 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) err |= __put_user(break_math, &fr->badinst); } - err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie); - err |= __put_user(cpc, &fr->epc); - if (unlikely(err)) { MIPS_FPU_EMU_INC_STATS(errors); + free_emuframe(fr_idx, current->mm); return SIGBUS; } + /* Record the PC of the branch, PC to continue from & frame index */ + current->thread.bd_emu_branch_pc = branch_pc; + current->thread.bd_emu_cont_pc = cont_pc; + atomic_set(¤t->thread.bd_emu_frame, fr_idx); + + /* Change user register context to execute the frame */ regs->cp0_epc = (unsigned long)&fr->emul | isa16; + /* Ensure the icache observes our newly written frame */ flush_cache_sigtramp((unsigned long)&fr->emul); return 0; } -int do_dsemulret(struct pt_regs *xcp) +bool do_dsemulret(struct pt_regs *xcp) { - int isa16 = get_isa16_mode(xcp->cp0_epc); - struct emuframe __user *fr; - unsigned long epc; - u32 insn, cookie; - int err = 0; - u16 instr[2]; - - fr = (struct emuframe __user *) - (msk_isa16_mode(xcp->cp0_epc) - sizeof(mips_instruction)); - - /* - * If we can't even access the area, something is very wrong, but we'll - * leave that to the default handling - */ - if (!access_ok(VERIFY_READ, fr, sizeof(struct emuframe))) - return 0; - - /* - * Do some sanity checking on the stackframe: - * - * - Is the instruction pointed to by the EPC an BREAK_MATH? - * - Is the following memory word the BD_COOKIE? - */ - if (isa16) { - err = __get_user(instr[0], - (u16 __user *)(&fr->badinst)); - err |= __get_user(instr[1], - (u16 __user *)((long)(&fr->badinst) + 2)); - insn = (instr[0] << 16) | instr[1]; - } else { - err = __get_user(insn, &fr->badinst); - } - err |= __get_user(cookie, &fr->cookie); - - if (unlikely(err || - insn != BREAK_MATH(isa16) || cookie != BD_COOKIE)) { + /* Cleanup the allocated frame, returning if there wasn't one */ + if (!dsemul_thread_cleanup(current)) { MIPS_FPU_EMU_INC_STATS(errors); - return 0; - } - - /* - * At this point, we are satisfied that it's a BD emulation trap. Yes, - * a user might have deliberately put two malformed and useless - * instructions in a row in his program, in which case he's in for a - * nasty surprise - the next instruction will be treated as a - * continuation address! Alas, this seems to be the only way that we - * can handle signals, recursion, and longjmps() in the context of - * emulating the branch delay instruction. - */ - - pr_debug("dsemulret\n"); - - if (__get_user(epc, &fr->epc)) { /* Saved EPC */ - /* This is not a good situation to be in */ - force_sig(SIGBUS, current); - - return 0; + return false; } /* Set EPC to return to post-branch instruction */ - xcp->cp0_epc = epc; - MIPS_FPU_EMU_INC_STATS(ds_emul); - return 1; + xcp->cp0_epc = current->thread.bd_emu_cont_pc; + pr_debug("dsemulret to 0x%08lx\n", xcp->cp0_epc); + return true; } From c16fb87374fdc11c3353a6ed2513da734cf90e64 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 20 May 2016 17:00:11 -0700 Subject: [PATCH 015/266] UPSTREAM: mn10300: let exit_fpu accept a task We need to call exit_thread from copy_process in a fail path. Since exit_thread on mn10300 calls exit_thread_runtime_instr, make it accept task_struct as a parameter now. Signed-off-by: Jiri Slaby Cc: "David S. Miller" Cc: "H. Peter Anvin" Cc: "James E.J. Bottomley" Cc: Aurelien Jacquiot Cc: Benjamin Herrenschmidt Cc: Catalin Marinas Cc: Chen Liqin Cc: Chris Metcalf Cc: Chris Zankel Cc: David Howells Cc: Fenghua Yu Cc: Geert Uytterhoeven Cc: Guan Xuetao Cc: Haavard Skinnemoen Cc: Hans-Christian Egtvedt Cc: Heiko Carstens Cc: Helge Deller Cc: Ingo Molnar Cc: Ivan Kokshaysky Cc: James Hogan Cc: Jeff Dike Cc: Jesper Nilsson Cc: Jiri Slaby Cc: Jonas Bonn Cc: Koichi Yasutake Cc: Lennox Wu Cc: Ley Foon Tan Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Turner Cc: Max Filippov Cc: Michael Ellerman Cc: Michal Simek Cc: Mikael Starvik Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Rich Felker Cc: Richard Henderson Cc: Richard Kuo Cc: Richard Weinberger Cc: Russell King Cc: Steven Miao Cc: Thomas Gleixner Cc: Tony Luck Cc: Vineet Gupta Cc: Will Deacon Cc: Yoshinori Sato Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 2ec656eb4054ce55e6d453b8614ef9669e84c542) Signed-off-by: Greg Kroah-Hartman --- arch/mn10300/include/asm/fpu.h | 6 ++---- arch/mn10300/kernel/process.c | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/mn10300/include/asm/fpu.h b/arch/mn10300/include/asm/fpu.h index 738ff72659d5..a47e995d45f3 100644 --- a/arch/mn10300/include/asm/fpu.h +++ b/arch/mn10300/include/asm/fpu.h @@ -76,11 +76,9 @@ static inline void unlazy_fpu(struct task_struct *tsk) preempt_enable(); } -static inline void exit_fpu(void) +static inline void exit_fpu(struct task_struct *tsk) { #ifdef CONFIG_LAZY_SAVE_FPU - struct task_struct *tsk = current; - preempt_disable(); if (fpu_state_owner == tsk) fpu_state_owner = NULL; @@ -123,7 +121,7 @@ static inline void fpu_init_state(void) {} static inline void fpu_save(struct fpu_state_struct *s) {} static inline void fpu_kill_state(struct task_struct *tsk) {} static inline void unlazy_fpu(struct task_struct *tsk) {} -static inline void exit_fpu(void) {} +static inline void exit_fpu(struct task_struct *tsk) {} static inline void flush_fpu(void) {} static inline int fpu_setup_sigcontext(struct fpucontext *buf) { return 0; } static inline int fpu_restore_sigcontext(struct fpucontext *buf) { return 0; } diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index 3707da583d05..74a96ccf7451 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -105,7 +105,7 @@ void show_regs(struct pt_regs *regs) */ void exit_thread(void) { - exit_fpu(); + exit_fpu(current); } void flush_thread(void) From af22cc785fe4a1127ce6df206405629ce4870761 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 20 May 2016 17:00:20 -0700 Subject: [PATCH 016/266] BACKPORT: exit_thread: accept a task parameter to be exited We need to call exit_thread from copy_process in a fail path. So make it accept task_struct as a parameter. [v2] * s390: exit_thread_runtime_instr doesn't make sense to be called for non-current tasks. * arm: fix the comment in vfp_thread_copy * change 'me' to 'tsk' for task_struct * now we can change only archs that actually have exit_thread [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Jiri Slaby Cc: "David S. Miller" Cc: "H. Peter Anvin" Cc: "James E.J. Bottomley" Cc: Aurelien Jacquiot Cc: Benjamin Herrenschmidt Cc: Catalin Marinas Cc: Chen Liqin Cc: Chris Metcalf Cc: Chris Zankel Cc: David Howells Cc: Fenghua Yu Cc: Geert Uytterhoeven Cc: Guan Xuetao Cc: Haavard Skinnemoen Cc: Hans-Christian Egtvedt Cc: Heiko Carstens Cc: Helge Deller Cc: Ingo Molnar Cc: Ivan Kokshaysky Cc: James Hogan Cc: Jeff Dike Cc: Jesper Nilsson Cc: Jiri Slaby Cc: Jonas Bonn Cc: Koichi Yasutake Cc: Lennox Wu Cc: Ley Foon Tan Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Turner Cc: Max Filippov Cc: Michael Ellerman Cc: Michal Simek Cc: Mikael Starvik Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Rich Felker Cc: Richard Henderson Cc: Richard Kuo Cc: Richard Weinberger Cc: Russell King Cc: Steven Miao Cc: Thomas Gleixner Cc: Tony Luck Cc: Vineet Gupta Cc: Will Deacon Cc: Yoshinori Sato Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit e64646946ed32902fd597fa6e514b1da84642de3) Conflicts: arch/s390/kernel/process.c Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/process.c | 4 ++-- arch/arm/vfp/vfpmodule.c | 4 ---- arch/avr32/kernel/process.c | 4 ++-- arch/cris/arch-v32/kernel/process.c | 4 ++-- arch/ia64/kernel/perfmon.c | 4 ++-- arch/ia64/kernel/process.c | 14 +++++++------- arch/metag/kernel/process.c | 6 +++--- arch/mn10300/kernel/process.c | 4 ++-- arch/sh/kernel/process_64.c | 5 ++--- arch/sparc/kernel/process_32.c | 12 ++++++------ arch/sparc/kernel/process_64.c | 4 ++-- arch/tile/kernel/process.c | 4 ++-- arch/x86/kernel/process.c | 5 ++--- arch/xtensa/kernel/process.c | 4 ++-- include/linux/sched.h | 4 ++-- kernel/exit.c | 2 +- 16 files changed, 39 insertions(+), 45 deletions(-) diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 0017b3edfea8..e06307ad1d1c 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -268,9 +268,9 @@ EXPORT_SYMBOL_GPL(thread_notify_head); /* * Free current thread data structures etc.. */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { - thread_notify(THREAD_NOTIFY_EXIT, current_thread_info()); + thread_notify(THREAD_NOTIFY_EXIT, task_thread_info(tsk)); } void flush_thread(void) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 2a61e4b04600..73085d3482ed 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -156,10 +156,6 @@ static void vfp_thread_copy(struct thread_info *thread) * - we could be preempted if tree preempt rcu is enabled, so * it is unsafe to use thread->cpu. * THREAD_NOTIFY_EXIT - * - the thread (v) will be running on the local CPU, so - * v === current_thread_info() - * - thread->cpu is the local CPU number at the time it is accessed, - * but may change at any time. * - we could be preempted if tree preempt rcu is enabled, so * it is unsafe to use thread->cpu. */ diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index 42a53e740a7e..68e5b9dac059 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c @@ -62,9 +62,9 @@ void machine_restart(char *cmd) /* * Free current thread data structures etc */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { - ocd_disable(current); + ocd_disable(tsk); } void flush_thread(void) diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index c7ce784a393c..4d1afa9f9fd3 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c @@ -33,9 +33,9 @@ void default_idle(void) */ extern void deconfigure_bp(long pid); -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { - deconfigure_bp(current->pid); + deconfigure_bp(tsk->pid); } /* diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 60e02f7747ff..c5d5955511d1 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -4543,8 +4543,8 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg /* - * called only from exit_thread(): task == current - * we come here only if current has a context attached (loaded or masked) + * called only from exit_thread() + * we come here only if the task has a context attached (loaded or masked) */ void pfm_exit_thread(struct task_struct *task) diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index b51514957620..aae6c4dc7ae7 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -570,22 +570,22 @@ flush_thread (void) } /* - * Clean up state associated with current thread. This is called when + * Clean up state associated with a thread. This is called when * the thread calls exit(). */ void -exit_thread (void) +exit_thread (struct task_struct *tsk) { - ia64_drop_fpu(current); + ia64_drop_fpu(tsk); #ifdef CONFIG_PERFMON /* if needed, stop monitoring and flush state to perfmon context */ - if (current->thread.pfm_context) - pfm_exit_thread(current); + if (tsk->thread.pfm_context) + pfm_exit_thread(tsk); /* free debug register resources */ - if (current->thread.flags & IA64_THREAD_DBG_VALID) - pfm_release_debug_registers(current); + if (tsk->thread.flags & IA64_THREAD_DBG_VALID) + pfm_release_debug_registers(tsk); #endif } diff --git a/arch/metag/kernel/process.c b/arch/metag/kernel/process.c index 7f546183a0f0..35062796edf2 100644 --- a/arch/metag/kernel/process.c +++ b/arch/metag/kernel/process.c @@ -345,10 +345,10 @@ void flush_thread(void) /* * Free current thread data structures etc. */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { - clear_fpu(¤t->thread); - clear_dsp(¤t->thread); + clear_fpu(&tsk->thread); + clear_dsp(&tsk->thread); } /* TODO: figure out how to unwind the kernel stack here to figure out diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index 74a96ccf7451..cbede4e88dee 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -103,9 +103,9 @@ void show_regs(struct pt_regs *regs) /* * free current thread data structures etc.. */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { - exit_fpu(current); + exit_fpu(tsk); } void flush_thread(void) diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index e2062e643341..9d3e9916555d 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -288,7 +288,7 @@ void show_regs(struct pt_regs *regs) /* * Free current thread data structures etc.. */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { /* * See arch/sparc/kernel/process.c for the precedent for doing @@ -307,9 +307,8 @@ void exit_thread(void) * which it would get safely nulled. */ #ifdef CONFIG_SH_FPU - if (last_task_used_math == current) { + if (last_task_used_math == tsk) last_task_used_math = NULL; - } #endif } diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index c5113c7ce2fd..b7780a5bef11 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -184,21 +184,21 @@ unsigned long thread_saved_pc(struct task_struct *tsk) /* * Free current thread data structures etc.. */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { #ifndef CONFIG_SMP - if(last_task_used_math == current) { + if (last_task_used_math == tsk) { #else - if (test_thread_flag(TIF_USEDFPU)) { + if (test_ti_thread_flag(task_thread_info(tsk), TIF_USEDFPU)) { #endif /* Keep process from leaving FPU in a bogon state. */ put_psr(get_psr() | PSR_EF); - fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, - ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); + fpsave(&tsk->thread.float_regs[0], &tsk->thread.fsr, + &tsk->thread.fpqueue[0], &tsk->thread.fpqdepth); #ifndef CONFIG_SMP last_task_used_math = NULL; #else - clear_thread_flag(TIF_USEDFPU); + clear_ti_thread_flag(task_thread_info(tsk), TIF_USEDFPU); #endif } } diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 46a59643bb1c..7c3fc5886038 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -417,9 +417,9 @@ unsigned long thread_saved_pc(struct task_struct *tsk) } /* Free current thread data structures etc.. */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { - struct thread_info *t = current_thread_info(); + struct thread_info *t = task_thread_info(tsk); if (t->utraps) { if (t->utraps[0] < 2) diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index a97ab1a69a90..c5f3c1a20507 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -539,7 +539,7 @@ void flush_thread(void) /* * Free current thread data structures etc.. */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { #ifdef CONFIG_HARDWALL /* @@ -548,7 +548,7 @@ void exit_thread(void) * the last reference to a hardwall fd, it would already have * been released and deactivated at this point.) */ - hardwall_deactivate_all(current); + hardwall_deactivate_all(tsk); #endif } diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index c1b21d61b769..2754dad26839 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -81,10 +81,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) /* * Free current thread data structures etc.. */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { - struct task_struct *me = current; - struct thread_struct *t = &me->thread; + struct thread_struct *t = &tsk->thread; unsigned long *bp = t->io_bitmap_ptr; struct fpu *fpu = &t->fpu; diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 1c85323f01d7..17a378c15a15 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -113,10 +113,10 @@ void arch_cpu_idle(void) /* * This is called when the thread calls exit(). */ -void exit_thread(void) +void exit_thread(struct task_struct *tsk) { #if XTENSA_HAVE_COPROCESSORS - coprocessor_release_all(current_thread_info()); + coprocessor_release_all(task_thread_info(tsk)); #endif } diff --git a/include/linux/sched.h b/include/linux/sched.h index 761ccea3eb4a..8377ac73a034 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2818,9 +2818,9 @@ static inline int copy_thread_tls( extern void flush_thread(void); #ifdef CONFIG_HAVE_EXIT_THREAD -extern void exit_thread(void); +extern void exit_thread(struct task_struct *tsk); #else -static inline void exit_thread(void) +static inline void exit_thread(struct task_struct *tsk) { } #endif diff --git a/kernel/exit.c b/kernel/exit.c index 4ceeac2e39f4..0003d8b97fd9 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -753,7 +753,7 @@ void do_exit(long code) disassociate_ctty(1); exit_task_namespaces(tsk); exit_task_work(tsk); - exit_thread(); + exit_thread(tsk); /* * Flush inherited counters to the parent - before the parent From 30bee7f9387b2b7a897ff1143bbb8dcbed28918c Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 22 Sep 2016 15:47:40 +0100 Subject: [PATCH 017/266] UPSTREAM: MIPS: Fix delay slot emulation count in debugfs Commit 432c6bacbd0c ("MIPS: Use per-mm page to execute branch delay slot instructions") accidentally removed use of the MIPS_FPU_EMU_INC_STATS macro from do_dsemulret, leading to the ds_emul file in debugfs always returning zero even though we perform delay slot emulations. Fix this by re-adding the use of the MIPS_FPU_EMU_INC_STATS macro. Signed-off-by: Paul Burton Fixes: 432c6bacbd0c ("MIPS: Use per-mm page to execute branch delay slot instructions") Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14301/ Signed-off-by: Ralf Baechle (cherry picked from commit 116e7111c8e3cc65ceef9664741bd593483e9517) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dsemul.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 72a4642eee2c..4a094f7acb3d 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -298,5 +298,6 @@ bool do_dsemulret(struct pt_regs *xcp) /* Set EPC to return to post-branch instruction */ xcp->cp0_epc = current->thread.bd_emu_cont_pc; pr_debug("dsemulret to 0x%08lx\n", xcp->cp0_epc); + MIPS_FPU_EMU_INC_STATS(ds_emul); return true; } From 18e152e0510756337aef3c2dc3ba858416293e4a Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 13 Nov 2015 00:46:44 +0000 Subject: [PATCH 018/266] UPSTREAM: MIPS: Use a union to access the ELF file header Rewrite `arch_elf_pt_proc' and `arch_check_elf' using a union to access the ELF file header. Signed-off-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11474/ Signed-off-by: Ralf Baechle (cherry picked from commit 2ed02dd415aee71a8bf4c621a9bd65c256642b96) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/elf.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 3afffc30ee12..c408465ea83a 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -68,15 +68,23 @@ static struct mode_req none_req = { true, true, false, true, true }; int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, bool is_interp, struct arch_elf_state *state) { - struct elf32_hdr *ehdr32 = _ehdr; + union { + struct elf32_hdr e32; + struct elf64_hdr e64; + } *ehdr = _ehdr; struct elf32_phdr *phdr32 = _phdr; struct elf64_phdr *phdr64 = _phdr; struct mips_elf_abiflags_v0 abiflags; + bool elf32; + u32 flags; int ret; + elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32; + flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags; + /* Lets see if this is an O32 ELF */ - if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) { - if (ehdr32->e_flags & EF_MIPS_FP64) { + if (elf32) { + if (flags & EF_MIPS_FP64) { /* * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it * later if needed @@ -123,10 +131,17 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, int arch_check_elf(void *_ehdr, bool has_interpreter, struct arch_elf_state *state) { - struct elf32_hdr *ehdr = _ehdr; + union { + struct elf32_hdr e32; + struct elf64_hdr e64; + } *ehdr = _ehdr; struct mode_req prog_req, interp_req; int fp_abi, interp_fp_abi, abi0, abi1, max_abi; - bool is_mips64; + bool elf32; + u32 flags; + + elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32; + flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags; if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) return 0; @@ -142,21 +157,18 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, abi0 = abi1 = fp_abi; } - is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) || - (ehdr->e_flags & EF_MIPS_ABI2); - - if (is_mips64) { - /* MIPS64 code always uses FR=1, thus the default is easy */ - state->overall_fp_mode = FP_FR1; - - /* Disallow access to the various FPXX & FP64 ABIs */ - max_abi = MIPS_ABI_FP_SOFT; - } else { + if (elf32 && !(flags & EF_MIPS_ABI2)) { /* Default to a mode capable of running code expecting FR=0 */ state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0; /* Allow all ABIs we know about */ max_abi = MIPS_ABI_FP_64A; + } else { + /* MIPS64 code always uses FR=1, thus the default is easy */ + state->overall_fp_mode = FP_FR1; + + /* Disallow access to the various FPXX & FP64 ABIs */ + max_abi = MIPS_ABI_FP_SOFT; } if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) || From 380f74966e731c6cde9464e026d1433e782bd2dd Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 13 Nov 2015 00:47:48 +0000 Subject: [PATCH 019/266] UPSTREAM: ELF: Also pass any interpreter's file header to `arch_check_elf' Also pass any interpreter's file header to `arch_check_elf' so that any architecture handler can have a look at it if needed. Signed-off-by: Maciej W. Rozycki Acked-by: Andrew Morton Acked-by: Al Viro Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11478/ Signed-off-by: Ralf Baechle (cherry picked from commit eb4bc076ff94b82fce04f6db061de597f71bd129) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/elf.h | 2 +- arch/mips/kernel/elf.c | 2 +- fs/binfmt_elf.c | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index b01a6ff468e0..891013578490 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -448,7 +448,7 @@ struct arch_elf_state { extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf, bool is_interp, struct arch_elf_state *state); -extern int arch_check_elf(void *ehdr, bool has_interpreter, +extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr, struct arch_elf_state *state); extern void mips_set_personality_fp(struct arch_elf_state *state); diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index c408465ea83a..d0181383c791 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -128,7 +128,7 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, return 0; } -int arch_check_elf(void *_ehdr, bool has_interpreter, +int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr, struct arch_elf_state *state) { union { diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 8a0243efd359..b9065d672887 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -491,6 +491,7 @@ static inline int arch_elf_pt_proc(struct elfhdr *ehdr, * arch_check_elf() - check an ELF executable * @ehdr: The main ELF header * @has_interp: True if the ELF has an interpreter, else false. + * @interp_ehdr: The interpreter's ELF header * @state: Architecture-specific state preserved throughout the process * of loading the ELF. * @@ -502,6 +503,7 @@ static inline int arch_elf_pt_proc(struct elfhdr *ehdr, * with that return code. */ static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp, + struct elfhdr *interp_ehdr, struct arch_elf_state *state) { /* Dummy implementation, always proceed */ @@ -829,7 +831,9 @@ static int load_elf_binary(struct linux_binprm *bprm) * still possible to return an error to the code that invoked * the exec syscall. */ - retval = arch_check_elf(&loc->elf_ex, !!interpreter, &arch_state); + retval = arch_check_elf(&loc->elf_ex, + !!interpreter, &loc->interp_elf_ex, + &arch_state); if (retval) goto out_free_dentry; From 43517cec9fba957b266b07724ed6920d4f973d63 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 13 Nov 2015 00:48:02 +0000 Subject: [PATCH 020/266] UPSTREAM: MIPS: ELF: Interpret the NAN2008 file header flag Handle the EF_MIPS_NAN2008 ELF file header flag and refuse execution where there is no support in the FPU for the NaN encoding mode requested by a binary invoked. Ensure that the setting of the bit in the binary matches one in any intepreter used. Set the thread's initial FCSR contents according to the value of the EF_MIPS_NAN2008. Set the values of the FCSR ABS2008 and NAN2008 bits both to the same value if possible, to take the approach taken with existing FPU hardware into account. As of now all implementations have both bits hardwired to the same value, that is both are fixed at 0 or both are fixed at 1, even though the architecture allows for implementations where the amount of control implemented with each of these two individual bits is independent of each other. Signed-off-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11479/ Signed-off-by: Ralf Baechle (cherry picked from commit 2b5e869ecfcb3112f7e1267cb0328f3ff6d49b18) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/elf.h | 9 ++++-- arch/mips/kernel/elf.c | 56 +++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 891013578490..3dba5d05830c 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -12,7 +12,6 @@ #include #include -#include #include /* ELF header e_flags defines. */ @@ -44,6 +43,7 @@ #define EF_MIPS_OPTIONS_FIRST 0x00000080 #define EF_MIPS_32BITMODE 0x00000100 #define EF_MIPS_FP64 0x00000200 +#define EF_MIPS_NAN2008 0x00000400 #define EF_MIPS_ABI 0x0000f000 #define EF_MIPS_ARCH 0xf0000000 @@ -305,7 +305,7 @@ do { \ \ current->thread.abi = &mips_abi; \ \ - current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31; \ + mips_set_personality_nan(state); \ } while (0) #endif /* CONFIG_32BIT */ @@ -367,7 +367,7 @@ do { \ else \ current->thread.abi = &mips_abi; \ \ - current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31; \ + mips_set_personality_nan(state); \ \ p = personality(current->personality); \ if (p != PER_LINUX32 && p != PER_LINUX) \ @@ -432,6 +432,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp); struct arch_elf_state { + int nan_2008; int fp_abi; int interp_fp_abi; int overall_fp_mode; @@ -440,6 +441,7 @@ struct arch_elf_state { #define MIPS_ABI_FP_UNKNOWN (-1) /* Unknown FP ABI (kernel internal) */ #define INIT_ARCH_ELF_STATE { \ + .nan_2008 = -1, \ .fp_abi = MIPS_ABI_FP_UNKNOWN, \ .interp_fp_abi = MIPS_ABI_FP_UNKNOWN, \ .overall_fp_mode = -1, \ @@ -451,6 +453,7 @@ extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf, extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr, struct arch_elf_state *state); +extern void mips_set_personality_nan(struct arch_elf_state *state); extern void mips_set_personality_fp(struct arch_elf_state *state); #endif /* _ASM_ELF_H */ diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index d0181383c791..33b4cef8ef20 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -11,6 +11,8 @@ #include #include +#include + /* FPU modes */ enum { FP_FRE, @@ -135,6 +137,10 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr, struct elf32_hdr e32; struct elf64_hdr e64; } *ehdr = _ehdr; + union { + struct elf32_hdr e32; + struct elf64_hdr e64; + } *iehdr = _interp_ehdr; struct mode_req prog_req, interp_req; int fp_abi, interp_fp_abi, abi0, abi1, max_abi; bool elf32; @@ -143,6 +149,32 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr, elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32; flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags; + /* + * Determine the NaN personality, reject the binary if no hardware + * support. Also ensure that any interpreter matches the executable. + */ + if (flags & EF_MIPS_NAN2008) { + if (cpu_has_nan_2008) + state->nan_2008 = 1; + else + return -ENOEXEC; + } else { + if (cpu_has_nan_legacy) + state->nan_2008 = 0; + else + return -ENOEXEC; + } + if (has_interpreter) { + bool ielf32; + u32 iflags; + + ielf32 = iehdr->e32.e_ident[EI_CLASS] == ELFCLASS32; + iflags = ielf32 ? iehdr->e32.e_flags : iehdr->e64.e_flags; + + if ((flags ^ iflags) & EF_MIPS_NAN2008) + return -ELIBBAD; + } + if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) return 0; @@ -266,3 +298,27 @@ void mips_set_personality_fp(struct arch_elf_state *state) BUG(); } } + +/* + * Select the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode + * in FCSR according to the ELF NaN personality. + */ +void mips_set_personality_nan(struct arch_elf_state *state) +{ + struct cpuinfo_mips *c = &boot_cpu_data; + struct task_struct *t = current; + + t->thread.fpu.fcr31 = c->fpu_csr31; + switch (state->nan_2008) { + case 0: + break; + case 1: + if (!(c->fpu_msk31 & FPU_CSR_NAN2008)) + t->thread.fpu.fcr31 |= FPU_CSR_NAN2008; + if (!(c->fpu_msk31 & FPU_CSR_ABS2008)) + t->thread.fpu.fcr31 |= FPU_CSR_ABS2008; + break; + default: + BUG(); + } +} From d73ca92398df3e7b42f95e39df13b6e7e23adb7b Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 13 Nov 2015 00:46:55 +0000 Subject: [PATCH 021/266] UPSTREAM: MIPS: Define the legacy-NaN and 2008-NaN features Allocate CPU option bits and define macros for the legacy-NaN and 2008-NaN IEEE Std 754 MIPS architecture features. Unconditionally mark the legacy-NaN feature as present across hardware and emulated floating-point configurations. Signed-off-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11475/ Signed-off-by: Ralf Baechle (cherry picked from commit 9519ef37a4a4e9c3c2d7d89ecbecfaf3c839208a) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/cpu-features.h | 7 +++++++ arch/mips/include/asm/cpu.h | 2 ++ arch/mips/kernel/cpu-probe.c | 2 ++ 3 files changed, 11 insertions(+) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index d1e04c943f5f..eeec8c8e2da2 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -414,4 +414,11 @@ # define cpu_has_small_pages (cpu_data[0].options & MIPS_CPU_SP) #endif +#ifndef cpu_has_nan_legacy +#define cpu_has_nan_legacy (cpu_data[0].options & MIPS_CPU_NAN_LEGACY) +#endif +#ifndef cpu_has_nan_2008 +#define cpu_has_nan_2008 (cpu_data[0].options & MIPS_CPU_NAN_2008) +#endif + #endif /* __ASM_CPU_FEATURES_H */ diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 82ad15f11049..a97ca97285ec 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -386,6 +386,8 @@ enum cpu_type_enum { #define MIPS_CPU_BP_GHIST 0x8000000000ull /* R12K+ Branch Prediction Global History */ #define MIPS_CPU_SP 0x10000000000ull /* Small (1KB) page support */ #define MIPS_CPU_FTLB 0x20000000000ull /* CPU has Fixed-page-size TLB */ +#define MIPS_CPU_NAN_LEGACY 0x40000000000ull /* Legacy NaN implemented */ +#define MIPS_CPU_NAN_2008 0x80000000000ull /* 2008 NaN implemented */ /* * CPU ASE encodings diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 6b9064499bd3..758b625d95e0 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -137,6 +137,7 @@ static void cpu_set_fpu_opts(struct cpuinfo_mips *c) } cpu_set_fpu_fcsr_mask(c); + c->options |= MIPS_CPU_NAN_LEGACY; } /* @@ -147,6 +148,7 @@ static void cpu_set_nofpu_opts(struct cpuinfo_mips *c) c->options &= ~MIPS_CPU_FPU; c->fpu_msk31 = mips_nofpu_msk31; + c->options |= MIPS_CPU_NAN_LEGACY; cpu_set_nofpu_id(c); } From 5dd3c3a431abd62207bd8dff868195e6c4249fdd Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 13 Nov 2015 00:48:15 +0000 Subject: [PATCH 022/266] UPSTREAM: MIPS: Determine the presence of IEEE Std 754-2008 features Determine the presence of and the amount of control available over IEEE Std 754-2008 features. In the case of a hardware FPU being used examine the FIR register for the presence of the HAS2008 bit and then the FCSR register for the writability of the ABS2008 and NAN2008 bits and the hardwired state of each of these bits if read-only. Update the initial FCSR contents used for threads and the FCSR writability mask accordingly. For full FPU emulation and MIPS32 or MIPS64 processors make the FCSR ABS2008 and NAN2008 bits writable. Signed-off-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11480/ Signed-off-by: Ralf Baechle (cherry picked from commit 93adeaf6dadcaed943a51ad9ea2d77e24e6d70a7) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/cpu-probe.c | 76 +++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 758b625d95e0..575102cab44a 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -98,6 +98,78 @@ static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c) c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mask; } +/* + * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes + * supported by FPU hardware. + */ +static void cpu_set_fpu_2008(struct cpuinfo_mips *c) +{ + if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | + MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | + MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { + unsigned long sr, fir, fcsr, fcsr0, fcsr1; + + sr = read_c0_status(); + __enable_fpu(FPU_AS_IS); + + fir = read_32bit_cp1_register(CP1_REVISION); + if (fir & MIPS_FPIR_HAS2008) { + fcsr = read_32bit_cp1_register(CP1_STATUS); + + fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); + write_32bit_cp1_register(CP1_STATUS, fcsr0); + fcsr0 = read_32bit_cp1_register(CP1_STATUS); + + fcsr1 = fcsr | FPU_CSR_ABS2008 | FPU_CSR_NAN2008; + write_32bit_cp1_register(CP1_STATUS, fcsr1); + fcsr1 = read_32bit_cp1_register(CP1_STATUS); + + write_32bit_cp1_register(CP1_STATUS, fcsr); + + if (!(fcsr0 & FPU_CSR_NAN2008)) + c->options |= MIPS_CPU_NAN_LEGACY; + if (fcsr1 & FPU_CSR_NAN2008) + c->options |= MIPS_CPU_NAN_2008; + + if ((fcsr0 ^ fcsr1) & FPU_CSR_ABS2008) + c->fpu_msk31 &= ~FPU_CSR_ABS2008; + else + c->fpu_csr31 |= fcsr & FPU_CSR_ABS2008; + + if ((fcsr0 ^ fcsr1) & FPU_CSR_NAN2008) + c->fpu_msk31 &= ~FPU_CSR_NAN2008; + else + c->fpu_csr31 |= fcsr & FPU_CSR_NAN2008; + } else { + c->options |= MIPS_CPU_NAN_LEGACY; + } + + write_c0_status(sr); + } else { + c->options |= MIPS_CPU_NAN_LEGACY; + } +} + +/* + * Set the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes + * for the FPU emulator. Clear the flags where required in case called + * from `fpu_disable', to override details obtained from FPU hardware. + */ +static void cpu_set_nofpu_2008(struct cpuinfo_mips *c) +{ + c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); + if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | + MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | + MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { + c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; + c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); + } else { + c->options &= ~MIPS_CPU_NAN_2008; + c->options |= MIPS_CPU_NAN_LEGACY; + c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; + } +} + /* * Set the FIR feature flags for the FPU emulator. */ @@ -137,7 +209,7 @@ static void cpu_set_fpu_opts(struct cpuinfo_mips *c) } cpu_set_fpu_fcsr_mask(c); - c->options |= MIPS_CPU_NAN_LEGACY; + cpu_set_fpu_2008(c); } /* @@ -148,7 +220,7 @@ static void cpu_set_nofpu_opts(struct cpuinfo_mips *c) c->options &= ~MIPS_CPU_FPU; c->fpu_msk31 = mips_nofpu_msk31; - c->options |= MIPS_CPU_NAN_LEGACY; + cpu_set_nofpu_2008(c); cpu_set_nofpu_id(c); } From 39dd84faa5ea2112f9377fcc5f9c6cb694b4bdbe Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 13 Nov 2015 00:48:29 +0000 Subject: [PATCH 023/266] UPSTREAM: MIPS: Add IEEE Std 754 conformance mode selection Add an `ieee754=' kernel parameter to control IEEE Std 754 conformance mode. Use separate flags copied from the respective CPU feature flags, and adjusted according to the conformance mode selected, to make binaries requesting individual NaN encoding modes accepted or rejected as needed. Update the initial setting for FCSR and, in the full FPU emulation mode, its read-only mask accordingly. Accept the mode selection requested for legacy processors as well. As with the EF_MIPS_NAN2008 ELF file header flag adjust both ABS2008 and NAN2008 bits at the same time, to match the choice made for hardware currently implemented. Signed-off-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11481/ Signed-off-by: Ralf Baechle (cherry picked from commit 503943e0e52bd3fbf014aa1d838ced37adb43121) Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 35 ++++++++++ arch/mips/include/asm/elf.h | 4 ++ arch/mips/kernel/cpu-probe.c | 105 +++++++++++++++++++++++++--- arch/mips/kernel/elf.c | 12 ++-- 4 files changed, 142 insertions(+), 14 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 9fee3a90deaa..e2072d12693b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1453,6 +1453,41 @@ bytes respectively. Such letter suffixes can also be entirely omitted. In such case C2/C3 won't be used again. idle=nomwait: Disable mwait for CPU C-states + ieee754= [MIPS] Select IEEE Std 754 conformance mode + Format: { strict | legacy | 2008 | relaxed } + Default: strict + + Choose which programs will be accepted for execution + based on the IEEE 754 NaN encoding(s) supported by + the FPU and the NaN encoding requested with the value + of an ELF file header flag individually set by each + binary. Hardware implementations are permitted to + support either or both of the legacy and the 2008 NaN + encoding mode. + + Available settings are as follows: + strict accept binaries that request a NaN encoding + supported by the FPU + legacy only accept legacy-NaN binaries, if supported + by the FPU + 2008 only accept 2008-NaN binaries, if supported + by the FPU + relaxed accept any binaries regardless of whether + supported by the FPU + + The FPU emulator is always able to support both NaN + encodings, so if no FPU hardware is present or it has + been disabled with 'nofpu', then the settings of + 'legacy' and '2008' strap the emulator accordingly, + 'relaxed' straps the emulator for both legacy-NaN and + 2008-NaN, whereas 'strict' enables legacy-NaN only on + legacy processors and both NaN encodings on MIPS32 or + MIPS64 CPUs. + + The setting for ABS.fmt/NEG.fmt instruction execution + mode generally follows that for the NaN encoding, + except where unsupported by hardware. + ignore_loglevel [KNL] Ignore loglevel setting - this will print /all/ kernel messages to the console. Useful for debugging. diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 3dba5d05830c..cefb7a596878 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -447,6 +447,10 @@ struct arch_elf_state { .overall_fp_mode = -1, \ } +/* Whether to accept legacy-NaN and 2008-NaN user binaries. */ +extern bool mips_use_nan_legacy; +extern bool mips_use_nan_2008; + extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf, bool is_interp, struct arch_elf_state *state); diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 575102cab44a..36fa414f2cc4 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -151,25 +151,108 @@ static void cpu_set_fpu_2008(struct cpuinfo_mips *c) } /* - * Set the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes - * for the FPU emulator. Clear the flags where required in case called - * from `fpu_disable', to override details obtained from FPU hardware. + * IEEE 754 conformance mode to use. Affects the NaN encoding and the + * ABS.fmt/NEG.fmt execution mode. + */ +static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT; + +/* + * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes + * to support by the FPU emulator according to the IEEE 754 conformance + * mode selected. Note that "relaxed" straps the emulator so that it + * allows 2008-NaN binaries even for legacy processors. */ static void cpu_set_nofpu_2008(struct cpuinfo_mips *c) { + c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY); c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { - c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; - c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); - } else { - c->options &= ~MIPS_CPU_NAN_2008; + c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); + + switch (ieee754) { + case STRICT: + if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | + MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | + MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { + c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; + } else { + c->options |= MIPS_CPU_NAN_LEGACY; + c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; + } + break; + case LEGACY: c->options |= MIPS_CPU_NAN_LEGACY; c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; + break; + case STD2008: + c->options |= MIPS_CPU_NAN_2008; + c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; + c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; + break; + case RELAXED: + c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; + break; } } +/* + * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode + * according to the "ieee754=" parameter. + */ +static void cpu_set_nan_2008(struct cpuinfo_mips *c) +{ + switch (ieee754) { + case STRICT: + mips_use_nan_legacy = !!cpu_has_nan_legacy; + mips_use_nan_2008 = !!cpu_has_nan_2008; + break; + case LEGACY: + mips_use_nan_legacy = !!cpu_has_nan_legacy; + mips_use_nan_2008 = !cpu_has_nan_legacy; + break; + case STD2008: + mips_use_nan_legacy = !cpu_has_nan_2008; + mips_use_nan_2008 = !!cpu_has_nan_2008; + break; + case RELAXED: + mips_use_nan_legacy = true; + mips_use_nan_2008 = true; + break; + } +} + +/* + * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override + * settings: + * + * strict: accept binaries that request a NaN encoding supported by the FPU + * legacy: only accept legacy-NaN binaries + * 2008: only accept 2008-NaN binaries + * relaxed: accept any binaries regardless of whether supported by the FPU + */ +static int __init ieee754_setup(char *s) +{ + if (!s) + return -1; + else if (!strcmp(s, "strict")) + ieee754 = STRICT; + else if (!strcmp(s, "legacy")) + ieee754 = LEGACY; + else if (!strcmp(s, "2008")) + ieee754 = STD2008; + else if (!strcmp(s, "relaxed")) + ieee754 = RELAXED; + else + return -1; + + if (!(boot_cpu_data.options & MIPS_CPU_FPU)) + cpu_set_nofpu_2008(&boot_cpu_data); + cpu_set_nan_2008(&boot_cpu_data); + + return 0; +} + +early_param("ieee754", ieee754_setup); + /* * Set the FIR feature flags for the FPU emulator. */ @@ -210,6 +293,7 @@ static void cpu_set_fpu_opts(struct cpuinfo_mips *c) cpu_set_fpu_fcsr_mask(c); cpu_set_fpu_2008(c); + cpu_set_nan_2008(c); } /* @@ -221,6 +305,7 @@ static void cpu_set_nofpu_opts(struct cpuinfo_mips *c) c->fpu_msk31 = mips_nofpu_msk31; cpu_set_nofpu_2008(c); + cpu_set_nan_2008(c); cpu_set_nofpu_id(c); } diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 33b4cef8ef20..d09cf9b0e89f 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -13,6 +13,10 @@ #include +/* Whether to accept legacy-NaN and 2008-NaN user binaries. */ +bool mips_use_nan_legacy; +bool mips_use_nan_2008; + /* FPU modes */ enum { FP_FRE, @@ -150,16 +154,16 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr, flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags; /* - * Determine the NaN personality, reject the binary if no hardware - * support. Also ensure that any interpreter matches the executable. + * Determine the NaN personality, reject the binary if not allowed. + * Also ensure that any interpreter matches the executable. */ if (flags & EF_MIPS_NAN2008) { - if (cpu_has_nan_2008) + if (mips_use_nan_2008) state->nan_2008 = 1; else return -ENOEXEC; } else { - if (cpu_has_nan_legacy) + if (mips_use_nan_legacy) state->nan_2008 = 0; else return -ENOEXEC; From b38614bbdfce1135d8c20b61a37851673608b985 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 8 Jul 2016 11:06:20 +0100 Subject: [PATCH 024/266] UPSTREAM: MIPS: non-exec stack & heap when non-exec PT_GNU_STACK is present The stack and heap have both been executable by default on MIPS until now. This patch changes the default to be non-executable, but only for ELF binaries with a non-executable PT_GNU_STACK header present. This does apply to both the heap & the stack, despite the name PT_GNU_STACK, and this matches the behaviour of other architectures like ARM & x86. Current MIPS toolchains do not produce the PT_GNU_STACK header, which means that we can rely upon this patch not changing the behaviour of existing binaries. The new default will only take effect for newly compiled binaries once toolchains are updated to support PT_GNU_STACK, and since those binaries are newly compiled they can be compiled expecting the change in default behaviour. Again this matches the way in which the ARM & x86 architectures handled their implementations of non-executable memory. Signed-off-by: Paul Burton Cc: Leonid Yegoshin Cc: Maciej Rozycki Cc: Faraz Shahbazker Cc: Raghu Gandham Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13765/ Signed-off-by: Ralf Baechle (cherry picked from commit 1a770b85c1f1c1ee37afd7cef5237ffc4c970f04) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/elf.h | 3 +++ arch/mips/include/asm/page.h | 6 ++++-- arch/mips/kernel/elf.c | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index cefb7a596878..dc72fdc73719 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -460,4 +460,7 @@ extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr, extern void mips_set_personality_nan(struct arch_elf_state *state); extern void mips_set_personality_fp(struct arch_elf_state *state); +#define elf_read_implies_exec(ex, stk) mips_elf_read_implies_exec(&(ex), stk) +extern int mips_elf_read_implies_exec(void *elf_ex, int exstack); + #endif /* _ASM_ELF_H */ diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index 21ed7150fec3..74cb004c2868 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -229,8 +229,10 @@ extern int __virt_addr_valid(const volatile void *kaddr); #define virt_addr_valid(kaddr) \ __virt_addr_valid((const volatile void *) (kaddr)) -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_DATA_DEFAULT_FLAGS \ + (VM_READ | VM_WRITE | \ + ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #define UNCAC_ADDR(addr) ((addr) - PAGE_OFFSET + UNCAC_BASE) #define CAC_ADDR(addr) ((addr) - UNCAC_BASE + PAGE_OFFSET) diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index d09cf9b0e89f..32ce422a6886 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -8,9 +8,12 @@ * option) any later version. */ +#include #include +#include #include +#include #include /* Whether to accept legacy-NaN and 2008-NaN user binaries. */ @@ -326,3 +329,19 @@ void mips_set_personality_nan(struct arch_elf_state *state) BUG(); } } + +int mips_elf_read_implies_exec(void *elf_ex, int exstack) +{ + if (exstack != EXSTACK_DISABLE_X) { + /* The binary doesn't request a non-executable stack */ + return 1; + } + + if (!cpu_has_rixi) { + /* The CPU doesn't support non-executable memory */ + return 1; + } + + return 0; +} +EXPORT_SYMBOL(mips_elf_read_implies_exec); From 71b31a91e393b454ecd5931fa474801b878069fa Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 13 Nov 2015 00:47:08 +0000 Subject: [PATCH 025/266] UPSTREAM: MIPS: math-emu: Add IEEE Std 754-2008 ABS.fmt and NEG.fmt emulation Implement IEEE Std 754-2008 non-arithmetic ABS.fmt and NEG.fmt emulation wired to the state of the FCSR.ABS2008 bit. In the non-arithmetic mode the sign bit is altered according to the operation requested regardless of the datum encoded in the input operand, no other bits are changed, the resulting bit pattern is written to the output operand and no exception is ever signalled. Signed-off-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11476/ Signed-off-by: Ralf Baechle (cherry picked from commit 198f70589e3c0f0f50da646152443787e959228f) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_simple.c | 38 ++++++++++++++++++++++------------ arch/mips/math-emu/sp_simple.c | 38 ++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/arch/mips/math-emu/dp_simple.c b/arch/mips/math-emu/dp_simple.c index 926d56bf37f2..eb96485ed939 100644 --- a/arch/mips/math-emu/dp_simple.c +++ b/arch/mips/math-emu/dp_simple.c @@ -23,27 +23,39 @@ union ieee754dp ieee754dp_neg(union ieee754dp x) { - unsigned int oldrm; union ieee754dp y; - oldrm = ieee754_csr.rm; - ieee754_csr.rm = FPU_CSR_RD; - y = ieee754dp_sub(ieee754dp_zero(0), x); - ieee754_csr.rm = oldrm; + if (ieee754_csr.abs2008) { + y = x; + DPSIGN(y) = !DPSIGN(x); + } else { + unsigned int oldrm; + + oldrm = ieee754_csr.rm; + ieee754_csr.rm = FPU_CSR_RD; + y = ieee754dp_sub(ieee754dp_zero(0), x); + ieee754_csr.rm = oldrm; + } return y; } union ieee754dp ieee754dp_abs(union ieee754dp x) { - unsigned int oldrm; union ieee754dp y; - oldrm = ieee754_csr.rm; - ieee754_csr.rm = FPU_CSR_RD; - if (DPSIGN(x)) - y = ieee754dp_sub(ieee754dp_zero(0), x); - else - y = ieee754dp_add(ieee754dp_zero(0), x); - ieee754_csr.rm = oldrm; + if (ieee754_csr.abs2008) { + y = x; + DPSIGN(y) = 0; + } else { + unsigned int oldrm; + + oldrm = ieee754_csr.rm; + ieee754_csr.rm = FPU_CSR_RD; + if (DPSIGN(x)) + y = ieee754dp_sub(ieee754dp_zero(0), x); + else + y = ieee754dp_add(ieee754dp_zero(0), x); + ieee754_csr.rm = oldrm; + } return y; } diff --git a/arch/mips/math-emu/sp_simple.c b/arch/mips/math-emu/sp_simple.c index c50e9451f2d2..756c9cf2dfd2 100644 --- a/arch/mips/math-emu/sp_simple.c +++ b/arch/mips/math-emu/sp_simple.c @@ -23,27 +23,39 @@ union ieee754sp ieee754sp_neg(union ieee754sp x) { - unsigned int oldrm; union ieee754sp y; - oldrm = ieee754_csr.rm; - ieee754_csr.rm = FPU_CSR_RD; - y = ieee754sp_sub(ieee754sp_zero(0), x); - ieee754_csr.rm = oldrm; + if (ieee754_csr.abs2008) { + y = x; + SPSIGN(y) = !SPSIGN(x); + } else { + unsigned int oldrm; + + oldrm = ieee754_csr.rm; + ieee754_csr.rm = FPU_CSR_RD; + y = ieee754sp_sub(ieee754sp_zero(0), x); + ieee754_csr.rm = oldrm; + } return y; } union ieee754sp ieee754sp_abs(union ieee754sp x) { - unsigned int oldrm; union ieee754sp y; - oldrm = ieee754_csr.rm; - ieee754_csr.rm = FPU_CSR_RD; - if (SPSIGN(x)) - y = ieee754sp_sub(ieee754sp_zero(0), x); - else - y = ieee754sp_add(ieee754sp_zero(0), x); - ieee754_csr.rm = oldrm; + if (ieee754_csr.abs2008) { + y = x; + SPSIGN(y) = 0; + } else { + unsigned int oldrm; + + oldrm = ieee754_csr.rm; + ieee754_csr.rm = FPU_CSR_RD; + if (SPSIGN(x)) + y = ieee754sp_sub(ieee754sp_zero(0), x); + else + y = ieee754sp_add(ieee754sp_zero(0), x); + ieee754_csr.rm = oldrm; + } return y; } From bb61ba21369b4d968f351de8379e895809feca80 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 13 Nov 2015 00:47:28 +0000 Subject: [PATCH 026/266] UPSTREAM: MIPS: math-emu: Add IEEE Std 754-2008 NaN encoding emulation Implement IEEE Std 754-2008 NaN encoding wired to the state of the FCSR.NAN2008 bit. Make the interpretation of the quiet bit in NaN data as follows: * in the legacy mode originally defined by the MIPS architecture the value of 1 denotes an sNaN whereas the value of 0 denotes a qNaN, * in the 2008 mode introduced with revision 5 of the MIPS architecture the value of 0 denotes an sNaN whereas the value of 1 denotes a qNaN, following the definition of the preferred NaN encoding introduced with IEEE Std 754-2008. In the 2008 mode, following the requirement of the said standard, quiet an sNaN where needed by setting the quiet bit to 1 and leaving all the NaN payload bits unchanged. Update format conversion operations according to the rules set by IEEE Std 754-2008 and the MIPS architecture. Specifically: * propagate NaN payload bits through conversions between floating-point formats such that as much information as possible is preserved and specifically a conversion from a narrower format to a wider format and then back to the original format does not change a qNaN payload in any way, * conversions from a floating-point to an integer format where the source is a NaN, infinity or a value that would convert to an integer outside the range of the result format produce, under the default exception handling, the respective values defined by the MIPS architecture. In full FPU emulation set the FIR.HAS2008 bit to 1, however do not make any further FCSR bits writable. Signed-off-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11477/ Signed-off-by: Ralf Baechle (cherry picked from commit 90d53a91fbd0c5a0882c29fa4279a3d2d700c76d) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/cpu-probe.c | 2 ++ arch/mips/math-emu/dp_tint.c | 9 ++++--- arch/mips/math-emu/dp_tlong.c | 9 ++++--- arch/mips/math-emu/ieee754.c | 6 +++-- arch/mips/math-emu/ieee754.h | 42 +++++++++++++++++++++++---------- arch/mips/math-emu/ieee754dp.c | 12 ++++++++-- arch/mips/math-emu/ieee754int.h | 12 +++++----- arch/mips/math-emu/ieee754sp.c | 12 ++++++++-- arch/mips/math-emu/sp_fdp.c | 13 ++++++---- arch/mips/math-emu/sp_tint.c | 9 ++++--- arch/mips/math-emu/sp_tlong.c | 9 ++++--- 11 files changed, 93 insertions(+), 42 deletions(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 36fa414f2cc4..b725b713b9f8 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -268,6 +268,8 @@ static void cpu_set_nofpu_id(struct cpuinfo_mips *c) if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W; + if (c->options & MIPS_CPU_NAN_2008) + value |= MIPS_FPIR_HAS2008; c->fpu_id = value; } diff --git a/arch/mips/math-emu/dp_tint.c b/arch/mips/math-emu/dp_tint.c index 6ffc336c530e..f3985617ce31 100644 --- a/arch/mips/math-emu/dp_tint.c +++ b/arch/mips/math-emu/dp_tint.c @@ -38,10 +38,13 @@ int ieee754dp_tint(union ieee754dp x) switch (xc) { case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754si_indef(); + case IEEE754_CLASS_INF: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754si_overflow(xs); + case IEEE754_CLASS_ZERO: return 0; @@ -53,7 +56,7 @@ int ieee754dp_tint(union ieee754dp x) /* Set invalid. We will only use overflow for floating point overflow */ ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754si_indef(); + return ieee754si_overflow(xs); } /* oh gawd */ if (xe > DP_FBITS) { @@ -93,7 +96,7 @@ int ieee754dp_tint(union ieee754dp x) if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) { /* This can happen after rounding */ ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754si_indef(); + return ieee754si_overflow(xs); } if (round || sticky) ieee754_setcx(IEEE754_INEXACT); diff --git a/arch/mips/math-emu/dp_tlong.c b/arch/mips/math-emu/dp_tlong.c index 9cdc145b75e0..748fa10ed4cf 100644 --- a/arch/mips/math-emu/dp_tlong.c +++ b/arch/mips/math-emu/dp_tlong.c @@ -38,10 +38,13 @@ s64 ieee754dp_tlong(union ieee754dp x) switch (xc) { case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754di_indef(); + case IEEE754_CLASS_INF: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754di_overflow(xs); + case IEEE754_CLASS_ZERO: return 0; @@ -56,7 +59,7 @@ s64 ieee754dp_tlong(union ieee754dp x) /* Set invalid. We will only use overflow for floating point overflow */ ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754di_indef(); + return ieee754di_overflow(xs); } /* oh gawd */ if (xe > DP_FBITS) { @@ -97,7 +100,7 @@ s64 ieee754dp_tlong(union ieee754dp x) if ((xm >> 63) != 0) { /* This can happen after rounding */ ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754di_indef(); + return ieee754di_overflow(xs); } if (round || sticky) ieee754_setcx(IEEE754_INEXACT); diff --git a/arch/mips/math-emu/ieee754.c b/arch/mips/math-emu/ieee754.c index 8e97acbbe22c..e16ae7b75dbb 100644 --- a/arch/mips/math-emu/ieee754.c +++ b/arch/mips/math-emu/ieee754.c @@ -59,7 +59,8 @@ const union ieee754dp __ieee754dp_spcvals[] = { DPCNST(1, 3, 0x4000000000000ULL), /* - 10.0 */ DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL), /* + infinity */ DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL), /* - infinity */ - DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL), /* + indef quiet Nan */ + DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL), /* + ind legacy qNaN */ + DPCNST(0, DP_EMAX + 1, 0x8000000000000ULL), /* + indef 2008 qNaN */ DPCNST(0, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* + max */ DPCNST(1, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* - max */ DPCNST(0, DP_EMIN, 0x0000000000000ULL), /* + min normal */ @@ -82,7 +83,8 @@ const union ieee754sp __ieee754sp_spcvals[] = { SPCNST(1, 3, 0x200000), /* - 10.0 */ SPCNST(0, SP_EMAX + 1, 0x000000), /* + infinity */ SPCNST(1, SP_EMAX + 1, 0x000000), /* - infinity */ - SPCNST(0, SP_EMAX + 1, 0x3FFFFF), /* + indef quiet Nan */ + SPCNST(0, SP_EMAX + 1, 0x3FFFFF), /* + indef legacy quiet NaN */ + SPCNST(0, SP_EMAX + 1, 0x400000), /* + indef 2008 quiet NaN */ SPCNST(0, SP_EMAX, 0x7FFFFF), /* + max normal */ SPCNST(1, SP_EMAX, 0x7FFFFF), /* - max normal */ SPCNST(0, SP_EMIN, 0x000000), /* + min normal */ diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index df94720714c7..d3be351aed15 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -221,15 +221,16 @@ union ieee754dp ieee754dp_dump(char *s, union ieee754dp x); #define IEEE754_SPCVAL_NTEN 5 /* -10.0 */ #define IEEE754_SPCVAL_PINFINITY 6 /* +inf */ #define IEEE754_SPCVAL_NINFINITY 7 /* -inf */ -#define IEEE754_SPCVAL_INDEF 8 /* quiet NaN */ -#define IEEE754_SPCVAL_PMAX 9 /* +max norm */ -#define IEEE754_SPCVAL_NMAX 10 /* -max norm */ -#define IEEE754_SPCVAL_PMIN 11 /* +min norm */ -#define IEEE754_SPCVAL_NMIN 12 /* -min norm */ -#define IEEE754_SPCVAL_PMIND 13 /* +min denorm */ -#define IEEE754_SPCVAL_NMIND 14 /* -min denorm */ -#define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ -#define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ +#define IEEE754_SPCVAL_INDEF_LEG 8 /* legacy quiet NaN */ +#define IEEE754_SPCVAL_INDEF_2008 9 /* IEEE 754-2008 quiet NaN */ +#define IEEE754_SPCVAL_PMAX 10 /* +max norm */ +#define IEEE754_SPCVAL_NMAX 11 /* -max norm */ +#define IEEE754_SPCVAL_PMIN 12 /* +min norm */ +#define IEEE754_SPCVAL_NMIN 13 /* -min norm */ +#define IEEE754_SPCVAL_PMIND 14 /* +min denorm */ +#define IEEE754_SPCVAL_NMIND 15 /* -min denorm */ +#define IEEE754_SPCVAL_P1E31 16 /* + 1.0e31 */ +#define IEEE754_SPCVAL_P1E63 17 /* + 1.0e63 */ extern const union ieee754dp __ieee754dp_spcvals[]; extern const union ieee754sp __ieee754sp_spcvals[]; @@ -243,7 +244,8 @@ extern const union ieee754sp __ieee754sp_spcvals[]; #define ieee754dp_zero(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) #define ieee754dp_one(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) #define ieee754dp_ten(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) -#define ieee754dp_indef() (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF]) +#define ieee754dp_indef() (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \ + ieee754_csr.nan2008]) #define ieee754dp_max(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) #define ieee754dp_min(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) #define ieee754dp_mind(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) @@ -254,7 +256,8 @@ extern const union ieee754sp __ieee754sp_spcvals[]; #define ieee754sp_zero(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) #define ieee754sp_one(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) #define ieee754sp_ten(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) -#define ieee754sp_indef() (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF]) +#define ieee754sp_indef() (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \ + ieee754_csr.nan2008]) #define ieee754sp_max(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) #define ieee754sp_min(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) #define ieee754sp_mind(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) @@ -266,12 +269,25 @@ extern const union ieee754sp __ieee754sp_spcvals[]; */ static inline int ieee754si_indef(void) { - return INT_MAX; + return ieee754_csr.nan2008 ? 0 : INT_MAX; } static inline s64 ieee754di_indef(void) { - return S64_MAX; + return ieee754_csr.nan2008 ? 0 : S64_MAX; +} + +/* + * Overflow integer value + */ +static inline int ieee754si_overflow(int xs) +{ + return ieee754_csr.nan2008 && xs ? INT_MIN : INT_MAX; +} + +static inline s64 ieee754di_overflow(int xs) +{ + return ieee754_csr.nan2008 && xs ? S64_MIN : S64_MAX; } /* result types for xctx.rt */ diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c index 522d843f2ffd..ad3c73436777 100644 --- a/arch/mips/math-emu/ieee754dp.c +++ b/arch/mips/math-emu/ieee754dp.c @@ -37,8 +37,11 @@ static inline int ieee754dp_isnan(union ieee754dp x) static inline int ieee754dp_issnan(union ieee754dp x) { + int qbit; + assert(ieee754dp_isnan(x)); - return (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1); + qbit = (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1); + return ieee754_csr.nan2008 ^ qbit; } @@ -51,7 +54,12 @@ union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r) assert(ieee754dp_issnan(r)); ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754dp_indef(); + if (ieee754_csr.nan2008) + DPMANT(r) |= DP_MBIT(DP_FBITS - 1); + else + r = ieee754dp_indef(); + + return r; } static u64 ieee754dp_get_rounding(int sn, u64 xm) diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index 6383e2c5c1ad..ed7bb277b3e0 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -63,10 +63,10 @@ static inline int ieee754_class_nan(int xc) if (ve == SP_EMAX+1+SP_EBIAS) { \ if (vm == 0) \ vc = IEEE754_CLASS_INF; \ - else if (vm & SP_MBIT(SP_FBITS-1)) \ - vc = IEEE754_CLASS_SNAN; \ - else \ + else if (ieee754_csr.nan2008 ^ !(vm & SP_MBIT(SP_FBITS - 1))) \ vc = IEEE754_CLASS_QNAN; \ + else \ + vc = IEEE754_CLASS_SNAN; \ } else if (ve == SP_EMIN-1+SP_EBIAS) { \ if (vm) { \ ve = SP_EMIN; \ @@ -97,10 +97,10 @@ static inline int ieee754_class_nan(int xc) if (ve == DP_EMAX+1+DP_EBIAS) { \ if (vm == 0) \ vc = IEEE754_CLASS_INF; \ - else if (vm & DP_MBIT(DP_FBITS-1)) \ - vc = IEEE754_CLASS_SNAN; \ - else \ + else if (ieee754_csr.nan2008 ^ !(vm & DP_MBIT(DP_FBITS - 1))) \ vc = IEEE754_CLASS_QNAN; \ + else \ + vc = IEEE754_CLASS_SNAN; \ } else if (ve == DP_EMIN-1+DP_EBIAS) { \ if (vm) { \ ve = DP_EMIN; \ diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index ca8e35e33bf7..def00ffc50fc 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c @@ -37,8 +37,11 @@ static inline int ieee754sp_isnan(union ieee754sp x) static inline int ieee754sp_issnan(union ieee754sp x) { + int qbit; + assert(ieee754sp_isnan(x)); - return SPMANT(x) & SP_MBIT(SP_FBITS - 1); + qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_FBITS - 1); + return ieee754_csr.nan2008 ^ qbit; } @@ -51,7 +54,12 @@ union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r) assert(ieee754sp_issnan(r)); ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754sp_indef(); + if (ieee754_csr.nan2008) + SPMANT(r) |= SP_MBIT(SP_FBITS - 1); + else + r = ieee754sp_indef(); + + return r; } static unsigned ieee754sp_get_rounding(int sn, unsigned xm) diff --git a/arch/mips/math-emu/sp_fdp.c b/arch/mips/math-emu/sp_fdp.c index 3797148893ad..5060e8fdcb0b 100644 --- a/arch/mips/math-emu/sp_fdp.c +++ b/arch/mips/math-emu/sp_fdp.c @@ -44,13 +44,16 @@ union ieee754sp ieee754sp_fdp(union ieee754dp x) switch (xc) { case IEEE754_CLASS_SNAN: - return ieee754sp_nanxcpt(ieee754sp_nan_fdp(xs, xm)); - + x = ieee754dp_nanxcpt(x); + EXPLODEXDP; + /* Fall through. */ case IEEE754_CLASS_QNAN: y = ieee754sp_nan_fdp(xs, xm); - EXPLODEYSP; - if (!ieee754_class_nan(yc)) - y = ieee754sp_indef(); + if (!ieee754_csr.nan2008) { + EXPLODEYSP; + if (!ieee754_class_nan(yc)) + y = ieee754sp_indef(); + } return y; case IEEE754_CLASS_INF: diff --git a/arch/mips/math-emu/sp_tint.c b/arch/mips/math-emu/sp_tint.c index 091299a31798..f4b4cabfe2e1 100644 --- a/arch/mips/math-emu/sp_tint.c +++ b/arch/mips/math-emu/sp_tint.c @@ -38,10 +38,13 @@ int ieee754sp_tint(union ieee754sp x) switch (xc) { case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754si_indef(); + case IEEE754_CLASS_INF: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754si_overflow(xs); + case IEEE754_CLASS_ZERO: return 0; @@ -56,7 +59,7 @@ int ieee754sp_tint(union ieee754sp x) /* Set invalid. We will only use overflow for floating point overflow */ ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754si_indef(); + return ieee754si_overflow(xs); } /* oh gawd */ if (xe > SP_FBITS) { @@ -97,7 +100,7 @@ int ieee754sp_tint(union ieee754sp x) if ((xm >> 31) != 0) { /* This can happen after rounding */ ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754si_indef(); + return ieee754si_overflow(xs); } if (round || sticky) ieee754_setcx(IEEE754_INEXACT); diff --git a/arch/mips/math-emu/sp_tlong.c b/arch/mips/math-emu/sp_tlong.c index 9f3c742c1cea..a2450c7e452a 100644 --- a/arch/mips/math-emu/sp_tlong.c +++ b/arch/mips/math-emu/sp_tlong.c @@ -39,10 +39,13 @@ s64 ieee754sp_tlong(union ieee754sp x) switch (xc) { case IEEE754_CLASS_SNAN: case IEEE754_CLASS_QNAN: - case IEEE754_CLASS_INF: ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754di_indef(); + case IEEE754_CLASS_INF: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754di_overflow(xs); + case IEEE754_CLASS_ZERO: return 0; @@ -57,7 +60,7 @@ s64 ieee754sp_tlong(union ieee754sp x) /* Set invalid. We will only use overflow for floating point overflow */ ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754di_indef(); + return ieee754di_overflow(xs); } /* oh gawd */ if (xe > SP_FBITS) { @@ -94,7 +97,7 @@ s64 ieee754sp_tlong(union ieee754sp x) if ((xm >> 63) != 0) { /* This can happen after rounding */ ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754di_indef(); + return ieee754di_overflow(xs); } if (round || sticky) ieee754_setcx(IEEE754_INEXACT); From 0c23219c3a7c0f3188d5584d9cebf2bcc0b65591 Mon Sep 17 00:00:00 2001 From: Adam Buchbinder Date: Thu, 25 Feb 2016 00:44:58 -0800 Subject: [PATCH 027/266] UPSTREAM: MIPS: Fix misspellings in comments. Signed-off-by: Adam Buchbinder Cc: linux-mips@linux-mips.org Cc: trivial@kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12617/ Signed-off-by: Ralf Baechle (cherry picked from commit 92a76f6d8545efc67f03278009e9a828bdad3419) Signed-off-by: Greg Kroah-Hartman --- arch/mips/alchemy/common/dbdma.c | 4 ++-- .../executive/cvmx-interrupt-decodes.c | 14 +++++++------- arch/mips/cavium-octeon/executive/cvmx-pko.c | 2 +- arch/mips/cavium-octeon/smp.c | 2 +- arch/mips/dec/int-handler.S | 2 +- arch/mips/fw/arc/memory.c | 2 +- .../asm/mach-cavium-octeon/kernel-entry-init.h | 2 +- .../asm/mach-generic/kernel-entry-init.h | 2 +- arch/mips/include/asm/mach-ip27/irq.h | 2 +- .../include/asm/mach-ip27/kernel-entry-init.h | 2 +- arch/mips/include/asm/mach-jz4740/gpio.h | 2 +- arch/mips/include/asm/mips-cm.h | 2 +- arch/mips/include/asm/octeon/cvmx-config.h | 2 +- arch/mips/include/asm/octeon/cvmx.h | 2 +- arch/mips/include/asm/pci/bridge.h | 18 +++++++++--------- arch/mips/include/asm/sgi/hpc3.h | 2 +- arch/mips/include/asm/sgiarcs.h | 4 ++-- arch/mips/include/asm/sn/ioc3.h | 2 +- arch/mips/include/asm/sn/sn0/hubio.h | 2 +- arch/mips/include/asm/uaccess.h | 2 +- arch/mips/kernel/mips-cm.c | 2 +- arch/mips/kernel/perf_event_mipsxx.c | 2 +- arch/mips/kernel/pm-cps.c | 2 +- arch/mips/kernel/process.c | 2 +- arch/mips/kernel/traps.c | 2 +- arch/mips/kvm/tlb.c | 2 +- arch/mips/kvm/trap_emul.c | 2 +- arch/mips/math-emu/ieee754dp.c | 6 +++--- arch/mips/math-emu/ieee754sp.c | 6 +++--- arch/mips/mm/sc-ip22.c | 2 +- arch/mips/mm/tlbex.c | 2 +- arch/mips/sgi-ip27/ip27-memory.c | 2 +- 32 files changed, 52 insertions(+), 52 deletions(-) diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c index 745695db5ba0..f2f264b5aafe 100644 --- a/arch/mips/alchemy/common/dbdma.c +++ b/arch/mips/alchemy/common/dbdma.c @@ -261,7 +261,7 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, au1x_dma_chan_t *cp; /* - * We do the intialization on the first channel allocation. + * We do the initialization on the first channel allocation. * We have to wait because of the interrupt handler initialization * which can't be done successfully during board set up. */ @@ -964,7 +964,7 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr) dp->dscr_source1 = dscr->dscr_source1; dp->dscr_cmd1 = dscr->dscr_cmd1; nbytes = dscr->dscr_cmd1; - /* Allow the caller to specifiy if an interrupt is generated */ + /* Allow the caller to specify if an interrupt is generated */ dp->dscr_cmd0 &= ~DSCR_CMD0_IE; dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V; ctp->chan_ptr->ddma_dbell = 0; diff --git a/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c b/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c index e59d1b79f24c..2f415d9d0f3c 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c +++ b/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c @@ -68,7 +68,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block) gmx_rx_int_en.s.pause_drp = 1; /* Skipping gmx_rx_int_en.s.reserved_16_18 */ /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.coldet = 1; // Collision detect */ /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ @@ -89,7 +89,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block) /*gmx_rx_int_en.s.phy_spd = 1; */ /*gmx_rx_int_en.s.phy_link = 1; */ /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.coldet = 1; // Collision detect */ /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ @@ -112,7 +112,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block) /*gmx_rx_int_en.s.phy_spd = 1; */ /*gmx_rx_int_en.s.phy_link = 1; */ /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.coldet = 1; // Collision detect */ /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ @@ -134,7 +134,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block) /*gmx_rx_int_en.s.phy_spd = 1; */ /*gmx_rx_int_en.s.phy_link = 1; */ /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.coldet = 1; // Collision detect */ /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ @@ -156,7 +156,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block) /*gmx_rx_int_en.s.phy_spd = 1; */ /*gmx_rx_int_en.s.phy_link = 1; */ /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.coldet = 1; // Collision detect */ /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ @@ -179,7 +179,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block) /*gmx_rx_int_en.s.phy_spd = 1; */ /*gmx_rx_int_en.s.phy_link = 1; */ /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.coldet = 1; // Collision detect */ /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ @@ -209,7 +209,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block) gmx_rx_int_en.s.pause_drp = 1; /* Skipping gmx_rx_int_en.s.reserved_16_18 */ /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.coldet = 1; // Collision detect */ /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ diff --git a/arch/mips/cavium-octeon/executive/cvmx-pko.c b/arch/mips/cavium-octeon/executive/cvmx-pko.c index 87be167a7a6a..676fab50dd2b 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-pko.c +++ b/arch/mips/cavium-octeon/executive/cvmx-pko.c @@ -189,7 +189,7 @@ void cvmx_pko_initialize_global(void) /* * Set the size of the PKO command buffers to an odd number of * 64bit words. This allows the normal two word send to stay - * aligned and never span a comamnd word buffer. + * aligned and never span a command word buffer. */ config.u64 = 0; config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL; diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index b7fa9ae28c36..42412ba0f3bf 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -331,7 +331,7 @@ static int octeon_update_boot_vector(unsigned int cpu) } if (!(avail_coremask & (1 << coreid))) { - /* core not available, assume, that catched by simple-executive */ + /* core not available, assume, that caught by simple-executive */ cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid); cvmx_write_csr(CVMX_CIU_PP_RST, 0); } diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index 554d1da97743..1910223a9c02 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -5,7 +5,7 @@ * Written by Ralf Baechle and Andreas Busse, modified for DECstation * support by Paul Antoine and Harald Koerfgen. * - * completly rewritten: + * completely rewritten: * Copyright (C) 1998 Harald Koerfgen * * Rewritten extensively for controller-driven IRQ support diff --git a/arch/mips/fw/arc/memory.c b/arch/mips/fw/arc/memory.c index 5537b94572b2..0d75b5a0bad4 100644 --- a/arch/mips/fw/arc/memory.c +++ b/arch/mips/fw/arc/memory.c @@ -9,7 +9,7 @@ * PROM library functions for acquiring/using memory descriptors given to us * from the ARCS firmware. This is only used when CONFIG_ARC_MEMORY is set * because on some machines like SGI IP27 the ARC memory configuration data - * completly bogus and alternate easier to use mechanisms are available. + * completely bogus and alternate easier to use mechanisms are available. */ #include #include diff --git a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h index cf92fe733995..c4873e8594ef 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h @@ -141,7 +141,7 @@ octeon_main_processor: .endm /* - * Do SMP slave processor setup necessary before we can savely execute C code. + * Do SMP slave processor setup necessary before we can safely execute C code. */ .macro smp_slave_setup .endm diff --git a/arch/mips/include/asm/mach-generic/kernel-entry-init.h b/arch/mips/include/asm/mach-generic/kernel-entry-init.h index 13b0751b010a..a229297c880b 100644 --- a/arch/mips/include/asm/mach-generic/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-generic/kernel-entry-init.h @@ -16,7 +16,7 @@ .endm /* - * Do SMP slave processor setup necessary before we can savely execute C code. + * Do SMP slave processor setup necessary before we can safely execute C code. */ .macro smp_slave_setup .endm diff --git a/arch/mips/include/asm/mach-ip27/irq.h b/arch/mips/include/asm/mach-ip27/irq.h index cf4384bfa846..b0b7261ff3ad 100644 --- a/arch/mips/include/asm/mach-ip27/irq.h +++ b/arch/mips/include/asm/mach-ip27/irq.h @@ -11,7 +11,7 @@ #define __ASM_MACH_IP27_IRQ_H /* - * A hardwired interrupt number is completly stupid for this system - a + * A hardwired interrupt number is completely stupid for this system - a * large configuration might have thousands if not tenthousands of * interrupts. */ diff --git a/arch/mips/include/asm/mach-ip27/kernel-entry-init.h b/arch/mips/include/asm/mach-ip27/kernel-entry-init.h index b087cb83da3a..f992c1db876b 100644 --- a/arch/mips/include/asm/mach-ip27/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-ip27/kernel-entry-init.h @@ -81,7 +81,7 @@ .endm /* - * Do SMP slave processor setup necessary before we can savely execute C code. + * Do SMP slave processor setup necessary before we can safely execute C code. */ .macro smp_slave_setup GET_NASID_ASM t1 diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h index bf8c3e1860e7..7c7708a23baa 100644 --- a/arch/mips/include/asm/mach-jz4740/gpio.h +++ b/arch/mips/include/asm/mach-jz4740/gpio.h @@ -27,7 +27,7 @@ enum jz_gpio_function { /* Usually a driver for a SoC component has to request several gpio pins and - configure them as funcion pins. + configure them as function pins. jz_gpio_bulk_request can be used to ease this process. Usually one would do something like: diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index b836ddec82b7..c66fb8073c75 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -28,7 +28,7 @@ extern void __iomem *mips_cm_l2sync_base; * This function returns the physical base address of the Coherence Manager * global control block, or 0 if no Coherence Manager is present. It provides * a default implementation which reads the CMGCRBase register where available, - * and may be overriden by platforms which determine this address in a + * and may be overridden by platforms which determine this address in a * different way by defining a function with the same prototype except for the * name mips_cm_phys_base (without underscores). */ diff --git a/arch/mips/include/asm/octeon/cvmx-config.h b/arch/mips/include/asm/octeon/cvmx-config.h index f7dd17d0dc22..f4f1996e0fac 100644 --- a/arch/mips/include/asm/octeon/cvmx-config.h +++ b/arch/mips/include/asm/octeon/cvmx-config.h @@ -33,7 +33,7 @@ /* Packet buffers */ #define CVMX_FPA_PACKET_POOL (0) #define CVMX_FPA_PACKET_POOL_SIZE CVMX_FPA_POOL_0_SIZE -/* Work queue entrys */ +/* Work queue entries */ #define CVMX_FPA_WQE_POOL (1) #define CVMX_FPA_WQE_POOL_SIZE CVMX_FPA_POOL_1_SIZE /* PKO queue command buffers */ diff --git a/arch/mips/include/asm/octeon/cvmx.h b/arch/mips/include/asm/octeon/cvmx.h index 774bb45834cb..56e3436f1c21 100644 --- a/arch/mips/include/asm/octeon/cvmx.h +++ b/arch/mips/include/asm/octeon/cvmx.h @@ -189,7 +189,7 @@ static inline uint64_t cvmx_ptr_to_phys(void *ptr) static inline void *cvmx_phys_to_ptr(uint64_t physical_address) { if (sizeof(void *) == 8) { - /* Just set the top bit, avoiding any TLB uglyness */ + /* Just set the top bit, avoiding any TLB ugliness */ return CASTPTR(void, CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, physical_address)); diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h index 8d7a63b52ac7..3206245d1ed6 100644 --- a/arch/mips/include/asm/pci/bridge.h +++ b/arch/mips/include/asm/pci/bridge.h @@ -269,16 +269,16 @@ typedef struct bridge_err_cmdword_s { union { u32 cmd_word; struct { - u32 didn:4, /* Destination ID */ - sidn:4, /* Source ID */ - pactyp:4, /* Packet type */ - tnum:5, /* Trans Number */ - coh:1, /* Coh Transacti */ - ds:2, /* Data size */ - gbr:1, /* GBR enable */ - vbpm:1, /* VBPM message */ + u32 didn:4, /* Destination ID */ + sidn:4, /* Source ID */ + pactyp:4, /* Packet type */ + tnum:5, /* Trans Number */ + coh:1, /* Coh Transaction */ + ds:2, /* Data size */ + gbr:1, /* GBR enable */ + vbpm:1, /* VBPM message */ error:1, /* Error occurred */ - barr:1, /* Barrier op */ + barr:1, /* Barrier op */ rsvd:8; } berr_st; } berr_un; diff --git a/arch/mips/include/asm/sgi/hpc3.h b/arch/mips/include/asm/sgi/hpc3.h index 59920b345942..4a9c99050c13 100644 --- a/arch/mips/include/asm/sgi/hpc3.h +++ b/arch/mips/include/asm/sgi/hpc3.h @@ -147,7 +147,7 @@ struct hpc3_ethregs { #define HPC3_EPCFG_P1 0x000f /* Cycles to spend in P1 state for PIO */ #define HPC3_EPCFG_P2 0x00f0 /* Cycles to spend in P2 state for PIO */ #define HPC3_EPCFG_P3 0x0f00 /* Cycles to spend in P3 state for PIO */ -#define HPC3_EPCFG_TST 0x1000 /* Diagnistic ram test feature bit */ +#define HPC3_EPCFG_TST 0x1000 /* Diagnostic ram test feature bit */ u32 _unused2[0x1000/4 - 8]; /* padding */ diff --git a/arch/mips/include/asm/sgiarcs.h b/arch/mips/include/asm/sgiarcs.h index 26ddfff28c8e..105a9479ac5f 100644 --- a/arch/mips/include/asm/sgiarcs.h +++ b/arch/mips/include/asm/sgiarcs.h @@ -144,7 +144,7 @@ struct linux_tinfo { struct linux_vdirent { ULONG namelen; unsigned char attr; - char fname[32]; /* XXX imperical, should be a define */ + char fname[32]; /* XXX empirical, should be a define */ }; /* Other stuff for files. */ @@ -179,7 +179,7 @@ struct linux_finfo { enum linux_devtypes dtype; unsigned long namelen; unsigned char attr; - char name[32]; /* XXX imperical, should be define */ + char name[32]; /* XXX empirical, should be define */ }; /* This describes the vector containing function pointers to the ARC diff --git a/arch/mips/include/asm/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h index e33f0363235b..feb385180f87 100644 --- a/arch/mips/include/asm/sn/ioc3.h +++ b/arch/mips/include/asm/sn/ioc3.h @@ -355,7 +355,7 @@ struct ioc3_etxd { #define SSCR_PAUSE_STATE 0x40000000 /* sets when PAUSE takes effect */ #define SSCR_RESET 0x80000000 /* reset DMA channels */ -/* all producer/comsumer pointers are the same bitfield */ +/* all producer/consumer pointers are the same bitfield */ #define PROD_CONS_PTR_4K 0x00000ff8 /* for 4K buffers */ #define PROD_CONS_PTR_1K 0x000003f8 /* for 1K buffers */ #define PROD_CONS_PTR_OFF 3 diff --git a/arch/mips/include/asm/sn/sn0/hubio.h b/arch/mips/include/asm/sn/sn0/hubio.h index 5998b13e9764..57ece90f8cf1 100644 --- a/arch/mips/include/asm/sn/sn0/hubio.h +++ b/arch/mips/include/asm/sn/sn0/hubio.h @@ -628,7 +628,7 @@ typedef union h1_icrbb_u { /* * Values for field imsgtype */ -#define IIO_ICRB_IMSGT_XTALK 0 /* Incoming Meessage from Xtalk */ +#define IIO_ICRB_IMSGT_XTALK 0 /* Incoming Message from Xtalk */ #define IIO_ICRB_IMSGT_BTE 1 /* Incoming message from BTE */ #define IIO_ICRB_IMSGT_SN0NET 2 /* Incoming message from SN0 net */ #define IIO_ICRB_IMSGT_CRB 3 /* Incoming message from CRB ??? */ diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h index c74c32ccc647..b6e20f3053f4 100644 --- a/arch/mips/include/asm/uaccess.h +++ b/arch/mips/include/asm/uaccess.h @@ -96,7 +96,7 @@ static inline bool eva_kernel_access(void) } /* - * Is a address valid? This does a straighforward calculation rather + * Is a address valid? This does a straightforward calculation rather * than tests. * * Address valid if: diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 1448c1f43d4e..760217bbb2fa 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -24,7 +24,7 @@ static char *cm2_tr[8] = { "0x04", "cpc", "0x06", "0x07" }; -/* CM3 Tag ECC transation type */ +/* CM3 Tag ECC transaction type */ static char *cm3_tr[16] = { [0x0] = "ReqNoData", [0x1] = "0x1", diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index d7b8dd43147a..9bc1191b1ab0 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -530,7 +530,7 @@ static void mipspmu_enable(struct pmu *pmu) /* * MIPS performance counters can be per-TC. The control registers can - * not be directly accessed accross CPUs. Hence if we want to do global + * not be directly accessed across CPUs. Hence if we want to do global * control, we need cross CPU calls. on_each_cpu() can help us, but we * can not make sure this function is called with interrupts enabled. So * here we pause local counters and then grab a rwlock and leave the diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 0b3e58a3189f..ebb227471700 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -471,7 +471,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) /* * Disable all but self interventions. The load from COHCTL is defined * by the interAptiv & proAptiv SUMs as ensuring that the operation - * resulting from the preceeding store is complete. + * resulting from the preceding store is complete. */ uasm_i_addiu(&p, t0, zero, 1 << cpu_data[cpu].core); uasm_i_sw(&p, t0, 0, r_pcohctl); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 474ce8d1f67d..fe61ce7ad9b1 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -712,7 +712,7 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) * allows us to only worry about whether an FP mode switch is in * progress when FP is first used in a tasks time slice. Pretty much all * of the mode switch overhead can thus be confined to cases where mode - * switches are actually occuring. That is, to here. However for the + * switches are actually occurring. That is, to here. However for the * thread performing the mode switch it may take a while... */ if (num_online_cpus() > 1) { diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 31ca2edd7218..133274082d0a 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2229,7 +2229,7 @@ void __init trap_init(void) /* * Copy the generic exception handlers to their final destination. - * This will be overriden later as suitable for a particular + * This will be overridden later as suitable for a particular * configuration. */ set_handler(0x180, &except_vec3_generic, 0x80); diff --git a/arch/mips/kvm/tlb.c b/arch/mips/kvm/tlb.c index eff71c75dc27..75d056022c64 100644 --- a/arch/mips/kvm/tlb.c +++ b/arch/mips/kvm/tlb.c @@ -683,7 +683,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) kvm_debug("%s: vcpu %p, cpu: %d\n", __func__, vcpu, cpu); - /* Alocate new kernel and user ASIDs if needed */ + /* Allocate new kernel and user ASIDs if needed */ local_irq_save(flags); diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c index 307cc4c98bdd..473aa4dff867 100644 --- a/arch/mips/kvm/trap_emul.c +++ b/arch/mips/kvm/trap_emul.c @@ -501,7 +501,7 @@ static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu) kvm_write_c0_guest_config7(cop0, (MIPS_CONF7_WII) | (1 << 10)); /* - * Setup IntCtl defaults, compatibilty mode for timer interrupts (HW5) + * Setup IntCtl defaults, compatibility mode for timer interrupts (HW5) */ kvm_write_c0_guest_intctl(cop0, 0xFC000000); diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c index ad3c73436777..47d26c805eac 100644 --- a/arch/mips/math-emu/ieee754dp.c +++ b/arch/mips/math-emu/ieee754dp.c @@ -97,7 +97,7 @@ union ieee754dp ieee754dp_format(int sn, int xe, u64 xm) { assert(xm); /* we don't gen exact zeros (probably should) */ - assert((xm >> (DP_FBITS + 1 + 3)) == 0); /* no execess */ + assert((xm >> (DP_FBITS + 1 + 3)) == 0); /* no excess */ assert(xm & (DP_HIDDEN_BIT << 3)); if (xe < DP_EMIN) { @@ -165,7 +165,7 @@ union ieee754dp ieee754dp_format(int sn, int xe, u64 xm) /* strip grs bits */ xm >>= 3; - assert((xm >> (DP_FBITS + 1)) == 0); /* no execess */ + assert((xm >> (DP_FBITS + 1)) == 0); /* no excess */ assert(xe >= DP_EMIN); if (xe > DP_EMAX) { @@ -198,7 +198,7 @@ union ieee754dp ieee754dp_format(int sn, int xe, u64 xm) ieee754_setcx(IEEE754_UNDERFLOW); return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); } else { - assert((xm >> (DP_FBITS + 1)) == 0); /* no execess */ + assert((xm >> (DP_FBITS + 1)) == 0); /* no excess */ assert(xm & DP_HIDDEN_BIT); return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index def00ffc50fc..e0b2c450b963 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c @@ -97,7 +97,7 @@ union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) { assert(xm); /* we don't gen exact zeros (probably should) */ - assert((xm >> (SP_FBITS + 1 + 3)) == 0); /* no execess */ + assert((xm >> (SP_FBITS + 1 + 3)) == 0); /* no excess */ assert(xm & (SP_HIDDEN_BIT << 3)); if (xe < SP_EMIN) { @@ -163,7 +163,7 @@ union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) /* strip grs bits */ xm >>= 3; - assert((xm >> (SP_FBITS + 1)) == 0); /* no execess */ + assert((xm >> (SP_FBITS + 1)) == 0); /* no excess */ assert(xe >= SP_EMIN); if (xe > SP_EMAX) { @@ -196,7 +196,7 @@ union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) ieee754_setcx(IEEE754_UNDERFLOW); return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); } else { - assert((xm >> (SP_FBITS + 1)) == 0); /* no execess */ + assert((xm >> (SP_FBITS + 1)) == 0); /* no excess */ assert(xm & SP_HIDDEN_BIT); return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); diff --git a/arch/mips/mm/sc-ip22.c b/arch/mips/mm/sc-ip22.c index efaf364fe581..f293a97cb885 100644 --- a/arch/mips/mm/sc-ip22.c +++ b/arch/mips/mm/sc-ip22.c @@ -172,7 +172,7 @@ static inline int __init indy_sc_probe(void) return 1; } -/* XXX Check with wje if the Indy caches can differenciate between +/* XXX Check with wje if the Indy caches can differentiate between writeback + invalidate and just invalidate. */ static struct bcache_ops indy_sc_ops = { .bc_enable = indy_sc_enable, diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 63b7d6f82d24..b5a0234da765 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -12,7 +12,7 @@ * Copyright (C) 2011 MIPS Technologies, Inc. * * ... and the days got worse and worse and now you see - * I've gone completly out of my mind. + * I've gone completely out of my mind. * * They're coming to take me a away haha * they're coming to take me a away hoho hihi haha diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index 8d0eb2643248..f1f88291451e 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -7,7 +7,7 @@ * Copyright (C) 2000 by Silicon Graphics, Inc. * Copyright (C) 2004 by Christoph Hellwig * - * On SGI IP27 the ARC memory configuration data is completly bogus but + * On SGI IP27 the ARC memory configuration data is completely bogus but * alternate easier to use mechanisms are available. */ #include From 9a89fca3bbe23559b25c8c5eeadd90aac2e95c44 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 13 Nov 2015 00:48:48 +0000 Subject: [PATCH 028/266] UPSTREAM: MIPS: math-emu: Always propagate sNaN payload in quieting Propagate sNaN payload in quieting in the legacy-NaN mode as well. If clearing the quiet bit would produce infinity, then set the next lower trailing significand field bit, matching the SB-1 and BMIPS5000 hardware implementations. Some other MIPS FPU hardware implementations do produce the default qNaN bit pattern instead. This reverts some changes made for semantics preservation with commit dc3ddf42 [MIPS: math-emu: Update sNaN quieting handlers], consequently bringing back most of the semantics from before commit fdffbafb [Lots of FPU bug fixes from Kjeld Borch Egevang.], except from the qNaN produced in the infinity case. Previously the default qNaN bit pattern was produced in that case. Signed-off-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11483/ Signed-off-by: Ralf Baechle (cherry picked from commit acd9e20cd9d0e6af5680e1870a966d8082a1130a) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/ieee754dp.c | 9 ++++++--- arch/mips/math-emu/ieee754sp.c | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c index 47d26c805eac..465a0342ed4c 100644 --- a/arch/mips/math-emu/ieee754dp.c +++ b/arch/mips/math-emu/ieee754dp.c @@ -54,10 +54,13 @@ union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r) assert(ieee754dp_issnan(r)); ieee754_setcx(IEEE754_INVALID_OPERATION); - if (ieee754_csr.nan2008) + if (ieee754_csr.nan2008) { DPMANT(r) |= DP_MBIT(DP_FBITS - 1); - else - r = ieee754dp_indef(); + } else { + DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1); + if (!ieee754dp_isnan(r)) + DPMANT(r) |= DP_MBIT(DP_FBITS - 2); + } return r; } diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index e0b2c450b963..860e9162097f 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c @@ -54,10 +54,13 @@ union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r) assert(ieee754sp_issnan(r)); ieee754_setcx(IEEE754_INVALID_OPERATION); - if (ieee754_csr.nan2008) + if (ieee754_csr.nan2008) { SPMANT(r) |= SP_MBIT(SP_FBITS - 1); - else - r = ieee754sp_indef(); + } else { + SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1); + if (!ieee754sp_isnan(r)) + SPMANT(r) |= SP_MBIT(SP_FBITS - 2); + } return r; } From b61e67de1ac44a2faca12e9fd476c87fa539efb5 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 14:04:45 +0100 Subject: [PATCH 029/266] UPSTREAM: MIPS: math-emu: Fix BC1{EQ,NE}Z emulation The conditions for branching when emulating the BC1EQZ & BC1NEZ instructions were backwards, leading to each of those instructions being treated as the other. Fix this by reversing the conditions, and clear up the code a little for readability & checkpatch. Fixes: c909ca718e8f ("MIPS: math-emu: Emulate missing BC1{EQ,NE}Z instructions") Signed-off-by: Paul Burton Reviewed-by: James Hogan Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13150/ Signed-off-by: Ralf Baechle (cherry picked from commit 93583e178ebfdd2fadf950eef1547f305cac12ca) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 066e0720a7f1..4ea9836cec58 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -975,9 +975,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, struct mm_decoded_insn dec_insn, void *__user *fault_addr) { unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; - unsigned int cond, cbit; + unsigned int cond, cbit, bit0; mips_instruction ir; int likely, pc_inc; + union fpureg *fpr; u32 __user *wva; u64 __user *dva; u32 wval; @@ -1189,14 +1190,14 @@ emul: return SIGILL; cond = likely = 0; + fpr = ¤t->thread.fpu.fpr[MIPSInst_RT(ir)]; + bit0 = get_fpr32(fpr, 0) & 0x1; switch (MIPSInst_RS(ir)) { case bc1eqz_op: - if (get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1) - cond = 1; + cond = bit0 == 0; break; case bc1nez_op: - if (!(get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)) - cond = 1; + cond = bit0 != 0; break; } goto branch_common; From 476f2f0a48ca04c5a3f9a385becdafe2adaf8666 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 14:04:48 +0100 Subject: [PATCH 030/266] UPSTREAM: MIPS: math-emu: Emulate MIPSr6 sel.fmt instruction Add support for emulating the MIPSr6 sel.fmt instruction, which was previously missing from the FPU emulation code. This instruction selects its result from 2 possible source registers, based upon bit 0 of the destination register, and is valid only for S (single) & D (double) data types. Signed-off-by: Paul Burton Cc: Maciej W. Rozycki Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13153/ Signed-off-by: Ralf Baechle (cherry picked from commit 4b820d95dc53c15e6e727da964430a3ed60e05ef) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 4ea9836cec58..06ffddd916c0 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1677,7 +1677,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, union ieee754sp(*b) (union ieee754sp, union ieee754sp); union ieee754sp(*u) (union ieee754sp); } handler; - union ieee754sp fs, ft; + union ieee754sp fd, fs, ft; switch (MIPSInst_FUNC(ir)) { /* binary ops */ @@ -1948,6 +1948,17 @@ copcsr: rfmt = w_fmt; goto copcsr; + case fsel_op: + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(fd, MIPSInst_FD(ir)); + if (fd.bits & 0x1) + SPFROMREG(rv.s, MIPSInst_FT(ir)); + else + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fcvtl_op: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; @@ -1996,7 +2007,7 @@ copcsr: } case d_fmt: { - union ieee754dp fs, ft; + union ieee754dp fd, fs, ft; union { union ieee754dp(*b) (union ieee754dp, union ieee754dp); union ieee754dp(*u) (union ieee754dp); @@ -2246,6 +2257,17 @@ dcopuop: rfmt = w_fmt; goto copcsr; + case fsel_op: + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(fd, MIPSInst_FD(ir)); + if (fd.bits & 0x1) + DPFROMREG(rv.d, MIPSInst_FT(ir)); + else + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fcvtl_op: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; From e6ba7699581f8d0cd0dd15674251cfff1f8bee09 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 14:04:49 +0100 Subject: [PATCH 031/266] UPSTREAM: MIPS: math-emu: Unify ieee754sp_m{add,sub}f The code for emulating MIPSr6 madd.s & msub.s instructions has previously been implemented as 2 different functions, namely ieee754sp_maddf & ieee754sp_msubf. The difference in behaviour of these 2 instructions is merely the sign of the product, so we can easily share the code implementing them. Do this for the single precision variant, removing the original ieee754sp_msubf in favor of reusing the code from ieee754sp_maddf. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13154/ Signed-off-by: Ralf Baechle (cherry picked from commit 6162051e87f6ea785cb51ad99bdcf8eb0bd9cb07) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/Makefile | 2 +- arch/mips/math-emu/sp_maddf.c | 22 ++- arch/mips/math-emu/sp_msubf.c | 258 ---------------------------------- 3 files changed, 21 insertions(+), 261 deletions(-) delete mode 100644 arch/mips/math-emu/sp_msubf.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index a19641d3ac23..3389aff21783 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -6,7 +6,7 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o dp_fmax.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o sp_fmax.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_2008class.o sp_fmin.o sp_fmax.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index dd1dd83e34eb..93b7132d60e2 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -14,8 +14,12 @@ #include "ieee754sp.h" -union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, - union ieee754sp y) +enum maddf_flags { + maddf_negate_product = 1 << 0, +}; + +static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y, enum maddf_flags flags) { int re; int rs; @@ -154,6 +158,8 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, re = xe + ye; rs = xs ^ ys; + if (flags & maddf_negate_product) + rs ^= 1; /* shunt to top of word */ xm <<= 32 - (SP_FBITS + 1); @@ -253,3 +259,15 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, } return ieee754sp_format(zs, ze, zm); } + +union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + return _sp_maddf(z, x, y, 0); +} + +union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + return _sp_maddf(z, x, y, maddf_negate_product); +} diff --git a/arch/mips/math-emu/sp_msubf.c b/arch/mips/math-emu/sp_msubf.c deleted file mode 100644 index 81c38b980d69..000000000000 --- a/arch/mips/math-emu/sp_msubf.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * IEEE754 floating point arithmetic - * single precision: MSUB.f (Fused Multiply Subtract) - * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) - * - * MIPS floating point support - * Copyright (C) 2015 Imagination Technologies, Ltd. - * Author: Markos Chandras - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License. - */ - -#include "ieee754sp.h" - -union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, - union ieee754sp y) -{ - int re; - int rs; - unsigned rm; - unsigned short lxm; - unsigned short hxm; - unsigned short lym; - unsigned short hym; - unsigned lrm; - unsigned hrm; - unsigned t; - unsigned at; - int s; - - COMPXSP; - COMPYSP; - u32 zm; int ze; int zs __maybe_unused; int zc; - - EXPLODEXSP; - EXPLODEYSP; - EXPLODESP(z, zc, zs, ze, zm) - - FLUSHXSP; - FLUSHYSP; - FLUSHSP(z, zc, zs, ze, zm); - - ieee754_clearcx(); - - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - SPDNORMx(zm, ze); - /* QNAN is handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754sp_nanxcpt(x); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): - return y; - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; - - /* - * Infinity handling - */ - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754sp_indef(); - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - return ieee754sp_inf(xs ^ ys); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - /* Multiplication is 0 so just return z */ - return z; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): - SPDNORMX; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - SPDNORMY; - break; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - SPDNORMX; - break; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - /* fall through to real compuation */ - } - - /* Finally get to do some computation */ - - /* - * Do the multiplication bit first - * - * rm = xm * ym, re = xe + ye basically - * - * At this point xm and ym should have been normalized. - */ - - /* rm = xm * ym, re = xe+ye basically */ - assert(xm & SP_HIDDEN_BIT); - assert(ym & SP_HIDDEN_BIT); - - re = xe + ye; - rs = xs ^ ys; - - /* shunt to top of word */ - xm <<= 32 - (SP_FBITS + 1); - ym <<= 32 - (SP_FBITS + 1); - - /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. - */ - lxm = xm & 0xffff; - hxm = xm >> 16; - lym = ym & 0xffff; - hym = ym >> 16; - - lrm = lxm * lym; /* 16 * 16 => 32 */ - hrm = hxm * hym; /* 16 * 16 => 32 */ - - t = lxm * hym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); - - t = hxm * lym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); - - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((int) rm < 0) { - rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | - ((rm << (SP_FBITS + 1 + 3)) != 0); - re++; - } else { - rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | - ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); - } - assert(rm & (SP_HIDDEN_BIT << 3)); - - /* And now the subtraction */ - - /* Flip sign of r and handle as add */ - rs ^= 1; - - assert(zm & SP_HIDDEN_BIT); - - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; - - if (ze > re) { - /* - * Have to shift y fraction right to align. - */ - s = ze - re; - SPXSRSYn(s); - } else if (re > ze) { - /* - * Have to shift x fraction right to align. - */ - s = re - ze; - SPXSRSYn(s); - } - assert(ze == re); - assert(ze <= SP_EMAX); - - if (zs == rs) { - /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in zm, zs and ze. - */ - zm = zm + rm; - - if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ - SPXSRSX1(); /* shift preserving sticky */ - } - } else { - if (zm >= rm) { - zm = zm - rm; - } else { - zm = rm - zm; - zs = rs; - } - if (zm == 0) - return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); - - /* - * Normalize in extended single precision - */ - while ((zm >> (SP_MBITS + 3)) == 0) { - zm <<= 1; - ze--; - } - - } - return ieee754sp_format(zs, ze, zm); -} From 8c50090eaeb37ade57e73c630c8dd4c6c2a2cb6d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 14:04:50 +0100 Subject: [PATCH 032/266] UPSTREAM: MIPS: math-emu: Unify ieee754dp_m{add,sub}f The code for emulating MIPSr6 madd.d & msub.d instructions has previously been implemented as 2 different functions, namely ieee754dp_maddf & ieee754dp_msubf. The difference in behaviour of these 2 instructions is merely the sign of the product, so we can easily share the code implementing them. Do this for the double precision variant, removing the original ieee754dp_msubf in favor of reusing the code from ieee754dp_maddf. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13155/ Signed-off-by: Ralf Baechle (cherry picked from commit d728f6709bcc49c98097485e3561f1faaf52b4f3) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/Makefile | 2 +- arch/mips/math-emu/dp_maddf.c | 22 ++- arch/mips/math-emu/dp_msubf.c | 269 ---------------------------------- 3 files changed, 21 insertions(+), 272 deletions(-) delete mode 100644 arch/mips/math-emu/dp_msubf.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index 3389aff21783..e9bbc2a6526f 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,7 +4,7 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o dp_fmax.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_2008class.o dp_fmin.o dp_fmax.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ sp_tint.o sp_fint.o sp_maddf.o sp_2008class.o sp_fmin.o sp_fmax.o \ dsemul.o diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 119eda9fa1ea..d5e0fb13ef0f 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -14,8 +14,12 @@ #include "ieee754dp.h" -union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, - union ieee754dp y) +enum maddf_flags { + maddf_negate_product = 1 << 0, +}; + +static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y, enum maddf_flags flags) { int re; int rs; @@ -154,6 +158,8 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, re = xe + ye; rs = xs ^ ys; + if (flags & maddf_negate_product) + rs ^= 1; /* shunt to top of word */ xm <<= 64 - (DP_FBITS + 1); @@ -263,3 +269,15 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, return ieee754dp_format(zs, ze, zm); } + +union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + return _dp_maddf(z, x, y, 0); +} + +union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + return _dp_maddf(z, x, y, maddf_negate_product); +} diff --git a/arch/mips/math-emu/dp_msubf.c b/arch/mips/math-emu/dp_msubf.c deleted file mode 100644 index 12241262f856..000000000000 --- a/arch/mips/math-emu/dp_msubf.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * IEEE754 floating point arithmetic - * double precision: MSUB.f (Fused Multiply Subtract) - * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) - * - * MIPS floating point support - * Copyright (C) 2015 Imagination Technologies, Ltd. - * Author: Markos Chandras - * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License. - */ - -#include "ieee754dp.h" - -union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, - union ieee754dp y) -{ - int re; - int rs; - u64 rm; - unsigned lxm; - unsigned hxm; - unsigned lym; - unsigned hym; - u64 lrm; - u64 hrm; - u64 t; - u64 at; - int s; - - COMPXDP; - COMPYDP; - - u64 zm; int ze; int zs __maybe_unused; int zc; - - EXPLODEXDP; - EXPLODEYDP; - EXPLODEDP(z, zc, zs, ze, zm) - - FLUSHXDP; - FLUSHYDP; - FLUSHDP(z, zc, zs, ze, zm); - - ieee754_clearcx(); - - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - DPDNORMx(zm, ze); - /* QNAN is handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754dp_nanxcpt(x); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): - return y; - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; - - - /* - * Infinity handling - */ - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754dp_indef(); - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - return ieee754dp_inf(xs ^ ys); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - /* Multiplication is 0 so just return z */ - return z; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): - DPDNORMX; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - DPDNORMY; - break; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - DPDNORMX; - break; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - /* fall through to real computations */ - } - - /* Finally get to do some computation */ - - /* - * Do the multiplication bit first - * - * rm = xm * ym, re = xe + ye basically - * - * At this point xm and ym should have been normalized. - */ - assert(xm & DP_HIDDEN_BIT); - assert(ym & DP_HIDDEN_BIT); - - re = xe + ye; - rs = xs ^ ys; - - /* shunt to top of word */ - xm <<= 64 - (DP_FBITS + 1); - ym <<= 64 - (DP_FBITS + 1); - - /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. - */ - - /* 32 * 32 => 64 */ -#define DPXMULT(x, y) ((u64)(x) * (u64)y) - - lxm = xm; - hxm = xm >> 32; - lym = ym; - hym = ym >> 32; - - lrm = DPXMULT(lxm, lym); - hrm = DPXMULT(hxm, hym); - - t = DPXMULT(lxm, hym); - - at = lrm + (t << 32); - hrm += at < lrm; - lrm = at; - - hrm = hrm + (t >> 32); - - t = DPXMULT(hxm, lym); - - at = lrm + (t << 32); - hrm += at < lrm; - lrm = at; - - hrm = hrm + (t >> 32); - - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((s64) rm < 0) { - rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | - ((rm << (DP_FBITS + 1 + 3)) != 0); - re++; - } else { - rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | - ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); - } - assert(rm & (DP_HIDDEN_BIT << 3)); - - /* And now the subtraction */ - - /* flip sign of r and handle as add */ - rs ^= 1; - - assert(zm & DP_HIDDEN_BIT); - - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; - - if (ze > re) { - /* - * Have to shift y fraction right to align. - */ - s = ze - re; - rm = XDPSRS(rm, s); - re += s; - } else if (re > ze) { - /* - * Have to shift x fraction right to align. - */ - s = re - ze; - zm = XDPSRS(zm, s); - ze += s; - } - assert(ze == re); - assert(ze <= DP_EMAX); - - if (zs == rs) { - /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in xm, xs and xe. - */ - zm = zm + rm; - - if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ - zm = XDPSRS1(zm); - ze++; - } - } else { - if (zm >= rm) { - zm = zm - rm; - } else { - zm = rm - zm; - zs = rs; - } - if (zm == 0) - return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); - - /* - * Normalize to rounding precision. - */ - while ((zm >> (DP_FBITS + 3)) == 0) { - zm <<= 1; - ze--; - } - } - - return ieee754dp_format(zs, ze, zm); -} From 663009749ffdb2786e75eb5bdb3c5e0174a8e12a Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 14:04:51 +0100 Subject: [PATCH 033/266] UPSTREAM: MIPS: math-emu: Add z argument macros Introduce macros for handling the "z" argument to maddf & msubf, making its handling consistent with that of the "x" & "y" arguments rather than open-coding equivalents. Signed-off-by: Paul Burton Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13156/ Signed-off-by: Ralf Baechle (cherry picked from commit e2d11e1a8398b7447d337add50521a5abc6267fd) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 9 ++++----- arch/mips/math-emu/ieee754dp.h | 1 + arch/mips/math-emu/ieee754int.h | 10 ++++++++++ arch/mips/math-emu/ieee754sp.h | 1 + arch/mips/math-emu/sp_maddf.c | 8 ++++---- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index d5e0fb13ef0f..0e1d4d80e22e 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -36,16 +36,15 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, COMPXDP; COMPYDP; - - u64 zm; int ze; int zs __maybe_unused; int zc; + COMPZDP; EXPLODEXDP; EXPLODEYDP; - EXPLODEDP(z, zc, zs, ze, zm) + EXPLODEZDP; FLUSHXDP; FLUSHYDP; - FLUSHDP(z, zc, zs, ze, zm); + FLUSHZDP; ieee754_clearcx(); @@ -54,7 +53,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754dp_nanxcpt(z); case IEEE754_CLASS_DNORM: - DPDNORMx(zm, ze); + DPDNORMZ; /* QNAN is handled separately below */ } diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h index e2babd98fee3..9ba023004eb6 100644 --- a/arch/mips/math-emu/ieee754dp.h +++ b/arch/mips/math-emu/ieee754dp.h @@ -60,6 +60,7 @@ static inline int ieee754dp_finite(union ieee754dp x) while ((m >> DP_FBITS) == 0) { m <<= 1; e--; } #define DPDNORMX DPDNORMx(xm, xe) #define DPDNORMY DPDNORMx(ym, ye) +#define DPDNORMZ DPDNORMx(zm, ze) static inline union ieee754dp builddp(int s, int bx, u64 m) { diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index ed7bb277b3e0..8bc2f6963324 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -55,6 +55,9 @@ static inline int ieee754_class_nan(int xc) #define COMPYSP \ unsigned ym; int ye; int ys; int yc +#define COMPZSP \ + unsigned zm; int ze; int zs; int zc + #define EXPLODESP(v, vc, vs, ve, vm) \ { \ vs = SPSIGN(v); \ @@ -81,6 +84,7 @@ static inline int ieee754_class_nan(int xc) } #define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm) #define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym) +#define EXPLODEZSP EXPLODESP(z, zc, zs, ze, zm) #define COMPXDP \ @@ -89,6 +93,9 @@ static inline int ieee754_class_nan(int xc) #define COMPYDP \ u64 ym; int ye; int ys; int yc +#define COMPZDP \ + u64 zm; int ze; int zs; int zc + #define EXPLODEDP(v, vc, vs, ve, vm) \ { \ vm = DPMANT(v); \ @@ -115,6 +122,7 @@ static inline int ieee754_class_nan(int xc) } #define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm) #define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym) +#define EXPLODEZDP EXPLODEDP(z, zc, zs, ze, zm) #define FLUSHDP(v, vc, vs, ve, vm) \ if (vc==IEEE754_CLASS_DNORM) { \ @@ -140,7 +148,9 @@ static inline int ieee754_class_nan(int xc) #define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm) #define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym) +#define FLUSHZDP FLUSHDP(z, zc, zs, ze, zm) #define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm) #define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym) +#define FLUSHZSP FLUSHSP(z, zc, zs, ze, zm) #endif /* __IEEE754INT_H */ diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 374a3f00a589..b24fdff90f21 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -65,6 +65,7 @@ static inline int ieee754sp_finite(union ieee754sp x) while ((m >> SP_FBITS) == 0) { m <<= 1; e--; } #define SPDNORMX SPDNORMx(xm, xe) #define SPDNORMY SPDNORMx(ym, ye) +#define SPDNORMZ SPDNORMx(zm, ze) static inline union ieee754sp buildsp(int s, int bx, unsigned m) { diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index 93b7132d60e2..86e1d0b25446 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -36,15 +36,15 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, COMPXSP; COMPYSP; - u32 zm; int ze; int zs __maybe_unused; int zc; + COMPZSP; EXPLODEXSP; EXPLODEYSP; - EXPLODESP(z, zc, zs, ze, zm) + EXPLODEZSP; FLUSHXSP; FLUSHYSP; - FLUSHSP(z, zc, zs, ze, zm); + FLUSHZSP; ieee754_clearcx(); @@ -53,7 +53,7 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754sp_nanxcpt(z); case IEEE754_CLASS_DNORM: - SPDNORMx(zm, ze); + SPDNORMZ; /* QNAN is handled separately below */ } From fb2a789d164e114d3b7fe3723d4df6c505d8b34e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 14:04:52 +0100 Subject: [PATCH 034/266] UPSTREAM: MIPS: math-emu: Fix bit-width in ieee754dp_{mul, maddf, msubf} comments A comment in ieee754dp_mul indicates that the code is about to perform a 32b x 32b multiplication & keep the high 32b of the result. It appears this was copied from the single-precision multiplication code, since the code actually goes on to perform a 64b x 64b multiplication & keep the high 64b of the result. Fix the comment to indicate 64b. It appears also that this comment was copied verbatim along with the rest of the multiplication code into ieee754dp_maddf, which has since been renamed _dp_maddf. Fix the same issue there. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13157/ Signed-off-by: Ralf Baechle (cherry picked from commit 95bff2410cdccfe2cf4b99f4e86165956767740e) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 2 +- arch/mips/math-emu/dp_mul.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 0e1d4d80e22e..dc83fdd43f60 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -165,7 +165,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, ym <<= 64 - (DP_FBITS + 1); /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + * Multiply 64 bits xm, ym to give high 64 bits rm with stickness. */ /* 32 * 32 => 64 */ diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index d0901f03fa19..d6a7573d2c52 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c @@ -125,7 +125,7 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) ym <<= 64 - (DP_FBITS + 1); /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + * Multiply 64 bits xm, ym to give high 64 bits rm with stickness. */ /* 32 * 32 => 64 */ From 478f521caf2a5232c46a83fef838c66a92631716 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 14:04:53 +0100 Subject: [PATCH 035/266] UPSTREAM: MIPS: math-emu: Fix code indentation A line incrementing the re variable was indented a level too deep in ieee754dp_mul, making the code unclear to read. Fix the indentation. This appears to have been copied verbatim along with the rest of the multiplication code to ieee754dp_maddf, now _dp_maddf, too so fix the indentation there too. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13158/ Signed-off-by: Ralf Baechle (cherry picked from commit 5c18c936b52ae80db5737849e11f436e79b84b2d) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 2 +- arch/mips/math-emu/dp_mul.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index dc83fdd43f60..4a2d03c72959 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -203,7 +203,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, if ((s64) rm < 0) { rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | ((rm << (DP_FBITS + 1 + 3)) != 0); - re++; + re++; } else { rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index d6a7573d2c52..87d0b44b0614 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c @@ -163,7 +163,7 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) if ((s64) rm < 0) { rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | ((rm << (DP_FBITS + 1 + 3)) != 0); - re++; + re++; } else { rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); From d3154ef7038bc2ffdb4056b40d9e3771994d3852 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 14:04:47 +0100 Subject: [PATCH 036/266] UPSTREAM: MIPS: inst: Declare fsel_op for sel.fmt instruction Declare the opcode for the MIPSr6 sel.fmt instruction, as fsel_op in order to match other FP op names. Signed-off-by: Paul Burton Cc: Maciej W. Rozycki Cc: Leonid Yegoshin Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13152/ Signed-off-by: Ralf Baechle (cherry picked from commit b6d5c4eda7a771e72b3640500e026d72c4f64419) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/uapi/asm/inst.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index b145749c743f..6122914a428a 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -166,6 +166,7 @@ enum cop1_sdw_func { fceill_op = 0x0a, ffloorl_op = 0x0b, fround_op = 0x0c, ftrunc_op = 0x0d, fceil_op = 0x0e, ffloor_op = 0x0f, + fsel_op = 0x10, fmovc_op = 0x11, fmovz_op = 0x12, fmovn_op = 0x13, fseleqz_op = 0x14, frecip_op = 0x15, frsqrt_op = 0x16, From f67d2acc25243b22b247c9659ba0602667aba936 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 14:04:54 +0100 Subject: [PATCH 037/266] UPSTREAM: MIPS: math-emu: Fix m{add,sub}.s shifts The code in _sp_maddf (formerly ieee754sp_madd) appears to have been copied verbatim from ieee754sp_add, and although it's adding the unpacked "r" & "z" floats it kept using macros that operate on "x" & "y". This led to the addition being carried out incorrectly on some mismash of the product, accumulator & multiplicand fields. Typically this would lead to the assertions "ze == re" & "ze <= SP_EMAX" failing since ze & re hadn't been operated upon. Signed-off-by: Paul Burton Fixes: e24c3bec3e8e ("MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction") Cc: Adam Buchbinder Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13159/ Signed-off-by: Ralf Baechle (cherry picked from commit db57f29d50683afd75c7f8b9908af7669837c3a9) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/ieee754sp.c | 3 ++- arch/mips/math-emu/ieee754sp.h | 16 +++++++--------- arch/mips/math-emu/sp_add.c | 6 ++++-- arch/mips/math-emu/sp_maddf.c | 13 ++++++++----- arch/mips/math-emu/sp_sub.c | 6 ++++-- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index 860e9162097f..260e68965907 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c @@ -141,7 +141,8 @@ union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) } else { /* sticky right shift es bits */ - SPXSRSXn(es); + xm = XSPSRS(xm, es); + xe += es; assert((xm & (SP_HIDDEN_BIT << 3)) == 0); assert(xe == SP_EMIN); } diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index b24fdff90f21..8476067075fe 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -46,19 +46,17 @@ static inline int ieee754sp_finite(union ieee754sp x) } /* 3bit extended single precision sticky right shift */ -#define SPXSRSXn(rs) \ - (xe += rs, \ - xm = (rs > (SP_FBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) +#define XSPSRS(v, rs) \ + ((rs > (SP_FBITS+3))?1:((v) >> (rs)) | ((v) << (32-(rs)) != 0)) + +#define XSPSRS1(m) \ + ((m >> 1) | (m & 1)) #define SPXSRSX1() \ - (xe++, (xm = (xm >> 1) | (xm & 1))) - -#define SPXSRSYn(rs) \ - (ye+=rs, \ - ym = (rs > (SP_FBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) + (xe++, (xm = XSPSRS1(xm))) #define SPXSRSY1() \ - (ye++, (ym = (ym >> 1) | (ym & 1))) + (ye++, (ym = XSPSRS1(ym))) /* convert denormal to normalized with extended exponent */ #define SPDNORMx(m,e) \ diff --git a/arch/mips/math-emu/sp_add.c b/arch/mips/math-emu/sp_add.c index f1c87b07d3b4..c55c0c00bca8 100644 --- a/arch/mips/math-emu/sp_add.c +++ b/arch/mips/math-emu/sp_add.c @@ -132,13 +132,15 @@ union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y) * Have to shift y fraction right to align. */ s = xe - ye; - SPXSRSYn(s); + ym = XSPSRS(ym, s); + ye += s; } else if (ye > xe) { /* * Have to shift x fraction right to align. */ s = ye - xe; - SPXSRSXn(s); + xm = XSPSRS(xm, s); + xe += s; } assert(xe == ye); assert(xe <= SP_EMAX); diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index 86e1d0b25446..a8cd8b4f235e 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -214,16 +214,18 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, if (ze > re) { /* - * Have to shift y fraction right to align. + * Have to shift r fraction right to align. */ s = ze - re; - SPXSRSYn(s); + rm = XSPSRS(rm, s); + re += s; } else if (re > ze) { /* - * Have to shift x fraction right to align. + * Have to shift z fraction right to align. */ s = re - ze; - SPXSRSYn(s); + zm = XSPSRS(zm, s); + ze += s; } assert(ze == re); assert(ze <= SP_EMAX); @@ -236,7 +238,8 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, zm = zm + rm; if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ - SPXSRSX1(); + zm = XSPSRS1(zm); + ze++; } } else { if (zm >= rm) { diff --git a/arch/mips/math-emu/sp_sub.c b/arch/mips/math-emu/sp_sub.c index ec5f937a8b3e..dc998ed47295 100644 --- a/arch/mips/math-emu/sp_sub.c +++ b/arch/mips/math-emu/sp_sub.c @@ -134,13 +134,15 @@ union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y) * have to shift y fraction right to align */ s = xe - ye; - SPXSRSYn(s); + ym = XSPSRS(ym, s); + ye += s; } else if (ye > xe) { /* * have to shift x fraction right to align */ s = ye - xe; - SPXSRSXn(s); + xm = XSPSRS(xm, s); + xe += s; } assert(xe == ye); assert(xe <= SP_EMAX); From b1529b8d20af549d4fc5856bec6a86ac9643c02c Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 4 Jul 2016 19:35:07 +0100 Subject: [PATCH 038/266] UPSTREAM: MIPS: inst.h: Rename b{eq,ne}zcji[al]c_op to pop{6,7}6_op The opcodes currently defined in inst.h as beqzcjic_op & bnezcjialc_op are actually defined in the MIPS base instruction set manuals as pop66 & pop76 respectively. Rename them as such, for consistency with the documentation. Signed-off-by: Paul Burton Signed-off-by: James Hogan Acked-by: Ralf Baechle Cc: linux-mips@linux-mips.org Signed-off-by: Paolo Bonzini (cherry picked from commit 1c66b79bb3b11942a98085fd89295cf6cddae41a) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/uapi/asm/inst.h | 4 ++-- arch/mips/kernel/branch.c | 4 ++-- arch/mips/math-emu/cp1emu.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index 6122914a428a..90a9c06a2b55 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -32,9 +32,9 @@ enum major_op { sb_op, sh_op, swl_op, sw_op, sdl_op, sdr_op, swr_op, cache_op, ll_op, lwc1_op, lwc2_op, bc6_op = lwc2_op, pref_op, - lld_op, ldc1_op, ldc2_op, beqzcjic_op = ldc2_op, ld_op, + lld_op, ldc1_op, ldc2_op, pop66_op = ldc2_op, ld_op, sc_op, swc1_op, swc2_op, balc6_op = swc2_op, major_3b_op, - scd_op, sdc1_op, sdc2_op, bnezcjialc_op = sdc2_op, sd_op + scd_op, sdc1_op, sdc2_op, pop76_op = sdc2_op, sd_op }; /* diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 71e8f4c0b8da..1d29885d633e 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -799,7 +799,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, epc += 4 + (insn.i_format.simmediate << 2); regs->cp0_epc = epc; break; - case beqzcjic_op: + case pop66_op: if (!cpu_has_mips_r6) { ret = -SIGILL; break; @@ -807,7 +807,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, /* Compact branch: BEQZC || JIC */ regs->cp0_epc += 8; break; - case bnezcjialc_op: + case pop76_op: if (!cpu_has_mips_r6) { ret = -SIGILL; break; diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 06ffddd916c0..052e72d05b5c 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -683,14 +683,14 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, dec_insn.next_pc_inc; return 1; - case beqzcjic_op: + case pop66_op: if (!cpu_has_mips_r6) break; *contpc = regs->cp0_epc + dec_insn.pc_inc + dec_insn.next_pc_inc; return 1; - case bnezcjialc_op: + case pop76_op: if (!cpu_has_mips_r6) break; if (!insn.i_format.rs) From 23080a1ef201305a9017dd3a116bf07ead7d597e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 4 Jul 2016 19:35:08 +0100 Subject: [PATCH 039/266] UPSTREAM: MIPS: inst.h: Rename cbcond{0,1}_op to pop{1,3}0_op The opcodes currently defined in inst.h as cbcond0_op & cbcond1_op are actually defined in the MIPS base instruction set manuals as pop10 & pop30 respectively. Rename them as such, for consistency with the documentation. Signed-off-by: Paul Burton Signed-off-by: James Hogan Acked-by: Ralf Baechle Cc: linux-mips@linux-mips.org Signed-off-by: Paolo Bonzini (cherry picked from commit 1b492600068d5fbd033196ce2bdb28735a23747e) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/uapi/asm/inst.h | 4 ++-- arch/mips/kernel/branch.c | 4 ++-- arch/mips/math-emu/cp1emu.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index 90a9c06a2b55..effeef52566b 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -21,11 +21,11 @@ enum major_op { spec_op, bcond_op, j_op, jal_op, beq_op, bne_op, blez_op, bgtz_op, - addi_op, cbcond0_op = addi_op, addiu_op, slti_op, sltiu_op, + addi_op, pop10_op = addi_op, addiu_op, slti_op, sltiu_op, andi_op, ori_op, xori_op, lui_op, cop0_op, cop1_op, cop2_op, cop1x_op, beql_op, bnel_op, blezl_op, bgtzl_op, - daddi_op, cbcond1_op = daddi_op, daddiu_op, ldl_op, ldr_op, + daddi_op, pop30_op = daddi_op, daddiu_op, ldl_op, ldr_op, spec2_op, jalx_op, mdmx_op, msa_op = mdmx_op, spec3_op, lb_op, lh_op, lwl_op, lw_op, lbu_op, lhu_op, lwr_op, lwu_op, diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 1d29885d633e..0f9bc15b69ca 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -820,8 +820,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, regs->cp0_epc += 8; break; #endif - case cbcond0_op: - case cbcond1_op: + case pop10_op: + case pop30_op: /* Only valid for MIPS R6 */ if (!cpu_has_mips_r6) { ret = -SIGILL; diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 052e72d05b5c..abf8a4f52eeb 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -627,8 +627,8 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, dec_insn.pc_inc + dec_insn.next_pc_inc; return 1; - case cbcond0_op: - case cbcond1_op: + case pop10_op: + case pop30_op: if (!cpu_has_mips_r6) break; if (insn.i_format.rt && !insn.i_format.rs) From a8955d815ec71515ff5d658efc08a0f65f63eb4d Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 4 Mar 2016 01:44:28 +0000 Subject: [PATCH 040/266] UPSTREAM: MIPS: traps: Correct the SIGTRAP debug ABI in `do_watch' and `do_trap_or_bp' Follow our own rules set in for SIGTRAP signals issued from `do_watch' and `do_trap_or_bp' by setting the signal code to TRAP_HWBKPT and TRAP_BRKPT respectively, for Watch exceptions and for those Breakpoint exceptions whose originating BREAK instruction's code does not have a special meaning. Keep Trap exceptions unaffected as these are not debug events. No existing user software is expected to examine signal codes for these signals as SI_KERNEL has been always used here. This change makes the MIPS port more like other Linux ports, which reduces the complexity and provides for performance improvement in GDB. Signed-off-by: Maciej W. Rozycki Cc: Pedro Alves Cc: Luis Machado Cc: linux-mips@linux-mips.org Cc: gdb@sourceware.org Patchwork: https://patchwork.linux-mips.org/patch/12758/ Signed-off-by: Ralf Baechle (cherry picked from commit 3b143cca6e1397188f507a6c727f4108861ceb8b) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/mips-r2-to-r6-emul.h | 2 +- arch/mips/kernel/mips-r2-to-r6-emul.c | 12 ++++++------ arch/mips/kernel/traps.c | 18 +++++++++++++----- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/arch/mips/include/asm/mips-r2-to-r6-emul.h b/arch/mips/include/asm/mips-r2-to-r6-emul.h index 1f6ea8352ca9..20621e1ca238 100644 --- a/arch/mips/include/asm/mips-r2-to-r6-emul.h +++ b/arch/mips/include/asm/mips-r2-to-r6-emul.h @@ -79,7 +79,7 @@ struct r2_decoder_table { }; -extern void do_trap_or_bp(struct pt_regs *regs, unsigned int code, +extern void do_trap_or_bp(struct pt_regs *regs, unsigned int code, int si_code, const char *str); #ifndef CONFIG_MIPSR2_TO_R6_EMULATOR diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index a7a9f7cfb870..66db8387ce1a 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -941,42 +941,42 @@ repeat: switch (rt) { case tgei_op: if ((long)regs->regs[rs] >= MIPSInst_SIMM(inst)) - do_trap_or_bp(regs, 0, "TGEI"); + do_trap_or_bp(regs, 0, 0, "TGEI"); MIPS_R2_STATS(traps); break; case tgeiu_op: if (regs->regs[rs] >= MIPSInst_UIMM(inst)) - do_trap_or_bp(regs, 0, "TGEIU"); + do_trap_or_bp(regs, 0, 0, "TGEIU"); MIPS_R2_STATS(traps); break; case tlti_op: if ((long)regs->regs[rs] < MIPSInst_SIMM(inst)) - do_trap_or_bp(regs, 0, "TLTI"); + do_trap_or_bp(regs, 0, 0, "TLTI"); MIPS_R2_STATS(traps); break; case tltiu_op: if (regs->regs[rs] < MIPSInst_UIMM(inst)) - do_trap_or_bp(regs, 0, "TLTIU"); + do_trap_or_bp(regs, 0, 0, "TLTIU"); MIPS_R2_STATS(traps); break; case teqi_op: if (regs->regs[rs] == MIPSInst_SIMM(inst)) - do_trap_or_bp(regs, 0, "TEQI"); + do_trap_or_bp(regs, 0, 0, "TEQI"); MIPS_R2_STATS(traps); break; case tnei_op: if (regs->regs[rs] != MIPSInst_SIMM(inst)) - do_trap_or_bp(regs, 0, "TNEI"); + do_trap_or_bp(regs, 0, 0, "TNEI"); MIPS_R2_STATS(traps); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 133274082d0a..e9215406469a 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -873,7 +874,7 @@ out: exception_exit(prev_state); } -void do_trap_or_bp(struct pt_regs *regs, unsigned int code, +void do_trap_or_bp(struct pt_regs *regs, unsigned int code, int si_code, const char *str) { siginfo_t info = { 0 }; @@ -930,7 +931,13 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code, default: scnprintf(b, sizeof(b), "%s instruction in kernel code", str); die_if_kernel(b, regs); - force_sig(SIGTRAP, current); + if (si_code) { + info.si_signo = SIGTRAP; + info.si_code = si_code; + force_sig_info(SIGTRAP, &info, current); + } else { + force_sig(SIGTRAP, current); + } } } @@ -1014,7 +1021,7 @@ asmlinkage void do_bp(struct pt_regs *regs) break; } - do_trap_or_bp(regs, bcode, "Break"); + do_trap_or_bp(regs, bcode, TRAP_BRKPT, "Break"); out: set_fs(seg); @@ -1056,7 +1063,7 @@ asmlinkage void do_tr(struct pt_regs *regs) tcode = (opcode >> 6) & ((1 << 10) - 1); } - do_trap_or_bp(regs, tcode, "Trap"); + do_trap_or_bp(regs, tcode, 0, "Trap"); out: set_fs(seg); @@ -1507,6 +1514,7 @@ asmlinkage void do_mdmx(struct pt_regs *regs) */ asmlinkage void do_watch(struct pt_regs *regs) { + siginfo_t info = { .si_signo = SIGTRAP, .si_code = TRAP_HWBKPT }; enum ctx_state prev_state; u32 cause; @@ -1527,7 +1535,7 @@ asmlinkage void do_watch(struct pt_regs *regs) if (test_tsk_thread_flag(current, TIF_LOAD_WATCH)) { mips_read_watch_registers(); local_irq_enable(); - force_sig(SIGTRAP, current); + force_sig_info(SIGTRAP, &info, current); } else { mips_clear_watch_registers(); local_irq_enable(); From d552d767e47c1697aa54675007c3af622e12311c Mon Sep 17 00:00:00 2001 From: Andrea Gelmini Date: Sat, 21 May 2016 14:01:20 +0200 Subject: [PATCH 041/266] UPSTREAM: MIPS: R6: Fix typo Signed-off-by: Andrea Gelmini Cc: macro@imgtec.com Cc: paul.burton@imgtec.com Cc: Leonid.Yegoshin@imgtec.com Cc: trivial@kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13329/ Signed-off-by: Ralf Baechle (cherry picked from commit f5be47f5a4b74ca4bc58348a0b2a6aa4c8cba1be) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mips-r2-to-r6-emul.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index 66db8387ce1a..7b349a27f9d2 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -2204,7 +2204,7 @@ fpu_emul: } /* - * Lets not return to userland just yet. It's constly and + * Lets not return to userland just yet. It's costly and * it's likely we have more R2 instructions to emulate */ if (!err && (pass++ < MIPS_R2_EMUL_TOTAL_PASS)) { From 66e81bda602748c4cf93b993e4df50d94c6ffad9 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 22 May 2016 00:39:18 +0200 Subject: [PATCH 042/266] UPSTREAM: MIPS: Spelling fix lets -> let's As noticed by Sergei in the discussion of Andrea Gelmini's patch series. Signed-off-by: Ralf Baechle Reported-by: Sergei Shtylyov (cherry picked from commit 4939788eb8559754a120531c49ffa96bb30fee06) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h | 2 +- arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h | 2 +- arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 2 +- arch/mips/kernel/branch.c | 4 ++-- arch/mips/kernel/elf.c | 2 +- arch/mips/kernel/mips-r2-to-r6-emul.c | 2 +- arch/mips/sgi-ip27/ip27-nmi.c | 2 +- arch/mips/sgi-ip27/ip27-xtalk.c | 2 +- arch/mips/sni/rm200.c | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h index ca8077afac4a..456ddba152c4 100644 --- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h +++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h @@ -100,7 +100,7 @@ typedef volatile struct au1xxx_ddma_desc { u32 dscr_nxtptr; /* Next descriptor pointer (mostly) */ /* * First 32 bytes are HW specific!!! - * Lets have some SW data following -- make sure it's 32 bytes. + * Let's have some SW data following -- make sure it's 32 bytes. */ u32 sw_status; u32 sw_context; diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h index 98d6a2f14aaf..642504188a5b 100644 --- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h @@ -22,7 +22,7 @@ /* * during early_printk no ioremap possible at this early stage - * lets use KSEG1 instead + * let's use KSEG1 instead */ #define LTQ_ASC0_BASE_ADDR 0x1E100C00 #define LTQ_EARLY_ASC KSEG1ADDR(LTQ_ASC0_BASE_ADDR) diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index dd6005b75e0c..b230347a2b84 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -75,7 +75,7 @@ extern __iomem void *ltq_cgu_membase; /* * during early_printk no ioremap is possible - * lets use KSEG1 instead + * let's use KSEG1 instead */ #define LTQ_ASC1_BASE_ADDR 0x1E100C00 #define LTQ_EARLY_ASC KSEG1ADDR(LTQ_ASC1_BASE_ADDR) diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 0f9bc15b69ca..41dab26c5d69 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -479,7 +479,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, /* * OK we are here either because we hit a NAL * instruction or because we are emulating an - * old bltzal{,l} one. Lets figure out what the + * old bltzal{,l} one. Let's figure out what the * case really is. */ if (!insn.i_format.rs) { @@ -511,7 +511,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, /* * OK we are here either because we hit a BAL * instruction or because we are emulating an - * old bgezal{,l} one. Lets figure out what the + * old bgezal{,l} one. Let's figure out what the * case really is. */ if (!insn.i_format.rs) { diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 32ce422a6886..2aaa0825e56d 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -91,7 +91,7 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32; flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags; - /* Lets see if this is an O32 ELF */ + /* Let's see if this is an O32 ELF */ if (elf32) { if (flags & EF_MIPS_FP64) { /* diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index 7b349a27f9d2..576a1b20bb0f 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -2204,7 +2204,7 @@ fpu_emul: } /* - * Lets not return to userland just yet. It's costly and + * Let's not return to userland just yet. It's costly and * it's likely we have more R2 instructions to emulate */ if (!err && (pass++ < MIPS_R2_EMUL_TOTAL_PASS)) { diff --git a/arch/mips/sgi-ip27/ip27-nmi.c b/arch/mips/sgi-ip27/ip27-nmi.c index a2358b44420c..cfceaea92724 100644 --- a/arch/mips/sgi-ip27/ip27-nmi.c +++ b/arch/mips/sgi-ip27/ip27-nmi.c @@ -23,7 +23,7 @@ typedef unsigned long machreg_t; static arch_spinlock_t nmi_lock = __ARCH_SPIN_LOCK_UNLOCKED; /* - * Lets see what else we need to do here. Set up sp, gp? + * Let's see what else we need to do here. Set up sp, gp? */ void nmi_dump(void) { diff --git a/arch/mips/sgi-ip27/ip27-xtalk.c b/arch/mips/sgi-ip27/ip27-xtalk.c index 20f582a2137a..4fe5678ba74d 100644 --- a/arch/mips/sgi-ip27/ip27-xtalk.c +++ b/arch/mips/sgi-ip27/ip27-xtalk.c @@ -67,7 +67,7 @@ static int xbow_probe(nasid_t nasid) return -ENODEV; /* - * Okay, here's a xbow. Lets arbitrate and find + * Okay, here's a xbow. Let's arbitrate and find * out if we should initialize it. Set enabled * hub connected at highest or lowest widget as * master. diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c index a046b302623e..160b88000b4b 100644 --- a/arch/mips/sni/rm200.c +++ b/arch/mips/sni/rm200.c @@ -263,7 +263,7 @@ spurious_8259A_irq: static int spurious_irq_mask; /* * At this point we can be sure the IRQ is spurious, - * lets ACK and report it. [once per IRQ] + * let's ACK and report it. [once per IRQ] */ if (!(spurious_irq_mask & irqmask)) { printk(KERN_DEBUG From aff62c8fadd7789f87c9a7b856db2f3168b298d7 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 13 Jul 2016 14:12:47 +0100 Subject: [PATCH 043/266] UPSTREAM: MIPS: c-r4k: Fix protected_writeback_scache_line for EVA The protected_writeback_scache_line() function is used by local_r4k_flush_cache_sigtramp() to flush an FPU delay slot emulation trampoline on the userland stack from the caches so it is visible to subsequent instruction fetches. Commit de8974e3f76c ("MIPS: asm: r4kcache: Add EVA cache flushing functions") updated some protected_ cache flush functions to use EVA CACHEE instructions via protected_cachee_op(), and commit 83fd43449baa ("MIPS: r4kcache: Add EVA case for protected_writeback_dcache_line") did the same thing for protected_writeback_dcache_line(), but protected_writeback_scache_line() never got updated. Lets fix that now to flush the right user address from the secondary cache rather than some arbitrary kernel unmapped address. This issue was spotted through code inspection, and it seems unlikely to be possible to hit this in practice. It theoretically affect EVA kernels on EVA capable cores with an L2 cache, where the icache fetches straight from RAM (cpu_icache_snoops_remote_store == 0), running a hard float userland with FPU disabled (nofpu). That both Malta and Boston platforms override cpu_icache_snoops_remote_store to 1 suggests that all MIPS cores fetch instructions into icache straight from L2 rather than RAM. Fixes: de8974e3f76c ("MIPS: asm: r4kcache: Add EVA cache flushing functions") Signed-off-by: James Hogan Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13800/ Signed-off-by: Ralf Baechle (cherry picked from commit 0758b116b4080d9a2a2a715bec6eee2cbd828215) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/r4kcache.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index 38902bf97adc..667ca3c467b7 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h @@ -210,7 +210,11 @@ static inline void protected_writeback_dcache_line(unsigned long addr) static inline void protected_writeback_scache_line(unsigned long addr) { +#ifdef CONFIG_EVA + protected_cachee_op(Hit_Writeback_Inv_SD, addr); +#else protected_cache_op(Hit_Writeback_Inv_SD, addr); +#endif } /* From 98561f4928838a8ab828a660d0d013db1dd50958 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 13 Jul 2016 14:12:48 +0100 Subject: [PATCH 044/266] UPSTREAM: MIPS: c-r4k: Fix sigtramp SMP call to use kmap Fix r4k_flush_cache_sigtramp() and local_r4k_flush_cache_sigtramp() to flush the delay slot emulation trampoline cacheline through a kmap rather than directly when the active_mm doesn't match that of the task initiating the flush, a bit like local_r4k_flush_cache_page() does. This would fix a corner case on SMP systems without hardware globalized hit cache ops, where a migration to another CPU after the flush, where that CPU did not have the same mm active at the time of the flush, could result in stale icache content being executed instead of the trampoline, e.g. from a previous delay slot emulation with a similar stack pointer. This case was artificially triggered by replacing the icache flush with a full indexed flush (not globalized on CM systems) and forcing the SMP call to take place, with a test program that alternated two FPU delay slots with a parent process repeatedly changing scheduler affinity. Signed-off-by: James Hogan Cc: Paul Burton Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13797/ Signed-off-by: Ralf Baechle (cherry picked from commit e523f289fe4d18d509f8827f8a293e8c5e4f51a1) Signed-off-by: Greg Kroah-Hartman --- arch/mips/mm/c-r4k.c | 75 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 5d3a25e1cfae..4d3859e11f12 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -780,25 +780,72 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) } #endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */ +struct flush_cache_sigtramp_args { + struct mm_struct *mm; + struct page *page; + unsigned long addr; +}; + /* * While we're protected against bad userland addresses we don't care * very much about what happens in that case. Usually a segmentation * fault will dump the process later on anyway ... */ -static void local_r4k_flush_cache_sigtramp(void * arg) +static void local_r4k_flush_cache_sigtramp(void *args) { + struct flush_cache_sigtramp_args *fcs_args = args; + unsigned long addr = fcs_args->addr; + struct page *page = fcs_args->page; + struct mm_struct *mm = fcs_args->mm; + int map_coherent = 0; + void *vaddr; + unsigned long ic_lsize = cpu_icache_line_size(); unsigned long dc_lsize = cpu_dcache_line_size(); unsigned long sc_lsize = cpu_scache_line_size(); - unsigned long addr = (unsigned long) arg; + + /* + * If owns no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (!has_valid_asid(mm)) + return; + + if (mm == current->active_mm) { + vaddr = NULL; + } else { + /* + * Use kmap_coherent or kmap_atomic to do flushes for + * another ASID than the current one. + */ + map_coherent = (cpu_has_dc_aliases && + page_mapcount(page) && + !Page_dcache_dirty(page)); + if (map_coherent) + vaddr = kmap_coherent(page, addr); + else + vaddr = kmap_atomic(page); + addr = (unsigned long)vaddr + (addr & ~PAGE_MASK); + } R4600_HIT_CACHEOP_WAR_IMPL; if (dc_lsize) - protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + vaddr ? flush_dcache_line(addr & ~(dc_lsize - 1)) + : protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); if (!cpu_icache_snoops_remote_store && scache_size) - protected_writeback_scache_line(addr & ~(sc_lsize - 1)); + vaddr ? flush_scache_line(addr & ~(sc_lsize - 1)) + : protected_writeback_scache_line(addr & ~(sc_lsize - 1)); if (ic_lsize) - protected_flush_icache_line(addr & ~(ic_lsize - 1)); + vaddr ? flush_icache_line(addr & ~(ic_lsize - 1)) + : protected_flush_icache_line(addr & ~(ic_lsize - 1)); + + if (vaddr) { + if (map_coherent) + kunmap_coherent(); + else + kunmap_atomic(vaddr); + } + if (MIPS4K_ICACHE_REFILL_WAR) { __asm__ __volatile__ ( ".set push\n\t" @@ -823,7 +870,23 @@ static void local_r4k_flush_cache_sigtramp(void * arg) static void r4k_flush_cache_sigtramp(unsigned long addr) { - r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr); + struct flush_cache_sigtramp_args args; + int npages; + + down_read(¤t->mm->mmap_sem); + + npages = get_user_pages_fast(addr, 1, 0, &args.page); + if (npages < 1) + goto out; + + args.mm = current->mm; + args.addr = addr; + + r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, &args); + + put_page(args.page); +out: + up_read(¤t->mm->mmap_sem); } static void r4k_flush_icache_all(void) From 1c7d67bedb0d84d045f5788536a9ca835f1768e8 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 21 Aug 2016 15:58:13 -0400 Subject: [PATCH 045/266] UPSTREAM: MIPS: kernel: Audit and remove any unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. The advantage in doing so is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each obj-y/bool instance for the presence of either and replace as needed. In the case of the n32/o32 files, we have to get rid of a couple no-op MODULE_ tags to facilitate the module.h removal. They piggy back off the fs/ elf binary support, which is also a bool Kconfig. Signed-off-by: Paul Gortmaker Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14032/ Signed-off-by: Ralf Baechle (cherry picked from commit d9d5417755eda87db8e370e4dd2175fbd8814acc) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/binfmt_elfn32.c | 8 +------- arch/mips/kernel/binfmt_elfo32.c | 8 +------- arch/mips/kernel/branch.c | 2 +- arch/mips/kernel/linux32.c | 1 - arch/mips/kernel/mips-r2-to-r6-emul.c | 1 - arch/mips/kernel/smp.c | 2 +- 6 files changed, 4 insertions(+), 18 deletions(-) diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c index 1188e00bb120..9fd86df3fcfa 100644 --- a/arch/mips/kernel/binfmt_elfn32.c +++ b/arch/mips/kernel/binfmt_elfn32.c @@ -1,5 +1,6 @@ /* * Support for n32 Linux/MIPS ELF binaries. + * Author: Ralf Baechle (ralf@linux-mips.org) * * Copyright (C) 1999, 2001 Ralf Baechle * Copyright (C) 1999, 2001 Silicon Graphics, Inc. @@ -51,7 +52,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2) #include -#include #include #include #include @@ -110,12 +110,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) #define ELF_CORE_EFLAGS EF_MIPS_ABI2 -MODULE_DESCRIPTION("Binary format loader for compatibility with n32 Linux/MIPS binaries"); -MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)"); - -#undef MODULE_DESCRIPTION -#undef MODULE_AUTHOR - #undef TASK_SIZE #define TASK_SIZE TASK_SIZE32 diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index 928767858b86..bccbc0123c13 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -1,5 +1,6 @@ /* * Support for o32 Linux/MIPS ELF binaries. + * Author: Ralf Baechle (ralf@linux-mips.org) * * Copyright (C) 1999, 2001 Ralf Baechle * Copyright (C) 1999, 2001 Silicon Graphics, Inc. @@ -72,7 +73,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #include -#include #include #include #include @@ -129,12 +129,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) value->tv_usec = rem / NSEC_PER_USEC; } -MODULE_DESCRIPTION("Binary format loader for compatibility with o32 Linux/MIPS binaries"); -MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)"); - -#undef MODULE_DESCRIPTION -#undef MODULE_AUTHOR - #undef TASK_SIZE #define TASK_SIZE TASK_SIZE32 diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 41dab26c5d69..56f166a48fbc 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 0b29646bcee7..50fb62544df7 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index 576a1b20bb0f..d163a8e0a617 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 4af08c197177..1ef11f46db5a 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include From fb0c12e677a335c99b7b2a2f72f6fc8ede79ad14 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 28 Oct 2016 08:21:03 +0100 Subject: [PATCH 046/266] UPSTREAM: MIPS: Fix FCSR Cause bit handling for correct SIGFPE issue Sanitize FCSR Cause bit handling, following a trail of past attempts: * commit 4249548454f7 ("MIPS: ptrace: Fix FP context restoration FCSR regression"), * commit 443c44032a54 ("MIPS: Always clear FCSR cause bits after emulation"), * commit 64bedffe4968 ("MIPS: Clear [MSA]FPE CSR.Cause after notify_die()"), * commit b1442d39fac2 ("MIPS: Prevent user from setting FCSR cause bits"), * commit b54d2901517d ("Properly handle branch delay slots in connection with signals."). Specifically do not mask these bits out in ptrace(2) processing and send a SIGFPE signal instead whenever a matching pair of an FCSR Cause and Enable bit is seen as execution of an affected context is about to resume. Only then clear Cause bits, and even then do not clear any bits that are set but masked with the respective Enable bits. Adjust Cause bit clearing throughout code likewise, except within the FPU emulator proper where they are set according to IEEE 754 exceptions raised as the operation emulated executed. Do so so that any IEEE 754 exceptions subject to their default handling are recorded like with operations executed by FPU hardware. Signed-off-by: Maciej W. Rozycki Cc: Paul Burton Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14460/ Signed-off-by: Ralf Baechle (cherry picked from commit 5a1aca4469fdccd5b74ba0b4e490173b2b447895) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/fpu_emulator.h | 13 +++++ arch/mips/include/asm/switch_to.h | 18 +++++++ arch/mips/kernel/mips-r2-to-r6-emul.c | 10 ++-- arch/mips/kernel/ptrace.c | 7 ++- arch/mips/kernel/traps.c | 72 +++++++++++++++------------ 5 files changed, 78 insertions(+), 42 deletions(-) diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h index 355dc25172e7..c05369e0b8d6 100644 --- a/arch/mips/include/asm/fpu_emulator.h +++ b/arch/mips/include/asm/fpu_emulator.h @@ -63,6 +63,8 @@ do { \ extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, int has_fpu, void *__user *fault_addr); +void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr, + struct task_struct *tsk); int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31); int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, @@ -81,4 +83,15 @@ static inline void fpu_emulator_init_fpu(void) set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN); } +/* + * Mask the FCSR Cause bits according to the Enable bits, observing + * that Unimplemented is always enabled. + */ +static inline unsigned long mask_fcr31_x(unsigned long fcr31) +{ + return fcr31 & (FPU_CSR_UNI_X | + ((fcr31 & FPU_CSR_ALL_E) << + (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E)))); +} + #endif /* _ASM_FPU_EMULATOR_H */ diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index ebb5c0f2f90d..c0ae27971e31 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -75,6 +75,22 @@ do { if (cpu_has_rw_llb) { \ } \ } while (0) +/* + * Check FCSR for any unmasked exceptions pending set with `ptrace', + * clear them and send a signal. + */ +#define __sanitize_fcr31(next) \ +do { \ + unsigned long fcr31 = mask_fcr31_x(next->thread.fpu.fcr31); \ + void __user *pc; \ + \ + if (unlikely(fcr31)) { \ + pc = (void __user *)task_pt_regs(next)->cp0_epc; \ + next->thread.fpu.fcr31 &= ~fcr31; \ + force_fcr31_sig(fcr31, pc, next); \ + } \ +} while (0) + /* * For newly created kernel threads switch_to() will return to * ret_from_kernel_thread, newly created user threads to ret_from_fork. @@ -85,6 +101,8 @@ do { if (cpu_has_rw_llb) { \ do { \ __mips_mt_fpaff_switch_to(prev); \ lose_fpu_inatomic(1, prev); \ + if (tsk_used_math(next)) \ + __sanitize_fcr31(next); \ if (cpu_has_dsp) { \ __save_dsp(prev); \ __restore_dsp(next); \ diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index d163a8e0a617..f6043441373d 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -899,7 +899,7 @@ static inline int mipsr2_find_op_func(struct pt_regs *regs, u32 inst, * mipsr2_decoder: Decode and emulate a MIPS R2 instruction * @regs: Process register set * @inst: Instruction to decode and emulate - * @fcr31: Floating Point Control and Status Register returned + * @fcr31: Floating Point Control and Status Register Cause bits returned */ int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31) { @@ -1172,13 +1172,13 @@ fpu_emul: err = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 0, &fault_addr); - *fcr31 = current->thread.fpu.fcr31; /* - * We can't allow the emulated instruction to leave any of - * the cause bits set in $fcr31. + * We can't allow the emulated instruction to leave any + * enabled Cause bits set in $fcr31. */ - current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; + *fcr31 = res = mask_fcr31_x(current->thread.fpu.fcr31); + current->thread.fpu.fcr31 &= ~res; /* * this is a tricky issue - lose_fpu() uses LL/SC atomics diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index c3d2d2c05fdb..0f0030e7f6d9 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -79,16 +79,15 @@ void ptrace_disable(struct task_struct *child) } /* - * Poke at FCSR according to its mask. Don't set the cause bits as - * this is currently not handled correctly in FP context restoration - * and will cause an oops if a corresponding enable bit is set. + * Poke at FCSR according to its mask. Set the Cause bits even + * if a corresponding Enable bit is set. This will be noticed at + * the time the thread is switched to and SIGFPE thrown accordingly. */ static void ptrace_setfcr31(struct task_struct *child, u32 value) { u32 fcr31; u32 mask; - value &= ~FPU_CSR_ALL_X; fcr31 = child->thread.fpu.fcr31; mask = boot_cpu_data.fpu_msk31; child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e9215406469a..2ad27a560f7f 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -706,6 +706,32 @@ asmlinkage void do_ov(struct pt_regs *regs) exception_exit(prev_state); } +/* + * Send SIGFPE according to FCSR Cause bits, which must have already + * been masked against Enable bits. This is impotant as Inexact can + * happen together with Overflow or Underflow, and `ptrace' can set + * any bits. + */ +void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr, + struct task_struct *tsk) +{ + struct siginfo si = { .si_addr = fault_addr, .si_signo = SIGFPE }; + + if (fcr31 & FPU_CSR_INV_X) + si.si_code = FPE_FLTINV; + else if (fcr31 & FPU_CSR_DIV_X) + si.si_code = FPE_FLTDIV; + else if (fcr31 & FPU_CSR_OVF_X) + si.si_code = FPE_FLTOVF; + else if (fcr31 & FPU_CSR_UDF_X) + si.si_code = FPE_FLTUND; + else if (fcr31 & FPU_CSR_INE_X) + si.si_code = FPE_FLTRES; + else + si.si_code = __SI_FAULT; + force_sig_info(SIGFPE, &si, tsk); +} + int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31) { struct siginfo si = { 0 }; @@ -715,27 +741,7 @@ int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31) return 0; case SIGFPE: - si.si_addr = fault_addr; - si.si_signo = sig; - /* - * Inexact can happen together with Overflow or Underflow. - * Respect the mask to deliver the correct exception. - */ - fcr31 &= (fcr31 & FPU_CSR_ALL_E) << - (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E)); - if (fcr31 & FPU_CSR_INV_X) - si.si_code = FPE_FLTINV; - else if (fcr31 & FPU_CSR_DIV_X) - si.si_code = FPE_FLTDIV; - else if (fcr31 & FPU_CSR_OVF_X) - si.si_code = FPE_FLTOVF; - else if (fcr31 & FPU_CSR_UDF_X) - si.si_code = FPE_FLTUND; - else if (fcr31 & FPU_CSR_INE_X) - si.si_code = FPE_FLTRES; - else - si.si_code = __SI_FAULT; - force_sig_info(sig, &si, current); + force_fcr31_sig(fcr31, fault_addr, current); return 1; case SIGBUS: @@ -798,13 +804,13 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode, /* Run the emulator */ sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, &fault_addr); - fcr31 = current->thread.fpu.fcr31; /* - * We can't allow the emulated instruction to leave any of - * the cause bits set in $fcr31. + * We can't allow the emulated instruction to leave any + * enabled Cause bits set in $fcr31. */ - current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; + fcr31 = mask_fcr31_x(current->thread.fpu.fcr31); + current->thread.fpu.fcr31 &= ~fcr31; /* Restore the hardware register state */ own_fpu(1); @@ -830,7 +836,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) goto out; /* Clear FCSR.Cause before enabling interrupts */ - write_32bit_cp1_register(CP1_STATUS, fcr31 & ~FPU_CSR_ALL_X); + write_32bit_cp1_register(CP1_STATUS, fcr31 & ~mask_fcr31_x(fcr31)); local_irq_enable(); die_if_kernel("FP exception in kernel code", regs); @@ -852,13 +858,13 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) /* Run the emulator */ sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, &fault_addr); - fcr31 = current->thread.fpu.fcr31; /* - * We can't allow the emulated instruction to leave any of - * the cause bits set in $fcr31. + * We can't allow the emulated instruction to leave any + * enabled Cause bits set in $fcr31. */ - current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; + fcr31 = mask_fcr31_x(current->thread.fpu.fcr31); + current->thread.fpu.fcr31 &= ~fcr31; /* Restore the hardware register state */ own_fpu(1); /* Using the FPU again. */ @@ -1437,13 +1443,13 @@ asmlinkage void do_cpu(struct pt_regs *regs) sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 0, &fault_addr); - fcr31 = current->thread.fpu.fcr31; /* * We can't allow the emulated instruction to leave - * any of the cause bits set in $fcr31. + * any enabled Cause bits set in $fcr31. */ - current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; + fcr31 = mask_fcr31_x(current->thread.fpu.fcr31); + current->thread.fpu.fcr31 &= ~fcr31; /* Send a signal if required. */ if (!process_fpemu_return(sig, fault_addr, fcr31) && !err) From f9b39ce8d4433676ce8ccc6e044a6818ebf5e649 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 20 Jun 2016 11:27:37 +0200 Subject: [PATCH 047/266] BACKPORT: MIPS: store the appended dtb address in a variable Instead of rewriting the arguments to match the UHI spec, store the address of a appended or UHI supplied dtb in fw_supplied_dtb. That way the original bootloader arugments are kept intact while still making the use of an appended dtb invisible for mach code. Mach code can still find out if it is an appended dtb by comparing fw_arg1 with fw_supplied_dtb. Signed-off-by: Jonas Gorski Cc: Kevin Cernekee Cc: Florian Fainelli Cc: John Crispin Cc: Paul Burton Cc: James Hogan Cc: Alban Bedel Cc: Daniel Gimpelevich Cc: Antony Pavlov Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13699/ Signed-off-by: Ralf Baechle (cherry picked from commit 15f37e1588920e010f20b53f04af94e91b8ee714) Conflicts: arch/mips/ath79/setup.c arch/mips/lantiq/prom.c arch/mips/pic32/pic32mzda/init.c Signed-off-by: Greg Kroah-Hartman --- arch/mips/bmips/setup.c | 4 ++-- arch/mips/include/asm/bootinfo.h | 4 ++++ arch/mips/kernel/head.S | 21 ++++++++++++++------- arch/mips/kernel/setup.c | 4 ++++ 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index 5b16d2955fbb..a2a8344b8a64 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -149,8 +149,8 @@ void __init plat_mem_setup(void) /* intended to somewhat resemble ARM; see Documentation/arm/Booting */ if (fw_arg0 == 0 && fw_arg1 == 0xffffffff) dtb = phys_to_virt(fw_arg2); - else if (fw_arg0 == -2) /* UHI interface */ - dtb = (void *)fw_arg1; + else if (fw_passed_dtb) /* UHI interface */ + dtb = (void *)fw_passed_dtb; else if (__dtb_start != __dtb_end) dtb = (void *)__dtb_start; else diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index b603804caac5..6effbf5c71ec 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -127,6 +127,10 @@ extern char arcs_cmdline[COMMAND_LINE_SIZE]; */ extern unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3; +#ifdef CONFIG_USE_OF +extern unsigned long fw_passed_dtb; +#endif + /* * Platform memory detection hook called by setup_arch */ diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 4e4cc5b9a771..462989e89ec9 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -94,21 +94,24 @@ NESTED(kernel_entry, 16, sp) # kernel entry point jr t0 0: +#ifdef CONFIG_USE_OF #ifdef CONFIG_MIPS_RAW_APPENDED_DTB - PTR_LA t0, __appended_dtb + PTR_LA t2, __appended_dtb #ifdef CONFIG_CPU_BIG_ENDIAN li t1, 0xd00dfeed #else li t1, 0xedfe0dd0 #endif - lw t2, (t0) - bne t1, t2, not_found - nop + lw t0, (t2) + beq t0, t1, dtb_found +#endif + li t1, -2 + beq a0, t1, dtb_found + move t2, a1 - move a1, t0 - PTR_LI a0, -2 -not_found: + li t2, 0 +dtb_found: #endif PTR_LA t0, __bss_start # clear .bss LONG_S zero, (t0) @@ -123,6 +126,10 @@ not_found: LONG_S a2, fw_arg2 LONG_S a3, fw_arg3 +#ifdef CONFIG_USE_OF + LONG_S t2, fw_passed_dtb +#endif + MTC0 zero, CP0_CONTEXT # clear context register PTR_LA $28, init_thread_union /* Set the SP after an empty pt_regs. */ diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 4f9f1ae49213..ac010f157763 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -886,6 +886,10 @@ void __init setup_arch(char **cmdline_p) unsigned long kernelsp[NR_CPUS]; unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3; +#ifdef CONFIG_USE_OF +unsigned long fw_passed_dtb; +#endif + #ifdef CONFIG_DEBUG_FS struct dentry *mips_debugfs_dir; static int __init debugfs_mips(void) From 0075089fffece3280029ec95d234079f3d9e72f3 Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Thu, 19 Nov 2015 17:38:21 -0800 Subject: [PATCH 048/266] UPSTREAM: MIPS: remove aliasing alignment if HW has antialising support MIPS hardware may have an antialising support and it works even page size is small. Setup a shared memory aliasing mask to page size if hardware has an antialising support. Big shared memory mask forces a disruption in page address assignment and that corrupts Android library memory handling. Signed-off-by: Leonid Yegoshin Cc: cernekee@gmail.com Cc: paul.gortmaker@windriver.com Cc: kumba@gentoo.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11516/ Signed-off-by: Ralf Baechle (cherry picked from commit cb80b2a38bd609b2f5a650e9ab87ea50105ad5ea) Signed-off-by: Greg Kroah-Hartman --- arch/mips/mm/c-r4k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 4d3859e11f12..5628f85bc5b0 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1733,7 +1733,7 @@ void r4k_cache_init(void) * This code supports virtually indexed processors and will be * unnecessarily inefficient on physically indexed processors. */ - if (c->dcache.linesz) + if (c->dcache.linesz && cpu_has_dc_aliases) shm_align_mask = max_t( unsigned long, c->dcache.sets * c->dcache.linesz - 1, PAGE_SIZE - 1); From 4fed79c571c30386bac6e7b1cf4fa5313d9add3f Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Mon, 13 Mar 2017 16:36:35 +0100 Subject: [PATCH 049/266] UPSTREAM: MIPS: r2-on-r6-emu: Fix BLEZL and BGTZL identification Fix the problem of inaccurate identification of instructions BLEZL and BGTZL in R2 emulation code by making sure all necessary encoding specifications are met. Previously, certain R6 instructions could be identified as BLEZL or BGTZL. R2 emulation routine didn't take into account that both BLEZL and BGTZL instructions require their rt field (bits 20 to 16 of instruction encoding) to be 0, and that, at same time, if the value in that field is not 0, the encoding may represent a legitimate MIPS R6 instruction. This means that a problem could occur after emulation optimization, when emulation routine tried to pipeline emulation, picked up a next candidate, and subsequently misrecognized an R6 instruction as BLEZL or BGTZL. It should be said that for single pass strategy, the problem does not happen because CPU doesn't trap on branch-compacts which share opcode space with BLEZL/BGTZL (but have rt field != 0, of course). Signed-off-by: Leonid Yegoshin Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Reported-by: Douglas Leung Reviewed-by: Paul Burton Cc: james.hogan@imgtec.com Cc: petar.jovanovic@imgtec.com Cc: goran.ferenc@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15456/ Signed-off-by: Ralf Baechle (cherry picked from commit 5bba7aa4958e271c3ffceb70d47d3206524cf489) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mips-r2-to-r6-emul.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index f6043441373d..8267f36191bd 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -1096,10 +1096,20 @@ repeat: } break; - case beql_op: - case bnel_op: case blezl_op: case bgtzl_op: + /* + * For BLEZL and BGTZL, rt field must be set to 0. If this + * is not the case, this may be an encoding of a MIPS R6 + * instruction, so return to CPU execution if this occurs + */ + if (MIPSInst_RT(inst)) { + err = SIGILL; + break; + } + /* fall through */ + case beql_op: + case bnel_op: if (delay_slot(regs)) { err = SIGILL; break; From 4e734c6f34248141045bf588de81b91441036bb6 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 13 Mar 2017 16:36:36 +0100 Subject: [PATCH 050/266] UPSTREAM: MIPS: r2-on-r6-emu: Clear BLTZALL and BGEZALL debugfs counters Add missing clearing of BLTZALL and BGEZALL emulation counters in function mipsr2_stats_clear_show(). Previously, it was not possible to reset BLTZALL and BGEZALL emulation counters - their value remained the same even after explicit request via debugfs. As far as other related counters are concerned, they all seem to be properly cleared. This change affects debugfs operation only, core R2 emulation functionality is not affected. Signed-off-by: Aleksandar Markovic Reviewed-by: Paul Burton Cc: james.hogan@imgtec.com Cc: leonid.yegoshin@imgtec.com Cc: douglas.leung@imgtec.com Cc: petar.jovanovic@imgtec.com Cc: miodrag.dinic@imgtec.com Cc: goran.ferenc@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15517/ Signed-off-by: Ralf Baechle (cherry picked from commit 411dac79cc2ed80f7e348ccc23eb4d8b0ba9f6d5) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mips-r2-to-r6-emul.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index 8267f36191bd..d7fbcc56c66f 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -2339,6 +2339,8 @@ static int mipsr2_stats_clear_show(struct seq_file *s, void *unused) __this_cpu_write((mipsr2bremustats).bgezl, 0); __this_cpu_write((mipsr2bremustats).bltzll, 0); __this_cpu_write((mipsr2bremustats).bgezll, 0); + __this_cpu_write((mipsr2bremustats).bltzall, 0); + __this_cpu_write((mipsr2bremustats).bgezall, 0); __this_cpu_write((mipsr2bremustats).bltzal, 0); __this_cpu_write((mipsr2bremustats).bgezal, 0); __this_cpu_write((mipsr2bremustats).beql, 0); From da8a6c79d7a1fd696b745a715045db3bb31110d2 Mon Sep 17 00:00:00 2001 From: Douglas Leung Date: Mon, 13 Mar 2017 16:36:37 +0100 Subject: [PATCH 051/266] UPSTREAM: MIPS: math-emu: Fix BC1EQZ and BC1NEZ condition handling Correct the treatment of branching conditions for BC1EQZ and BC1NEZ instructions in function isBranchInstr(). Previously, corresponding conditions were swapped, which in turn meant that, for these two instructions, function isBranchInstr() returned wrong value in its output parameter contpc. This change is actually an extension of the fix done by the commit 93583e178ebf ("MIPS: math-emu: Fix BC1{EQ,NE}Z emulation"). That commit dealt with a similar problem in function cop1Emulate(), while this commit deals with condition handling in function isBranchInstr(). The code styles of changes in these two commits are kept as consistent as possible. Signed-off-by: Douglas Leung Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Reviewed-by: Paul Burton Cc: james.hogan@imgtec.com Cc: leonid.yegoshin@imgtec.com Cc: petar.jovanovic@imgtec.com Cc: goran.ferenc@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15489/ Signed-off-by: Ralf Baechle (cherry picked from commit 8bcd84a4a37c88d8304ca3a64f0461a51487e239) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index abf8a4f52eeb..f32ec09a8ad4 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -440,6 +440,8 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, union mips_instruction insn = (union mips_instruction)dec_insn.insn; unsigned int fcr31; unsigned int bit = 0; + unsigned int bit0; + union fpureg *fpr; switch (insn.i_format.opcode) { case spec_op: @@ -707,14 +709,14 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, ((insn.i_format.rs == bc1eqz_op) || (insn.i_format.rs == bc1nez_op))) { bit = 0; + fpr = ¤t->thread.fpu.fpr[insn.i_format.rt]; + bit0 = get_fpr32(fpr, 0) & 0x1; switch (insn.i_format.rs) { case bc1eqz_op: - if (get_fpr32(¤t->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1) - bit = 1; + bit = bit0 == 0; break; case bc1nez_op: - if (!(get_fpr32(¤t->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1)) - bit = 1; + bit = bit0 != 0; break; } if (bit) From 54c1aa3ea2d1bc8612535c677f01b4f14b7551ab Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Apr 2016 12:25:38 +0100 Subject: [PATCH 052/266] UPSTREAM: MIPS: Allow emulation for unaligned [LS]DXC1 instructions If an address error exception occurs for a LDXC1 or SDXC1 instruction, within the cop1x opcode space, allow it to be passed through to the FPU emulator rather than resulting in a SIGILL. This causes LDXC1 & SDXC1 to be handled in a manner consistent with the more common LDC1 & SDC1 instructions. Signed-off-by: Paul Burton Tested-by: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13143/ Signed-off-by: Ralf Baechle (cherry picked from commit e70ac023f9515c70cf2b291a294f0f250df29847) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/unaligned.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 5c62065cbf22..28b3af73a17b 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -1191,6 +1191,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, case ldc1_op: case swc1_op: case sdc1_op: + case cop1x_op: die_if_kernel("Unaligned FP access in kernel code", regs); BUG_ON(!used_math()); From 62725e3e7dc340d70d965a5cdf5c23389a1a5af8 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:19 +0100 Subject: [PATCH 053/266] UPSTREAM: MIPS: Support generating Flattened Image Trees (.itb) Add support for generating kernel images in the Flattened Image Tree (.itb) format as supported by U-Boot. This format is essentially a Flattened Device Tree binary containing images (kernels, DTBs, ramdisks) and configurations which link those images together. The big advantages of FIT images over the uImage format are: - We can include FDTs in the kernel image in a way that the bootloader can extract it & manipulate it before providing it to the kernel. Thus we can ship FDTs as part of the kernel giving us the advantages of being able to develop & maintain the DT within the kernel tree, but also have the benefits of the bootloader being able to manipulate the FDT. Example uses for this would be to inject the kernel command line into the chosen node, or to fill in the correct memory size. - We can include multiple configurations in a single kernel image. This means that a single FIT image can, given appropriate bootloaders, be booted on different boards with the bootloader selecting an appropriate configuration & providing the correct FDT to the kernel. - We can support a multitude of hashes over the data. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14352/ Signed-off-by: Ralf Baechle (cherry picked from commit cf2a5e0bb4c66e8c43caf9f1be93a1bd7fd07b17) Signed-off-by: Greg Kroah-Hartman --- arch/mips/Makefile | 8 +++++- arch/mips/boot/Makefile | 57 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 252e347958f3..0ed953e3a5fe 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -263,7 +263,8 @@ KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y) KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0) bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) \ - VMLINUX_ENTRY_ADDRESS=$(entry-y) + VMLINUX_ENTRY_ADDRESS=$(entry-y) \ + PLATFORM=$(platform-y) LDFLAGS += -m $(ld-emul) @@ -303,6 +304,11 @@ boot-y += uImage.gz boot-y += uImage.lzma boot-y += uImage.lzo endif +boot-y += vmlinux.itb +boot-y += vmlinux.gz.itb +boot-y += vmlinux.bz2.itb +boot-y += vmlinux.lzma.itb +boot-y += vmlinux.lzo.itb # compressed boot image targets (arch/mips/boot/compressed/) bootz-y := vmlinuz diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile index acb1988f354e..ed656636acce 100644 --- a/arch/mips/boot/Makefile +++ b/arch/mips/boot/Makefile @@ -100,3 +100,60 @@ $(obj)/uImage.lzo: $(obj)/vmlinux.bin.lzo FORCE $(obj)/uImage: $(obj)/uImage.$(suffix-y) @ln -sf $(notdir $<) $@ @echo ' Image $@ is ready' + +# +# Flattened Image Tree (.itb) images +# + +targets += vmlinux.itb +targets += vmlinux.gz.itb +targets += vmlinux.bz2.itb +targets += vmlinux.lzma.itb +targets += vmlinux.lzo.itb + +quiet_cmd_cpp_its_S = ITS $@ + cmd_cpp_its_S = $(CPP) $(cpp_flags) -P -C -o $@ $< \ + -DKERNEL_NAME="\"Linux $(KERNELRELEASE)\"" \ + -DVMLINUX_BINARY="\"$(3)\"" \ + -DVMLINUX_COMPRESSION="\"$(2)\"" \ + -DVMLINUX_LOAD_ADDRESS=$(VMLINUX_LOAD_ADDRESS) \ + -DVMLINUX_ENTRY_ADDRESS=$(VMLINUX_ENTRY_ADDRESS) + +$(obj)/vmlinux.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,none,vmlinux.bin) + +$(obj)/vmlinux.gz.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,gzip,vmlinux.bin.gz) + +$(obj)/vmlinux.bz2.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,bzip2,vmlinux.bin.bz2) + +$(obj)/vmlinux.lzma.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,lzma,vmlinux.bin.lzma) + +$(obj)/vmlinux.lzo.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE + $(call if_changed_dep,cpp_its_S,lzo,vmlinux.bin.lzo) + +quiet_cmd_itb-image = ITB $@ + cmd_itb-image = \ + env PATH="$(objtree)/scripts/dtc:$(PATH)" \ + $(CONFIG_SHELL) $(MKIMAGE) \ + -D "-I dts -O dtb -p 500 \ + --include $(objtree)/arch/mips \ + --warning no-unit_address_vs_reg" \ + -f $(2) $@ + +$(obj)/vmlinux.itb: $(obj)/vmlinux.its $(obj)/vmlinux.bin FORCE + $(call if_changed,itb-image,$<) + +$(obj)/vmlinux.gz.itb: $(obj)/vmlinux.gz.its $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,itb-image,$<) + +$(obj)/vmlinux.bz2.itb: $(obj)/vmlinux.bz2.its $(obj)/vmlinux.bin.bz2 FORCE + $(call if_changed,itb-image,$<) + +$(obj)/vmlinux.lzma.itb: $(obj)/vmlinux.lzma.its $(obj)/vmlinux.bin.lzma FORCE + $(call if_changed,itb-image,$<) + +$(obj)/vmlinux.lzo.itb: $(obj)/vmlinux.lzo.its $(obj)/vmlinux.bin.lzo FORCE + $(call if_changed,itb-image,$<) From 9c0e042c61a2c66013b6905ea3c04f0766460ebb Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:20 +0100 Subject: [PATCH 054/266] UPSTREAM: MIPS: generic: Introduce generic DT-based board support Introduce a "generic" platform, which aims to be board-agnostic by making use of device trees passed by the boot protocol defined in the MIPS UHI (Universal Hosting Interface) specification. Provision is made for supporting boards which use a legacy boot protocol that can't be changed, but adding support for such boards or any others is left to followon patches. Right now the built kernels expect to be loaded to 0x80100000, ie. in kseg0. This is fine for the vast majority of MIPS platforms, but nevertheless it would be good to remove this limitation in the future by mapping the kernel via the TLB such that it can be loaded anywhere & map itself appropriately. Configuration is handled by dynamically generating configs using scripts/kconfig/merge_config.sh, somewhat similar to the way powerpc makes use of it. This allows for variations upon the configuration, eg. differing architecture revisions or subsets of driver support for differing boards, to be handled without having a large number of defconfig files. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14353/ Signed-off-by: Ralf Baechle (cherry picked from commit eed0eabd12ef061821cbfa20d903476e07645320) Signed-off-by: Greg Kroah-Hartman --- arch/mips/Kbuild.platforms | 1 + arch/mips/Kconfig | 52 ++++++ arch/mips/Makefile | 56 +++++++ arch/mips/boot/Makefile | 11 +- arch/mips/configs/generic/32r1.config | 2 + arch/mips/configs/generic/32r2.config | 3 + arch/mips/configs/generic/32r6.config | 2 + arch/mips/configs/generic/64r1.config | 4 + arch/mips/configs/generic/64r2.config | 5 + arch/mips/configs/generic/64r6.config | 4 + arch/mips/configs/generic/eb.config | 1 + arch/mips/configs/generic/el.config | 1 + arch/mips/configs/generic/micro32r2.config | 4 + arch/mips/configs/generic_defconfig | 96 +++++++++++ arch/mips/generic/Kconfig | 12 ++ arch/mips/generic/Makefile | 13 ++ arch/mips/generic/Platform | 14 ++ arch/mips/generic/init.c | 176 +++++++++++++++++++++ arch/mips/generic/irq.c | 64 ++++++++ arch/mips/generic/proc.c | 29 ++++ arch/mips/generic/vmlinux.its.S | 31 ++++ arch/mips/include/asm/machine.h | 63 ++++++++ 22 files changed, 643 insertions(+), 1 deletion(-) create mode 100644 arch/mips/configs/generic/32r1.config create mode 100644 arch/mips/configs/generic/32r2.config create mode 100644 arch/mips/configs/generic/32r6.config create mode 100644 arch/mips/configs/generic/64r1.config create mode 100644 arch/mips/configs/generic/64r2.config create mode 100644 arch/mips/configs/generic/64r6.config create mode 100644 arch/mips/configs/generic/eb.config create mode 100644 arch/mips/configs/generic/el.config create mode 100644 arch/mips/configs/generic/micro32r2.config create mode 100644 arch/mips/configs/generic_defconfig create mode 100644 arch/mips/generic/Kconfig create mode 100644 arch/mips/generic/Makefile create mode 100644 arch/mips/generic/Platform create mode 100644 arch/mips/generic/init.c create mode 100644 arch/mips/generic/irq.c create mode 100644 arch/mips/generic/proc.c create mode 100644 arch/mips/generic/vmlinux.its.S create mode 100644 arch/mips/include/asm/machine.h diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index a96c81d1d22e..5631eaa8e54b 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -11,6 +11,7 @@ platforms += cavium-octeon platforms += cobalt platforms += dec platforms += emma +platforms += generic platforms += jazz platforms += jz4740 platforms += lantiq diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 75e92584013b..a5db20d06584 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -73,6 +73,57 @@ choice prompt "System type" default SGI_IP22 +config MIPS_GENERIC + bool "Generic board-agnostic MIPS kernel" + select BOOT_RAW + select BUILTIN_DTB + select CEVT_R4K + select CLKSRC_MIPS_GIC + select COMMON_CLK + select CPU_MIPSR2_IRQ_VI + select CPU_MIPSR2_IRQ_EI + select CSRC_R4K + select DMA_PERDEV_COHERENT + select HW_HAS_PCI + select IRQ_MIPS_CPU + select LIBFDT + select MIPS_CPU_SCACHE + select MIPS_GIC + select MIPS_L1_CACHE_SHIFT_7 + select NO_EXCEPT_FILL + select PCI_DRIVERS_GENERIC + select PINCTRL + select SMP_UP if SMP + select SYS_HAS_CPU_MIPS32_R1 + select SYS_HAS_CPU_MIPS32_R2 + select SYS_HAS_CPU_MIPS32_R6 + select SYS_HAS_CPU_MIPS64_R1 + select SYS_HAS_CPU_MIPS64_R2 + select SYS_HAS_CPU_MIPS64_R6 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_HIGHMEM + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_MICROMIPS + select SYS_SUPPORTS_MIPS_CPS + select SYS_SUPPORTS_MIPS16 + select SYS_SUPPORTS_MULTITHREADING + select SYS_SUPPORTS_RELOCATABLE + select SYS_SUPPORTS_SMARTMIPS + select USB_EHCI_BIG_ENDIAN_DESC if BIG_ENDIAN + select USB_EHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN + select USB_OHCI_BIG_ENDIAN_DESC if BIG_ENDIAN + select USB_OHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN + select USB_UHCI_BIG_ENDIAN_DESC if BIG_ENDIAN + select USB_UHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN + select USE_OF + help + Select this to build a kernel which aims to support multiple boards, + generally using a flattened device tree passed from the bootloader + using the boot protocol defined in the UHI (Unified Hosting + Interface) specification. + config MIPS_ALCHEMY bool "Alchemy processor based machines" select ARCH_PHYS_ADDR_T_64BIT @@ -979,6 +1030,7 @@ source "arch/mips/ath79/Kconfig" source "arch/mips/bcm47xx/Kconfig" source "arch/mips/bcm63xx/Kconfig" source "arch/mips/bmips/Kconfig" +source "arch/mips/generic/Kconfig" source "arch/mips/jazz/Kconfig" source "arch/mips/jz4740/Kconfig" source "arch/mips/lantiq/Kconfig" diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 0ed953e3a5fe..9a1f330eb7ff 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -265,6 +265,12 @@ KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0) bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) \ VMLINUX_ENTRY_ADDRESS=$(entry-y) \ PLATFORM=$(platform-y) +ifdef CONFIG_32BIT +bootvars-y += ADDR_BITS=32 +endif +ifdef CONFIG_64BIT +bootvars-y += ADDR_BITS=64 +endif LDFLAGS += -m $(ld-emul) @@ -419,4 +425,54 @@ define archhelp echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)' echo echo ' These will be default as appropriate for a configured platform.' + echo + echo ' If you are targeting a system supported by generic kernels you may' + echo ' configure the kernel for a given architecture target like so:' + echo + echo ' {micro32,32,64}{r1,r2,r6}{el,}_defconfig ' + echo + echo ' Otherwise, the following default configurations are available:' endef + +generic_config_dir = $(srctree)/arch/$(ARCH)/configs/generic +generic_defconfigs := + +# +# If the user generates a generic kernel configuration without specifying a +# list of boards to include the config fragments for, default to including all +# available board config fragments. +# +ifeq ($(BOARDS),) +BOARDS = $(patsubst board-%.config,%,$(notdir $(wildcard $(generic_config_dir)/board-*.config))) +endif + +# +# Generic kernel configurations which merge generic_defconfig with the +# appropriate config fragments from arch/mips/configs/generic/, resulting in +# the ability to easily configure the kernel for a given architecture, +# endianness & set of boards without duplicating the needed configuration in +# hundreds of defconfig files. +# +define gen_generic_defconfigs +$(foreach bits,$(1),$(foreach rev,$(2),$(foreach endian,$(3), +target := $(bits)$(rev)$(filter el,$(endian))_defconfig +generic_defconfigs += $$(target) +$$(target): $(generic_config_dir)/$(bits)$(rev).config +$$(target): $(generic_config_dir)/$(endian).config +))) +endef + +$(eval $(call gen_generic_defconfigs,32 64,r1 r2 r6,eb el)) +$(eval $(call gen_generic_defconfigs,micro32,r2,eb el)) + +.PHONY: $(generic_defconfigs) +$(generic_defconfigs): + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \ + -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/generic_defconfig $^ \ + $(foreach board,$(BOARDS),$(generic_config_dir)/board-$(board).config) + $(Q)$(MAKE) olddefconfig + +# +# Prevent generic merge_config rules attempting to merge single fragments +# +$(generic_config_dir)/%.config: ; diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile index ed656636acce..2728a9a9c7c5 100644 --- a/arch/mips/boot/Makefile +++ b/arch/mips/boot/Makefile @@ -111,13 +111,22 @@ targets += vmlinux.bz2.itb targets += vmlinux.lzma.itb targets += vmlinux.lzo.itb +ifeq ($(ADDR_BITS),32) + itb_addr_cells = 1 +endif +ifeq ($(ADDR_BITS),64) + itb_addr_cells = 2 +endif + quiet_cmd_cpp_its_S = ITS $@ cmd_cpp_its_S = $(CPP) $(cpp_flags) -P -C -o $@ $< \ -DKERNEL_NAME="\"Linux $(KERNELRELEASE)\"" \ -DVMLINUX_BINARY="\"$(3)\"" \ -DVMLINUX_COMPRESSION="\"$(2)\"" \ -DVMLINUX_LOAD_ADDRESS=$(VMLINUX_LOAD_ADDRESS) \ - -DVMLINUX_ENTRY_ADDRESS=$(VMLINUX_ENTRY_ADDRESS) + -DVMLINUX_ENTRY_ADDRESS=$(VMLINUX_ENTRY_ADDRESS) \ + -DADDR_BITS=$(ADDR_BITS) \ + -DADDR_CELLS=$(itb_addr_cells) $(obj)/vmlinux.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE $(call if_changed_dep,cpp_its_S,none,vmlinux.bin) diff --git a/arch/mips/configs/generic/32r1.config b/arch/mips/configs/generic/32r1.config new file mode 100644 index 000000000000..a11cd8715519 --- /dev/null +++ b/arch/mips/configs/generic/32r1.config @@ -0,0 +1,2 @@ +CONFIG_CPU_MIPS32_R1=y +CONFIG_HIGHMEM=y diff --git a/arch/mips/configs/generic/32r2.config b/arch/mips/configs/generic/32r2.config new file mode 100644 index 000000000000..9570672d4f9f --- /dev/null +++ b/arch/mips/configs/generic/32r2.config @@ -0,0 +1,3 @@ +CONFIG_CPU_MIPS32_R2=y +CONFIG_MIPS_O32_FP64_SUPPORT=y +CONFIG_HIGHMEM=y diff --git a/arch/mips/configs/generic/32r6.config b/arch/mips/configs/generic/32r6.config new file mode 100644 index 000000000000..ca606e71f4d0 --- /dev/null +++ b/arch/mips/configs/generic/32r6.config @@ -0,0 +1,2 @@ +CONFIG_CPU_MIPS32_R6=y +CONFIG_HIGHMEM=y diff --git a/arch/mips/configs/generic/64r1.config b/arch/mips/configs/generic/64r1.config new file mode 100644 index 000000000000..7c1ea7e7bae3 --- /dev/null +++ b/arch/mips/configs/generic/64r1.config @@ -0,0 +1,4 @@ +CONFIG_CPU_MIPS64_R1=y +CONFIG_64BIT=y +CONFIG_MIPS32_O32=y +CONFIG_MIPS32_N32=y diff --git a/arch/mips/configs/generic/64r2.config b/arch/mips/configs/generic/64r2.config new file mode 100644 index 000000000000..b4d31ae8bfec --- /dev/null +++ b/arch/mips/configs/generic/64r2.config @@ -0,0 +1,5 @@ +CONFIG_CPU_MIPS64_R2=y +CONFIG_MIPS_O32_FP64_SUPPORT=y +CONFIG_64BIT=y +CONFIG_MIPS32_O32=y +CONFIG_MIPS32_N32=y diff --git a/arch/mips/configs/generic/64r6.config b/arch/mips/configs/generic/64r6.config new file mode 100644 index 000000000000..7cac0339c4d5 --- /dev/null +++ b/arch/mips/configs/generic/64r6.config @@ -0,0 +1,4 @@ +CONFIG_CPU_MIPS64_R6=y +CONFIG_64BIT=y +CONFIG_MIPS32_O32=y +CONFIG_MIPS32_N32=y diff --git a/arch/mips/configs/generic/eb.config b/arch/mips/configs/generic/eb.config new file mode 100644 index 000000000000..c5cdc99a6530 --- /dev/null +++ b/arch/mips/configs/generic/eb.config @@ -0,0 +1 @@ +CONFIG_CPU_BIG_ENDIAN=y diff --git a/arch/mips/configs/generic/el.config b/arch/mips/configs/generic/el.config new file mode 100644 index 000000000000..ee43fdb3b8f4 --- /dev/null +++ b/arch/mips/configs/generic/el.config @@ -0,0 +1 @@ +CONFIG_CPU_LITTLE_ENDIAN=y diff --git a/arch/mips/configs/generic/micro32r2.config b/arch/mips/configs/generic/micro32r2.config new file mode 100644 index 000000000000..b701fe7aaa68 --- /dev/null +++ b/arch/mips/configs/generic/micro32r2.config @@ -0,0 +1,4 @@ +CONFIG_CPU_MIPS32_R2=y +CONFIG_CPU_MICROMIPS=y +CONFIG_MIPS_O32_FP64_SUPPORT=y +CONFIG_HIGHMEM=y diff --git a/arch/mips/configs/generic_defconfig b/arch/mips/configs/generic_defconfig new file mode 100644 index 000000000000..c95d94c7838b --- /dev/null +++ b/arch/mips/configs/generic_defconfig @@ -0,0 +1,96 @@ +CONFIG_MIPS_GENERIC=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_MIPS_CPS=y +CONFIG_CPU_HAS_MSA=y +CONFIG_HIGHMEM=y +CONFIG_NR_CPUS=2 +CONFIG_MIPS_O32_FP64_SUPPORT=y +CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_BPF_SYSCALL=y +CONFIG_USERFAULTFD=y +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_TRIM_UNUSED_KSYMS=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_NETFILTER=y +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_SCSI=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_HW_RANDOM=y +# CONFIG_HWMON is not set +CONFIG_MFD_SYSCON=y +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +# CONFIG_USB_SUPPORT is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_FANOTIFY=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_REDUCED=y +CONFIG_DEBUG_FS=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_FTRACE is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon" +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set diff --git a/arch/mips/generic/Kconfig b/arch/mips/generic/Kconfig new file mode 100644 index 000000000000..baddb0646b23 --- /dev/null +++ b/arch/mips/generic/Kconfig @@ -0,0 +1,12 @@ +if MIPS_GENERIC + +config LEGACY_BOARDS + bool + help + Select this from your board if the board must use a legacy, non-UHI, + boot protocol. This will cause the kernel to scan through the list of + supported machines calling their detect functions in turn if the + kernel is booted without being provided with an FDT via the UHI + boot protocol. + +endif diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile new file mode 100644 index 000000000000..26e64207f7ad --- /dev/null +++ b/arch/mips/generic/Makefile @@ -0,0 +1,13 @@ +# +# Copyright (C) 2016 Imagination Technologies +# Author: Paul Burton +# +# 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. +# + +obj-y += init.o +obj-y += irq.o +obj-y += proc.o diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform new file mode 100644 index 000000000000..9a30d69e2281 --- /dev/null +++ b/arch/mips/generic/Platform @@ -0,0 +1,14 @@ +# +# Copyright (C) 2016 Imagination Technologies +# Author: Paul Burton +# +# 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. +# + +platform-$(CONFIG_MIPS_GENERIC) += generic/ +cflags-$(CONFIG_MIPS_GENERIC) += -I$(srctree)/arch/mips/include/asm/mach-generic +load-$(CONFIG_MIPS_GENERIC) += 0xffffffff80100000 +all-$(CONFIG_MIPS_GENERIC) := vmlinux.gz.itb diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c new file mode 100644 index 000000000000..0ea73e845440 --- /dev/null +++ b/arch/mips/generic/init.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static __initdata const void *fdt; +static __initdata const struct mips_machine *mach; +static __initdata const void *mach_match_data; + +void __init prom_init(void) +{ + const struct mips_machine *check_mach; + const struct of_device_id *match; + + if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) { + /* + * We booted using the UHI boot protocol, so we have been + * provided with the appropriate device tree for the board. + * Make use of it & search for any machine struct based upon + * the root compatible string. + */ + fdt = (void *)fw_arg1; + + for_each_mips_machine(check_mach) { + match = mips_machine_is_compatible(check_mach, fdt); + if (match) { + mach = check_mach; + mach_match_data = match->data; + break; + } + } + } else if (IS_ENABLED(CONFIG_LEGACY_BOARDS)) { + /* + * We weren't booted using the UHI boot protocol, but do + * support some number of boards with legacy boot protocols. + * Attempt to find the right one. + */ + for_each_mips_machine(check_mach) { + if (!check_mach->detect) + continue; + + if (!check_mach->detect()) + continue; + + mach = check_mach; + } + + /* + * If we don't recognise the machine then we can't continue, so + * die here. + */ + BUG_ON(!mach); + + /* Retrieve the machine's FDT */ + fdt = mach->fdt; + } + + BUG_ON(!fdt); +} + +void __init *plat_get_fdt(void) +{ + return (void *)fdt; +} + +void __init plat_mem_setup(void) +{ + if (mach && mach->fixup_fdt) + fdt = mach->fixup_fdt(fdt, mach_match_data); + + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); + __dt_setup_arch((void *)fdt); +} + +void __init device_tree_init(void) +{ + int err; + + unflatten_and_copy_device_tree(); + mips_cpc_probe(); + + err = register_cps_smp_ops(); + if (err) + err = register_up_smp_ops(); +} + +void __init plat_time_init(void) +{ + struct device_node *np; + struct clk *clk; + + of_clk_init(NULL); + + if (!cpu_has_counter) { + mips_hpt_frequency = 0; + } else if (mach && mach->measure_hpt_freq) { + mips_hpt_frequency = mach->measure_hpt_freq(); + } else { + np = of_get_cpu_node(0, NULL); + if (!np) { + pr_err("Failed to get CPU node\n"); + return; + } + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk)); + return; + } + + mips_hpt_frequency = clk_get_rate(clk); + clk_put(clk); + + switch (boot_cpu_type()) { + case CPU_20KC: + case CPU_25KF: + /* The counter runs at the CPU clock rate */ + break; + default: + /* The counter runs at half the CPU clock rate */ + mips_hpt_frequency /= 2; + break; + } + } + + clocksource_probe(); +} + +void __init arch_init_irq(void) +{ + struct device_node *intc_node; + + intc_node = of_find_compatible_node(NULL, NULL, + "mti,cpu-interrupt-controller"); + if (!cpu_has_veic && !intc_node) + mips_cpu_irq_init(); + + irqchip_init(); +} + +static int __init publish_devices(void) +{ + if (!of_have_populated_dt()) + panic("Device-tree not present"); + + if (of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL)) + panic("Failed to populate DT"); + + return 0; +} +arch_initcall(publish_devices); + +void __init prom_free_prom_memory(void) +{ +} diff --git a/arch/mips/generic/irq.c b/arch/mips/generic/irq.c new file mode 100644 index 000000000000..14064bdd91dd --- /dev/null +++ b/arch/mips/generic/irq.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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 +#include +#include +#include +#include +#include + +#include + +int get_c0_fdc_int(void) +{ + int mips_cpu_fdc_irq; + + if (cpu_has_veic) + panic("Unimplemented!"); + else if (gic_present) + mips_cpu_fdc_irq = gic_get_c0_fdc_int(); + else if (cp0_fdc_irq >= 0) + mips_cpu_fdc_irq = MIPS_CPU_IRQ_BASE + cp0_fdc_irq; + else + mips_cpu_fdc_irq = -1; + + return mips_cpu_fdc_irq; +} + +int get_c0_perfcount_int(void) +{ + int mips_cpu_perf_irq; + + if (cpu_has_veic) + panic("Unimplemented!"); + else if (gic_present) + mips_cpu_perf_irq = gic_get_c0_perfcount_int(); + else if (cp0_perfcount_irq >= 0) + mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; + else + mips_cpu_perf_irq = -1; + + return mips_cpu_perf_irq; +} + +unsigned int get_c0_compare_int(void) +{ + int mips_cpu_timer_irq; + + if (cpu_has_veic) + panic("Unimplemented!"); + else if (gic_present) + mips_cpu_timer_irq = gic_get_c0_compare_int(); + else + mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; + + return mips_cpu_timer_irq; +} diff --git a/arch/mips/generic/proc.c b/arch/mips/generic/proc.c new file mode 100644 index 000000000000..42b33250a4a2 --- /dev/null +++ b/arch/mips/generic/proc.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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 + +#include + +const char *get_system_type(void) +{ + const char *str; + int err; + + err = of_property_read_string(of_root, "model", &str); + if (!err) + return str; + + err = of_property_read_string_index(of_root, "compatible", 0, &str); + if (!err) + return str; + + return "Unknown"; +} diff --git a/arch/mips/generic/vmlinux.its.S b/arch/mips/generic/vmlinux.its.S new file mode 100644 index 000000000000..f67fbf1c8541 --- /dev/null +++ b/arch/mips/generic/vmlinux.its.S @@ -0,0 +1,31 @@ +/dts-v1/; + +/ { + description = KERNEL_NAME; + #address-cells = ; + + images { + kernel@0 { + description = KERNEL_NAME; + data = /incbin/(VMLINUX_BINARY); + type = "kernel"; + arch = "mips"; + os = "linux"; + compression = VMLINUX_COMPRESSION; + load = /bits/ ADDR_BITS ; + entry = /bits/ ADDR_BITS ; + hash@0 { + algo = "sha1"; + }; + }; + }; + + configurations { + default = "conf@default"; + + conf@default { + description = "Generic Linux kernel"; + kernel = "kernel@0"; + }; + }; +}; diff --git a/arch/mips/include/asm/machine.h b/arch/mips/include/asm/machine.h new file mode 100644 index 000000000000..6b444cd9526f --- /dev/null +++ b/arch/mips/include/asm/machine.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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. + */ + +#ifndef __MIPS_ASM_MACHINE_H__ +#define __MIPS_ASM_MACHINE_H__ + +#include +#include + +struct mips_machine { + const struct of_device_id *matches; + const void *fdt; + bool (*detect)(void); + const void *(*fixup_fdt)(const void *fdt, const void *match_data); + unsigned int (*measure_hpt_freq)(void); +}; + +extern long __mips_machines_start; +extern long __mips_machines_end; + +#define MIPS_MACHINE(name) \ + static const struct mips_machine __mips_mach_##name \ + __used __section(.mips.machines.init) + +#define for_each_mips_machine(mach) \ + for ((mach) = (struct mips_machine *)&__mips_machines_start; \ + (mach) < (struct mips_machine *)&__mips_machines_end; \ + (mach)++) + +/** + * mips_machine_is_compatible() - check if a machine is compatible with an FDT + * @mach: the machine struct to check + * @fdt: the FDT to check for compatibility with + * + * Check whether the given machine @mach is compatible with the given flattened + * device tree @fdt, based upon the compatibility property of the root node. + * + * Return: the device id matched if any, else NULL + */ +static inline const struct of_device_id * +mips_machine_is_compatible(const struct mips_machine *mach, const void *fdt) +{ + const struct of_device_id *match; + + if (!mach->matches) + return NULL; + + for (match = mach->matches; match->compatible; match++) { + if (fdt_node_check_compatible(fdt, 0, match->compatible) == 0) + return match; + } + + return NULL; +} + +#endif /* __MIPS_ASM_MACHINE_H__ */ From bdb66e07860f072f60d095c5dd9ab7f508d5ea00 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Sat, 15 Oct 2016 23:03:43 +0100 Subject: [PATCH 055/266] UPSTREAM: MIPS: CPC: Provide default mips_cpc_default_phys_base to ignore CPC Provide a default implementation of mips_cpc_default_phys_base() which simply returns 0, and adjust mips_cpc_phys_base() to allow for mips_cpc_default_phys_base() returning 0. This allows kernels which include CPC support to be built without platform code & simply ignore the CPC if it wasn't already enabled by the bootloader. This fixes link failures such as the following from generic defconfigs: arch/mips/built-in.o: In function `mips_cpc_phys_base': arch/mips/kernel/mips-cpc.c:47: undefined reference to `mips_cpc_default_phys_base' [ralf@linux-mips.org: changed prototype for coding style compliance.] Signed-off-by: Paul Burton Reported-by: kbuild test robot Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14401/ Signed-off-by: Ralf Baechle (cherry picked from commit 682c1e52215da4a3e89c14aad60bfc0d400b025f) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mips-cpc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index 566b8d2c092c..b232caf4d53c 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -21,6 +21,11 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock); static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); +phys_addr_t __weak mips_cpc_default_phys_base(void) +{ + return 0; +} + /** * mips_cpc_phys_base - retrieve the physical base address of the CPC * @@ -43,8 +48,12 @@ static phys_addr_t mips_cpc_phys_base(void) if (cpc_base & CM_GCR_CPC_BASE_CPCEN_MSK) return cpc_base & CM_GCR_CPC_BASE_CPCBASE_MSK; - /* Otherwise, give it the default address & enable it */ + /* Otherwise, use the default address */ cpc_base = mips_cpc_default_phys_base(); + if (!cpc_base) + return cpc_base; + + /* Enable the CPC, mapped at the default address */ write_gcr_cpc_base(cpc_base | CM_GCR_CPC_BASE_CPCEN_MSK); return cpc_base; } From ad0828f49b4e70ee6527f2d8f25bca2d0fbc71fd Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:14 +0100 Subject: [PATCH 056/266] UPSTREAM: MIPS: Sanitise coherentio semantics The coherentio variable has previously been used as a boolean value, indicating whether the user specified that coherent I/O should be enabled or disabled. It failed to take into account the case where the user does not specify any preference, in which case it makes sense that we should default to coherent I/O if the hardware supports it (hw_coherentio is non-zero). Introduce an enum to clarify the 3 different values of coherentio & use it throughout the code, modifying plat_device_is_coherent() & r4k_cache_init() to take into account the default case. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/14347/ Signed-off-by: Ralf Baechle (cherry picked from commit f23020230e682a43cc4706cabb041bba469df2d6) Signed-off-by: Greg Kroah-Hartman --- arch/mips/alchemy/common/setup.c | 6 +++--- arch/mips/include/asm/dma-coherence.h | 12 +++++++++--- arch/mips/include/asm/mach-generic/dma-coherence.h | 10 +++++++++- arch/mips/mm/c-r4k.c | 3 ++- arch/mips/mm/dma-default.c | 7 ++++--- arch/mips/mti-malta/malta-setup.c | 4 ++-- arch/mips/pci/pci-alchemy.c | 3 ++- 7 files changed, 31 insertions(+), 14 deletions(-) diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 2902138b3e0f..7faaa6d593a7 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c @@ -48,17 +48,17 @@ void __init plat_mem_setup(void) clear_c0_config(1 << 19); /* Clear Config[OD] */ hw_coherentio = 0; - coherentio = 1; + coherentio = IO_COHERENCE_ENABLED; switch (alchemy_get_cputype()) { case ALCHEMY_CPU_AU1000: case ALCHEMY_CPU_AU1500: case ALCHEMY_CPU_AU1100: - coherentio = 0; + coherentio = IO_COHERENCE_DISABLED; break; case ALCHEMY_CPU_AU1200: /* Au1200 AB USB does not support coherent memory */ if (0 == (read_c0_prid() & PRID_REV_MASK)) - coherentio = 0; + coherentio = IO_COHERENCE_DISABLED; break; } diff --git a/arch/mips/include/asm/dma-coherence.h b/arch/mips/include/asm/dma-coherence.h index bc5e85d579e6..4fbce79fb57f 100644 --- a/arch/mips/include/asm/dma-coherence.h +++ b/arch/mips/include/asm/dma-coherence.h @@ -9,14 +9,20 @@ #ifndef __ASM_DMA_COHERENCE_H #define __ASM_DMA_COHERENCE_H +enum coherent_io_user_state { + IO_COHERENCE_DEFAULT, + IO_COHERENCE_ENABLED, + IO_COHERENCE_DISABLED, +}; + #ifdef CONFIG_DMA_MAYBE_COHERENT -extern int coherentio; +extern enum coherent_io_user_state coherentio; extern int hw_coherentio; #else #ifdef CONFIG_DMA_COHERENT -#define coherentio 1 +#define coherentio IO_COHERENCE_ENABLED #else -#define coherentio 0 +#define coherentio IO_COHERENCE_DISABLED #endif #define hw_coherentio 0 #endif /* CONFIG_DMA_MAYBE_COHERENT */ diff --git a/arch/mips/include/asm/mach-generic/dma-coherence.h b/arch/mips/include/asm/mach-generic/dma-coherence.h index 0f8a354fd468..8484f82fc794 100644 --- a/arch/mips/include/asm/mach-generic/dma-coherence.h +++ b/arch/mips/include/asm/mach-generic/dma-coherence.h @@ -49,7 +49,15 @@ static inline int plat_dma_supported(struct device *dev, u64 mask) static inline int plat_device_is_coherent(struct device *dev) { - return coherentio; + switch (coherentio) { + default: + case IO_COHERENCE_DEFAULT: + return hw_coherentio; + case IO_COHERENCE_ENABLED: + return 1; + case IO_COHERENCE_DISABLED: + return 0; + } } #ifndef plat_post_dma_flush diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 5628f85bc5b0..1602ae199017 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1759,7 +1759,8 @@ void r4k_cache_init(void) local_flush_icache_range = local_r4k_flush_icache_range; #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT) - if (coherentio) { + if ((coherentio == IO_COHERENCE_ENABLED) || + ((coherentio == IO_COHERENCE_DEFAULT) && hw_coherentio)) { _dma_cache_wback_inv = (void *)cache_noop; _dma_cache_wback = (void *)cache_noop; _dma_cache_inv = (void *)cache_noop; diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 730d394ce5f0..7276b8941d17 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -25,13 +25,14 @@ #include #ifdef CONFIG_DMA_MAYBE_COHERENT -int coherentio = 0; /* User defined DMA coherency from command line. */ +/* User defined DMA coherency from command line. */ +enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT; EXPORT_SYMBOL_GPL(coherentio); int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */ static int __init setcoherentio(char *str) { - coherentio = 1; + coherentio = IO_COHERENCE_ENABLED; pr_info("Hardware DMA cache coherency (command line)\n"); return 0; } @@ -39,7 +40,7 @@ early_param("coherentio", setcoherentio); static int __init setnocoherentio(char *str) { - coherentio = 0; + coherentio = IO_COHERENCE_DISABLED; pr_info("Software DMA cache coherency (command line)\n"); return 0; } diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c index 36b09b2ea972..363c9a34e57e 100644 --- a/arch/mips/mti-malta/malta-setup.c +++ b/arch/mips/mti-malta/malta-setup.c @@ -154,12 +154,12 @@ static void __init plat_setup_iocoherency(void) * coherency instead. */ if (plat_enable_iocoherency()) { - if (coherentio == 0) + if (coherentio == IO_COHERENCE_DISABLED) pr_info("Hardware DMA cache coherency disabled\n"); else pr_info("Hardware DMA cache coherency enabled\n"); } else { - if (coherentio == 1) + if (coherentio == IO_COHERENCE_ENABLED) pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n"); else pr_info("Software DMA cache coherency enabled\n"); diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c index 28952637a862..f945ee85dcaf 100644 --- a/arch/mips/pci/pci-alchemy.c +++ b/arch/mips/pci/pci-alchemy.c @@ -429,7 +429,8 @@ static int alchemy_pci_probe(struct platform_device *pdev) /* Au1500 revisions older than AD have borked coherent PCI */ if ((alchemy_get_cputype() == ALCHEMY_CPU_AU1500) && - (read_c0_prid() < 0x01030202) && !coherentio) { + (read_c0_prid() < 0x01030202) && + (coherentio == IO_COHERENCE_DISABLED)) { val = __raw_readl(ctx->regs + PCI_REG_CONFIG); val |= PCI_CONFIG_NC; __raw_writel(val, ctx->regs + PCI_REG_CONFIG); From 5e7488820cf9e76f9395701fa8cff0b2c1767eee Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:15 +0100 Subject: [PATCH 057/266] UPSTREAM: MIPS: dma-default: Don't check hw_coherentio if device is non-coherent There are no cases where plat_device_is_coherent() will return zero whilst hw_coherentio is non-zero, and acting any differently in such a case doesn't make much sense - if a device is non-coherent with the CPU caches then access to memory "coherent" with DMA must be uncached. Clean up the nonsensical case. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14348/ Signed-off-by: Ralf Baechle (cherry picked from commit cfa93fb9c2eae805f2c16d72bad04ca49b6e16d2) Signed-off-by: Greg Kroah-Hartman --- arch/mips/mm/dma-default.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 7276b8941d17..feb87be3b62c 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -160,8 +160,7 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size, *dma_handle = plat_map_dma_mem(dev, ret, size); if (!plat_device_is_coherent(dev)) { dma_cache_wback_inv((unsigned long) ret, size); - if (!hw_coherentio) - ret = UNCAC_ADDR(ret); + ret = UNCAC_ADDR(ret); } return ret; @@ -189,7 +188,7 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); - if (!plat_device_is_coherent(dev) && !hw_coherentio) + if (!plat_device_is_coherent(dev)) addr = CAC_ADDR(addr); page = virt_to_page((void *) addr); @@ -209,7 +208,7 @@ static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma, unsigned long pfn; int ret = -ENXIO; - if (!plat_device_is_coherent(dev) && !hw_coherentio) + if (!plat_device_is_coherent(dev)) addr = CAC_ADDR(addr); pfn = page_to_pfn(virt_to_page((void *)addr)); From df5314d4c24b9ec8c36a794e58db67745fdbe410 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Oct 2016 18:18:16 +0100 Subject: [PATCH 058/266] UPSTREAM: MIPS: Support per-device DMA coherence On some MIPS systems, a subset of devices may have DMA coherent with CPU caches. For example in systems including a MIPS I/O Coherence Unit (IOCU), some devices may be connected to that IOCU whilst others are not. Prior to this patch, we have a plat_device_is_coherent() function but no implementation which does anything besides return a global true or false, optionally chosen at runtime. For devices such as those described above this is insufficient. Fix this by tracking DMA coherence on a per-device basis with a dma_coherent field in struct dev_archdata. Setting this from arch_setup_dma_ops() takes care of devices which set the dma-coherent property via device tree, and any PCI devices beneath a bridge described in DT, automatically. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14349/ Signed-off-by: Ralf Baechle (cherry picked from commit 20d330645cfb8cfecfb82b369e4d3084e429e68a) Signed-off-by: Greg Kroah-Hartman --- arch/mips/Kconfig | 4 ++++ arch/mips/include/asm/device.h | 5 +++++ arch/mips/include/asm/dma-coherence.h | 4 +++- arch/mips/include/asm/dma-mapping.h | 10 ++++++++++ arch/mips/include/asm/mach-generic/dma-coherence.h | 4 ++++ arch/mips/mm/c-r4k.c | 4 ++++ arch/mips/mm/dma-default.c | 2 +- 7 files changed, 31 insertions(+), 2 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index a5db20d06584..c9479fead851 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1140,6 +1140,10 @@ config DMA_MAYBE_COHERENT select DMA_NONCOHERENT bool +config DMA_PERDEV_COHERENT + bool + select DMA_MAYBE_COHERENT + config DMA_COHERENT bool diff --git a/arch/mips/include/asm/device.h b/arch/mips/include/asm/device.h index c94fafba9e62..21c2082a0dfb 100644 --- a/arch/mips/include/asm/device.h +++ b/arch/mips/include/asm/device.h @@ -11,6 +11,11 @@ struct dma_map_ops; struct dev_archdata { /* DMA operations on that device */ struct dma_map_ops *dma_ops; + +#ifdef CONFIG_DMA_PERDEV_COHERENT + /* Non-zero if DMA is coherent with CPU caches */ + bool dma_coherent; +#endif }; struct pdev_archdata { diff --git a/arch/mips/include/asm/dma-coherence.h b/arch/mips/include/asm/dma-coherence.h index 4fbce79fb57f..72d0eab02afc 100644 --- a/arch/mips/include/asm/dma-coherence.h +++ b/arch/mips/include/asm/dma-coherence.h @@ -15,7 +15,9 @@ enum coherent_io_user_state { IO_COHERENCE_DISABLED, }; -#ifdef CONFIG_DMA_MAYBE_COHERENT +#if defined(CONFIG_DMA_PERDEV_COHERENT) +/* Don't provide (hw_)coherentio to avoid misuse */ +#elif defined(CONFIG_DMA_MAYBE_COHERENT) extern enum coherent_io_user_state coherentio; extern int hw_coherentio; #else diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index e604f760c4a0..953236992be3 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -34,4 +34,14 @@ static inline void dma_mark_clean(void *addr, size_t size) {} extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); +#define arch_setup_dma_ops arch_setup_dma_ops +static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, + u64 size, const struct iommu_ops *iommu, + bool coherent) +{ +#ifdef CONFIG_DMA_PERDEV_COHERENT + dev->archdata.dma_coherent = coherent; +#endif +} + #endif /* _ASM_DMA_MAPPING_H */ diff --git a/arch/mips/include/asm/mach-generic/dma-coherence.h b/arch/mips/include/asm/mach-generic/dma-coherence.h index 8484f82fc794..61addb1677e9 100644 --- a/arch/mips/include/asm/mach-generic/dma-coherence.h +++ b/arch/mips/include/asm/mach-generic/dma-coherence.h @@ -49,6 +49,9 @@ static inline int plat_dma_supported(struct device *dev, u64 mask) static inline int plat_device_is_coherent(struct device *dev) { +#ifdef CONFIG_DMA_PERDEV_COHERENT + return dev->archdata.dma_coherent; +#else switch (coherentio) { default: case IO_COHERENCE_DEFAULT: @@ -58,6 +61,7 @@ static inline int plat_device_is_coherent(struct device *dev) case IO_COHERENCE_DISABLED: return 0; } +#endif } #ifndef plat_post_dma_flush diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 1602ae199017..d66a61efb143 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1759,8 +1759,12 @@ void r4k_cache_init(void) local_flush_icache_range = local_r4k_flush_icache_range; #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT) +# if defined(CONFIG_DMA_PERDEV_COHERENT) + if (0) { +# else if ((coherentio == IO_COHERENCE_ENABLED) || ((coherentio == IO_COHERENCE_DEFAULT) && hw_coherentio)) { +# endif _dma_cache_wback_inv = (void *)cache_noop; _dma_cache_wback = (void *)cache_noop; _dma_cache_inv = (void *)cache_noop; diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index feb87be3b62c..3ae73ae45938 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -24,7 +24,7 @@ #include -#ifdef CONFIG_DMA_MAYBE_COHERENT +#if defined(CONFIG_DMA_MAYBE_COHERENT) && !defined(CONFIG_DMA_PERDEV_COHERENT) /* User defined DMA coherency from command line. */ enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT; EXPORT_SYMBOL_GPL(coherentio); From 91fe2ac4d28f139e7b6ffb1b5d888164a3e7cee0 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 19 Jun 2017 17:50:12 +0200 Subject: [PATCH 059/266] UPSTREAM: MIPS: math-emu: Handle zero accumulator case in MADDF and MSUBF separately If accumulator value is zero, just return the value of previously calculated product. This brings logic in MADDF/MSUBF implementation closer to the logic in ADD/SUB case. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: James.Hogan@imgtec.com Cc: Paul.Burton@imgtec.com Cc: Raghu.Gandham@imgtec.com Cc: Leonid.Yegoshin@imgtec.com Cc: Douglas.Leung@imgtec.com Cc: Petar.Jovanovic@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16512/ Signed-off-by: Ralf Baechle (cherry picked from commit ddbfff7429a75d954bf5bdff9f2222bceb4c236a) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 5 ++++- arch/mips/math-emu/sp_maddf.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 4a2d03c72959..caa62f20a888 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -54,7 +54,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, return ieee754dp_nanxcpt(z); case IEEE754_CLASS_DNORM: DPDNORMZ; - /* QNAN is handled separately below */ + /* QNAN and ZERO cases are handled separately below */ } switch (CLPAIR(xc, yc)) { @@ -210,6 +210,9 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, } assert(rm & (DP_HIDDEN_BIT << 3)); + if (zc == IEEE754_CLASS_ZERO) + return ieee754dp_format(rs, re, rm); + /* And now the addition */ assert(zm & DP_HIDDEN_BIT); diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index a8cd8b4f235e..c91d5e5d9b5f 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -54,7 +54,7 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, return ieee754sp_nanxcpt(z); case IEEE754_CLASS_DNORM: SPDNORMZ; - /* QNAN is handled separately below */ + /* QNAN and ZERO cases are handled separately below */ } switch (CLPAIR(xc, yc)) { @@ -203,6 +203,9 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, } assert(rm & (SP_HIDDEN_BIT << 3)); + if (zc == IEEE754_CLASS_ZERO) + return ieee754sp_format(rs, re, rm); + /* And now the addition */ assert(zm & SP_HIDDEN_BIT); From 678610b55ab6ec747be68f33afde096e1e1b28a1 Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Mon, 19 Jun 2017 17:50:08 +0200 Subject: [PATCH 060/266] UPSTREAM: MIPS: cmdline: Add support for 'memmap' parameter Implement support for parsing 'memmap' kernel command line parameter. This patch covers parsing of the following two formats for 'memmap' parameter values: - nn[KMG]@ss[KMG] - nn[KMG]$ss[KMG] ([KMG] = K M or G (kilo, mega, giga)) These two allowed formats for parameter value are already documented in file kernel-parameters.txt in Documentation/admin-guide folder. Some architectures already support them, but Mips did not prior to this patch. Excerpt from Documentation/admin-guide/kernel-parameters.txt: memmap=nn[KMG]@ss[KMG] [KNL] Force usage of a specific region of memory. Region of memory to be used is from ss to ss+nn. memmap=nn[KMG]$ss[KMG] Mark specific memory as reserved. Region of memory to be reserved is from ss to ss+nn. Example: Exclude memory from 0x18690000-0x1869ffff memmap=64K$0x18690000 or memmap=0x10000$0x18690000 There is no need to update this documentation file with respect to this patch. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: James.Hogan@imgtec.com Cc: Paul.Burton@imgtec.com Cc: Raghu.Gandham@imgtec.com Cc: Leonid.Yegoshin@imgtec.com Cc: Douglas.Leung@imgtec.com Cc: Petar.Jovanovic@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16508/ Signed-off-by: Ralf Baechle (cherry picked from commit 296a7624f5b292af610d728e7e347fda341a985e) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/setup.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index ac010f157763..162a14e62669 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -597,6 +597,46 @@ static int __init early_parse_mem(char *p) } early_param("mem", early_parse_mem); +static int __init early_parse_memmap(char *p) +{ + char *oldp; + u64 start_at, mem_size; + + if (!p) + return -EINVAL; + + if (!strncmp(p, "exactmap", 8)) { + pr_err("\"memmap=exactmap\" invalid on MIPS\n"); + return 0; + } + + oldp = p; + mem_size = memparse(p, &p); + if (p == oldp) + return -EINVAL; + + if (*p == '@') { + start_at = memparse(p+1, &p); + add_memory_region(start_at, mem_size, BOOT_MEM_RAM); + } else if (*p == '#') { + pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on MIPS\n"); + return -EINVAL; + } else if (*p == '$') { + start_at = memparse(p+1, &p); + add_memory_region(start_at, mem_size, BOOT_MEM_RESERVED); + } else { + pr_err("\"memmap\" invalid format!\n"); + return -EINVAL; + } + + if (*p == '\0') { + usermem = 1; + return 0; + } else + return -EINVAL; +} +early_param("memmap", early_parse_memmap); + #ifdef CONFIG_PROC_VMCORE unsigned long setup_elfcorehdr, setup_elfcorehdr_size; static int __init early_parse_elfcorehdr(char *p) From 40a5b6cb8310515fd963f5a9fba92b6bb9bd281a Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Mon, 19 Jun 2017 17:50:09 +0200 Subject: [PATCH 061/266] UPSTREAM: MIPS: build: Fix "-modd-spreg" switch usage when compiling for mips32r6 Add "-modd-spreg" when compiling the kernel for mips32r6 target. This makes sure the kernel builds properly even with toolchains that use "-mno-odd-spreg" by default. This is the case with Android gcc. Prior to this patch, kernel builds using gcc for Android failed with following error messages, if target architecture is set to mips32r6: arch/mips/kernel/r4k_switch.S: Assembler messages: .../r4k_switch.S:210: Error: float register should be even, was 1 .../r4k_switch.S:212: Error: float register should be even, was 3 .../r4k_switch.S:214: Error: float register should be even, was 5 .../r4k_switch.S:216: Error: float register should be even, was 7 .../r4k_switch.S:218: Error: float register should be even, was 9 .../r4k_switch.S:220: Error: float register should be even, was 11 .../r4k_switch.S:222: Error: float register should be even, was 13 .../r4k_switch.S:224: Error: float register should be even, was 15 .../r4k_switch.S:226: Error: float register should be even, was 17 .../r4k_switch.S:228: Error: float register should be even, was 19 .../r4k_switch.S:230: Error: float register should be even, was 21 .../r4k_switch.S:232: Error: float register should be even, was 23 .../r4k_switch.S:234: Error: float register should be even, was 25 .../r4k_switch.S:236: Error: float register should be even, was 27 .../r4k_switch.S:238: Error: float register should be even, was 29 .../r4k_switch.S:240: Error: float register should be even, was 31 make[2]: *** [arch/mips/kernel/r4k_switch.o] Error 1 Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: James.Hogan@imgtec.com Cc: Paul.Burton@imgtec.com Cc: Raghu.Gandham@imgtec.com Cc: Leonid.Yegoshin@imgtec.com Cc: Douglas.Leung@imgtec.com Cc: Petar.Jovanovic@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16509/ Signed-off-by: Ralf Baechle (cherry picked from commit 21855a6e5b44999fb9f5493cc2c8c9eed5f32876) Signed-off-by: Greg Kroah-Hartman --- arch/mips/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 9a1f330eb7ff..a13dc908224d 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -138,7 +138,7 @@ cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS -Wa,-mips32 -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ -Wa,-mips32r2 -Wa,--trap -cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap +cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \ -Wa,-mips64 -Wa,--trap cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \ From a78332d6d8bbe6f2cf2a5e11dd8c56c2a7e988aa Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Mon, 19 Jun 2017 17:50:11 +0200 Subject: [PATCH 062/266] UPSTREAM: MIPS: unaligned: Add DSP lwx & lhx missaligned access support Add handling of missaligned access for DSP load instructions lwx & lhx. Since DSP instructions share SPECIAL3 opcode with other non-DSP instructions, necessary logic was inserted for distinguishing between instructions with SPECIAL3 opcode. For that purpose, the instruction format for DSP instructions is added to arch/mips/include/uapi/asm/inst.h. Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Cc: James.Hogan@imgtec.com Cc: Paul.Burton@imgtec.com Cc: Raghu.Gandham@imgtec.com Cc: Leonid.Yegoshin@imgtec.com Cc: Douglas.Leung@imgtec.com Cc: Petar.Jovanovic@imgtec.com Cc: Goran.Ferenc@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16511/ Signed-off-by: Ralf Baechle (cherry picked from commit 3f88ec633362efa454ca4ea289d4ad91cd44a976) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/uapi/asm/inst.h | 11 ++ arch/mips/kernel/unaligned.c | 182 +++++++++++++++++------------- 2 files changed, 115 insertions(+), 78 deletions(-) diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index effeef52566b..bd817e626da1 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -645,6 +645,16 @@ struct msa_mi10_format { /* MSA MI10 */ ;)))))) }; +struct dsp_format { /* SPEC3 DSP format instructions */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(unsigned int base : 5, + __BITFIELD_FIELD(unsigned int index : 5, + __BITFIELD_FIELD(unsigned int rd : 5, + __BITFIELD_FIELD(unsigned int op : 5, + __BITFIELD_FIELD(unsigned int func : 6, + ;)))))) +}; + struct spec3_format { /* SPEC3 */ __BITFIELD_FIELD(unsigned int opcode:6, __BITFIELD_FIELD(unsigned int rs:5, @@ -933,6 +943,7 @@ union mips_instruction { struct b_format b_format; struct ps_format ps_format; struct v_format v_format; + struct dsp_format dsp_format; struct spec3_format spec3_format; struct fb_format fb_format; struct fp0_format fp0_format; diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 28b3af73a17b..0aa4bae4d4d4 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -939,88 +939,114 @@ static void emulate_load_store_insn(struct pt_regs *regs, * The remaining opcodes are the ones that are really of * interest. */ -#ifdef CONFIG_EVA case spec3_op: - /* - * we can land here only from kernel accessing user memory, - * so we need to "switch" the address limit to user space, so - * address check can work properly. - */ - seg = get_fs(); - set_fs(USER_DS); - switch (insn.spec3_format.func) { - case lhe_op: - if (!access_ok(VERIFY_READ, addr, 2)) { - set_fs(seg); - goto sigbus; + if (insn.dsp_format.func == lx_op) { + switch (insn.dsp_format.op) { + case lwx_op: + if (!access_ok(VERIFY_READ, addr, 4)) + goto sigbus; + LoadW(addr, value, res); + if (res) + goto fault; + compute_return_epc(regs); + regs->regs[insn.dsp_format.rd] = value; + break; + case lhx_op: + if (!access_ok(VERIFY_READ, addr, 2)) + goto sigbus; + LoadHW(addr, value, res); + if (res) + goto fault; + compute_return_epc(regs); + regs->regs[insn.dsp_format.rd] = value; + break; + default: + goto sigill; } - LoadHWE(addr, value, res); - if (res) { - set_fs(seg); - goto fault; - } - compute_return_epc(regs); - regs->regs[insn.spec3_format.rt] = value; - break; - case lwe_op: - if (!access_ok(VERIFY_READ, addr, 4)) { - set_fs(seg); - goto sigbus; - } - LoadWE(addr, value, res); - if (res) { - set_fs(seg); - goto fault; - } - compute_return_epc(regs); - regs->regs[insn.spec3_format.rt] = value; - break; - case lhue_op: - if (!access_ok(VERIFY_READ, addr, 2)) { - set_fs(seg); - goto sigbus; - } - LoadHWUE(addr, value, res); - if (res) { - set_fs(seg); - goto fault; - } - compute_return_epc(regs); - regs->regs[insn.spec3_format.rt] = value; - break; - case she_op: - if (!access_ok(VERIFY_WRITE, addr, 2)) { - set_fs(seg); - goto sigbus; - } - compute_return_epc(regs); - value = regs->regs[insn.spec3_format.rt]; - StoreHWE(addr, value, res); - if (res) { - set_fs(seg); - goto fault; - } - break; - case swe_op: - if (!access_ok(VERIFY_WRITE, addr, 4)) { - set_fs(seg); - goto sigbus; - } - compute_return_epc(regs); - value = regs->regs[insn.spec3_format.rt]; - StoreWE(addr, value, res); - if (res) { - set_fs(seg); - goto fault; - } - break; - default: - set_fs(seg); - goto sigill; } - set_fs(seg); - break; +#ifdef CONFIG_EVA + else { + /* + * we can land here only from kernel accessing user + * memory, so we need to "switch" the address limit to + * user space, so that address check can work properly. + */ + seg = get_fs(); + set_fs(USER_DS); + switch (insn.spec3_format.func) { + case lhe_op: + if (!access_ok(VERIFY_READ, addr, 2)) { + set_fs(seg); + goto sigbus; + } + LoadHWE(addr, value, res); + if (res) { + set_fs(seg); + goto fault; + } + compute_return_epc(regs); + regs->regs[insn.spec3_format.rt] = value; + break; + case lwe_op: + if (!access_ok(VERIFY_READ, addr, 4)) { + set_fs(seg); + goto sigbus; + } + LoadWE(addr, value, res); + if (res) { + set_fs(seg); + goto fault; + } + compute_return_epc(regs); + regs->regs[insn.spec3_format.rt] = value; + break; + case lhue_op: + if (!access_ok(VERIFY_READ, addr, 2)) { + set_fs(seg); + goto sigbus; + } + LoadHWUE(addr, value, res); + if (res) { + set_fs(seg); + goto fault; + } + compute_return_epc(regs); + regs->regs[insn.spec3_format.rt] = value; + break; + case she_op: + if (!access_ok(VERIFY_WRITE, addr, 2)) { + set_fs(seg); + goto sigbus; + } + compute_return_epc(regs); + value = regs->regs[insn.spec3_format.rt]; + StoreHWE(addr, value, res); + if (res) { + set_fs(seg); + goto fault; + } + break; + case swe_op: + if (!access_ok(VERIFY_WRITE, addr, 4)) { + set_fs(seg); + goto sigbus; + } + compute_return_epc(regs); + value = regs->regs[insn.spec3_format.rt]; + StoreWE(addr, value, res); + if (res) { + set_fs(seg); + goto fault; + } + break; + default: + set_fs(seg); + goto sigill; + } + set_fs(seg); + } #endif + break; case lh_op: if (!access_ok(VERIFY_READ, addr, 2)) goto sigbus; From 7ff79d8a3d814e5eba3417658537108ca704ad60 Mon Sep 17 00:00:00 2001 From: Goran Ferenc Date: Wed, 28 Jun 2017 17:55:28 +0200 Subject: [PATCH 063/266] UPSTREAM: MIPS: VDSO: Fix conversions in do_monotonic()/do_monotonic_coarse() Fix incorrect calculation in do_monotonic() and do_monotonic_coarse() function that in turn caused incorrect values returned by the vdso version of system call clock_gettime() on mips64 if its system clock ID parameter was CLOCK_MONOTONIC or CLOCK_MONOTONIC_COARSE. Consider these variables and their types on mips32 and mips64: tk->wall_to_monotonic.tv_sec s64, s64 (kernel/vdso.c) vdso_data.wall_to_mono_sec u32, u32 (kernel/vdso.c) to_mono_sec u32, u32 (vdso/gettimeofday.c) ts->tv_sec s32, s64 (vdso/gettimeofday.c) For mips64 case, u32 vdso_data.wall_to_mono_sec variable is updated from the 64-bit signed variable tk->wall_to_monotonic.tv_sec (kernel/vdso.c:76) which is a negative number holding the time passed from 1970-01-01 to the time boot started. This 64-bit signed value is currently around 47+ years, in seconds. For instance, let this value be: -1489757461 or 11111111111111111111111111111111 10100111001101000001101011101011 By updating 32-bit vdso_data.wall_to_mono_sec variable, we lose upper 32 bits (signed 1's). to_mono_sec variable is a parameter of do_monotonic() and do_monotonic_coarse() functions which holds vdso_data.wall_to_mono_sec value. Its value needs to be added (or subtracted considering it holds negative value from the tk->wall_to_monotonic.tv_sec) to the current time passed from 1970-01-01 (ts->tv_sec), which is again something like 47+ years, but increased by the time passed from the boot to the current time. ts->tv_sec is 32-bit long in case of 32-bit architecture and 64-bit long in case of 64-bit architecture. Consider the update of ts->tv_sec (vdso/gettimeofday.c:55 & 167): ts->tv_sec += to_mono_sec; mips32 case: This update will be performed correctly, since both ts->tv_sec and to_mono_sec are 32-bit long and the sign in to_mono_sec is preserved. Implicit conversion from u32 to s32 will be done correctly. mips64 case: This update will be wrong, since the implicit conversion will not be done correctly. The reason is that the conversion will be from u32 to s64. This is because to_mono_sec is 32-bit long for both mips32 and mips64 cases and s64..33 bits of converted to_mono_sec variable will be zeros. So, in order to make MIPS64 implementation work properly for MONOTONIC and MONOTONIC_COARSE clock ids on mips64, the size of wall_to_mono_sec variable in mips_vdso_data union and respective parameters in do_monotonic() and do_monotonic_coarse() functions should be changed from u32 to u64. Because of consistency, this size change from u32 and u64 is also done for wall_to_mono_nsec variable and corresponding function parameters. As far as similar situations for other architectures are concerned, let's take a look at arm. Arm has two distinct vdso_data structures for 32-bit & 64-bit cases, and arm's wall_to_mono_sec and wall_to_mono_nsec are u32 for 32-bit and u64 for 64-bit cases. On the other hand, MIPS has only one structure (mips_vdso_data), hence the need for changing the size of above mentioned parameters. Signed-off-by: Goran Ferenc Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: James Hogan Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16638/ Signed-off-by: Ralf Baechle (cherry picked from commit 8ec7f15b8cca4f790df5cdf33f26e2926d4ee2fd) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/vdso.h | 4 ++-- arch/mips/vdso/gettimeofday.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/vdso.h b/arch/mips/include/asm/vdso.h index 8f4ca5dd992b..b7cd6cf77b83 100644 --- a/arch/mips/include/asm/vdso.h +++ b/arch/mips/include/asm/vdso.h @@ -79,8 +79,8 @@ union mips_vdso_data { struct { u64 xtime_sec; u64 xtime_nsec; - u32 wall_to_mono_sec; - u32 wall_to_mono_nsec; + u64 wall_to_mono_sec; + u64 wall_to_mono_nsec; u32 seq_count; u32 cs_shift; u8 clock_mode; diff --git a/arch/mips/vdso/gettimeofday.c b/arch/mips/vdso/gettimeofday.c index ce89c9e294f9..fd7d433970bf 100644 --- a/arch/mips/vdso/gettimeofday.c +++ b/arch/mips/vdso/gettimeofday.c @@ -39,8 +39,8 @@ static __always_inline int do_monotonic_coarse(struct timespec *ts, const union mips_vdso_data *data) { u32 start_seq; - u32 to_mono_sec; - u32 to_mono_nsec; + u64 to_mono_sec; + u64 to_mono_nsec; do { start_seq = vdso_data_read_begin(data); @@ -148,8 +148,8 @@ static __always_inline int do_monotonic(struct timespec *ts, { u32 start_seq; u64 ns; - u32 to_mono_sec; - u32 to_mono_nsec; + u64 to_mono_sec; + u64 to_mono_nsec; do { start_seq = vdso_data_read_begin(data); From 3ab7b67564de5335868033205bd11cdfa7da4377 Mon Sep 17 00:00:00 2001 From: Goran Ferenc Date: Wed, 28 Jun 2017 17:55:29 +0200 Subject: [PATCH 064/266] UPSTREAM: MIPS: VDSO: Add implementation of clock_gettime() fallback This patch adds clock_gettime_fallback() function that wraps assembly invocation of clock_gettime() syscall using __NR_clock_gettime. This function is used if pure VDSO implementation of clock_gettime() does not succeed for any reason. For example, it is called if the clkid parameter of clock_gettime() is not one of the clkids listed in the switch-case block of the function __vdso_clock_gettime() (one such case for clkid is CLOCK_BOOTIME). If syscall invocation via __NR_clock_gettime fails, register a3 will be set. So, after the syscall, register a3 is tested and the return value is negated if it's set. Signed-off-by: Goran Ferenc Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: James Hogan Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16639/ Signed-off-by: Ralf Baechle (cherry picked from commit 180902e08f051f72c89ffa366f4e4f7a8e9c753e) Signed-off-by: Greg Kroah-Hartman --- arch/mips/vdso/gettimeofday.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/arch/mips/vdso/gettimeofday.c b/arch/mips/vdso/gettimeofday.c index fd7d433970bf..5f6337545ee2 100644 --- a/arch/mips/vdso/gettimeofday.c +++ b/arch/mips/vdso/gettimeofday.c @@ -20,6 +20,24 @@ #include #include +static __always_inline long clock_gettime_fallback(clockid_t _clkid, + struct timespec *_ts) +{ + register struct timespec *ts asm("a1") = _ts; + register clockid_t clkid asm("a0") = _clkid; + register long ret asm("v0"); + register long nr asm("v0") = __NR_clock_gettime; + register long error asm("a3"); + + asm volatile( + " syscall\n" + : "=r" (ret), "=r" (error) + : "r" (clkid), "r" (ts), "r" (nr) + : "memory"); + + return error ? -ret : ret; +} + static __always_inline int do_realtime_coarse(struct timespec *ts, const union mips_vdso_data *data) { @@ -207,7 +225,7 @@ int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts) { const union mips_vdso_data *data = get_vdso_data(); - int ret; + int ret = -1; switch (clkid) { case CLOCK_REALTIME_COARSE: @@ -223,10 +241,11 @@ int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts) ret = do_monotonic(ts, data); break; default: - ret = -ENOSYS; break; } - /* If we return -ENOSYS libc should fall back to a syscall. */ + if (ret) + ret = clock_gettime_fallback(clkid, ts); + return ret; } From 491fef35384656b5e11f3bf4ea21693b7a3cc9e4 Mon Sep 17 00:00:00 2001 From: Goran Ferenc Date: Wed, 28 Jun 2017 17:55:30 +0200 Subject: [PATCH 065/266] UPSTREAM: MIPS: VDSO: Add implementation of gettimeofday() fallback This patch adds gettimeofday_fallback() function that wraps assembly invocation of gettimeofday() syscall using __NR_gettimeofday. This function is used if pure VDSO implementation gettimeofday() does not succeed for any reason. Its imeplementation is enclosed in "#ifdef CONFIG_MIPS_CLOCK_VSYSCALL" to be in sync with the similar arrangement for __vdso_gettimeofday(). If syscall invocation via __NR_gettimeofday fails, register a3 will be set. So, after the syscall, register a3 is tested and the return valuem is negated if it's set. Signed-off-by: Goran Ferenc Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: James Hogan Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16640/ Signed-off-by: Ralf Baechle (cherry picked from commit 0b523a85e134d41f57ddd8c5193bd9f0a5e20b0d) Signed-off-by: Greg Kroah-Hartman --- arch/mips/vdso/gettimeofday.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/mips/vdso/gettimeofday.c b/arch/mips/vdso/gettimeofday.c index 5f6337545ee2..23305bf6c7a2 100644 --- a/arch/mips/vdso/gettimeofday.c +++ b/arch/mips/vdso/gettimeofday.c @@ -20,6 +20,28 @@ #include #include +#ifdef CONFIG_MIPS_CLOCK_VSYSCALL + +static __always_inline long gettimeofday_fallback(struct timeval *_tv, + struct timezone *_tz) +{ + register struct timezone *tz asm("a1") = _tz; + register struct timeval *tv asm("a0") = _tv; + register long ret asm("v0"); + register long nr asm("v0") = __NR_gettimeofday; + register long error asm("a3"); + + asm volatile( + " syscall\n" + : "=r" (ret), "=r" (error) + : "r" (tv), "r" (tz), "r" (nr) + : "memory"); + + return error ? -ret : ret; +} + +#endif + static __always_inline long clock_gettime_fallback(clockid_t _clkid, struct timespec *_ts) { @@ -205,7 +227,7 @@ int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) ret = do_realtime(&ts, data); if (ret) - return ret; + return gettimeofday_fallback(tv, tz); if (tv) { tv->tv_sec = ts.tv_sec; From 2150cb63454b07e0ff1ba440231503fd2630c00f Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Wed, 28 Jun 2017 17:55:31 +0200 Subject: [PATCH 066/266] UPSTREAM: MIPS: VDSO: Fix a mismatch between comment and preprocessor constant Sync the comment with its preprocessor constant counterpart. Signed-off-by: Aleksandar Markovic Cc: James Hogan Cc: Miodrag Dinic Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16641/ Signed-off-by: Ralf Baechle (cherry picked from commit bdb94f6e824d5bd1577c3f80cbe0c6b4beab5a5c) Signed-off-by: Greg Kroah-Hartman --- arch/mips/vdso/gettimeofday.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/vdso/gettimeofday.c b/arch/mips/vdso/gettimeofday.c index 23305bf6c7a2..974276e828b2 100644 --- a/arch/mips/vdso/gettimeofday.c +++ b/arch/mips/vdso/gettimeofday.c @@ -242,7 +242,7 @@ int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) return 0; } -#endif /* CONFIG_CLKSRC_MIPS_GIC */ +#endif /* CONFIG_MIPS_CLOCK_VSYSCALL */ int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts) { From 5381edf8435d65b85e774ed2e681bd4b812ff2c8 Mon Sep 17 00:00:00 2001 From: Goran Ferenc Date: Thu, 27 Jul 2017 18:08:47 +0200 Subject: [PATCH 067/266] UPSTREAM: MIPS: VDSO: Fix clobber lists in fallback code paths Extend clobber lists to include all GP registers. Fixes: 0b523a85e134 ("MIPS: VDSO: Add implementation of gettimeofday() fallback") Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Reviewed-by: James Hogan Cc: Bo Hu Cc: Douglas Leung Cc: James Hogan Cc: Jin Qian Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16879/ Signed-off-by: Ralf Baechle (cherry picked from commit b399ee28c29c07f6a7ad87dade9148828757e6e9) Signed-off-by: Greg Kroah-Hartman --- arch/mips/vdso/gettimeofday.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/mips/vdso/gettimeofday.c b/arch/mips/vdso/gettimeofday.c index 974276e828b2..e2690d7ca4dd 100644 --- a/arch/mips/vdso/gettimeofday.c +++ b/arch/mips/vdso/gettimeofday.c @@ -35,7 +35,8 @@ static __always_inline long gettimeofday_fallback(struct timeval *_tv, " syscall\n" : "=r" (ret), "=r" (error) : "r" (tv), "r" (tz), "r" (nr) - : "memory"); + : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", + "$14", "$15", "$24", "$25", "hi", "lo", "memory"); return error ? -ret : ret; } @@ -55,7 +56,8 @@ static __always_inline long clock_gettime_fallback(clockid_t _clkid, " syscall\n" : "=r" (ret), "=r" (error) : "r" (clkid), "r" (ts), "r" (nr) - : "memory"); + : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", + "$14", "$15", "$24", "$25", "hi", "lo", "memory"); return error ? -ret : ret; } From 872946b047f1146c220956bd8457eb90d4b241e9 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 9 Jan 2017 01:26:37 +0100 Subject: [PATCH 068/266] UPSTREAM: tty: goldfish: Fix a parameter of a call to free_irq 'request_irq()' and 'free_irq()' should be called with the same dev_id. Signed-off-by: Christophe JAILLET Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 1a5c2d1de7d35f5eb9793266237903348989502b) Signed-off-by: Greg Kroah-Hartman --- drivers/tty/goldfish.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 1e332855b933..b2f830d6a654 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -300,7 +300,7 @@ static int goldfish_tty_probe(struct platform_device *pdev) return 0; err_tty_register_device_failed: - free_irq(irq, pdev); + free_irq(irq, qtty); err_request_irq_failed: goldfish_tty_current_line_count--; if (goldfish_tty_current_line_count == 0) From 9d434b683579802d247cdfe96cd7808186d495a8 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 27 Jul 2017 18:08:54 +0200 Subject: [PATCH 069/266] UPSTREAM: MIPS: math-emu: .: Fix NaN propagation Fix the cases of . when any of three inputs is any NaN. Correct behavior of . fd, fs, ft is following: - if any of inputs is sNaN, return a sNaN using following rules: if only one input is sNaN, return that one; if more than one input is sNaN, order of precedence for return value is fd, fs, ft - if no input is sNaN, but at least one of inputs is qNaN, return a qNaN using following rules: if only one input is qNaN, return that one; if more than one input is qNaN, order of precedence for return value is fd, fs, ft The previous code contained correct handling of some above cases, but not all. Also, such handling was scattered into various cases of "switch (CLPAIR(xc, yc))" statement, and elsewhere. With this patch, this logic is placed in one place, and "switch (CLPAIR(xc, yc))" is significantly simplified. A relevant example: MADDF.S fd,fs,ft: If fs contains qNaN1, ft contains qNaN2, and fd contains qNaN3, fd is going to contain qNaN3 (without this patch, it used to contain qNaN1). Fixes: e24c3bec3e8e ("MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction") Fixes: 83d43305a1df ("MIPS: math-emu: Add support for the MIPS R6 MSUBF FPU instruction") Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Reviewed-by: James Hogan Cc: Bo Hu Cc: Douglas Leung Cc: Jin Qian Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: # 4.7+ Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16886/ Signed-off-by: Ralf Baechle (cherry picked from commit e840be6e7057757befc3581e1699e30fe7f0dd51) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 66 +++++++++++----------------------- arch/mips/math-emu/sp_maddf.c | 68 ++++++++++++----------------------- 2 files changed, 42 insertions(+), 92 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index caa62f20a888..8b1bd42aad3c 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -48,52 +48,34 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, ieee754_clearcx(); - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); + /* + * Handle the cases when at least one of x, y or z is a NaN. + * Order of precedence is sNaN, qNaN and z, x, y. + */ + if (zc == IEEE754_CLASS_SNAN) return ieee754dp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - DPDNORMZ; - /* QNAN and ZERO cases are handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + if (xc == IEEE754_CLASS_SNAN) return ieee754dp_nanxcpt(x); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + if (yc == IEEE754_CLASS_SNAN) + return ieee754dp_nanxcpt(y); + if (zc == IEEE754_CLASS_QNAN) + return z; + if (xc == IEEE754_CLASS_QNAN) + return x; + if (yc == IEEE754_CLASS_QNAN) return y; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; + if (zc == IEEE754_CLASS_DNORM) + DPDNORMZ; + /* ZERO z cases are handled separately below */ + switch (CLPAIR(xc, yc)) { /* * Infinity handling */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754dp_indef(); @@ -102,8 +84,6 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; return ieee754dp_inf(xs ^ ys); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): @@ -120,25 +100,19 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, DPDNORMX; case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754dp_inf(zs); DPDNORMY; break; case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754dp_inf(zs); DPDNORMX; break; case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754dp_inf(zs); /* fall through to real computations */ } diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index c91d5e5d9b5f..6cdaa2a85c9d 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -48,51 +48,35 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, ieee754_clearcx(); - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); + /* + * Handle the cases when at least one of x, y or z is a NaN. + * Order of precedence is sNaN, qNaN and z, x, y. + */ + if (zc == IEEE754_CLASS_SNAN) return ieee754sp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - SPDNORMZ; - /* QNAN and ZERO cases are handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + if (xc == IEEE754_CLASS_SNAN) return ieee754sp_nanxcpt(x); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + if (yc == IEEE754_CLASS_SNAN) + return ieee754sp_nanxcpt(y); + if (zc == IEEE754_CLASS_QNAN) + return z; + if (xc == IEEE754_CLASS_QNAN) + return x; + if (yc == IEEE754_CLASS_QNAN) return y; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; + if (zc == IEEE754_CLASS_DNORM) + SPDNORMZ; + /* ZERO z cases are handled separately below */ + + switch (CLPAIR(xc, yc)) { + /* * Infinity handling */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754sp_indef(); @@ -101,8 +85,6 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; return ieee754sp_inf(xs ^ ys); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): @@ -119,25 +101,19 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, SPDNORMX; case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754sp_inf(zs); SPDNORMY; break; case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754sp_inf(zs); SPDNORMX; break; case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754sp_inf(zs); /* fall through to real computations */ } From a2e223208c437b9d8b74c5fa9672fe17b9956501 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 27 Jul 2017 18:08:55 +0200 Subject: [PATCH 070/266] UPSTREAM: MIPS: math-emu: .: Fix some cases of infinite inputs Fix the cases of . when any of two multiplicands is infinity. The correct behavior in such cases is affected by the nature of third input. Cases of addition of infinities with opposite signs and subtraction of infinities with same signs may arise and must be handles separately. Also, the value od flags argument (that determines whether the instruction is MADDF or MSUBF) affects the outcome. Relevant examples: MADDF.S fd,fs,ft: If fs contains +inf, ft contains +inf, and fd contains -inf, fd is going to contain indef (without this patch, it used to contain -inf). MSUBF.S fd,fs,ft: If fs contains +inf, ft contains 1.0, and fd contains +0.0, fd is going to contain -inf (without this patch, it used to contain +inf). Fixes: e24c3bec3e8e ("MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction") Fixes: 83d43305a1df ("MIPS: math-emu: Add support for the MIPS R6 MSUBF FPU instruction") Signed-off-by: Douglas Leung Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Reviewed-by: James Hogan Cc: Douglas Leung Cc: Bo Hu Cc: Jin Qian Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: # 4.7+ Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16887/ Signed-off-by: Ralf Baechle (cherry picked from commit 0c64fe6348687f0e1cea9a608eae9d351124a73a) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 22 +++++++++++++++++++++- arch/mips/math-emu/sp_maddf.c | 22 +++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 8b1bd42aad3c..557a0a118827 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -84,7 +84,27 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - return ieee754dp_inf(xs ^ ys); + if ((zc == IEEE754_CLASS_INF) && + ((!(flags & maddf_negate_product) && (zs != (xs ^ ys))) || + ((flags & maddf_negate_product) && (zs == (xs ^ ys))))) { + /* + * Cases of addition of infinities with opposite signs + * or subtraction of infinities with same signs. + */ + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); + } + /* + * z is here either not an infinity, or an infinity having the + * same sign as product (x*y) (in case of MADDF.D instruction) + * or product -(x*y) (in MSUBF.D case). The result must be an + * infinity, and its sign is determined only by the value of + * (flags & maddf_negate_product) and the signs of x and y. + */ + if (flags & maddf_negate_product) + return ieee754dp_inf(1 ^ (xs ^ ys)); + else + return ieee754dp_inf(xs ^ ys); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index 6cdaa2a85c9d..0d8d25f4b737 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -85,7 +85,27 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - return ieee754sp_inf(xs ^ ys); + if ((zc == IEEE754_CLASS_INF) && + ((!(flags & maddf_negate_product) && (zs != (xs ^ ys))) || + ((flags & maddf_negate_product) && (zs == (xs ^ ys))))) { + /* + * Cases of addition of infinities with opposite signs + * or subtraction of infinities with same signs. + */ + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); + } + /* + * z is here either not an infinity, or an infinity having the + * same sign as product (x*y) (in case of MADDF.D instruction) + * or product -(x*y) (in MSUBF.D case). The result must be an + * infinity, and its sign is determined only by the value of + * (flags & maddf_negate_product) and the signs of x and y. + */ + if (flags & maddf_negate_product) + return ieee754sp_inf(1 ^ (xs ^ ys)); + else + return ieee754sp_inf(xs ^ ys); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): From 91e26d5b2df5d9ce97379914eb27fbfd7691c137 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 27 Jul 2017 18:08:56 +0200 Subject: [PATCH 071/266] UPSTREAM: MIPS: math-emu: .: Fix some cases of zero inputs Fix the cases of . when any of two multiplicands is +0 or -0, and the third input is also +0 or -0. Depending on the signs of inputs, certain special cases must be handled. A relevant example: MADDF.S fd,fs,ft: If fs contains +0.0, ft contains -0.0, and fd contains 0.0, fd is going to contain +0.0 (without this patch, it used to contain -0.0). Fixes: e24c3bec3e8e ("MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction") Fixes: 83d43305a1df ("MIPS: math-emu: Add support for the MIPS R6 MSUBF FPU instruction") Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Reviewed-by: James Hogan Cc: Bo Hu Cc: Douglas Leung Cc: Jin Qian Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: # 4.7+ Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16888/ Signed-off-by: Ralf Baechle (cherry picked from commit 7cf64ce4d37f1b4f44365fcf77f565d523819dcd) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 18 +++++++++++++++++- arch/mips/math-emu/sp_maddf.c | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 557a0a118827..c38fe1bde875 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -113,7 +113,23 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): if (zc == IEEE754_CLASS_INF) return ieee754dp_inf(zs); - /* Multiplication is 0 so just return z */ + if (zc == IEEE754_CLASS_ZERO) { + /* Handle cases +0 + (-0) and similar ones. */ + if ((!(flags & maddf_negate_product) + && (zs == (xs ^ ys))) || + ((flags & maddf_negate_product) + && (zs != (xs ^ ys)))) + /* + * Cases of addition of zeros of equal signs + * or subtraction of zeroes of opposite signs. + * The sign of the resulting zero is in any + * such case determined only by the sign of z. + */ + return z; + + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); + } + /* x*y is here 0, and z is not 0, so just return z */ return z; case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index 0d8d25f4b737..4241ec19df12 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -114,7 +114,23 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): if (zc == IEEE754_CLASS_INF) return ieee754sp_inf(zs); - /* Multiplication is 0 so just return z */ + if (zc == IEEE754_CLASS_ZERO) { + /* Handle cases +0 + (-0) and similar ones. */ + if ((!(flags & maddf_negate_product) + && (zs == (xs ^ ys))) || + ((flags & maddf_negate_product) + && (zs != (xs ^ ys)))) + /* + * Cases of addition of zeros of equal signs + * or subtraction of zeroes of opposite signs. + * The sign of the resulting zero is in any + * such case determined only by the sign of z. + */ + return z; + + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); + } + /* x*y is here 0, and z is not 0, so just return z */ return z; case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): From 75edb6197d50591fd77a19d4b7f7f36a24eb7bfc Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 27 Jul 2017 18:08:57 +0200 Subject: [PATCH 072/266] UPSTREAM: MIPS: math-emu: .: Clean up "maddf_flags" enumeration Fix definition and usage of "maddf_flags" enumeration. Avoid duplicate definition and apply more common capitalization. This patch does not change any scenario. It just makes MADDF and MSUBF emulation code more readable and easier to maintain, and hopefully prevents future bugs as well. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Reviewed-by: James Hogan Cc: Bo Hu Cc: Douglas Leung Cc: Jin Qian Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: # 4.7+ Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16889/ Signed-off-by: Ralf Baechle (cherry picked from commit ae11c0619973ffd73a496308d8a1cb5e1a353737) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 19 ++++++++----------- arch/mips/math-emu/ieee754int.h | 4 ++++ arch/mips/math-emu/sp_maddf.c | 19 ++++++++----------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index c38fe1bde875..e799fc826b0c 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -14,9 +14,6 @@ #include "ieee754dp.h" -enum maddf_flags { - maddf_negate_product = 1 << 0, -}; static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp y, enum maddf_flags flags) @@ -85,8 +82,8 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): if ((zc == IEEE754_CLASS_INF) && - ((!(flags & maddf_negate_product) && (zs != (xs ^ ys))) || - ((flags & maddf_negate_product) && (zs == (xs ^ ys))))) { + ((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) || + ((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) { /* * Cases of addition of infinities with opposite signs * or subtraction of infinities with same signs. @@ -99,9 +96,9 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, * same sign as product (x*y) (in case of MADDF.D instruction) * or product -(x*y) (in MSUBF.D case). The result must be an * infinity, and its sign is determined only by the value of - * (flags & maddf_negate_product) and the signs of x and y. + * (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y. */ - if (flags & maddf_negate_product) + if (flags & MADDF_NEGATE_PRODUCT) return ieee754dp_inf(1 ^ (xs ^ ys)); else return ieee754dp_inf(xs ^ ys); @@ -115,9 +112,9 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, return ieee754dp_inf(zs); if (zc == IEEE754_CLASS_ZERO) { /* Handle cases +0 + (-0) and similar ones. */ - if ((!(flags & maddf_negate_product) + if ((!(flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))) || - ((flags & maddf_negate_product) + ((flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys)))) /* * Cases of addition of zeros of equal signs @@ -167,7 +164,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, re = xe + ye; rs = xs ^ ys; - if (flags & maddf_negate_product) + if (flags & MADDF_NEGATE_PRODUCT) rs ^= 1; /* shunt to top of word */ @@ -291,5 +288,5 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, union ieee754dp y) { - return _dp_maddf(z, x, y, maddf_negate_product); + return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT); } diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index 8bc2f6963324..dd2071f430e0 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -26,6 +26,10 @@ #define CLPAIR(x, y) ((x)*6+(y)) +enum maddf_flags { + MADDF_NEGATE_PRODUCT = 1 << 0, +}; + static inline void ieee754_clearcx(void) { ieee754_csr.cx = 0; diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index 4241ec19df12..07f5a9bb1312 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -14,9 +14,6 @@ #include "ieee754sp.h" -enum maddf_flags { - maddf_negate_product = 1 << 0, -}; static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp y, enum maddf_flags flags) @@ -86,8 +83,8 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): if ((zc == IEEE754_CLASS_INF) && - ((!(flags & maddf_negate_product) && (zs != (xs ^ ys))) || - ((flags & maddf_negate_product) && (zs == (xs ^ ys))))) { + ((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) || + ((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) { /* * Cases of addition of infinities with opposite signs * or subtraction of infinities with same signs. @@ -100,9 +97,9 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, * same sign as product (x*y) (in case of MADDF.D instruction) * or product -(x*y) (in MSUBF.D case). The result must be an * infinity, and its sign is determined only by the value of - * (flags & maddf_negate_product) and the signs of x and y. + * (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y. */ - if (flags & maddf_negate_product) + if (flags & MADDF_NEGATE_PRODUCT) return ieee754sp_inf(1 ^ (xs ^ ys)); else return ieee754sp_inf(xs ^ ys); @@ -116,9 +113,9 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, return ieee754sp_inf(zs); if (zc == IEEE754_CLASS_ZERO) { /* Handle cases +0 + (-0) and similar ones. */ - if ((!(flags & maddf_negate_product) + if ((!(flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))) || - ((flags & maddf_negate_product) + ((flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys)))) /* * Cases of addition of zeros of equal signs @@ -170,7 +167,7 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, re = xe + ye; rs = xs ^ ys; - if (flags & maddf_negate_product) + if (flags & MADDF_NEGATE_PRODUCT) rs ^= 1; /* shunt to top of word */ @@ -287,5 +284,5 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, union ieee754sp y) { - return _sp_maddf(z, x, y, maddf_negate_product); + return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT); } From 93716dce827bf4b17504a73a112b106b89b28cee Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 21 Aug 2017 14:24:47 +0200 Subject: [PATCH 073/266] UPSTREAM: MIPS: math-emu: CMP.Sxxx.: Prevent occurrences of SIGILL crashes Fix CMP.Sxxx. SIGILL crashes by fixing main switch/case statement in fpu_emul() function so that inadvertent fall-troughs are prevented. Consider, let's say, CMP.SAF.S instruction when one of inputs is zero and another input is a signaling NaN. The desired output is zero, and the exception flag "invalid operation" set. For such case, the main portion of the implementation is within "d_fmt" case of the main "switch/case" statement in fpu_emul() function. The execution will follow one of "if-else" branches that doesn't contain "goto cop1scr;" statement, and will therefore reach the end of "d_fmt" case. It will subsequently fall through to the next case, "l_fmt". After following similar pattern, the execution will fall through to the succeeding case, which is "default". The "default" case contains "return SIGILL;" statement only. This means that the caller application will crash with "illegal instruction" message. It is obvious that above described fall-throughs are unnecessary and harmful. This patch rectifies that behavior by providing "break;" statements at the end of cases "d_fmt" and "l_fmt". There are 22 instructions affected by this problem: CMP... Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: James Hogan Cc: Maciej W. Rozycki Cc: Masahiro Yamada Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/17140/ Signed-off-by: Ralf Baechle (cherry picked from commit 1ff8560ac9db1cbffcd700b70e1661f2fcc2e5d7) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index f32ec09a8ad4..9ed65360b596 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -2395,6 +2395,7 @@ dcopuop: break; } } + break; } case l_fmt: @@ -2468,6 +2469,8 @@ dcopuop: break; } } + break; + default: return SIGILL; } From fdb44c1063e82a850fa173bc0f20908bc6479814 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 21 Aug 2017 14:24:48 +0200 Subject: [PATCH 074/266] BACKPORT: MIPS: math-emu: RINT.: Fix several problems by reimplementation Reimplement RINT. kernel emulation so that all RINT. specifications are met. For the sake of simplicity, let's analyze RINT.S only. Prior to this patch, RINT.S emulation was essentially implemented as (in pseudocode) = ieee754sp_flong(ieee754sp_tlong()), where ieee754sp_tlong() and ieee754sp_flong() are functions providing conversion from double to integer, and from integer to double, respectively. On surface, this implementation looks correct, but actually fails in many cases. Following problems were detected: 1. NaN and infinity cases will not be handled properly. The function ieee754sp_flong() never returns NaN nor infinity. 2. For RINT.S, for all inputs larger than LONG_MAX, and smaller than FLT_MAX, the result will be wrong, and the overflow exception will be erroneously set. A similar problem for negative inputs exists as well. 3. For some rounding modes, for some negative inputs close to zero, the return value will be zero, and should be -zero. This is because ieee754sp_flong() never returns -zero. This patch removes the problems above by implementing dedicated functions for RINT. emulation. The core of the new function functionality is adapted version of the core of the function ieee754sp_tlong(). However, there are many details that are implemented to match RINT. specification. It should be said that the functionality of ieee754sp_tlong() actually closely corresponds to CVT.L.S instruction, and it is used while emulating CVT.L.S. However, RINT.S and CVT.L.S instructions differ in many aspects. This patch fulfills missing support for RINT.. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: David S. Miller Cc: Douglas Leung Cc: Greg Kroah-Hartman Cc: Hans Verkuil Cc: James Hogan Cc: Maciej W. Rozycki Cc: Masahiro Yamada Cc: Mauro Carvalho Chehab Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: Randy Dunlap Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/17141/ Signed-off-by: Ralf Baechle (cherry picked from commit 3ec404d88cefbe42d96a46f20f554f8366d64c33) Conflicts: MAINTAINERS Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 7 +++ arch/mips/math-emu/Makefile | 6 ++- arch/mips/math-emu/cp1emu.c | 6 +-- arch/mips/math-emu/dp_rint.c | 89 +++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 2 + arch/mips/math-emu/sp_rint.c | 90 ++++++++++++++++++++++++++++++++++++ 6 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 arch/mips/math-emu/dp_rint.c create mode 100644 arch/mips/math-emu/sp_rint.c diff --git a/MAINTAINERS b/MAINTAINERS index 263e4dfb3fb0..bbdff393fa2f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7054,6 +7054,13 @@ S: Supported F: Documentation/mips/ F: arch/mips/ +MIPS RINT INSTRUCTION EMULATION +M: Aleksandar Markovic +L: linux-mips@linux-mips.org +S: Supported +F: arch/mips/math-emu/sp_rint.c +F: arch/mips/math-emu/dp_rint.c + MIROSOUND PCM20 FM RADIO RECEIVER DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index e9bbc2a6526f..e9f10b88b695 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,11 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_2008class.o dp_fmin.o dp_fmax.o \ + dp_tint.o dp_fint.o dp_rint.o dp_maddf.o dp_2008class.o dp_fmin.o \ + dp_fmax.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_2008class.o sp_fmin.o sp_fmax.o \ + sp_tint.o sp_fint.o sp_rint.o sp_maddf.o sp_2008class.o sp_fmin.o \ + sp_fmax.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 9ed65360b596..ed7aeac55bf5 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1807,8 +1807,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, return SIGILL; SPFROMREG(fs, MIPSInst_FS(ir)); - rv.l = ieee754sp_tlong(fs); - rv.s = ieee754sp_flong(rv.l); + rv.s = ieee754sp_rint(fs); goto copcsr; } @@ -2136,8 +2135,7 @@ copcsr: return SIGILL; DPFROMREG(fs, MIPSInst_FS(ir)); - rv.l = ieee754dp_tlong(fs); - rv.d = ieee754dp_flong(rv.l); + rv.d = ieee754dp_rint(fs); goto copcsr; } diff --git a/arch/mips/math-emu/dp_rint.c b/arch/mips/math-emu/dp_rint.c new file mode 100644 index 000000000000..c3b9077ff357 --- /dev/null +++ b/arch/mips/math-emu/dp_rint.c @@ -0,0 +1,89 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. + * Copyright (C) 2017 Imagination Technologies, Ltd. + * Author: Aleksandar Markovic + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. + */ + +#include "ieee754dp.h" + +union ieee754dp ieee754dp_rint(union ieee754dp x) +{ + union ieee754dp ret; + u64 residue; + int sticky; + int round; + int odd; + + COMPXDP; + + ieee754_clearcx(); + + EXPLODEXDP; + FLUSHXDP; + + if (xc == IEEE754_CLASS_SNAN) + return ieee754dp_nanxcpt(x); + + if ((xc == IEEE754_CLASS_QNAN) || + (xc == IEEE754_CLASS_INF) || + (xc == IEEE754_CLASS_ZERO)) + return x; + + if (xe >= DP_FBITS) + return x; + + if (xe < -1) { + residue = xm; + round = 0; + sticky = residue != 0; + xm = 0; + } else { + residue = xm << (64 - DP_FBITS + xe); + round = (residue >> 63) != 0; + sticky = (residue << 1) != 0; + xm >>= DP_FBITS - xe; + } + + odd = (xm & 0x1) != 0x0; + + switch (ieee754_csr.rm) { + case FPU_CSR_RN: /* toward nearest */ + if (round && (sticky || odd)) + xm++; + break; + case FPU_CSR_RZ: /* toward zero */ + break; + case FPU_CSR_RU: /* toward +infinity */ + if ((round || sticky) && !xs) + xm++; + break; + case FPU_CSR_RD: /* toward -infinity */ + if ((round || sticky) && xs) + xm++; + break; + } + + if (round || sticky) + ieee754_setcx(IEEE754_INEXACT); + + ret = ieee754dp_flong(xm); + DPSIGN(ret) = xs; + + return ret; +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index d3be351aed15..92dc8fa565cb 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -67,6 +67,7 @@ union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y); union ieee754sp ieee754sp_fint(int x); union ieee754sp ieee754sp_flong(s64 x); union ieee754sp ieee754sp_fdp(union ieee754dp x); +union ieee754sp ieee754sp_rint(union ieee754sp x); int ieee754sp_tint(union ieee754sp x); s64 ieee754sp_tlong(union ieee754sp x); @@ -101,6 +102,7 @@ union ieee754dp ieee754dp_neg(union ieee754dp x); union ieee754dp ieee754dp_fint(int x); union ieee754dp ieee754dp_flong(s64 x); union ieee754dp ieee754dp_fsp(union ieee754sp x); +union ieee754dp ieee754dp_rint(union ieee754dp x); int ieee754dp_tint(union ieee754dp x); s64 ieee754dp_tlong(union ieee754dp x); diff --git a/arch/mips/math-emu/sp_rint.c b/arch/mips/math-emu/sp_rint.c new file mode 100644 index 000000000000..70765b17e196 --- /dev/null +++ b/arch/mips/math-emu/sp_rint.c @@ -0,0 +1,90 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. + * Copyright (C) 2017 Imagination Technologies, Ltd. + * Author: Aleksandar Markovic + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. + */ + +#include "ieee754sp.h" + +union ieee754sp ieee754sp_rint(union ieee754sp x) +{ + union ieee754sp ret; + u32 residue; + int sticky; + int round; + int odd; + + COMPXDP; /* <-- DP needed for 64-bit mantissa tmp */ + + ieee754_clearcx(); + + EXPLODEXSP; + FLUSHXSP; + + if (xc == IEEE754_CLASS_SNAN) + return ieee754sp_nanxcpt(x); + + if ((xc == IEEE754_CLASS_QNAN) || + (xc == IEEE754_CLASS_INF) || + (xc == IEEE754_CLASS_ZERO)) + return x; + + if (xe >= SP_FBITS) + return x; + + if (xe < -1) { + residue = xm; + round = 0; + sticky = residue != 0; + xm = 0; + } else { + residue = xm << (xe + 1); + residue <<= 31 - SP_FBITS; + round = (residue >> 31) != 0; + sticky = (residue << 1) != 0; + xm >>= SP_FBITS - xe; + } + + odd = (xm & 0x1) != 0x0; + + switch (ieee754_csr.rm) { + case FPU_CSR_RN: /* toward nearest */ + if (round && (sticky || odd)) + xm++; + break; + case FPU_CSR_RZ: /* toward zero */ + break; + case FPU_CSR_RU: /* toward +infinity */ + if ((round || sticky) && !xs) + xm++; + break; + case FPU_CSR_RD: /* toward -infinity */ + if ((round || sticky) && xs) + xm++; + break; + } + + if (round || sticky) + ieee754_setcx(IEEE754_INEXACT); + + ret = ieee754sp_flong(xm); + SPSIGN(ret) = xs; + + return ret; +} From 49ab66eb1e5724a238d307a167712f09b43590bd Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 21 Aug 2017 14:24:49 +0200 Subject: [PATCH 075/266] BACKPORT: MIPS: math-emu: CLASS.D: Zero bits 32-63 of the result Fix content of CLASS.D output bits 32-63 to match hardware behavior. Prior to this patch, bits 32-63 of CLASS.D output were not initialized, causing different 32-63 bits content of CLASS.D, based on circumstances. However, the hardware consistently returns all these bits zeroed. The documentation is not clear whether these bits should be zero or unpredictable. Since technically "all zero" case still can be viewed as belonging to "unpredictable" class of results, it is better to zero bits 32-63. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: James Hogan Cc: Maciej W. Rozycki Cc: Masahiro Yamada Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/17142/ Signed-off-by: Ralf Baechle (cherry picked from commit e1231dd6b1cfbed9dfda5de488ce23c2414e1f04) Conflicts: arch/mips/math-emu/cp1emu.c Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index ed7aeac55bf5..6ad7bd871508 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -2146,8 +2146,8 @@ copcsr: return SIGILL; DPFROMREG(fs, MIPSInst_FS(ir)); - rv.w = ieee754dp_2008class(fs); - rfmt = w_fmt; + rv.l = ieee754dp_2008class(fs); + rfmt = l_fmt; goto copcsr; } From b4c0bacf7fb7225df9ed6cc3ef27cf0d5bfed025 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 21 Aug 2017 14:24:50 +0200 Subject: [PATCH 076/266] UPSTREAM: MIPS: math-emu: Add FP emu debugfs statistics for branches Add FP emu debugfs counter for branches. The new counter is displayed the same way as existing counter, and its default path is /sys/kernel/debug/mips/fpuemustats/. The limitation of this counter is that it counts only R6 branch instructions BC1NEZ and BC1EQZ. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: James Hogan Cc: Maciej W. Rozycki Cc: Masahiro Yamada Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/17143/ Signed-off-by: Ralf Baechle (cherry picked from commit ae5f3f5b81dd2c776f0ad49d6d121ce1255b35eb) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/fpu_emulator.h | 1 + arch/mips/math-emu/cp1emu.c | 1 + arch/mips/math-emu/me-debugfs.c | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h index c05369e0b8d6..7f5cf1f4bcbd 100644 --- a/arch/mips/include/asm/fpu_emulator.h +++ b/arch/mips/include/asm/fpu_emulator.h @@ -36,6 +36,7 @@ struct mips_fpu_emulator_stats { unsigned long emulated; unsigned long loads; unsigned long stores; + unsigned long branches; unsigned long cp1ops; unsigned long cp1xops; unsigned long errors; diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 6ad7bd871508..008372d19a6a 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1231,6 +1231,7 @@ emul: break; } branch_common: + MIPS_FPU_EMU_INC_STATS(branches); set_delay_slot(xcp); if (cond) { /* diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c index be650ed7db59..78b26c8dc697 100644 --- a/arch/mips/math-emu/me-debugfs.c +++ b/arch/mips/math-emu/me-debugfs.c @@ -53,6 +53,7 @@ do { \ FPU_STAT_CREATE(emulated); FPU_STAT_CREATE(loads); FPU_STAT_CREATE(stores); + FPU_STAT_CREATE(branches); FPU_STAT_CREATE(cp1ops); FPU_STAT_CREATE(cp1xops); FPU_STAT_CREATE(errors); From ba44d882f5189316ff5c5a283e7b61a224f5203b Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 21 Aug 2017 14:24:51 +0200 Subject: [PATCH 077/266] UPSTREAM: MIPS: math-emu: Add FP emu debugfs clear functionality Add capability for the user to clear all FP emu debugfs counters. This is achieved by having a special debugfs file "fpuemustats_clear" (under default location "/sys/kernel/debug/mips"). Each access to the file results in setting all counters to zero (it is enough, let's say, to issue a "cat /sys/kernel/debug/mips/fpuemustats_clear"). This functionality already exists for R2 emulation statistics, but was missing for FP emulation statistics. The implementation in this patch is consistent with its R2 emulation counterpart. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: James Hogan Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/17144/ Signed-off-by: Ralf Baechle (cherry picked from commit 25ad8db632ec54c60daad9107ddf25a2a608a450) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/me-debugfs.c | 38 ++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c index 78b26c8dc697..f080493ba743 100644 --- a/arch/mips/math-emu/me-debugfs.c +++ b/arch/mips/math-emu/me-debugfs.c @@ -28,15 +28,51 @@ static int fpuemu_stat_get(void *data, u64 *val) } DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n"); +static int fpuemustats_clear_show(struct seq_file *s, void *unused) +{ + __this_cpu_write((fpuemustats).emulated, 0); + __this_cpu_write((fpuemustats).loads, 0); + __this_cpu_write((fpuemustats).stores, 0); + __this_cpu_write((fpuemustats).branches, 0); + __this_cpu_write((fpuemustats).cp1ops, 0); + __this_cpu_write((fpuemustats).cp1xops, 0); + __this_cpu_write((fpuemustats).errors, 0); + __this_cpu_write((fpuemustats).ieee754_inexact, 0); + __this_cpu_write((fpuemustats).ieee754_underflow, 0); + __this_cpu_write((fpuemustats).ieee754_overflow, 0); + __this_cpu_write((fpuemustats).ieee754_zerodiv, 0); + __this_cpu_write((fpuemustats).ieee754_invalidop, 0); + __this_cpu_write((fpuemustats).ds_emul, 0); + + return 0; +} + +static int fpuemustats_clear_open(struct inode *inode, struct file *file) +{ + return single_open(file, fpuemustats_clear_show, inode->i_private); +} + +static const struct file_operations fpuemustats_clear_fops = { + .open = fpuemustats_clear_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int __init debugfs_fpuemu(void) { - struct dentry *d, *dir; + struct dentry *d, *dir, *reset_file; if (!mips_debugfs_dir) return -ENODEV; dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir); if (!dir) return -ENOMEM; + reset_file = debugfs_create_file("fpuemustats_clear", 0444, + mips_debugfs_dir, NULL, + &fpuemustats_clear_fops); + if (!reset_file) + return -ENOMEM; #define FPU_EMU_STAT_OFFSET(m) \ offsetof(struct mips_fpu_emulator_stats, m) From 80a1b3334ae491328f67b27f954df361e653138a Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 21 Aug 2017 14:24:52 +0200 Subject: [PATCH 078/266] UPSTREAM: MIPS: math-emu: Add FP emu debugfs stats for individual instructions Add FP emulation debugfs statistics for individual instructions. The debugfs files that contain counter values are placed in a separate directory called "instructions". This means that the default path for these new stat is "/sys/kernel/debug/mips/fpuemustats/instructions". Each instruction counter is mapped to the debugfs file that has the same name as instruction name. The lowercase is choosen as more commonly used case for instruction names. One example of usage: mips_host::/sys/kernel/debug/mips/fpuemustats/instructions # grep "" * The shortened output of this command is: abs.d:34 abs.s:5711 add.d:10401 add.s:399307 bc1eqz:3199 ... ... ... sub.s:167211 trunc.l.d:375 trunc.l.s:8054 trunc.w.d:421 trunc.w.s:27032 The limitation of this patch is that it handles R6 FP emulation instructions only. There are altogether 114 handled instructions. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: James Hogan Cc: Maciej W. Rozycki Cc: Masahiro Yamada Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/17145/ Signed-off-by: Ralf Baechle (cherry picked from commit 454854ace22f5a9fdd369a4e428493159a02f029) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/fpu_emulator.h | 115 +++++++++++ arch/mips/math-emu/cp1emu.c | 258 ++++++++++++++++++++++++ arch/mips/math-emu/me-debugfs.c | 281 ++++++++++++++++++++++++++- 3 files changed, 650 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h index 7f5cf1f4bcbd..c7544dea523b 100644 --- a/arch/mips/include/asm/fpu_emulator.h +++ b/arch/mips/include/asm/fpu_emulator.h @@ -46,6 +46,121 @@ struct mips_fpu_emulator_stats { unsigned long ieee754_zerodiv; unsigned long ieee754_invalidop; unsigned long ds_emul; + + unsigned long abs_s; + unsigned long abs_d; + unsigned long add_s; + unsigned long add_d; + unsigned long bc1eqz; + unsigned long bc1nez; + unsigned long ceil_w_s; + unsigned long ceil_w_d; + unsigned long ceil_l_s; + unsigned long ceil_l_d; + unsigned long class_s; + unsigned long class_d; + unsigned long cmp_af_s; + unsigned long cmp_af_d; + unsigned long cmp_eq_s; + unsigned long cmp_eq_d; + unsigned long cmp_le_s; + unsigned long cmp_le_d; + unsigned long cmp_lt_s; + unsigned long cmp_lt_d; + unsigned long cmp_ne_s; + unsigned long cmp_ne_d; + unsigned long cmp_or_s; + unsigned long cmp_or_d; + unsigned long cmp_ueq_s; + unsigned long cmp_ueq_d; + unsigned long cmp_ule_s; + unsigned long cmp_ule_d; + unsigned long cmp_ult_s; + unsigned long cmp_ult_d; + unsigned long cmp_un_s; + unsigned long cmp_un_d; + unsigned long cmp_une_s; + unsigned long cmp_une_d; + unsigned long cmp_saf_s; + unsigned long cmp_saf_d; + unsigned long cmp_seq_s; + unsigned long cmp_seq_d; + unsigned long cmp_sle_s; + unsigned long cmp_sle_d; + unsigned long cmp_slt_s; + unsigned long cmp_slt_d; + unsigned long cmp_sne_s; + unsigned long cmp_sne_d; + unsigned long cmp_sor_s; + unsigned long cmp_sor_d; + unsigned long cmp_sueq_s; + unsigned long cmp_sueq_d; + unsigned long cmp_sule_s; + unsigned long cmp_sule_d; + unsigned long cmp_sult_s; + unsigned long cmp_sult_d; + unsigned long cmp_sun_s; + unsigned long cmp_sun_d; + unsigned long cmp_sune_s; + unsigned long cmp_sune_d; + unsigned long cvt_d_l; + unsigned long cvt_d_s; + unsigned long cvt_d_w; + unsigned long cvt_l_s; + unsigned long cvt_l_d; + unsigned long cvt_s_d; + unsigned long cvt_s_l; + unsigned long cvt_s_w; + unsigned long cvt_w_s; + unsigned long cvt_w_d; + unsigned long div_s; + unsigned long div_d; + unsigned long floor_w_s; + unsigned long floor_w_d; + unsigned long floor_l_s; + unsigned long floor_l_d; + unsigned long maddf_s; + unsigned long maddf_d; + unsigned long max_s; + unsigned long max_d; + unsigned long maxa_s; + unsigned long maxa_d; + unsigned long min_s; + unsigned long min_d; + unsigned long mina_s; + unsigned long mina_d; + unsigned long mov_s; + unsigned long mov_d; + unsigned long msubf_s; + unsigned long msubf_d; + unsigned long mul_s; + unsigned long mul_d; + unsigned long neg_s; + unsigned long neg_d; + unsigned long recip_s; + unsigned long recip_d; + unsigned long rint_s; + unsigned long rint_d; + unsigned long round_w_s; + unsigned long round_w_d; + unsigned long round_l_s; + unsigned long round_l_d; + unsigned long rsqrt_s; + unsigned long rsqrt_d; + unsigned long sel_s; + unsigned long sel_d; + unsigned long seleqz_s; + unsigned long seleqz_d; + unsigned long selnez_s; + unsigned long selnez_d; + unsigned long sqrt_s; + unsigned long sqrt_d; + unsigned long sub_s; + unsigned long sub_d; + unsigned long trunc_w_s; + unsigned long trunc_w_d; + unsigned long trunc_l_s; + unsigned long trunc_l_d; }; DECLARE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 008372d19a6a..aa44e16db1ab 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1196,9 +1196,11 @@ emul: bit0 = get_fpr32(fpr, 0) & 0x1; switch (MIPSInst_RS(ir)) { case bc1eqz_op: + MIPS_FPU_EMU_INC_STATS(bc1eqz); cond = bit0 == 0; break; case bc1nez_op: + MIPS_FPU_EMU_INC_STATS(bc1nez); cond = bit0 != 0; break; } @@ -1685,15 +1687,19 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, switch (MIPSInst_FUNC(ir)) { /* binary ops */ case fadd_op: + MIPS_FPU_EMU_INC_STATS(add_s); handler.b = ieee754sp_add; goto scopbop; case fsub_op: + MIPS_FPU_EMU_INC_STATS(sub_s); handler.b = ieee754sp_sub; goto scopbop; case fmul_op: + MIPS_FPU_EMU_INC_STATS(mul_s); handler.b = ieee754sp_mul; goto scopbop; case fdiv_op: + MIPS_FPU_EMU_INC_STATS(div_s); handler.b = ieee754sp_div; goto scopbop; @@ -1702,6 +1708,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_2_3_4_5_r) return SIGILL; + MIPS_FPU_EMU_INC_STATS(sqrt_s); handler.u = ieee754sp_sqrt; goto scopuop; @@ -1714,6 +1721,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_4_5_64_r2_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(rsqrt_s); handler.u = fpemu_sp_rsqrt; goto scopuop; @@ -1721,6 +1729,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_4_5_64_r2_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(recip_s); handler.u = fpemu_sp_recip; goto scopuop; @@ -1757,6 +1766,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(seleqz_s); SPFROMREG(rv.s, MIPSInst_FT(ir)); if (rv.w & 0x1) rv.w = 0; @@ -1768,6 +1778,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(selnez_s); SPFROMREG(rv.s, MIPSInst_FT(ir)); if (rv.w & 0x1) SPFROMREG(rv.s, MIPSInst_FS(ir)); @@ -1781,6 +1792,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(maddf_s); SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); SPFROMREG(fd, MIPSInst_FD(ir)); @@ -1794,6 +1806,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(msubf_s); SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); SPFROMREG(fd, MIPSInst_FD(ir)); @@ -1807,6 +1820,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(rint_s); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_rint(fs); goto copcsr; @@ -1818,6 +1832,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(class_s); SPFROMREG(fs, MIPSInst_FS(ir)); rv.w = ieee754sp_2008class(fs); rfmt = w_fmt; @@ -1830,6 +1845,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(min_s); SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmin(fs, ft); @@ -1842,6 +1858,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(mina_s); SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmina(fs, ft); @@ -1854,6 +1871,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(max_s); SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmax(fs, ft); @@ -1866,6 +1884,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(maxa_s); SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmaxa(fs, ft); @@ -1873,15 +1892,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, } case fabs_op: + MIPS_FPU_EMU_INC_STATS(abs_s); handler.u = ieee754sp_abs; goto scopuop; case fneg_op: + MIPS_FPU_EMU_INC_STATS(neg_s); handler.u = ieee754sp_neg; goto scopuop; case fmov_op: /* an easy one */ + MIPS_FPU_EMU_INC_STATS(mov_s); SPFROMREG(rv.s, MIPSInst_FS(ir)); goto copcsr; @@ -1924,12 +1946,14 @@ copcsr: return SIGILL; /* not defined */ case fcvtd_op: + MIPS_FPU_EMU_INC_STATS(cvt_d_s); SPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fsp(fs); rfmt = d_fmt; goto copcsr; case fcvtw_op: + MIPS_FPU_EMU_INC_STATS(cvt_w_s); SPFROMREG(fs, MIPSInst_FS(ir)); rv.w = ieee754sp_tint(fs); rfmt = w_fmt; @@ -1942,6 +1966,15 @@ copcsr: if (!cpu_has_mips_2_3_4_5_r) return SIGILL; + if (MIPSInst_FUNC(ir) == fceil_op) + MIPS_FPU_EMU_INC_STATS(ceil_w_s); + if (MIPSInst_FUNC(ir) == ffloor_op) + MIPS_FPU_EMU_INC_STATS(floor_w_s); + if (MIPSInst_FUNC(ir) == fround_op) + MIPS_FPU_EMU_INC_STATS(round_w_s); + if (MIPSInst_FUNC(ir) == ftrunc_op) + MIPS_FPU_EMU_INC_STATS(trunc_w_s); + oldrm = ieee754_csr.rm; SPFROMREG(fs, MIPSInst_FS(ir)); ieee754_csr.rm = MIPSInst_FUNC(ir); @@ -1954,6 +1987,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(sel_s); SPFROMREG(fd, MIPSInst_FD(ir)); if (fd.bits & 0x1) SPFROMREG(rv.s, MIPSInst_FT(ir)); @@ -1965,6 +1999,7 @@ copcsr: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(cvt_l_s); SPFROMREG(fs, MIPSInst_FS(ir)); rv.l = ieee754sp_tlong(fs); rfmt = l_fmt; @@ -1977,6 +2012,15 @@ copcsr: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; + if (MIPSInst_FUNC(ir) == fceill_op) + MIPS_FPU_EMU_INC_STATS(ceil_l_s); + if (MIPSInst_FUNC(ir) == ffloorl_op) + MIPS_FPU_EMU_INC_STATS(floor_l_s); + if (MIPSInst_FUNC(ir) == froundl_op) + MIPS_FPU_EMU_INC_STATS(round_l_s); + if (MIPSInst_FUNC(ir) == ftruncl_op) + MIPS_FPU_EMU_INC_STATS(trunc_l_s); + oldrm = ieee754_csr.rm; SPFROMREG(fs, MIPSInst_FS(ir)); ieee754_csr.rm = MIPSInst_FUNC(ir); @@ -2018,15 +2062,19 @@ copcsr: switch (MIPSInst_FUNC(ir)) { /* binary ops */ case fadd_op: + MIPS_FPU_EMU_INC_STATS(add_d); handler.b = ieee754dp_add; goto dcopbop; case fsub_op: + MIPS_FPU_EMU_INC_STATS(sub_d); handler.b = ieee754dp_sub; goto dcopbop; case fmul_op: + MIPS_FPU_EMU_INC_STATS(mul_d); handler.b = ieee754dp_mul; goto dcopbop; case fdiv_op: + MIPS_FPU_EMU_INC_STATS(div_d); handler.b = ieee754dp_div; goto dcopbop; @@ -2035,6 +2083,7 @@ copcsr: if (!cpu_has_mips_2_3_4_5_r) return SIGILL; + MIPS_FPU_EMU_INC_STATS(sqrt_d); handler.u = ieee754dp_sqrt; goto dcopuop; /* @@ -2046,12 +2095,14 @@ copcsr: if (!cpu_has_mips_4_5_64_r2_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(rsqrt_d); handler.u = fpemu_dp_rsqrt; goto dcopuop; case frecip_op: if (!cpu_has_mips_4_5_64_r2_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(recip_d); handler.u = fpemu_dp_recip; goto dcopuop; case fmovc_op: @@ -2085,6 +2136,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(seleqz_d); DPFROMREG(rv.d, MIPSInst_FT(ir)); if (rv.l & 0x1) rv.l = 0; @@ -2096,6 +2148,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(selnez_d); DPFROMREG(rv.d, MIPSInst_FT(ir)); if (rv.l & 0x1) DPFROMREG(rv.d, MIPSInst_FS(ir)); @@ -2109,6 +2162,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(maddf_d); DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); DPFROMREG(fd, MIPSInst_FD(ir)); @@ -2122,6 +2176,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(msubf_d); DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); DPFROMREG(fd, MIPSInst_FD(ir)); @@ -2135,6 +2190,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(rint_d); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_rint(fs); goto copcsr; @@ -2146,6 +2202,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(class_d); DPFROMREG(fs, MIPSInst_FS(ir)); rv.l = ieee754dp_2008class(fs); rfmt = l_fmt; @@ -2158,6 +2215,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(min_d); DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmin(fs, ft); @@ -2170,6 +2228,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(mina_d); DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmina(fs, ft); @@ -2182,6 +2241,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(max_d); DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmax(fs, ft); @@ -2194,6 +2254,7 @@ copcsr: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(maxa_d); DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmaxa(fs, ft); @@ -2201,15 +2262,18 @@ copcsr: } case fabs_op: + MIPS_FPU_EMU_INC_STATS(abs_d); handler.u = ieee754dp_abs; goto dcopuop; case fneg_op: + MIPS_FPU_EMU_INC_STATS(neg_d); handler.u = ieee754dp_neg; goto dcopuop; case fmov_op: /* an easy one */ + MIPS_FPU_EMU_INC_STATS(mov_d); DPFROMREG(rv.d, MIPSInst_FS(ir)); goto copcsr; @@ -2229,6 +2293,7 @@ dcopuop: * unary conv ops */ case fcvts_op: + MIPS_FPU_EMU_INC_STATS(cvt_s_d); DPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fdp(fs); rfmt = s_fmt; @@ -2238,6 +2303,7 @@ dcopuop: return SIGILL; /* not defined */ case fcvtw_op: + MIPS_FPU_EMU_INC_STATS(cvt_w_d); DPFROMREG(fs, MIPSInst_FS(ir)); rv.w = ieee754dp_tint(fs); /* wrong */ rfmt = w_fmt; @@ -2250,6 +2316,15 @@ dcopuop: if (!cpu_has_mips_2_3_4_5_r) return SIGILL; + if (MIPSInst_FUNC(ir) == fceil_op) + MIPS_FPU_EMU_INC_STATS(ceil_w_d); + if (MIPSInst_FUNC(ir) == ffloor_op) + MIPS_FPU_EMU_INC_STATS(floor_w_d); + if (MIPSInst_FUNC(ir) == fround_op) + MIPS_FPU_EMU_INC_STATS(round_w_d); + if (MIPSInst_FUNC(ir) == ftrunc_op) + MIPS_FPU_EMU_INC_STATS(trunc_w_d); + oldrm = ieee754_csr.rm; DPFROMREG(fs, MIPSInst_FS(ir)); ieee754_csr.rm = MIPSInst_FUNC(ir); @@ -2262,6 +2337,7 @@ dcopuop: if (!cpu_has_mips_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(sel_d); DPFROMREG(fd, MIPSInst_FD(ir)); if (fd.bits & 0x1) DPFROMREG(rv.d, MIPSInst_FT(ir)); @@ -2273,6 +2349,7 @@ dcopuop: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; + MIPS_FPU_EMU_INC_STATS(cvt_l_d); DPFROMREG(fs, MIPSInst_FS(ir)); rv.l = ieee754dp_tlong(fs); rfmt = l_fmt; @@ -2285,6 +2362,15 @@ dcopuop: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; + if (MIPSInst_FUNC(ir) == fceill_op) + MIPS_FPU_EMU_INC_STATS(ceil_l_d); + if (MIPSInst_FUNC(ir) == ffloorl_op) + MIPS_FPU_EMU_INC_STATS(floor_l_d); + if (MIPSInst_FUNC(ir) == froundl_op) + MIPS_FPU_EMU_INC_STATS(round_l_d); + if (MIPSInst_FUNC(ir) == ftruncl_op) + MIPS_FPU_EMU_INC_STATS(trunc_l_d); + oldrm = ieee754_csr.rm; DPFROMREG(fs, MIPSInst_FS(ir)); ieee754_csr.rm = MIPSInst_FUNC(ir); @@ -2326,12 +2412,14 @@ dcopuop: switch (MIPSInst_FUNC(ir)) { case fcvts_op: /* convert word to single precision real */ + MIPS_FPU_EMU_INC_STATS(cvt_s_w); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fint(fs.bits); rfmt = s_fmt; goto copcsr; case fcvtd_op: /* convert word to double precision real */ + MIPS_FPU_EMU_INC_STATS(cvt_d_w); SPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fint(fs.bits); rfmt = d_fmt; @@ -2351,6 +2439,90 @@ dcopuop: (MIPSInst_FUNC(ir) & 0x20)) return SIGILL; + if (!sig) { + if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { + switch (cmpop) { + case 0: + MIPS_FPU_EMU_INC_STATS(cmp_af_s); + break; + case 1: + MIPS_FPU_EMU_INC_STATS(cmp_un_s); + break; + case 2: + MIPS_FPU_EMU_INC_STATS(cmp_eq_s); + break; + case 3: + MIPS_FPU_EMU_INC_STATS(cmp_ueq_s); + break; + case 4: + MIPS_FPU_EMU_INC_STATS(cmp_lt_s); + break; + case 5: + MIPS_FPU_EMU_INC_STATS(cmp_ult_s); + break; + case 6: + MIPS_FPU_EMU_INC_STATS(cmp_le_s); + break; + case 7: + MIPS_FPU_EMU_INC_STATS(cmp_ule_s); + break; + } + } else { + switch (cmpop) { + case 1: + MIPS_FPU_EMU_INC_STATS(cmp_or_s); + break; + case 2: + MIPS_FPU_EMU_INC_STATS(cmp_une_s); + break; + case 3: + MIPS_FPU_EMU_INC_STATS(cmp_ne_s); + break; + } + } + } else { + if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { + switch (cmpop) { + case 0: + MIPS_FPU_EMU_INC_STATS(cmp_saf_s); + break; + case 1: + MIPS_FPU_EMU_INC_STATS(cmp_sun_s); + break; + case 2: + MIPS_FPU_EMU_INC_STATS(cmp_seq_s); + break; + case 3: + MIPS_FPU_EMU_INC_STATS(cmp_sueq_s); + break; + case 4: + MIPS_FPU_EMU_INC_STATS(cmp_slt_s); + break; + case 5: + MIPS_FPU_EMU_INC_STATS(cmp_sult_s); + break; + case 6: + MIPS_FPU_EMU_INC_STATS(cmp_sle_s); + break; + case 7: + MIPS_FPU_EMU_INC_STATS(cmp_sule_s); + break; + } + } else { + switch (cmpop) { + case 1: + MIPS_FPU_EMU_INC_STATS(cmp_sor_s); + break; + case 2: + MIPS_FPU_EMU_INC_STATS(cmp_sune_s); + break; + case 3: + MIPS_FPU_EMU_INC_STATS(cmp_sne_s); + break; + } + } + } + /* fmt is w_fmt for single precision so fix it */ rfmt = s_fmt; /* default to false */ @@ -2407,11 +2579,13 @@ dcopuop: switch (MIPSInst_FUNC(ir)) { case fcvts_op: /* convert long to single precision real */ + MIPS_FPU_EMU_INC_STATS(cvt_s_l); rv.s = ieee754sp_flong(bits); rfmt = s_fmt; goto copcsr; case fcvtd_op: /* convert long to double precision real */ + MIPS_FPU_EMU_INC_STATS(cvt_d_l); rv.d = ieee754dp_flong(bits); rfmt = d_fmt; goto copcsr; @@ -2425,6 +2599,90 @@ dcopuop: (MIPSInst_FUNC(ir) & 0x20)) return SIGILL; + if (!sig) { + if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { + switch (cmpop) { + case 0: + MIPS_FPU_EMU_INC_STATS(cmp_af_d); + break; + case 1: + MIPS_FPU_EMU_INC_STATS(cmp_un_d); + break; + case 2: + MIPS_FPU_EMU_INC_STATS(cmp_eq_d); + break; + case 3: + MIPS_FPU_EMU_INC_STATS(cmp_ueq_d); + break; + case 4: + MIPS_FPU_EMU_INC_STATS(cmp_lt_d); + break; + case 5: + MIPS_FPU_EMU_INC_STATS(cmp_ult_d); + break; + case 6: + MIPS_FPU_EMU_INC_STATS(cmp_le_d); + break; + case 7: + MIPS_FPU_EMU_INC_STATS(cmp_ule_d); + break; + } + } else { + switch (cmpop) { + case 1: + MIPS_FPU_EMU_INC_STATS(cmp_or_d); + break; + case 2: + MIPS_FPU_EMU_INC_STATS(cmp_une_d); + break; + case 3: + MIPS_FPU_EMU_INC_STATS(cmp_ne_d); + break; + } + } + } else { + if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { + switch (cmpop) { + case 0: + MIPS_FPU_EMU_INC_STATS(cmp_saf_d); + break; + case 1: + MIPS_FPU_EMU_INC_STATS(cmp_sun_d); + break; + case 2: + MIPS_FPU_EMU_INC_STATS(cmp_seq_d); + break; + case 3: + MIPS_FPU_EMU_INC_STATS(cmp_sueq_d); + break; + case 4: + MIPS_FPU_EMU_INC_STATS(cmp_slt_d); + break; + case 5: + MIPS_FPU_EMU_INC_STATS(cmp_sult_d); + break; + case 6: + MIPS_FPU_EMU_INC_STATS(cmp_sle_d); + break; + case 7: + MIPS_FPU_EMU_INC_STATS(cmp_sule_d); + break; + } + } else { + switch (cmpop) { + case 1: + MIPS_FPU_EMU_INC_STATS(cmp_sor_d); + break; + case 2: + MIPS_FPU_EMU_INC_STATS(cmp_sune_d); + break; + case 3: + MIPS_FPU_EMU_INC_STATS(cmp_sne_d); + break; + } + } + } + /* fmt is l_fmt for double precision so fix it */ rfmt = d_fmt; /* default to false */ diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c index f080493ba743..8c0ec154aecc 100644 --- a/arch/mips/math-emu/me-debugfs.c +++ b/arch/mips/math-emu/me-debugfs.c @@ -28,6 +28,26 @@ static int fpuemu_stat_get(void *data, u64 *val) } DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n"); +/* + * Used to obtain names for a debugfs instruction counter, given field name + * in fpuemustats structure. For example, for input "cmp_sueq_d", the output + * would be "cmp.sueq.d". This is needed since dots are not allowed to be + * used in structure field names, and are, on the other hand, desired to be + * used in debugfs item names to be clearly associated to corresponding + * MIPS FPU instructions. + */ +static void adjust_instruction_counter_name(char *out_name, char *in_name) +{ + int i = 0; + + strcpy(out_name, in_name); + while (in_name[i] != '\0') { + if (out_name[i] == '_') + out_name[i] = '.'; + i++; + } +} + static int fpuemustats_clear_show(struct seq_file *s, void *unused) { __this_cpu_write((fpuemustats).emulated, 0); @@ -44,6 +64,121 @@ static int fpuemustats_clear_show(struct seq_file *s, void *unused) __this_cpu_write((fpuemustats).ieee754_invalidop, 0); __this_cpu_write((fpuemustats).ds_emul, 0); + __this_cpu_write((fpuemustats).abs_s, 0); + __this_cpu_write((fpuemustats).abs_d, 0); + __this_cpu_write((fpuemustats).add_s, 0); + __this_cpu_write((fpuemustats).add_d, 0); + __this_cpu_write((fpuemustats).bc1eqz, 0); + __this_cpu_write((fpuemustats).bc1nez, 0); + __this_cpu_write((fpuemustats).ceil_w_s, 0); + __this_cpu_write((fpuemustats).ceil_w_d, 0); + __this_cpu_write((fpuemustats).ceil_l_s, 0); + __this_cpu_write((fpuemustats).ceil_l_d, 0); + __this_cpu_write((fpuemustats).class_s, 0); + __this_cpu_write((fpuemustats).class_d, 0); + __this_cpu_write((fpuemustats).cmp_af_s, 0); + __this_cpu_write((fpuemustats).cmp_af_d, 0); + __this_cpu_write((fpuemustats).cmp_eq_s, 0); + __this_cpu_write((fpuemustats).cmp_eq_d, 0); + __this_cpu_write((fpuemustats).cmp_le_s, 0); + __this_cpu_write((fpuemustats).cmp_le_d, 0); + __this_cpu_write((fpuemustats).cmp_lt_s, 0); + __this_cpu_write((fpuemustats).cmp_lt_d, 0); + __this_cpu_write((fpuemustats).cmp_ne_s, 0); + __this_cpu_write((fpuemustats).cmp_ne_d, 0); + __this_cpu_write((fpuemustats).cmp_or_s, 0); + __this_cpu_write((fpuemustats).cmp_or_d, 0); + __this_cpu_write((fpuemustats).cmp_ueq_s, 0); + __this_cpu_write((fpuemustats).cmp_ueq_d, 0); + __this_cpu_write((fpuemustats).cmp_ule_s, 0); + __this_cpu_write((fpuemustats).cmp_ule_d, 0); + __this_cpu_write((fpuemustats).cmp_ult_s, 0); + __this_cpu_write((fpuemustats).cmp_ult_d, 0); + __this_cpu_write((fpuemustats).cmp_un_s, 0); + __this_cpu_write((fpuemustats).cmp_un_d, 0); + __this_cpu_write((fpuemustats).cmp_une_s, 0); + __this_cpu_write((fpuemustats).cmp_une_d, 0); + __this_cpu_write((fpuemustats).cmp_saf_s, 0); + __this_cpu_write((fpuemustats).cmp_saf_d, 0); + __this_cpu_write((fpuemustats).cmp_seq_s, 0); + __this_cpu_write((fpuemustats).cmp_seq_d, 0); + __this_cpu_write((fpuemustats).cmp_sle_s, 0); + __this_cpu_write((fpuemustats).cmp_sle_d, 0); + __this_cpu_write((fpuemustats).cmp_slt_s, 0); + __this_cpu_write((fpuemustats).cmp_slt_d, 0); + __this_cpu_write((fpuemustats).cmp_sne_s, 0); + __this_cpu_write((fpuemustats).cmp_sne_d, 0); + __this_cpu_write((fpuemustats).cmp_sor_s, 0); + __this_cpu_write((fpuemustats).cmp_sor_d, 0); + __this_cpu_write((fpuemustats).cmp_sueq_s, 0); + __this_cpu_write((fpuemustats).cmp_sueq_d, 0); + __this_cpu_write((fpuemustats).cmp_sule_s, 0); + __this_cpu_write((fpuemustats).cmp_sule_d, 0); + __this_cpu_write((fpuemustats).cmp_sult_s, 0); + __this_cpu_write((fpuemustats).cmp_sult_d, 0); + __this_cpu_write((fpuemustats).cmp_sun_s, 0); + __this_cpu_write((fpuemustats).cmp_sun_d, 0); + __this_cpu_write((fpuemustats).cmp_sune_s, 0); + __this_cpu_write((fpuemustats).cmp_sune_d, 0); + __this_cpu_write((fpuemustats).cvt_d_l, 0); + __this_cpu_write((fpuemustats).cvt_d_s, 0); + __this_cpu_write((fpuemustats).cvt_d_w, 0); + __this_cpu_write((fpuemustats).cvt_l_s, 0); + __this_cpu_write((fpuemustats).cvt_l_d, 0); + __this_cpu_write((fpuemustats).cvt_s_d, 0); + __this_cpu_write((fpuemustats).cvt_s_l, 0); + __this_cpu_write((fpuemustats).cvt_s_w, 0); + __this_cpu_write((fpuemustats).cvt_w_s, 0); + __this_cpu_write((fpuemustats).cvt_w_d, 0); + __this_cpu_write((fpuemustats).div_s, 0); + __this_cpu_write((fpuemustats).div_d, 0); + __this_cpu_write((fpuemustats).floor_w_s, 0); + __this_cpu_write((fpuemustats).floor_w_d, 0); + __this_cpu_write((fpuemustats).floor_l_s, 0); + __this_cpu_write((fpuemustats).floor_l_d, 0); + __this_cpu_write((fpuemustats).maddf_s, 0); + __this_cpu_write((fpuemustats).maddf_d, 0); + __this_cpu_write((fpuemustats).max_s, 0); + __this_cpu_write((fpuemustats).max_d, 0); + __this_cpu_write((fpuemustats).maxa_s, 0); + __this_cpu_write((fpuemustats).maxa_d, 0); + __this_cpu_write((fpuemustats).min_s, 0); + __this_cpu_write((fpuemustats).min_d, 0); + __this_cpu_write((fpuemustats).mina_s, 0); + __this_cpu_write((fpuemustats).mina_d, 0); + __this_cpu_write((fpuemustats).mov_s, 0); + __this_cpu_write((fpuemustats).mov_d, 0); + __this_cpu_write((fpuemustats).msubf_s, 0); + __this_cpu_write((fpuemustats).msubf_d, 0); + __this_cpu_write((fpuemustats).mul_s, 0); + __this_cpu_write((fpuemustats).mul_d, 0); + __this_cpu_write((fpuemustats).neg_s, 0); + __this_cpu_write((fpuemustats).neg_d, 0); + __this_cpu_write((fpuemustats).recip_s, 0); + __this_cpu_write((fpuemustats).recip_d, 0); + __this_cpu_write((fpuemustats).rint_s, 0); + __this_cpu_write((fpuemustats).rint_d, 0); + __this_cpu_write((fpuemustats).round_w_s, 0); + __this_cpu_write((fpuemustats).round_w_d, 0); + __this_cpu_write((fpuemustats).round_l_s, 0); + __this_cpu_write((fpuemustats).round_l_d, 0); + __this_cpu_write((fpuemustats).rsqrt_s, 0); + __this_cpu_write((fpuemustats).rsqrt_d, 0); + __this_cpu_write((fpuemustats).sel_s, 0); + __this_cpu_write((fpuemustats).sel_d, 0); + __this_cpu_write((fpuemustats).seleqz_s, 0); + __this_cpu_write((fpuemustats).seleqz_d, 0); + __this_cpu_write((fpuemustats).selnez_s, 0); + __this_cpu_write((fpuemustats).selnez_d, 0); + __this_cpu_write((fpuemustats).sqrt_s, 0); + __this_cpu_write((fpuemustats).sqrt_d, 0); + __this_cpu_write((fpuemustats).sub_s, 0); + __this_cpu_write((fpuemustats).sub_d, 0); + __this_cpu_write((fpuemustats).trunc_w_s, 0); + __this_cpu_write((fpuemustats).trunc_w_d, 0); + __this_cpu_write((fpuemustats).trunc_l_s, 0); + __this_cpu_write((fpuemustats).trunc_l_d, 0); + return 0; } @@ -61,13 +196,18 @@ static const struct file_operations fpuemustats_clear_fops = { static int __init debugfs_fpuemu(void) { - struct dentry *d, *dir, *reset_file; + struct dentry *fpuemu_debugfs_base_dir; + struct dentry *fpuemu_debugfs_inst_dir; + struct dentry *d, *reset_file; if (!mips_debugfs_dir) return -ENODEV; - dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir); - if (!dir) + + fpuemu_debugfs_base_dir = debugfs_create_dir("fpuemustats", + mips_debugfs_dir); + if (!fpuemu_debugfs_base_dir) return -ENOMEM; + reset_file = debugfs_create_file("fpuemustats_clear", 0444, mips_debugfs_dir, NULL, &fpuemustats_clear_fops); @@ -79,7 +219,7 @@ static int __init debugfs_fpuemu(void) #define FPU_STAT_CREATE(m) \ do { \ - d = debugfs_create_file(#m , S_IRUGO, dir, \ + d = debugfs_create_file(#m, 0444, fpuemu_debugfs_base_dir, \ (void *)FPU_EMU_STAT_OFFSET(m), \ &fops_fpuemu_stat); \ if (!d) \ @@ -100,6 +240,139 @@ do { \ FPU_STAT_CREATE(ieee754_invalidop); FPU_STAT_CREATE(ds_emul); + fpuemu_debugfs_inst_dir = debugfs_create_dir("instructions", + fpuemu_debugfs_base_dir); + if (!fpuemu_debugfs_inst_dir) + return -ENOMEM; + +#define FPU_STAT_CREATE_EX(m) \ +do { \ + char name[32]; \ + \ + adjust_instruction_counter_name(name, #m); \ + \ + d = debugfs_create_file(name, 0444, fpuemu_debugfs_inst_dir, \ + (void *)FPU_EMU_STAT_OFFSET(m), \ + &fops_fpuemu_stat); \ + if (!d) \ + return -ENOMEM; \ +} while (0) + + FPU_STAT_CREATE_EX(abs_s); + FPU_STAT_CREATE_EX(abs_d); + FPU_STAT_CREATE_EX(add_s); + FPU_STAT_CREATE_EX(add_d); + FPU_STAT_CREATE_EX(bc1eqz); + FPU_STAT_CREATE_EX(bc1nez); + FPU_STAT_CREATE_EX(ceil_w_s); + FPU_STAT_CREATE_EX(ceil_w_d); + FPU_STAT_CREATE_EX(ceil_l_s); + FPU_STAT_CREATE_EX(ceil_l_d); + FPU_STAT_CREATE_EX(class_s); + FPU_STAT_CREATE_EX(class_d); + FPU_STAT_CREATE_EX(cmp_af_s); + FPU_STAT_CREATE_EX(cmp_af_d); + FPU_STAT_CREATE_EX(cmp_eq_s); + FPU_STAT_CREATE_EX(cmp_eq_d); + FPU_STAT_CREATE_EX(cmp_le_s); + FPU_STAT_CREATE_EX(cmp_le_d); + FPU_STAT_CREATE_EX(cmp_lt_s); + FPU_STAT_CREATE_EX(cmp_lt_d); + FPU_STAT_CREATE_EX(cmp_ne_s); + FPU_STAT_CREATE_EX(cmp_ne_d); + FPU_STAT_CREATE_EX(cmp_or_s); + FPU_STAT_CREATE_EX(cmp_or_d); + FPU_STAT_CREATE_EX(cmp_ueq_s); + FPU_STAT_CREATE_EX(cmp_ueq_d); + FPU_STAT_CREATE_EX(cmp_ule_s); + FPU_STAT_CREATE_EX(cmp_ule_d); + FPU_STAT_CREATE_EX(cmp_ult_s); + FPU_STAT_CREATE_EX(cmp_ult_d); + FPU_STAT_CREATE_EX(cmp_un_s); + FPU_STAT_CREATE_EX(cmp_un_d); + FPU_STAT_CREATE_EX(cmp_une_s); + FPU_STAT_CREATE_EX(cmp_une_d); + FPU_STAT_CREATE_EX(cmp_saf_s); + FPU_STAT_CREATE_EX(cmp_saf_d); + FPU_STAT_CREATE_EX(cmp_seq_s); + FPU_STAT_CREATE_EX(cmp_seq_d); + FPU_STAT_CREATE_EX(cmp_sle_s); + FPU_STAT_CREATE_EX(cmp_sle_d); + FPU_STAT_CREATE_EX(cmp_slt_s); + FPU_STAT_CREATE_EX(cmp_slt_d); + FPU_STAT_CREATE_EX(cmp_sne_s); + FPU_STAT_CREATE_EX(cmp_sne_d); + FPU_STAT_CREATE_EX(cmp_sor_s); + FPU_STAT_CREATE_EX(cmp_sor_d); + FPU_STAT_CREATE_EX(cmp_sueq_s); + FPU_STAT_CREATE_EX(cmp_sueq_d); + FPU_STAT_CREATE_EX(cmp_sule_s); + FPU_STAT_CREATE_EX(cmp_sule_d); + FPU_STAT_CREATE_EX(cmp_sult_s); + FPU_STAT_CREATE_EX(cmp_sult_d); + FPU_STAT_CREATE_EX(cmp_sun_s); + FPU_STAT_CREATE_EX(cmp_sun_d); + FPU_STAT_CREATE_EX(cmp_sune_s); + FPU_STAT_CREATE_EX(cmp_sune_d); + FPU_STAT_CREATE_EX(cvt_d_l); + FPU_STAT_CREATE_EX(cvt_d_s); + FPU_STAT_CREATE_EX(cvt_d_w); + FPU_STAT_CREATE_EX(cvt_l_s); + FPU_STAT_CREATE_EX(cvt_l_d); + FPU_STAT_CREATE_EX(cvt_s_d); + FPU_STAT_CREATE_EX(cvt_s_l); + FPU_STAT_CREATE_EX(cvt_s_w); + FPU_STAT_CREATE_EX(cvt_w_s); + FPU_STAT_CREATE_EX(cvt_w_d); + FPU_STAT_CREATE_EX(div_s); + FPU_STAT_CREATE_EX(div_d); + FPU_STAT_CREATE_EX(floor_w_s); + FPU_STAT_CREATE_EX(floor_w_d); + FPU_STAT_CREATE_EX(floor_l_s); + FPU_STAT_CREATE_EX(floor_l_d); + FPU_STAT_CREATE_EX(maddf_s); + FPU_STAT_CREATE_EX(maddf_d); + FPU_STAT_CREATE_EX(max_s); + FPU_STAT_CREATE_EX(max_d); + FPU_STAT_CREATE_EX(maxa_s); + FPU_STAT_CREATE_EX(maxa_d); + FPU_STAT_CREATE_EX(min_s); + FPU_STAT_CREATE_EX(min_d); + FPU_STAT_CREATE_EX(mina_s); + FPU_STAT_CREATE_EX(mina_d); + FPU_STAT_CREATE_EX(mov_s); + FPU_STAT_CREATE_EX(mov_d); + FPU_STAT_CREATE_EX(msubf_s); + FPU_STAT_CREATE_EX(msubf_d); + FPU_STAT_CREATE_EX(mul_s); + FPU_STAT_CREATE_EX(mul_d); + FPU_STAT_CREATE_EX(neg_s); + FPU_STAT_CREATE_EX(neg_d); + FPU_STAT_CREATE_EX(recip_s); + FPU_STAT_CREATE_EX(recip_d); + FPU_STAT_CREATE_EX(rint_s); + FPU_STAT_CREATE_EX(rint_d); + FPU_STAT_CREATE_EX(round_w_s); + FPU_STAT_CREATE_EX(round_w_d); + FPU_STAT_CREATE_EX(round_l_s); + FPU_STAT_CREATE_EX(round_l_d); + FPU_STAT_CREATE_EX(rsqrt_s); + FPU_STAT_CREATE_EX(rsqrt_d); + FPU_STAT_CREATE_EX(sel_s); + FPU_STAT_CREATE_EX(sel_d); + FPU_STAT_CREATE_EX(seleqz_s); + FPU_STAT_CREATE_EX(seleqz_d); + FPU_STAT_CREATE_EX(selnez_s); + FPU_STAT_CREATE_EX(selnez_d); + FPU_STAT_CREATE_EX(sqrt_s); + FPU_STAT_CREATE_EX(sqrt_d); + FPU_STAT_CREATE_EX(sub_s); + FPU_STAT_CREATE_EX(sub_d); + FPU_STAT_CREATE_EX(trunc_w_s); + FPU_STAT_CREATE_EX(trunc_w_d); + FPU_STAT_CREATE_EX(trunc_l_s); + FPU_STAT_CREATE_EX(trunc_l_d); + return 0; } arch_initcall(debugfs_fpuemu); From 67fdb99cce96c5bd4a7690e77b920f1ea474a118 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Tue, 29 Aug 2017 15:53:18 +0200 Subject: [PATCH 079/266] UPSTREAM: tty: goldfish: Refactor constants to better reflect their nature Classify constants GOLDFISH_TTY_xxx into two groups: command ids and register offsets. Apply different naming for register offsets (add 'REG_' after 'GOLDFISH_TTY_' in constant names). Change implementation to use preprocessor's '#define' statements instead of 'enum' declaration (as this is more common way of implementation in such cases). This makes the driver code easier to follow and hopefully prevents future bugs. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 2296eee704e70dac7fef8ac13f2716e4896dd13e) Signed-off-by: Greg Kroah-Hartman --- drivers/tty/goldfish.c | 50 ++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index b2f830d6a654..7b903c0047b9 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -23,20 +23,18 @@ #include #include -enum { - GOLDFISH_TTY_PUT_CHAR = 0x00, - GOLDFISH_TTY_BYTES_READY = 0x04, - GOLDFISH_TTY_CMD = 0x08, +/* Goldfish tty register's offsets */ +#define GOLDFISH_TTY_REG_BYTES_READY 0x04 +#define GOLDFISH_TTY_REG_CMD 0x08 +#define GOLDFISH_TTY_REG_DATA_PTR 0x10 +#define GOLDFISH_TTY_REG_DATA_LEN 0x14 +#define GOLDFISH_TTY_REG_DATA_PTR_HIGH 0x18 - GOLDFISH_TTY_DATA_PTR = 0x10, - GOLDFISH_TTY_DATA_LEN = 0x14, - GOLDFISH_TTY_DATA_PTR_HIGH = 0x18, - - GOLDFISH_TTY_CMD_INT_DISABLE = 0, - GOLDFISH_TTY_CMD_INT_ENABLE = 1, - GOLDFISH_TTY_CMD_WRITE_BUFFER = 2, - GOLDFISH_TTY_CMD_READ_BUFFER = 3, -}; +/* Goldfish tty commands */ +#define GOLDFISH_TTY_CMD_INT_DISABLE 0 +#define GOLDFISH_TTY_CMD_INT_ENABLE 1 +#define GOLDFISH_TTY_CMD_WRITE_BUFFER 2 +#define GOLDFISH_TTY_CMD_READ_BUFFER 3 struct goldfish_tty { struct tty_port port; @@ -59,10 +57,10 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count) struct goldfish_tty *qtty = &goldfish_ttys[line]; void __iomem *base = qtty->base; spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, - base + GOLDFISH_TTY_DATA_PTR_HIGH); - writel(count, base + GOLDFISH_TTY_DATA_LEN); - writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD); + gf_write_ptr(buf, base + GOLDFISH_TTY_REG_DATA_PTR, + base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); + writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); + writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_REG_CMD); spin_unlock_irqrestore(&qtty->lock, irq_flags); } @@ -74,16 +72,16 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) unsigned char *buf; u32 count; - count = readl(base + GOLDFISH_TTY_BYTES_READY); + count = readl(base + GOLDFISH_TTY_REG_BYTES_READY); if (count == 0) return IRQ_NONE; count = tty_prepare_flip_string(&qtty->port, &buf, count); spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, - base + GOLDFISH_TTY_DATA_PTR_HIGH); - writel(count, base + GOLDFISH_TTY_DATA_LEN); - writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD); + gf_write_ptr(buf, base + GOLDFISH_TTY_REG_DATA_PTR, + base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); + writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); + writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_REG_CMD); spin_unlock_irqrestore(&qtty->lock, irq_flags); tty_schedule_flip(&qtty->port); return IRQ_HANDLED; @@ -93,7 +91,7 @@ static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty) { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); - writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD); + writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_REG_CMD); return 0; } @@ -101,7 +99,7 @@ static void goldfish_tty_shutdown(struct tty_port *port) { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); - writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD); + writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_REG_CMD); } static int goldfish_tty_open(struct tty_struct *tty, struct file *filp) @@ -136,7 +134,7 @@ static int goldfish_tty_chars_in_buffer(struct tty_struct *tty) { struct goldfish_tty *qtty = &goldfish_ttys[tty->index]; void __iomem *base = qtty->base; - return readl(base + GOLDFISH_TTY_BYTES_READY); + return readl(base + GOLDFISH_TTY_REG_BYTES_READY); } static void goldfish_tty_console_write(struct console *co, const char *b, @@ -272,7 +270,7 @@ static int goldfish_tty_probe(struct platform_device *pdev) qtty->base = base; qtty->irq = irq; - writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD); + writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD); ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", qtty); From 77ed324e037215406d317fd805e7828f15e13da0 Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Tue, 29 Aug 2017 15:53:19 +0200 Subject: [PATCH 080/266] UPSTREAM: tty: goldfish: Use streaming DMA for r/w operations on Ranchu platforms Implement tty r/w operations using streaming DMA. Goldfish tty for Ranchu platforms has been modified to use streaming DMA mappings for read/write operations. This change eliminates the need for snooping through the TLB in QEMU using cpu_get_phys_page_debug() which does not guarantee that it will return the valid va -> pa mapping. The streaming DMA mapping is implemented using dma_map_single() per transfer, while dma_unmap_single() is used for unmapping right after the DMA transfer. Using DMA API is the proper way for handling r/w transfers and makes this driver more portable, thus effectively eliminating the need for virt_to_page() and page_to_phys() conversions. This change does not affect the old style Goldfish tty behaviour which is still used by the Goldfish emulator. Version register has been added and probed to see which platform is running this driver. Reading from the new register GOLDFISH_TTY_REG_VERSION using the Goldfish emulator will return 0 and driver will work with virtual addresses. Whereas if run on Ranchu it returns 1, and thus DMA is used. (Goldfish and Ranchu are code names for the first and the second generation of virtual boards used by Android emulator.) Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 7157d2be23da9f8860c69e2b79184a4e02701dad) Signed-off-by: Greg Kroah-Hartman --- drivers/tty/goldfish.c | 166 ++++++++++++++++++++++++++++++++++------- 1 file changed, 139 insertions(+), 27 deletions(-) diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 7b903c0047b9..40f472843a8d 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include /* Goldfish tty register's offsets */ #define GOLDFISH_TTY_REG_BYTES_READY 0x04 @@ -29,6 +31,7 @@ #define GOLDFISH_TTY_REG_DATA_PTR 0x10 #define GOLDFISH_TTY_REG_DATA_LEN 0x14 #define GOLDFISH_TTY_REG_DATA_PTR_HIGH 0x18 +#define GOLDFISH_TTY_REG_VERSION 0x20 /* Goldfish tty commands */ #define GOLDFISH_TTY_CMD_INT_DISABLE 0 @@ -43,6 +46,8 @@ struct goldfish_tty { u32 irq; int opencount; struct console console; + u32 version; + struct device *dev; }; static DEFINE_MUTEX(goldfish_tty_lock); @@ -51,24 +56,95 @@ static u32 goldfish_tty_line_count = 8; static u32 goldfish_tty_current_line_count; static struct goldfish_tty *goldfish_ttys; -static void goldfish_tty_do_write(int line, const char *buf, unsigned count) +static void do_rw_io(struct goldfish_tty *qtty, + unsigned long address, + unsigned int count, + int is_write) { unsigned long irq_flags; - struct goldfish_tty *qtty = &goldfish_ttys[line]; void __iomem *base = qtty->base; + spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write_ptr(buf, base + GOLDFISH_TTY_REG_DATA_PTR, + gf_write_ptr((void *)address, base + GOLDFISH_TTY_REG_DATA_PTR, base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); - writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_REG_CMD); + + if (is_write) + writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, + base + GOLDFISH_TTY_REG_CMD); + else + writel(GOLDFISH_TTY_CMD_READ_BUFFER, + base + GOLDFISH_TTY_REG_CMD); + spin_unlock_irqrestore(&qtty->lock, irq_flags); } +static void goldfish_tty_rw(struct goldfish_tty *qtty, + unsigned long addr, + unsigned int count, + int is_write) +{ + dma_addr_t dma_handle; + enum dma_data_direction dma_dir; + + dma_dir = (is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (qtty->version > 0) { + /* + * Goldfish TTY for Ranchu platform uses + * physical addresses and DMA for read/write operations + */ + unsigned long addr_end = addr + count; + + while (addr < addr_end) { + unsigned long pg_end = (addr & PAGE_MASK) + PAGE_SIZE; + unsigned long next = + pg_end < addr_end ? pg_end : addr_end; + unsigned long avail = next - addr; + + /* + * Map the buffer's virtual address to the DMA address + * so the buffer can be accessed by the device. + */ + dma_handle = dma_map_single(qtty->dev, (void *)addr, + avail, dma_dir); + + if (dma_mapping_error(qtty->dev, dma_handle)) { + dev_err(qtty->dev, "tty: DMA mapping error.\n"); + return; + } + do_rw_io(qtty, dma_handle, avail, is_write); + + /* + * Unmap the previously mapped region after + * the completion of the read/write operation. + */ + dma_unmap_single(qtty->dev, dma_handle, avail, dma_dir); + + addr += avail; + } + } else { + /* + * Old style Goldfish TTY used on the Goldfish platform + * uses virtual addresses. + */ + do_rw_io(qtty, addr, count, is_write); + } +} + +static void goldfish_tty_do_write(int line, const char *buf, + unsigned int count) +{ + struct goldfish_tty *qtty = &goldfish_ttys[line]; + unsigned long address = (unsigned long)(void *)buf; + + goldfish_tty_rw(qtty, address, count, 1); +} + static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) { struct goldfish_tty *qtty = dev_id; void __iomem *base = qtty->base; - unsigned long irq_flags; + unsigned long address; unsigned char *buf; u32 count; @@ -77,12 +153,10 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) return IRQ_NONE; count = tty_prepare_flip_string(&qtty->port, &buf, count); - spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write_ptr(buf, base + GOLDFISH_TTY_REG_DATA_PTR, - base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); - writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); - writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_REG_CMD); - spin_unlock_irqrestore(&qtty->lock, irq_flags); + + address = (unsigned long)(void *)buf; + goldfish_tty_rw(qtty, address, count, 0); + tty_schedule_flip(&qtty->port); return IRQ_HANDLED; } @@ -225,7 +299,7 @@ static void goldfish_tty_delete_driver(void) static int goldfish_tty_probe(struct platform_device *pdev) { struct goldfish_tty *qtty; - int ret = -EINVAL; + int ret = -ENODEV; struct resource *r; struct device *ttydev; void __iomem *base; @@ -233,16 +307,22 @@ static int goldfish_tty_probe(struct platform_device *pdev) unsigned int line; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) - return -EINVAL; + if (!r) { + pr_err("goldfish_tty: No MEM resource available!\n"); + return -ENOMEM; + } base = ioremap(r->start, 0x1000); - if (base == NULL) - pr_err("goldfish_tty: unable to remap base\n"); + if (!base) { + pr_err("goldfish_tty: Unable to ioremap base!\n"); + return -ENOMEM; + } r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (r == NULL) + if (!r) { + pr_err("goldfish_tty: No IRQ resource available!\n"); goto err_unmap; + } irq = r->start; @@ -253,13 +333,17 @@ static int goldfish_tty_probe(struct platform_device *pdev) else line = pdev->id; - if (line >= goldfish_tty_line_count) - goto err_create_driver_failed; + if (line >= goldfish_tty_line_count) { + pr_err("goldfish_tty: Reached maximum tty number of %d.\n", + goldfish_tty_current_line_count); + ret = -ENOMEM; + goto err_unlock; + } if (goldfish_tty_current_line_count == 0) { ret = goldfish_tty_create_driver(); if (ret) - goto err_create_driver_failed; + goto err_unlock; } goldfish_tty_current_line_count++; @@ -269,17 +353,45 @@ static int goldfish_tty_probe(struct platform_device *pdev) qtty->port.ops = &goldfish_port_ops; qtty->base = base; qtty->irq = irq; + qtty->dev = &pdev->dev; + + /* + * Goldfish TTY device used by the Goldfish emulator + * should identify itself with 0, forcing the driver + * to use virtual addresses. Goldfish TTY device + * on Ranchu emulator (qemu2) returns 1 here and + * driver will use physical addresses. + */ + qtty->version = readl(base + GOLDFISH_TTY_REG_VERSION); + + /* + * Goldfish TTY device on Ranchu emulator (qemu2) + * will use DMA for read/write IO operations. + */ + if (qtty->version > 0) { + /* + * Initialize dma_mask to 32-bits. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "No suitable DMA available.\n"); + goto err_dec_line_count; + } + } writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD); ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, - "goldfish_tty", qtty); - if (ret) - goto err_request_irq_failed; - + "goldfish_tty", qtty); + if (ret) { + pr_err("goldfish_tty: No IRQ available!\n"); + goto err_dec_line_count; + } ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver, - line, &pdev->dev); + line, &pdev->dev); if (IS_ERR(ttydev)) { ret = PTR_ERR(ttydev); goto err_tty_register_device_failed; @@ -299,11 +411,11 @@ static int goldfish_tty_probe(struct platform_device *pdev) err_tty_register_device_failed: free_irq(irq, qtty); -err_request_irq_failed: +err_dec_line_count: goldfish_tty_current_line_count--; if (goldfish_tty_current_line_count == 0) goldfish_tty_delete_driver(); -err_create_driver_failed: +err_unlock: mutex_unlock(&goldfish_tty_lock); err_unmap: iounmap(base); From 3d36fb9f2a723c95718ee84fe8420607cf548e25 Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Tue, 29 Aug 2017 15:53:20 +0200 Subject: [PATCH 081/266] UPSTREAM: tty: goldfish: Implement support for kernel 'earlycon' parameter Add early console functionality to the Goldfish tty driver. When 'earlycon' kernel command line parameter is used with no options, the early console is determined by the 'stdout-path' property in device tree's 'chosen' node. This is illustrated in the following device tree source example: Device tree example: chosen { stdout-path = "/goldfish_tty@1f004000"; }; goldfish_tty@1f004000 { interrupts = <0xc>; reg = <0x1f004000 0x0 0x1000>; compatible = "google,goldfish-tty"; }; Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 3840ed9548f778717aaab5eab744da798c3ea055) Signed-off-by: Greg Kroah-Hartman --- drivers/tty/Kconfig | 3 +++ drivers/tty/goldfish.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index c01f45095877..cadfc5f370f1 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -403,6 +403,9 @@ config PPC_EARLY_DEBUG_EHV_BC_HANDLE config GOLDFISH_TTY tristate "Goldfish TTY Driver" depends on GOLDFISH + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help Console and system TTY driver for the Goldfish virtual platform. diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 40f472843a8d..41c701401f71 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Google, Inc. * Copyright (C) 2012 Intel, Inc. + * Copyright (C) 2017 Imagination Technologies Ltd. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -24,6 +25,7 @@ #include #include #include +#include /* Goldfish tty register's offsets */ #define GOLDFISH_TTY_REG_BYTES_READY 0x04 @@ -440,6 +442,30 @@ static int goldfish_tty_remove(struct platform_device *pdev) return 0; } +static void gf_early_console_putchar(struct uart_port *port, int ch) +{ + __raw_writel(ch, port->membase); +} + +static void gf_early_write(struct console *con, const char *s, unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, gf_early_console_putchar); +} + +static int __init gf_earlycon_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = gf_early_write; + return 0; +} + +OF_EARLYCON_DECLARE(early_gf_tty, "google,goldfish-tty", gf_earlycon_setup); + static const struct of_device_id goldfish_tty_of_match[] = { { .compatible = "google,goldfish-tty", }, {}, From 150e79518f3095f73a6d2c6fe7e80c1a083fbca9 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Fri, 18 Aug 2017 15:08:53 +0200 Subject: [PATCH 082/266] BACKPORT: dt-bindings: Add device tree binding for Goldfish RTC driver Add documentation for DT binding of Goldfish RTC driver. The compatible string used by OS for binding the driver is "google,goldfish-rtc". Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Alexandre Belloni (cherry picked from commit 7a08de1d8fd27ac60ed8ce7a15efb88471014080) Conflicts: MAINTAINERS Signed-off-by: Greg Kroah-Hartman --- .../bindings/rtc/google,goldfish-rtc.txt | 17 +++++++++++++++++ MAINTAINERS | 5 +++++ 2 files changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt b/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt new file mode 100644 index 000000000000..634312dd95ca --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt @@ -0,0 +1,17 @@ +Android Goldfish RTC + +Android Goldfish RTC device used by Android emulator. + +Required properties: + +- compatible : should contain "google,goldfish-rtc" +- reg : +- interrupts : + +Example: + + goldfish_timer@9020000 { + compatible = "google,goldfish-rtc"; + reg = <0x9020000 0x1000>; + interrupts = <0x3>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index bbdff393fa2f..dc56d4d951b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -756,6 +756,11 @@ S: Supported F: drivers/android/ F: drivers/staging/android/ +ANDROID GOLDFISH RTC DRIVER +M: Miodrag Dinic +S: Supported +F: Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt + AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg L: linuxppc-dev@lists.ozlabs.org From e33cff3589a728d0f0f4e2800a7d1ead7f031636 Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Fri, 18 Aug 2017 15:08:54 +0200 Subject: [PATCH 083/266] UPSTREAM: rtc: goldfish: Add RTC driver for Android emulator Add device driver for a virtual RTC device in Android emulator. The compatible string used by OS for binding the driver is defined as "google,goldfish-rtc". Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Alexandre Belloni (cherry picked from commit f22d9cdcb5eb7ed1c4629a167474d68df0003a3d) Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + drivers/rtc/Kconfig | 8 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-goldfish.c | 237 +++++++++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 drivers/rtc/rtc-goldfish.c diff --git a/MAINTAINERS b/MAINTAINERS index dc56d4d951b2..a9925754dd49 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -760,6 +760,7 @@ ANDROID GOLDFISH RTC DRIVER M: Miodrag Dinic S: Supported F: Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt +F: drivers/rtc/rtc-goldfish.c AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2a524244afec..b5f12198e535 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1627,5 +1627,13 @@ config RTC_DRV_HID_SENSOR_TIME If this driver is compiled as a module, it will be named rtc-hid-sensor-time. +config RTC_DRV_GOLDFISH + tristate "Goldfish Real Time Clock" + depends on MIPS && (GOLDFISH || COMPILE_TEST) + help + Say yes to enable RTC driver for the Goldfish based virtual platform. + + Goldfish is a code name for the virtual platform developed by Google + for Android emulation. endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 231f76451615..e9f66679a51e 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -161,3 +161,4 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o +obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o diff --git a/drivers/rtc/rtc-goldfish.c b/drivers/rtc/rtc-goldfish.c new file mode 100644 index 000000000000..d67769265185 --- /dev/null +++ b/drivers/rtc/rtc-goldfish.c @@ -0,0 +1,237 @@ +/* drivers/rtc/rtc-goldfish.c + * + * Copyright (C) 2007 Google, Inc. + * Copyright (C) 2017 Imagination Technologies Ltd. + * + * 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 +#include +#include +#include + +#define TIMER_TIME_LOW 0x00 /* get low bits of current time */ + /* and update TIMER_TIME_HIGH */ +#define TIMER_TIME_HIGH 0x04 /* get high bits of time at last */ + /* TIMER_TIME_LOW read */ +#define TIMER_ALARM_LOW 0x08 /* set low bits of alarm and */ + /* activate it */ +#define TIMER_ALARM_HIGH 0x0c /* set high bits of next alarm */ +#define TIMER_IRQ_ENABLED 0x10 +#define TIMER_CLEAR_ALARM 0x14 +#define TIMER_ALARM_STATUS 0x18 +#define TIMER_CLEAR_INTERRUPT 0x1c + +struct goldfish_rtc { + void __iomem *base; + int irq; + struct rtc_device *rtc; +}; + +static int goldfish_rtc_read_alarm(struct device *dev, + struct rtc_wkalrm *alrm) +{ + u64 rtc_alarm; + u64 rtc_alarm_low; + u64 rtc_alarm_high; + void __iomem *base; + struct goldfish_rtc *rtcdrv; + + rtcdrv = dev_get_drvdata(dev); + base = rtcdrv->base; + + rtc_alarm_low = readl(base + TIMER_ALARM_LOW); + rtc_alarm_high = readl(base + TIMER_ALARM_HIGH); + rtc_alarm = (rtc_alarm_high << 32) | rtc_alarm_low; + + do_div(rtc_alarm, NSEC_PER_SEC); + memset(alrm, 0, sizeof(struct rtc_wkalrm)); + + rtc_time_to_tm(rtc_alarm, &alrm->time); + + if (readl(base + TIMER_ALARM_STATUS)) + alrm->enabled = 1; + else + alrm->enabled = 0; + + return 0; +} + +static int goldfish_rtc_set_alarm(struct device *dev, + struct rtc_wkalrm *alrm) +{ + struct goldfish_rtc *rtcdrv; + unsigned long rtc_alarm; + u64 rtc_alarm64; + u64 rtc_status_reg; + void __iomem *base; + int ret = 0; + + rtcdrv = dev_get_drvdata(dev); + base = rtcdrv->base; + + if (alrm->enabled) { + ret = rtc_tm_to_time(&alrm->time, &rtc_alarm); + if (ret != 0) + return ret; + + rtc_alarm64 = rtc_alarm * NSEC_PER_SEC; + writel((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH); + writel(rtc_alarm64, base + TIMER_ALARM_LOW); + } else { + /* + * if this function was called with enabled=0 + * then it could mean that the application is + * trying to cancel an ongoing alarm + */ + rtc_status_reg = readl(base + TIMER_ALARM_STATUS); + if (rtc_status_reg) + writel(1, base + TIMER_CLEAR_ALARM); + } + + return ret; +} + +static int goldfish_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + void __iomem *base; + struct goldfish_rtc *rtcdrv; + + rtcdrv = dev_get_drvdata(dev); + base = rtcdrv->base; + + if (enabled) + writel(1, base + TIMER_IRQ_ENABLED); + else + writel(0, base + TIMER_IRQ_ENABLED); + + return 0; +} + +static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id) +{ + struct goldfish_rtc *rtcdrv = dev_id; + void __iomem *base = rtcdrv->base; + + writel(1, base + TIMER_CLEAR_INTERRUPT); + + rtc_update_irq(rtcdrv->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct goldfish_rtc *rtcdrv; + void __iomem *base; + u64 time_high; + u64 time_low; + u64 time; + + rtcdrv = dev_get_drvdata(dev); + base = rtcdrv->base; + + time_low = readl(base + TIMER_TIME_LOW); + time_high = readl(base + TIMER_TIME_HIGH); + time = (time_high << 32) | time_low; + + do_div(time, NSEC_PER_SEC); + + rtc_time_to_tm(time, tm); + + return 0; +} + +static int goldfish_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct goldfish_rtc *rtcdrv; + void __iomem *base; + unsigned long now; + u64 now64; + int ret; + + rtcdrv = dev_get_drvdata(dev); + base = rtcdrv->base; + + ret = rtc_tm_to_time(tm, &now); + if (ret == 0) { + now64 = now * NSEC_PER_SEC; + writel((now64 >> 32), base + TIMER_TIME_HIGH); + writel(now64, base + TIMER_TIME_LOW); + } + + return ret; +} + +static const struct rtc_class_ops goldfish_rtc_ops = { + .read_time = goldfish_rtc_read_time, + .set_time = goldfish_rtc_set_time, + .read_alarm = goldfish_rtc_read_alarm, + .set_alarm = goldfish_rtc_set_alarm, + .alarm_irq_enable = goldfish_rtc_alarm_irq_enable +}; + +static int goldfish_rtc_probe(struct platform_device *pdev) +{ + struct goldfish_rtc *rtcdrv; + struct resource *r; + int err; + + rtcdrv = devm_kzalloc(&pdev->dev, sizeof(*rtcdrv), GFP_KERNEL); + if (!rtcdrv) + return -ENOMEM; + + platform_set_drvdata(pdev, rtcdrv); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + return -ENODEV; + + rtcdrv->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(rtcdrv->base)) + return -ENODEV; + + rtcdrv->irq = platform_get_irq(pdev, 0); + if (rtcdrv->irq < 0) + return -ENODEV; + + rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &goldfish_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtcdrv->rtc)) + return PTR_ERR(rtcdrv->rtc); + + err = devm_request_irq(&pdev->dev, rtcdrv->irq, + goldfish_rtc_interrupt, + 0, pdev->name, rtcdrv); + if (err) + return err; + + return 0; +} + +static const struct of_device_id goldfish_rtc_of_match[] = { + { .compatible = "google,goldfish-rtc", }, + {}, +}; +MODULE_DEVICE_TABLE(of, goldfish_rtc_of_match); + +static struct platform_driver goldfish_rtc = { + .probe = goldfish_rtc_probe, + .driver = { + .name = "goldfish_rtc", + .of_match_table = goldfish_rtc_of_match, + } +}; + +module_platform_driver(goldfish_rtc); From 1faba225e9bf454caaae3f3b469941361afc0a50 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 14 Aug 2017 12:21:48 +0200 Subject: [PATCH 084/266] UPSTREAM: MIPS: math-emu: do not use bools for arithmetic GCC-7 complains about a boolean value being used with an arithmetic AND: arch/mips/math-emu/cp1emu.c: In function 'cop1Emulate': arch/mips/math-emu/cp1emu.c:838:14: warning: '~' on a boolean expression [-Wbool-operation] fpr = (x) & ~(cop1_64bit(xcp) == 0); \ ^ arch/mips/math-emu/cp1emu.c:1068:3: note: in expansion of macro 'DITOREG' DITOREG(dval, MIPSInst_RT(ir)); ^~~~~~~ arch/mips/math-emu/cp1emu.c:838:14: note: did you mean to use logical not? fpr = (x) & ~(cop1_64bit(xcp) == 0); \ Since cop1_64bit() returns and int, just flip the LSB. Suggested-by: Maciej W. Rozycki Signed-off-by: Manuel Lauss Reviewed-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/17058/ Signed-off-by: Ralf Baechle (cherry picked from commit 8535f2ba0a9b971df62a5890699b9dfe2e0d5580) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index aa44e16db1ab..3c53aaff3ae3 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -831,12 +831,12 @@ do { \ } while (0) #define DIFROMREG(di, x) \ - ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0)) + ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) ^ 1)], 0)) #define DITOREG(di, x) \ do { \ unsigned fpr, i; \ - fpr = (x) & ~(cop1_64bit(xcp) == 0); \ + fpr = (x) & ~(cop1_64bit(xcp) ^ 1); \ set_fpr64(&ctx->fpr[fpr], 0, di); \ for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++) \ set_fpr64(&ctx->fpr[fpr], i, 0); \ From 848a96c7c180a528ac79b0ab73886842f707ec8e Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Fri, 20 Oct 2017 16:27:44 +0200 Subject: [PATCH 085/266] UPSTREAM: MIPS: Update RINT emulation maintainer email address Change all relevant instances of aleksandar.markovic@imgtec.com email address to aleksandar.markovic@mips.com. Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Patchwork: https://patchwork.linux-mips.org/patch/17514/ Signed-off-by: James Hogan (cherry picked from commit 89677e44b26ef49fd57208c7885fdd729b3724e5) Signed-off-by: Greg Kroah-Hartman --- .mailmap | 1 + MAINTAINERS | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index b1e9a97653dc..8c5993eefdcc 100644 --- a/.mailmap +++ b/.mailmap @@ -14,6 +14,7 @@ Adrian Bunk Alan Cox Alan Cox Aleksey Gorelov +Aleksandar Markovic Al Viro Al Viro Andreas Herrmann diff --git a/MAINTAINERS b/MAINTAINERS index a9925754dd49..d24aa29fdb13 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7061,7 +7061,7 @@ F: Documentation/mips/ F: arch/mips/ MIPS RINT INSTRUCTION EMULATION -M: Aleksandar Markovic +M: Aleksandar Markovic L: linux-mips@linux-mips.org S: Supported F: arch/mips/math-emu/sp_rint.c From 960cfd07111c3ec84829bb2665d9baf506e126bf Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Fri, 20 Oct 2017 16:27:45 +0200 Subject: [PATCH 086/266] UPSTREAM: MIPS: Update Goldfish RTC driver maintainer email address Change all relevant instances of miodrag.dinic@imgtec.com email address to miodrag.dinic@mips.com. Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Patchwork: https://patchwork.linux-mips.org/patch/17515/ [jhogan@kernel.org: Fix .mailmap direction] Signed-off-by: James Hogan (cherry picked from commit 0464a53eba0af434b8516c2e01d881aa587cd517) Signed-off-by: Greg Kroah-Hartman --- .mailmap | 1 + MAINTAINERS | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index 8c5993eefdcc..8cbe2bd7d090 100644 --- a/.mailmap +++ b/.mailmap @@ -86,6 +86,7 @@ Matthieu CASTET Mayuresh Janorkar Michael Buesch Michel Dänzer +Miodrag Dinic Mitesh shah Mohit Kumar Morten Welinder diff --git a/MAINTAINERS b/MAINTAINERS index d24aa29fdb13..48bf18de18bb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -757,7 +757,7 @@ F: drivers/android/ F: drivers/staging/android/ ANDROID GOLDFISH RTC DRIVER -M: Miodrag Dinic +M: Miodrag Dinic S: Supported F: Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt F: drivers/rtc/rtc-goldfish.c From 171e64fc7e69d6a5096a2d7e961da6ee2a3c2d52 Mon Sep 17 00:00:00 2001 From: Douglas Leung Date: Thu, 27 Jul 2017 18:08:58 +0200 Subject: [PATCH 087/266] UPSTREAM: MIPS: math-emu: .S: Fix accuracy (32-bit case) Implement fused multiply-add with correct accuracy. Fused multiply-add operation has better accuracy than respective sequential execution of multiply and add operations applied on the same inputs. This is because accuracy errors accumulate in latter case. This patch implements fused multiply-add with the same accuracy as it is implemented in hardware, using 64-bit intermediate calculations. One test case example (raw bits) that this patch fixes: MADDF.S fd,fs,ft: fd = 0x22575225 fs = ft = 0x3727c5ac Fixes: e24c3bec3e8e ("MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction") Fixes: 83d43305a1df ("MIPS: math-emu: Add support for the MIPS R6 MSUBF FPU instruction") Signed-off-by: Douglas Leung Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: Bo Hu Cc: James Hogan Cc: Jin Qian Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: # 4.7+ Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16890/ Signed-off-by: Ralf Baechle (cherry picked from commit b3b8e1eb27c523e32b6a8aa7ec8ac4754456af57) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/ieee754sp.h | 4 ++ arch/mips/math-emu/sp_maddf.c | 116 +++++++++++++-------------------- 2 files changed, 50 insertions(+), 70 deletions(-) diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 8476067075fe..0f63e4202cff 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -45,6 +45,10 @@ static inline int ieee754sp_finite(union ieee754sp x) return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; } +/* 64 bit right shift with rounding */ +#define XSPSRS64(v, rs) \ + (((rs) >= 64) ? ((v) != 0) : ((v) >> (rs)) | ((v) << (64-(rs)) != 0)) + /* 3bit extended single precision sticky right shift */ #define XSPSRS(v, rs) \ ((rs > (SP_FBITS+3))?1:((v) >> (rs)) | ((v) << (32-(rs)) != 0)) diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index 07f5a9bb1312..7195fe785d81 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -21,14 +21,8 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, int re; int rs; unsigned rm; - unsigned short lxm; - unsigned short hxm; - unsigned short lym; - unsigned short hym; - unsigned lrm; - unsigned hrm; - unsigned t; - unsigned at; + uint64_t rm64; + uint64_t zm64; int s; COMPXSP; @@ -170,108 +164,90 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, if (flags & MADDF_NEGATE_PRODUCT) rs ^= 1; - /* shunt to top of word */ - xm <<= 32 - (SP_FBITS + 1); - ym <<= 32 - (SP_FBITS + 1); + /* Multiple 24 bit xm and ym to give 48 bit results */ + rm64 = (uint64_t)xm * ym; - /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. - */ - lxm = xm & 0xffff; - hxm = xm >> 16; - lym = ym & 0xffff; - hym = ym >> 16; + /* Shunt to top of word */ + rm64 = rm64 << 16; - lrm = lxm * lym; /* 16 * 16 => 32 */ - hrm = hxm * hym; /* 16 * 16 => 32 */ - - t = lxm * hym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); - - t = hxm * lym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); - - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((int) rm < 0) { - rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | - ((rm << (SP_FBITS + 1 + 3)) != 0); + /* Put explicit bit at bit 62 if necessary */ + if ((int64_t) rm64 < 0) { + rm64 = rm64 >> 1; re++; - } else { - rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | - ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); } - assert(rm & (SP_HIDDEN_BIT << 3)); - if (zc == IEEE754_CLASS_ZERO) + assert(rm64 & (1 << 62)); + + if (zc == IEEE754_CLASS_ZERO) { + /* + * Move explicit bit from bit 62 to bit 26 since the + * ieee754sp_format code expects the mantissa to be + * 27 bits wide (24 + 3 rounding bits). + */ + rm = XSPSRS64(rm64, (62 - 26)); return ieee754sp_format(rs, re, rm); + } - /* And now the addition */ - - assert(zm & SP_HIDDEN_BIT); - - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; + /* Move explicit bit from bit 23 to bit 62 */ + zm64 = (uint64_t)zm << (62 - 23); + assert(zm64 & (1 << 62)); + /* Make the exponents the same */ if (ze > re) { /* * Have to shift r fraction right to align. */ s = ze - re; - rm = XSPSRS(rm, s); + rm64 = XSPSRS64(rm64, s); re += s; } else if (re > ze) { /* * Have to shift z fraction right to align. */ s = re - ze; - zm = XSPSRS(zm, s); + zm64 = XSPSRS64(zm64, s); ze += s; } assert(ze == re); assert(ze <= SP_EMAX); + /* Do the addition */ if (zs == rs) { /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in zm, zs and ze. + * Generate 64 bit result by adding two 63 bit numbers + * leaving result in zm64, zs and ze. */ - zm = zm + rm; - - if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ - zm = XSPSRS1(zm); + zm64 = zm64 + rm64; + if ((int64_t)zm64 < 0) { /* carry out */ + zm64 = XSPSRS1(zm64); ze++; } } else { - if (zm >= rm) { - zm = zm - rm; + if (zm64 >= rm64) { + zm64 = zm64 - rm64; } else { - zm = rm - zm; + zm64 = rm64 - zm64; zs = rs; } - if (zm == 0) + if (zm64 == 0) return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); /* - * Normalize in extended single precision + * Put explicit bit at bit 62 if necessary. */ - while ((zm >> (SP_MBITS + 3)) == 0) { - zm <<= 1; + while ((zm64 >> 62) == 0) { + zm64 <<= 1; ze--; } - } + + /* + * Move explicit bit from bit 62 to bit 26 since the + * ieee754sp_format code expects the mantissa to be + * 27 bits wide (24 + 3 rounding bits). + */ + zm = XSPSRS64(zm64, (62 - 26)); + return ieee754sp_format(zs, ze, zm); } From 7970be560ee7407c54811ca29df21f7fca76e970 Mon Sep 17 00:00:00 2001 From: Douglas Leung Date: Thu, 27 Jul 2017 18:08:59 +0200 Subject: [PATCH 088/266] UPSTREAM: MIPS: math-emu: .D: Fix accuracy (64-bit case) Implement fused multiply-add with correct accuracy. Fused multiply-add operation has better accuracy than respective sequential execution of multiply and add operations applied on the same inputs. This is because accuracy errors accumulate in latter case. This patch implements fused multiply-add with the same accuracy as it is implemented in hardware, using 128-bit intermediate calculations. One test case example (raw bits) that this patch fixes: MADDF.D fd,fs,ft: fd = 0x00000ca000000000 fs = ft = 0x3f40624dd2f1a9fc Fixes: e24c3bec3e8e ("MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction") Fixes: 83d43305a1df ("MIPS: math-emu: Add support for the MIPS R6 MSUBF FPU instruction") Signed-off-by: Douglas Leung Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Cc: Douglas Leung Cc: Bo Hu Cc: James Hogan Cc: Jin Qian Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: # 4.7+ Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16891/ Signed-off-by: Ralf Baechle (cherry picked from commit 2cfa58259f4b65b33ebe8f167019a1f89c6c3289) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 133 ++++++++++++++++++++++++---------- 1 file changed, 94 insertions(+), 39 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index e799fc826b0c..e0d9be5fbf4c 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -15,18 +15,44 @@ #include "ieee754dp.h" +/* 128 bits shift right logical with rounding. */ +void srl128(u64 *hptr, u64 *lptr, int count) +{ + u64 low; + + if (count >= 128) { + *lptr = *hptr != 0 || *lptr != 0; + *hptr = 0; + } else if (count >= 64) { + if (count == 64) { + *lptr = *hptr | (*lptr != 0); + } else { + low = *lptr; + *lptr = *hptr >> (count - 64); + *lptr |= (*hptr << (128 - count)) != 0 || low != 0; + } + *hptr = 0; + } else { + low = *lptr; + *lptr = low >> count | *hptr << (64 - count); + *lptr |= (low << (64 - count)) != 0; + *hptr = *hptr >> count; + } +} + static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp y, enum maddf_flags flags) { int re; int rs; - u64 rm; unsigned lxm; unsigned hxm; unsigned lym; unsigned hym; u64 lrm; u64 hrm; + u64 lzm; + u64 hzm; u64 t; u64 at; int s; @@ -172,7 +198,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, ym <<= 64 - (DP_FBITS + 1); /* - * Multiply 64 bits xm, ym to give high 64 bits rm with stickness. + * Multiply 64 bits xm and ym to give 128 bits result in hrm:lrm. */ /* 32 * 32 => 64 */ @@ -202,81 +228,110 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, hrm = hrm + (t >> 32); - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((s64) rm < 0) { - rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | - ((rm << (DP_FBITS + 1 + 3)) != 0); + /* Put explicit bit at bit 126 if necessary */ + if ((int64_t)hrm < 0) { + lrm = (hrm << 63) | (lrm >> 1); + hrm = hrm >> 1; re++; - } else { - rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | - ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); } - assert(rm & (DP_HIDDEN_BIT << 3)); - if (zc == IEEE754_CLASS_ZERO) - return ieee754dp_format(rs, re, rm); + assert(hrm & (1 << 62)); - /* And now the addition */ - assert(zm & DP_HIDDEN_BIT); + if (zc == IEEE754_CLASS_ZERO) { + /* + * Move explicit bit from bit 126 to bit 55 since the + * ieee754dp_format code expects the mantissa to be + * 56 bits wide (53 + 3 rounding bits). + */ + srl128(&hrm, &lrm, (126 - 55)); + return ieee754dp_format(rs, re, lrm); + } - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; + /* Move explicit bit from bit 52 to bit 126 */ + lzm = 0; + hzm = zm << 10; + assert(hzm & (1 << 62)); + /* Make the exponents the same */ if (ze > re) { /* * Have to shift y fraction right to align. */ s = ze - re; - rm = XDPSRS(rm, s); + srl128(&hrm, &lrm, s); re += s; } else if (re > ze) { /* * Have to shift x fraction right to align. */ s = re - ze; - zm = XDPSRS(zm, s); + srl128(&hzm, &lzm, s); ze += s; } assert(ze == re); assert(ze <= DP_EMAX); + /* Do the addition */ if (zs == rs) { /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in xm, xs and xe. + * Generate 128 bit result by adding two 127 bit numbers + * leaving result in hzm:lzm, zs and ze. */ - zm = zm + rm; - - if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ - zm = XDPSRS1(zm); + hzm = hzm + hrm + (lzm > (lzm + lrm)); + lzm = lzm + lrm; + if ((int64_t)hzm < 0) { /* carry out */ + srl128(&hzm, &lzm, 1); ze++; } } else { - if (zm >= rm) { - zm = zm - rm; + if (hzm > hrm || (hzm == hrm && lzm >= lrm)) { + hzm = hzm - hrm - (lzm < lrm); + lzm = lzm - lrm; } else { - zm = rm - zm; + hzm = hrm - hzm - (lrm < lzm); + lzm = lrm - lzm; zs = rs; } - if (zm == 0) + if (lzm == 0 && hzm == 0) return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); /* - * Normalize to rounding precision. + * Put explicit bit at bit 126 if necessary. */ - while ((zm >> (DP_FBITS + 3)) == 0) { - zm <<= 1; - ze--; + if (hzm == 0) { + /* left shift by 63 or 64 bits */ + if ((int64_t)lzm < 0) { + /* MSB of lzm is the explicit bit */ + hzm = lzm >> 1; + lzm = lzm << 63; + ze -= 63; + } else { + hzm = lzm; + lzm = 0; + ze -= 64; + } + } + + t = 0; + while ((hzm >> (62 - t)) == 0) + t++; + + assert(t <= 62); + if (t) { + hzm = hzm << t | lzm >> (64 - t); + lzm = lzm << t; + ze -= t; } } - return ieee754dp_format(zs, ze, zm); + /* + * Move explicit bit from bit 126 to bit 55 since the + * ieee754dp_format code expects the mantissa to be + * 56 bits wide (53 + 3 rounding bits). + */ + srl128(&hzm, &lzm, (126 - 55)); + + return ieee754dp_format(zs, ze, lzm); } union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, From 851d630a4e30adce79a50f9d0f508d3292aee247 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 2 Nov 2017 12:13:59 +0100 Subject: [PATCH 089/266] UPSTREAM: MIPS: math-emu: Use preferred flavor of unsigned integer declarations Fix occurences of unsigned integer variable declarations that are not preferred by standards of checkpatch scripts. This removes a significant number of checkpatch warnings for files in math-emu directory (several files become completely warning-free), and thus makes easier to spot (now and in the future) other, perhaps more significant, checkpatch errors and warnings. Signed-off-by: Aleksandar Markovic Reviewed-by: James Hogan Cc: Ralf Baechle Cc: Douglas Leung Cc: Goran Ferenc Cc: "Maciej W. Rozycki" Cc: Manuel Lauss Cc: Miodrag Dinic Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/17582/ Signed-off-by: James Hogan (cherry picked from commit a58f85b5d5bbe44ee9dc8eae03a4f21fa3e087cc) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 18 ++++++++++-------- arch/mips/math-emu/dp_maddf.c | 8 ++++---- arch/mips/math-emu/dp_mul.c | 8 ++++---- arch/mips/math-emu/dp_sqrt.c | 4 ++-- arch/mips/math-emu/ieee754.h | 15 ++++++++------- arch/mips/math-emu/ieee754int.h | 6 +++--- arch/mips/math-emu/ieee754sp.c | 4 ++-- arch/mips/math-emu/ieee754sp.h | 2 +- arch/mips/math-emu/sp_div.c | 4 ++-- arch/mips/math-emu/sp_fint.c | 2 +- arch/mips/math-emu/sp_maddf.c | 6 +++--- arch/mips/math-emu/sp_mul.c | 10 +++++----- 12 files changed, 45 insertions(+), 42 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 3c53aaff3ae3..cd0f6c06147c 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -811,7 +811,7 @@ do { \ #define SITOREG(si, x) \ do { \ if (cop1_64bit(xcp) && !hybrid_fprs()) { \ - unsigned i; \ + unsigned int i; \ set_fpr32(&ctx->fpr[x], 0, si); \ for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ set_fpr32(&ctx->fpr[x], i, 0); \ @@ -824,7 +824,7 @@ do { \ #define SITOHREG(si, x) \ do { \ - unsigned i; \ + unsigned int i; \ set_fpr32(&ctx->fpr[x], 1, si); \ for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ set_fpr32(&ctx->fpr[x], i, 0); \ @@ -835,7 +835,7 @@ do { \ #define DITOREG(di, x) \ do { \ - unsigned fpr, i; \ + unsigned int fpr, i; \ fpr = (x) & ~(cop1_64bit(xcp) ^ 1); \ set_fpr64(&ctx->fpr[fpr], 0, di); \ for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++) \ @@ -1467,7 +1467,7 @@ DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, mips_instruction ir, void *__user *fault_addr) { - unsigned rcsr = 0; /* resulting csr */ + unsigned int rcsr = 0; /* resulting csr */ MIPS_FPU_EMU_INC_STATS(cp1xops); @@ -1663,10 +1663,10 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, mips_instruction ir) { int rfmt; /* resulting format */ - unsigned rcsr = 0; /* resulting csr */ + unsigned int rcsr = 0; /* resulting csr */ unsigned int oldrm; unsigned int cbit; - unsigned cond; + unsigned int cond; union { union ieee754dp d; union ieee754sp s; @@ -2031,9 +2031,10 @@ copcsr: default: if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { - unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; + unsigned int cmpop; union ieee754sp fs, ft; + cmpop = MIPSInst_FUNC(ir) - fcmp_op; SPFROMREG(fs, MIPSInst_FS(ir)); SPFROMREG(ft, MIPSInst_FT(ir)); rv.w = ieee754sp_cmp(fs, ft, @@ -2381,9 +2382,10 @@ dcopuop: default: if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { - unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; + unsigned int cmpop; union ieee754dp fs, ft; + cmpop = MIPSInst_FUNC(ir) - fcmp_op; DPFROMREG(fs, MIPSInst_FS(ir)); DPFROMREG(ft, MIPSInst_FT(ir)); rv.w = ieee754dp_cmp(fs, ft, diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index e0d9be5fbf4c..7ad79ed411f5 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -45,10 +45,10 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, { int re; int rs; - unsigned lxm; - unsigned hxm; - unsigned lym; - unsigned hym; + unsigned int lxm; + unsigned int hxm; + unsigned int lym; + unsigned int hym; u64 lrm; u64 hrm; u64 lzm; diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index 87d0b44b0614..60c8bfe40947 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c @@ -26,10 +26,10 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) int re; int rs; u64 rm; - unsigned lxm; - unsigned hxm; - unsigned lym; - unsigned hym; + unsigned int lxm; + unsigned int hxm; + unsigned int lym; + unsigned int hym; u64 lrm; u64 hrm; u64 t; diff --git a/arch/mips/math-emu/dp_sqrt.c b/arch/mips/math-emu/dp_sqrt.c index cd5bc083001e..cea907b83146 100644 --- a/arch/mips/math-emu/dp_sqrt.c +++ b/arch/mips/math-emu/dp_sqrt.c @@ -21,7 +21,7 @@ #include "ieee754dp.h" -static const unsigned table[] = { +static const unsigned int table[] = { 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215, 83599, 71378, 60428, 50647, 41945, 34246, @@ -33,7 +33,7 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x) { struct _ieee754_csr oldcsr; union ieee754dp y, z, t; - unsigned scalx, yh; + unsigned int scalx, yh; COMPXDP; EXPLODEXDP; diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 92dc8fa565cb..e0eb7a965fdf 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -165,11 +165,12 @@ struct _ieee754_csr { }; #define ieee754_csr (*(struct _ieee754_csr *)(¤t->thread.fpu.fcr31)) -static inline unsigned ieee754_getrm(void) +static inline unsigned int ieee754_getrm(void) { return (ieee754_csr.rm); } -static inline unsigned ieee754_setrm(unsigned rm) + +static inline unsigned int ieee754_setrm(unsigned int rm) { return (ieee754_csr.rm = rm); } @@ -177,14 +178,14 @@ static inline unsigned ieee754_setrm(unsigned rm) /* * get current exceptions */ -static inline unsigned ieee754_getcx(void) +static inline unsigned int ieee754_getcx(void) { return (ieee754_csr.cx); } /* test for current exception condition */ -static inline int ieee754_cxtest(unsigned n) +static inline int ieee754_cxtest(unsigned int n) { return (ieee754_csr.cx & n); } @@ -192,21 +193,21 @@ static inline int ieee754_cxtest(unsigned n) /* * get sticky exceptions */ -static inline unsigned ieee754_getsx(void) +static inline unsigned int ieee754_getsx(void) { return (ieee754_csr.sx); } /* clear sticky conditions */ -static inline unsigned ieee754_clrsx(void) +static inline unsigned int ieee754_clrsx(void) { return (ieee754_csr.sx = 0); } /* test for sticky exception condition */ -static inline int ieee754_sxtest(unsigned n) +static inline int ieee754_sxtest(unsigned int n) { return (ieee754_csr.sx & n); } diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index dd2071f430e0..06ac0e2ac7ac 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -54,13 +54,13 @@ static inline int ieee754_class_nan(int xc) } #define COMPXSP \ - unsigned xm; int xe; int xs __maybe_unused; int xc + unsigned int xm; int xe; int xs __maybe_unused; int xc #define COMPYSP \ - unsigned ym; int ye; int ys; int yc + unsigned int ym; int ye; int ys; int yc #define COMPZSP \ - unsigned zm; int ze; int zs; int zc + unsigned int zm; int ze; int zs; int zc #define EXPLODESP(v, vc, vs, ve, vm) \ { \ diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index 260e68965907..8423e4c5e415 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c @@ -65,7 +65,7 @@ union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r) return r; } -static unsigned ieee754sp_get_rounding(int sn, unsigned xm) +static unsigned int ieee754sp_get_rounding(int sn, unsigned int xm) { /* inexact must round of 3 bits */ @@ -96,7 +96,7 @@ static unsigned ieee754sp_get_rounding(int sn, unsigned xm) * xe is an unbiased exponent * xm is 3bit extended precision value. */ -union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) +union ieee754sp ieee754sp_format(int sn, int xe, unsigned int xm) { assert(xm); /* we don't gen exact zeros (probably should) */ diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 0f63e4202cff..8c5a63804873 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -69,7 +69,7 @@ static inline int ieee754sp_finite(union ieee754sp x) #define SPDNORMY SPDNORMx(ym, ye) #define SPDNORMZ SPDNORMx(zm, ze) -static inline union ieee754sp buildsp(int s, int bx, unsigned m) +static inline union ieee754sp buildsp(int s, int bx, unsigned int m) { union ieee754sp r; diff --git a/arch/mips/math-emu/sp_div.c b/arch/mips/math-emu/sp_div.c index 27f6db3a0a4c..23587b31ca87 100644 --- a/arch/mips/math-emu/sp_div.c +++ b/arch/mips/math-emu/sp_div.c @@ -23,9 +23,9 @@ union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y) { - unsigned rm; + unsigned int rm; int re; - unsigned bm; + unsigned int bm; COMPXSP; COMPYSP; diff --git a/arch/mips/math-emu/sp_fint.c b/arch/mips/math-emu/sp_fint.c index d5d8495b2cc4..1a35d12b6fc8 100644 --- a/arch/mips/math-emu/sp_fint.c +++ b/arch/mips/math-emu/sp_fint.c @@ -23,7 +23,7 @@ union ieee754sp ieee754sp_fint(int x) { - unsigned xm; + unsigned int xm; int xe; int xs; diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index 7195fe785d81..f823338dbb65 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -20,9 +20,9 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, { int re; int rs; - unsigned rm; - uint64_t rm64; - uint64_t zm64; + unsigned int rm; + u64 rm64; + u64 zm64; int s; COMPXSP; diff --git a/arch/mips/math-emu/sp_mul.c b/arch/mips/math-emu/sp_mul.c index d910c43a6f30..4015101fbc37 100644 --- a/arch/mips/math-emu/sp_mul.c +++ b/arch/mips/math-emu/sp_mul.c @@ -25,15 +25,15 @@ union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y) { int re; int rs; - unsigned rm; + unsigned int rm; unsigned short lxm; unsigned short hxm; unsigned short lym; unsigned short hym; - unsigned lrm; - unsigned hrm; - unsigned t; - unsigned at; + unsigned int lrm; + unsigned int hrm; + unsigned int t; + unsigned int at; COMPXSP; COMPYSP; From 0dcb34db9f488646f3be9f88365c12a6df4d4f76 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 9 Nov 2017 18:09:30 +0100 Subject: [PATCH 090/266] UPSTREAM: Documentation: Add device tree binding for Goldfish FB driver Add documentation for DT binding of Goldfish FB driver. The compatible string used by OS for binding the driver is "google,goldfish-fb". Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Acked-by: Rob Herring Cc: David Airlie Cc: Douglas Leung Cc: James Hogan Cc: Mark Rutland Cc: Paul Burton Cc: Petar Jovanovic Cc: Raghu Gandham Signed-off-by: Bartlomiej Zolnierkiewicz (cherry picked from commit bad12f43d0b164aad2a32b48bdc09d0d9680a213) Signed-off-by: Greg Kroah-Hartman --- .../bindings/display/google,goldfish-fb.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/google,goldfish-fb.txt diff --git a/Documentation/devicetree/bindings/display/google,goldfish-fb.txt b/Documentation/devicetree/bindings/display/google,goldfish-fb.txt new file mode 100644 index 000000000000..751fa9f51e5d --- /dev/null +++ b/Documentation/devicetree/bindings/display/google,goldfish-fb.txt @@ -0,0 +1,17 @@ +Android Goldfish framebuffer + +Android Goldfish framebuffer device used by Android emulator. + +Required properties: + +- compatible : should contain "google,goldfish-fb" +- reg : +- interrupts : + +Example: + + display-controller@1f008000 { + compatible = "google,goldfish-fb"; + interrupts = <0x10>; + reg = <0x1f008000 0x100>; + }; From 9684a8cd1c07521cac2f57d7b834134ad864ac0d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:21 +0000 Subject: [PATCH 091/266] UPSTREAM: MIPS: Detect MIPSr6 Virtual Processor support MIPSr6 introduces support for "Virtual Processors", which are conceptually similar to VPEs from the now-deprecated MT ASE. Detect whether the system supports VPs using the VP bit in Config5, adding cpu_has_vp for use by later patches. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Maciej W. Rozycki Cc: Joshua Kinard Cc: Steven J. Hill Cc: Leonid Yegoshin Cc: James Hogan Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12327/ Signed-off-by: Ralf Baechle (cherry picked from commit f270d881fa552c9c21c37417af2bf95da9a74347) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/cpu-features.h | 4 ++++ arch/mips/include/asm/cpu.h | 1 + arch/mips/include/asm/mipsregs.h | 1 + arch/mips/kernel/cpu-probe.c | 2 ++ 4 files changed, 8 insertions(+) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index eeec8c8e2da2..57cdc5be9545 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -311,6 +311,10 @@ #define cpu_has_mipsmt (cpu_data[0].ases & MIPS_ASE_MIPSMT) #endif +#ifndef cpu_has_vp +#define cpu_has_vp (cpu_data[0].options & MIPS_CPU_VP) +#endif + #ifndef cpu_has_userlocal #define cpu_has_userlocal (cpu_data[0].options & MIPS_CPU_ULRI) #endif diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index a97ca97285ec..82a26ed17515 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -388,6 +388,7 @@ enum cpu_type_enum { #define MIPS_CPU_FTLB 0x20000000000ull /* CPU has Fixed-page-size TLB */ #define MIPS_CPU_NAN_LEGACY 0x40000000000ull /* Legacy NaN implemented */ #define MIPS_CPU_NAN_2008 0x80000000000ull /* 2008 NaN implemented */ +#define MIPS_CPU_VP 0x100000000000ull /* MIPSr6 Virtual Processors (multi-threading) */ /* * CPU ASE encodings diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index e43aca183c99..c785da1d8660 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -589,6 +589,7 @@ #define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5) +#define MIPS_CONF5_VP (_ULCAST_(1) << 7) #define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_MSAEN (_ULCAST_(1) << 27) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index b725b713b9f8..e38442d5cd6e 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -796,6 +796,8 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c) if (config5 & MIPS_CONF5_MVH) c->options |= MIPS_CPU_XPA; #endif + if (cpu_has_mips_r6 && (config5 & MIPS_CONF5_VP)) + c->options |= MIPS_CPU_VP; return config5 & MIPS_CONF_M; } From 518b875ac8eb7080f3db4dd45d39fd08239f589f Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Wed, 3 Feb 2016 03:15:22 +0000 Subject: [PATCH 092/266] UPSTREAM: MIPS: traps: Make sure secondary cores have a sane ebase register We shouldn't trust that the secondary cores will have a sane ebase register (either from the bootloader or during the hardware design phase) so use the ebase address as calculated by the boot CPU. Signed-off-by: Markos Chandras Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: James Hogan Cc: Petri Gynther Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12328/ Signed-off-by: Ralf Baechle (cherry picked from commit 04d83f948510f17f8f2ab320b2386f4b5fbd0bd4) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/traps.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 2ad27a560f7f..e23f4775b10b 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2140,6 +2140,13 @@ void per_cpu_trap_init(bool is_boot_cpu) * o read IntCtl.IPFDC to determine the fast debug channel interrupt */ if (cpu_has_mips_r2_r6) { + /* + * We shouldn't trust a secondary core has a sane EBASE register + * so use the one calculated by the boot CPU. + */ + if (!is_boot_cpu) + write_c0_ebase(ebase); + cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP; cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7; cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7; From 55454ca1bd24d950af9f3fd74d9943aef07deb2e Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Wed, 3 Feb 2016 03:15:23 +0000 Subject: [PATCH 093/266] UPSTREAM: MIPS: pm-cps: Avoid offset overflow on MIPSr6 This is similar to commit 934c79231c1b ("MIPS: asm: r4kcache: Add MIPS R6 cache unroll functions"). The CACHE instruction has been redefined for MIPSr6 and it reduced its offset field to 8 bits. This leads to micro-assembler field overflow warnings when booting SMP MIPSr6 cores like the following one: Call Trace: [] show_stack+0x68/0x88 [] dump_stack+0x68/0x88 [] warn_slowpath_common+0x8c/0xc8 [] warn_slowpath_fmt+0x38/0x48 [] build_insn+0x514/0x5c0 [] cps_gen_cache_routine.isra.3+0xe0/0x1b8 [] cps_pm_init+0x364/0x9ec [] do_one_initcall+0x90/0x1a8 [] kernel_init_freeable+0x160/0x21c [] kernel_init+0x10/0xf8 [] ret_from_kernel_thread+0x14/0x1c We fix this by incrementing the base register on every loop. Signed-off-by: Markos Chandras Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12329/ Signed-off-by: Ralf Baechle (cherry picked from commit 0f2a1484487407390196ca5b3c3a07bee6df15ad) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/pm-cps.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index ebb227471700..91901dbb3830 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -223,11 +223,18 @@ static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, uasm_build_label(pl, *pp, lbl); /* Generate the cache ops */ - for (i = 0; i < unroll_lines; i++) - uasm_i_cache(pp, op, i * cache->linesz, t0); + for (i = 0; i < unroll_lines; i++) { + if (cpu_has_mips_r6) { + uasm_i_cache(pp, op, 0, t0); + uasm_i_addiu(pp, t0, t0, cache->linesz); + } else { + uasm_i_cache(pp, op, i * cache->linesz, t0); + } + } - /* Update the base address */ - uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz); + if (!cpu_has_mips_r6) + /* Update the base address */ + uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz); /* Loop if we haven't reached the end address yet */ uasm_il_bne(pp, pr, t0, t1, lbl); From 2ea248c38c525966b695adf7833c875836000bff Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Wed, 3 Feb 2016 03:15:24 +0000 Subject: [PATCH 094/266] UPSTREAM: MIPS: CPC: Add start, stop and running CM3 CPC registers Add the new CM3 registers for controlling bringing up and powering down VPs on MIPSR6 cores. Signed-off-by: Markos Chandras Signed-off-by: Paul Burton Cc: Bjorn Helgaas Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12330/ Signed-off-by: Ralf Baechle (cherry picked from commit 88036557bac3c831a564dcd6c860da48ae55756f) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/mips-cpc.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h index e09035239e53..8c519f9827a3 100644 --- a/arch/mips/include/asm/mips-cpc.h +++ b/arch/mips/include/asm/mips-cpc.h @@ -106,6 +106,9 @@ BUILD_CPC_R_(revision, MIPS_CPC_GCB_OFS + 0x20) BUILD_CPC_Cx_RW(cmd, 0x00) BUILD_CPC_Cx_RW(stat_conf, 0x08) BUILD_CPC_Cx_RW(other, 0x10) +BUILD_CPC_Cx_RW(vp_stop, 0x20) +BUILD_CPC_Cx_RW(vp_run, 0x28) +BUILD_CPC_Cx_RW(vp_running, 0x30) /* CPC_Cx_CMD register fields */ #define CPC_Cx_CMD_SHF 0 From 9eab7bcece0f430c323250b5d1d371c20e0611b4 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:25 +0000 Subject: [PATCH 095/266] UPSTREAM: MIPS: CM: Add CM GCR_BEV_BASE accessors Generate accessor functions for the GCR_BEV_BASE register introduced by CM3, for use by a later patch. Signed-off-by: Paul Burton Cc: Matt Redfearn Cc: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12331/ Signed-off-by: Ralf Baechle (cherry picked from commit db8e00af7b4a09ef5924140c1c42494fc88204ef) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/mips-cm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index c66fb8073c75..7b18653fbda2 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -208,6 +208,7 @@ BUILD_CM_RW(l2_config, MIPS_CM_GCB_OFS + 0x130) BUILD_CM_RW(sys_config2, MIPS_CM_GCB_OFS + 0x150) BUILD_CM_RW(l2_pft_control, MIPS_CM_GCB_OFS + 0x300) BUILD_CM_RW(l2_pft_control_b, MIPS_CM_GCB_OFS + 0x308) +BUILD_CM_RW(bev_base, MIPS_CM_GCB_OFS + 0x680) /* Core Local & Core Other register accessor functions */ BUILD_CM_Cx_RW(reset_release, 0x00) From 17aa10a65c9be29ad4ee65656ce2d23c5273ec41 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:26 +0000 Subject: [PATCH 096/266] UPSTREAM: MIPS: CM: Fix mips_cm_max_vp_width for UP kernels Fix mips_cm_max_vp_width for UP kernels where it previously referenced smp_num_siblings, which is not declared for UP kernels. This led to build errors such as the following: drivers/built-in.o: In function `$L446': irq-mips-gic.c:(.text+0x1994): undefined reference to `smp_num_siblings' drivers/built-in.o:irq-mips-gic.c:(.text+0x199c): more undefined references to `smp_num_siblings' follow On UP kernels simply return 1, leaving the reference to smp_num_siblings in place only for SMP kernels. Signed-off-by: Paul Burton Cc: Matt Redfearn Cc: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12332/ Signed-off-by: Ralf Baechle (cherry picked from commit a60ae81e5e5918138703f22427dd8f2445985b55) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/mips-cm.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 7b18653fbda2..70ad1c759555 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -458,7 +458,10 @@ static inline unsigned int mips_cm_max_vp_width(void) if (mips_cm_revision() >= CM_REV_CM3) return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW_MSK; - return smp_num_siblings; + if (config_enabled(CONFIG_SMP)) + return smp_num_siblings; + + return 1; } /** From 70dd808bc7794898b84688bda3ebf7103970603c Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:27 +0000 Subject: [PATCH 097/266] UPSTREAM: irqchip: mips-gic: Use HW IDs for VPE_OTHER_ADDR The Linux CPU number doesn't necessarily match up with the ID used for a VP by hardware. Convert the CPU number to the HW ID using mips_cm_vp_id when writing to the VP(E)_OTHER_ADDR register in order to ensure that we correctly access registers for the VPs of secondary cores. This most notably affects systems using CM3, such as those based around I6400. Signed-off-by: Paul Burton Acked-by: Jason Cooper Cc: Marc Zyngier Cc: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12333/ Signed-off-by: Ralf Baechle (cherry picked from commit d46812bb0bef04efa4e6cba677ba54c2e4f1ae59) Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-mips-gic.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 6f1dbd52ec91..57c0e1a29715 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -181,7 +181,7 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu) local_irq_save(flags); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), mips_cm_vp_id(cpu)); if (mips_cm_is64) { gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt); @@ -534,7 +534,8 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); @@ -548,7 +549,8 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); @@ -665,7 +667,8 @@ static void __init gic_basic_init(void) for (i = 0; i < gic_vpes; i++) { unsigned int j; - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { if (!gic_local_irq_is_routable(j)) continue; @@ -710,7 +713,8 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, for (i = 0; i < gic_vpes; i++) { u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin; - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); switch (intr) { case GIC_LOCAL_INT_WD: From 11afd7041257637e50e6fbd830b294f58879f901 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:28 +0000 Subject: [PATCH 098/266] UPSTREAM: irqchip: mips-gic: Provide VP ID accessor Provide a gic_read_local_vp_id() function to read the VCNUM field of the GICs local VP_IDENT register. This will be used by a further patch to check that the value reported by the GIC matches up with the kernels calculation. Signed-off-by: Paul Burton Acked-by: Jason Cooper Cc: Andrew Bresticker Cc: Jason Cooper Cc: Thomas Gleixner Cc: James Hogan Cc: Marc Zyngier Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12334/ Signed-off-by: Ralf Baechle (cherry picked from commit 835d2b452969820fd67a755a2c01fb6e12822448) Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-mips-gic.c | 8 ++++++++ include/linux/irqchip/mips-gic.h | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 57c0e1a29715..3f79b3a203aa 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -230,6 +230,14 @@ void gic_stop_count(void) #endif +unsigned gic_read_local_vp_id(void) +{ + unsigned long ident; + + ident = gic_read(GIC_REG(VPE_LOCAL, GIC_VP_IDENT)); + return ident & GIC_VP_IDENT_VCNUM_MSK; +} + static bool gic_local_irq_is_routable(int intr) { u32 vpe_ctl; diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h index ce824db48d64..d5d82c72e207 100644 --- a/include/linux/irqchip/mips-gic.h +++ b/include/linux/irqchip/mips-gic.h @@ -103,6 +103,7 @@ #define GIC_VPE_SWINT0_MAP_OFS 0x0054 #define GIC_VPE_SWINT1_MAP_OFS 0x0058 #define GIC_VPE_OTHER_ADDR_OFS 0x0080 +#define GIC_VP_IDENT_OFS 0x0088 #define GIC_VPE_WD_CONFIG0_OFS 0x0090 #define GIC_VPE_WD_COUNT0_OFS 0x0094 #define GIC_VPE_WD_INITIAL0_OFS 0x0098 @@ -211,6 +212,10 @@ #define GIC_VPE_SMASK_FDC_SHF 6 #define GIC_VPE_SMASK_FDC_MSK (MSK(1) << GIC_VPE_SMASK_FDC_SHF) +/* GIC_VP_IDENT fields */ +#define GIC_VP_IDENT_VCNUM_SHF 0 +#define GIC_VP_IDENT_VCNUM_MSK (MSK(6) << GIC_VP_IDENT_VCNUM_SHF) + /* GIC nomenclature for Core Interrupt Pins. */ #define GIC_CPU_INT0 0 /* Core Interrupt 2 */ #define GIC_CPU_INT1 1 /* . */ @@ -281,4 +286,16 @@ static inline int gic_get_usm_range(struct resource *gic_usm_res) #endif /* CONFIG_MIPS_GIC */ +/** + * gic_read_local_vp_id() - read the local VPs VCNUM + * + * Read the VCNUM of the local VP from the GIC_VP_IDENT register and + * return it to the caller. This ID should be used to refer to the VP + * via the GICs VP-other region, or when calculating an offset to a + * bit representing the VP in interrupt masks. + * + * Return: The VCNUM value for the local VP. + */ +extern unsigned gic_read_local_vp_id(void); + #endif /* __LINUX_IRQCHIP_MIPS_GIC_H */ From 85e9df5b2a8347cd124042faab2c2d0f85b5fd04 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:29 +0000 Subject: [PATCH 099/266] UPSTREAM: MIPS: smp-cps: Ensure our VP ident calculation is correct When bringing up a CPU, ensure that its local ID as provided by the GIC matches up with our calculation of it. This is vital, since if the condition doesn't hold then we won't have configured interrupts correctly for the VP. Signed-off-by: Paul Burton Cc: Rusty Russell Cc: Matt Redfearn Cc: Niklas Cassel Cc: Ezequiel Garcia Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12335/ Signed-off-by: Ralf Baechle (cherry picked from commit ba1c0a490a1fa61971b1cf9dd89acc7b4424e798) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/smp-cps.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index e04c8057b882..7f7ac25d379b 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -304,6 +304,17 @@ static void cps_init_secondary(void) if (cpu_has_mipsmt) dmt(); + if (mips_cm_revision() >= CM_REV_CM3) { + unsigned ident = gic_read_local_vp_id(); + + /* + * Ensure that our calculation of the VP ID matches up with + * what the GIC reports, otherwise we'll have configured + * interrupts incorrectly. + */ + BUG_ON(ident != mips_cm_vp_id(smp_processor_id())); + } + change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); } From d71fec6285d8acfe156525b48806784f37f56087 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:30 +0000 Subject: [PATCH 100/266] UPSTREAM: MIPS: smp-cps: Pull cache init into a function In preparation for further modifications to mips_cps_core_entry, pull the L1 cache initialisation out into a separate function. This both makes the code in mips_cps_core_entry read more clearly, particularly when modifying it, and shortens it which will become important as code is added that needs to continue to fit within the reset vector. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12336/ Signed-off-by: Ralf Baechle (cherry picked from commit 3dbc9971618ba0e88f25f2168aa5731b53af6f0b) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/cps-vec.S | 143 ++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 67 deletions(-) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index ac81edd44563..8d5ea4b778f9 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -90,74 +90,9 @@ not_nmi: li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS mtc0 t0, CP0_STATUS - /* - * Clear the bits used to index the caches. Note that the architecture - * dictates that writing to any of TagLo or TagHi selects 0 or 2 should - * be valid for all MIPS32 CPUs, even those for which said writes are - * unnecessary. - */ - mtc0 zero, CP0_TAGLO, 0 - mtc0 zero, CP0_TAGHI, 0 - mtc0 zero, CP0_TAGLO, 2 - mtc0 zero, CP0_TAGHI, 2 - ehb - - /* Primary cache configuration is indicated by Config1 */ - mfc0 v0, CP0_CONFIG, 1 - - /* Detect I-cache line size */ - _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ - beqz t0, icache_done - li t1, 2 - sllv t0, t1, t0 - - /* Detect I-cache size */ - _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ - xori t2, t1, 0x7 - beqz t2, 1f - li t3, 32 - addiu t1, t1, 1 - sllv t1, t3, t1 -1: /* At this point t1 == I-cache sets per way */ - _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ - addiu t2, t2, 1 - mul t1, t1, t0 - mul t1, t1, t2 - - li a0, CKSEG0 - PTR_ADD a1, a0, t1 -1: cache Index_Store_Tag_I, 0(a0) - PTR_ADD a0, a0, t0 - bne a0, a1, 1b + /* Initialize the L1 caches */ + jal mips_cps_cache_init nop -icache_done: - - /* Detect D-cache line size */ - _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ - beqz t0, dcache_done - li t1, 2 - sllv t0, t1, t0 - - /* Detect D-cache size */ - _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ - xori t2, t1, 0x7 - beqz t2, 1f - li t3, 32 - addiu t1, t1, 1 - sllv t1, t3, t1 -1: /* At this point t1 == D-cache sets per way */ - _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ - addiu t2, t2, 1 - mul t1, t1, t0 - mul t1, t1, t2 - - li a0, CKSEG0 - PTR_ADDU a1, a0, t1 - PTR_SUBU a1, a1, t0 -1: cache Index_Store_Tag_D, 0(a0) - bne a0, a1, 1b - PTR_ADD a0, a0, t0 -dcache_done: /* Set Kseg0 CCA to that in s0 */ mfc0 t0, CP0_CONFIG @@ -486,6 +421,80 @@ LEAF(mips_cps_boot_vpes) nop END(mips_cps_boot_vpes) +LEAF(mips_cps_cache_init) + /* + * Clear the bits used to index the caches. Note that the architecture + * dictates that writing to any of TagLo or TagHi selects 0 or 2 should + * be valid for all MIPS32 CPUs, even those for which said writes are + * unnecessary. + */ + mtc0 zero, CP0_TAGLO, 0 + mtc0 zero, CP0_TAGHI, 0 + mtc0 zero, CP0_TAGLO, 2 + mtc0 zero, CP0_TAGHI, 2 + ehb + + /* Primary cache configuration is indicated by Config1 */ + mfc0 v0, CP0_CONFIG, 1 + + /* Detect I-cache line size */ + _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ + beqz t0, icache_done + li t1, 2 + sllv t0, t1, t0 + + /* Detect I-cache size */ + _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ + xori t2, t1, 0x7 + beqz t2, 1f + li t3, 32 + addiu t1, t1, 1 + sllv t1, t3, t1 +1: /* At this point t1 == I-cache sets per way */ + _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ + addiu t2, t2, 1 + mul t1, t1, t0 + mul t1, t1, t2 + + li a0, CKSEG0 + PTR_ADD a1, a0, t1 +1: cache Index_Store_Tag_I, 0(a0) + PTR_ADD a0, a0, t0 + bne a0, a1, 1b + nop +icache_done: + + /* Detect D-cache line size */ + _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ + beqz t0, dcache_done + li t1, 2 + sllv t0, t1, t0 + + /* Detect D-cache size */ + _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ + xori t2, t1, 0x7 + beqz t2, 1f + li t3, 32 + addiu t1, t1, 1 + sllv t1, t3, t1 +1: /* At this point t1 == D-cache sets per way */ + _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ + addiu t2, t2, 1 + mul t1, t1, t0 + mul t1, t1, t2 + + li a0, CKSEG0 + PTR_ADDU a1, a0, t1 + PTR_SUBU a1, a1, t0 +1: cache Index_Store_Tag_D, 0(a0) + bne a0, a1, 1b + PTR_ADD a0, a0, t0 +dcache_done: + + jr ra + nop + END(mips_cps_cache_init) + #if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM) /* Calculate a pointer to this CPUs struct mips_static_suspend_state */ From e71f7c351f4f3acf0be9173ec3e7016f87b7880e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:31 +0000 Subject: [PATCH 101/266] UPSTREAM: MIPS: smp-cps: Pull boot config retrieval out of mips_cps_boot_vpes The mips_cps_boot_vpes function previously included code to retrieve pointers to the core & VPE boot configuration structs. These structures were used both by mips_cps_boot_vpes and by its mips_cps_core_entry callsite. In preparation for skipping the call to mips_cps_boot_vpes on some invocations of mips_cps_core_entry, pull the calculation of those pointers out into a separate function such that it can continue to be shared. Signed-off-by: Paul Burton Cc: Rusty Russell Cc: Matt Redfearn Cc: Niklas Cassel Cc: Ezequiel Garcia Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12337/ Signed-off-by: Ralf Baechle (cherry picked from commit f12401d7219f5a1e361ded834016e5777a10262b) Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/smp-cps.h | 2 +- arch/mips/kernel/cps-vec.S | 74 ++++++++++++++++++++------------- arch/mips/kernel/smp-cps.c | 7 +++- 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h index 326c16ebd589..2ae1f61a4a95 100644 --- a/arch/mips/include/asm/smp-cps.h +++ b/arch/mips/include/asm/smp-cps.h @@ -29,7 +29,7 @@ extern struct core_boot_config *mips_cps_core_bootcfg; extern void mips_cps_core_entry(void); extern void mips_cps_core_init(void); -extern struct vpe_boot_config *mips_cps_boot_vpes(void); +extern void mips_cps_boot_vpes(struct core_boot_config *cfg, unsigned vpe); extern void mips_cps_pm_save(void); extern void mips_cps_pm_restore(void); diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 8d5ea4b778f9..2613de9bcb2d 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -60,6 +60,17 @@ nop .endm + /* Calculate an uncached address for the CM GCRs */ + .macro cmgcrb dest + .set push + .set noat + MFC0 $1, CP0_CMGCRBASE + PTR_SLL $1, $1, 4 + PTR_LI \dest, UNCAC_BASE + PTR_ADDU \dest, \dest, $1 + .set pop + .endm + .section .text.cps-vec .balign 0x1000 @@ -102,13 +113,8 @@ not_nmi: mtc0 t0, CP0_CONFIG ehb - /* Calculate an uncached address for the CM GCRs */ - MFC0 v1, CP0_CMGCRBASE - PTR_SLL v1, v1, 4 - PTR_LI t0, UNCAC_BASE - PTR_ADDU v1, v1, t0 - /* Enter the coherent domain */ + cmgcrb v1 li t0, 0xff sw t0, GCR_CL_COHERENCE_OFS(v1) ehb @@ -128,17 +134,22 @@ not_nmi: /* Do any EVA initialization if necessary */ eva_init + /* Retrieve boot configuration pointers */ + jal mips_cps_get_bootcfg + nop + /* * Boot any other VPEs within this core that should be online, and * deactivate this VPE if it should be offline. */ + move a1, t9 jal mips_cps_boot_vpes - nop + move a0, v0 /* Off we go! */ - PTR_L t1, VPEBOOTCFG_PC(v0) - PTR_L gp, VPEBOOTCFG_GP(v0) - PTR_L sp, VPEBOOTCFG_SP(v0) + PTR_L t1, VPEBOOTCFG_PC(v1) + PTR_L gp, VPEBOOTCFG_GP(v1) + PTR_L sp, VPEBOOTCFG_SP(v1) jr t1 nop END(mips_cps_core_entry) @@ -258,18 +269,21 @@ LEAF(mips_cps_core_init) nop END(mips_cps_core_init) -LEAF(mips_cps_boot_vpes) - /* Retrieve CM base address */ - PTR_LA t0, mips_cm_base - PTR_L t0, 0(t0) - +/** + * mips_cps_get_bootcfg() - retrieve boot configuration pointers + * + * Returns: pointer to struct core_boot_config in v0, pointer to + * struct vpe_boot_config in v1, VPE ID in t9 + */ +LEAF(mips_cps_get_bootcfg) /* Calculate a pointer to this cores struct core_boot_config */ + cmgcrb t0 lw t0, GCR_CL_ID_OFS(t0) li t1, COREBOOTCFG_SIZE mul t0, t0, t1 PTR_LA t1, mips_cps_core_bootcfg PTR_L t1, 0(t1) - PTR_ADDU t0, t0, t1 + PTR_ADDU v0, t0, t1 /* Calculate this VPEs ID. If the core doesn't support MT use 0 */ li t9, 0 @@ -297,22 +311,27 @@ LEAF(mips_cps_boot_vpes) 1: /* Calculate a pointer to this VPEs struct vpe_boot_config */ li t1, VPEBOOTCFG_SIZE - mul v0, t9, t1 - PTR_L ta3, COREBOOTCFG_VPECONFIG(t0) - PTR_ADDU v0, v0, ta3 + mul v1, t9, t1 + PTR_L ta3, COREBOOTCFG_VPECONFIG(v0) + PTR_ADDU v1, v1, ta3 -#ifdef CONFIG_MIPS_MT_SMP - - /* If the core doesn't support MT then return */ - bnez ta2, 1f - nop jr ra nop + END(mips_cps_get_bootcfg) + +LEAF(mips_cps_boot_vpes) + PTR_L ta2, COREBOOTCFG_VPEMASK(a0) + PTR_L ta3, COREBOOTCFG_VPECONFIG(a0) + +#ifdef CONFIG_MIPS_MT .set push .set mt -1: /* Enter VPE configuration state */ + /* If the core doesn't support MT then return */ + has_mt t0, 5f + + /* Enter VPE configuration state */ dvpe PTR_LA t1, 1f jr.hb t1 @@ -323,7 +342,6 @@ LEAF(mips_cps_boot_vpes) ehb /* Loop through each VPE */ - PTR_L ta2, COREBOOTCFG_VPEMASK(t0) move t8, ta2 li ta1, 0 @@ -400,7 +418,7 @@ LEAF(mips_cps_boot_vpes) /* Check whether this VPE is meant to be running */ li t0, 1 - sll t0, t0, t9 + sll t0, t0, a1 and t0, t0, t8 bnez t0, 2f nop @@ -417,7 +435,7 @@ LEAF(mips_cps_boot_vpes) #endif /* CONFIG_MIPS_MT_SMP */ /* Return */ - jr ra +5: jr ra nop END(mips_cps_boot_vpes) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 7f7ac25d379b..af59951bd5ab 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -247,7 +247,10 @@ static void boot_core(unsigned core) static void remote_vpe_boot(void *dummy) { - mips_cps_boot_vpes(); + unsigned core = current_cpu_data.core; + struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core]; + + mips_cps_boot_vpes(core_cfg, cpu_vpe_id(¤t_cpu_data)); } static void cps_boot_secondary(int cpu, struct task_struct *idle) @@ -293,7 +296,7 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) BUG_ON(!cpu_has_mipsmt); /* Boot a VPE on this core */ - mips_cps_boot_vpes(); + mips_cps_boot_vpes(core_cfg, vpe_id); out: preempt_enable(); } From 5857ebce0d057ae81eb704010652d5a68add21d4 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:32 +0000 Subject: [PATCH 102/266] UPSTREAM: MIPS: smp-cps: Skip core setup if coherent In preparation for supporting MIPSr6 multithreading (ie. VPs) which will begin execution from the core reset vector, skip core level setup if the core is already coherent. This is never the case when a core is first started, since boot_core explicitly clears the cores GCR_Cx_COH_EN register, and always the case when secondary VPs start since the first VP to start will have enabled coherence after initialising the core & its caches. One notable side effect of this patch is that eva_init gets called slightly earlier, prior to mips_cps_core_init rather than after it. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12338/ Signed-off-by: Ralf Baechle (cherry picked from commit 87a70bcdb41008decfcf7c217e26b0bcd7f52642) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/cps-vec.S | 39 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 2613de9bcb2d..4849cbd47ccc 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -101,43 +101,52 @@ not_nmi: li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS mtc0 t0, CP0_STATUS + /* Skip cache & coherence setup if we're already coherent */ + cmgcrb v1 + lw s7, GCR_CL_COHERENCE_OFS(v1) + bnez s7, 1f + nop + /* Initialize the L1 caches */ jal mips_cps_cache_init nop + /* Enter the coherent domain */ + li t0, 0xff + sw t0, GCR_CL_COHERENCE_OFS(v1) + ehb + /* Set Kseg0 CCA to that in s0 */ - mfc0 t0, CP0_CONFIG +1: mfc0 t0, CP0_CONFIG ori t0, 0x7 xori t0, 0x7 or t0, t0, s0 mtc0 t0, CP0_CONFIG ehb - /* Enter the coherent domain */ - cmgcrb v1 - li t0, 0xff - sw t0, GCR_CL_COHERENCE_OFS(v1) - ehb - /* Jump to kseg0 */ PTR_LA t0, 1f jr t0 nop /* - * We're up, cached & coherent. Perform any further required core-level - * initialisation. + * We're up, cached & coherent. Perform any EVA initialization necessary + * before we access memory. */ -1: jal mips_cps_core_init - nop - - /* Do any EVA initialization if necessary */ - eva_init +1: eva_init /* Retrieve boot configuration pointers */ jal mips_cps_get_bootcfg nop + /* Skip core-level init if we started up coherent */ + bnez s7, 1f + nop + + /* Perform any further required core-level initialisation */ + jal mips_cps_core_init + nop + /* * Boot any other VPEs within this core that should be online, and * deactivate this VPE if it should be offline. @@ -147,7 +156,7 @@ not_nmi: move a0, v0 /* Off we go! */ - PTR_L t1, VPEBOOTCFG_PC(v1) +1: PTR_L t1, VPEBOOTCFG_PC(v1) PTR_L gp, VPEBOOTCFG_GP(v1) PTR_L sp, VPEBOOTCFG_SP(v1) jr t1 From f7eed353c580e6d3e83ed13180f470ee9191dbdc Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:33 +0000 Subject: [PATCH 103/266] UPSTREAM: MIPS: smp-cps: Support MIPSr6 Virtual Processors Introduce support for bringing up Virtual Processors in MIPSr6 systems as CPUs, much like their VPE parallel from the now-deprecated MT ASE. The existing mips_cps_boot_vpes function fits the MIPSr6 architecture pretty well - it can now simply write the mask of running VPs to the VC_RUN register, rather than looping through each & starting or stopping as appropriate as is done for VPEs from the MT ASE. Thus the VP support is in general an extension & simplification of the existing MT ASE VPE (aka SMVP) support. Signed-off-by: Paul Burton Cc: Matt Redfearn Cc: Rusty Russell Cc: Maciej W. Rozycki Cc: Niklas Cassel Cc: Ezequiel Garcia Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12339/ Signed-off-by: Ralf Baechle (cherry picked from commit 5a3e7c02d84fd31e6a2b1b242612363b6131a09e) Signed-off-by: Greg Kroah-Hartman --- arch/mips/Kconfig | 2 +- arch/mips/include/asm/cpu-info.h | 4 +-- arch/mips/kernel/cps-vec.S | 53 ++++++++++++++++++++++++++++++-- arch/mips/kernel/smp-cps.c | 35 ++++++++++++++++++--- 4 files changed, 85 insertions(+), 9 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index c9479fead851..7b673c1cc2dc 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2328,7 +2328,7 @@ config MIPS_CMP config MIPS_CPS bool "MIPS Coherent Processing System support" - depends on SYS_SUPPORTS_MIPS_CPS && !CPU_MIPSR6 + depends on SYS_SUPPORTS_MIPS_CPS select MIPS_CM select MIPS_CPC select MIPS_CPS_PM if HOTPLUG_CPU diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index e7dc785a91ca..aa526c304115 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h @@ -68,7 +68,7 @@ struct cpuinfo_mips { #ifdef CONFIG_64BIT int vmbits; /* Virtual memory size in bits */ #endif -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) /* * There is not necessarily a 1:1 mapping of VPE num to CPU number * in particular on multi-core systems. @@ -125,7 +125,7 @@ struct proc_cpuinfo_notifier_args { unsigned long n; }; -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) # define cpu_vpe_id(cpuinfo) ((cpuinfo)->vpe_id) #else # define cpu_vpe_id(cpuinfo) ({ (void)cpuinfo; 0; }) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 4849cbd47ccc..c28138d53d32 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -18,9 +18,12 @@ #include #include +#define GCR_CPC_BASE_OFS 0x0088 #define GCR_CL_COHERENCE_OFS 0x2008 #define GCR_CL_ID_OFS 0x2028 +#define CPC_CL_VC_RUN_OFS 0x2028 + .extern mips_cm_base .set noreorder @@ -60,6 +63,26 @@ nop .endm + /* + * Set dest to non-zero if the core supports MIPSr6 multithreading + * (ie. VPs), else zero. If MIPSr6 multithreading is not supported then + * branch to nomt. + */ + .macro has_vp dest, nomt + mfc0 \dest, CP0_CONFIG, 1 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 2 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 3 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 4 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 5 + andi \dest, \dest, MIPS_CONF5_VP + beqz \dest, \nomt + nop + .endm + /* Calculate an uncached address for the CM GCRs */ .macro cmgcrb dest .set push @@ -296,7 +319,17 @@ LEAF(mips_cps_get_bootcfg) /* Calculate this VPEs ID. If the core doesn't support MT use 0 */ li t9, 0 -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_CPU_MIPSR6) + has_vp ta2, 1f + + /* + * Assume non-contiguous numbering. Perhaps some day we'll need + * to handle contiguous VP numbering, but no such systems yet + * exist. + */ + mfc0 t9, $3, 1 + andi t9, t9, 0xff +#elif defined(CONFIG_MIPS_MT_SMP) has_mt ta2, 1f /* Find the number of VPEs present in the core */ @@ -332,7 +365,23 @@ LEAF(mips_cps_boot_vpes) PTR_L ta2, COREBOOTCFG_VPEMASK(a0) PTR_L ta3, COREBOOTCFG_VPECONFIG(a0) -#ifdef CONFIG_MIPS_MT +#if defined(CONFIG_CPU_MIPSR6) + + has_vp t0, 5f + + /* Find base address of CPC */ + cmgcrb t3 + PTR_L t1, GCR_CPC_BASE_OFS(t3) + PTR_LI t2, ~0x7fff + and t1, t1, t2 + PTR_LI t2, UNCAC_BASE + PTR_ADD t1, t1, t2 + + /* Set VC_RUN to the VPE mask */ + PTR_S ta2, CPC_CL_VC_RUN_OFS(t1) + ehb + +#elif defined(CONFIG_MIPS_MT) .set push .set mt diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index af59951bd5ab..d353482d176b 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -35,7 +35,8 @@ static unsigned core_vpe_count(unsigned core) { unsigned cfg; - if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) + if ((!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) + && (!config_enabled(CONFIG_CPU_MIPSR6) || !cpu_has_vp)) return 1; mips_cm_lock_other(core, 0); @@ -47,11 +48,12 @@ static unsigned core_vpe_count(unsigned core) static void __init cps_smp_setup(void) { unsigned int ncores, nvpes, core_vpes; + unsigned long core_entry; int c, v; /* Detect & record VPE topology */ ncores = mips_cm_numcores(); - pr_info("VPE topology "); + pr_info("%s topology ", cpu_has_mips_r6 ? "VP" : "VPE"); for (c = nvpes = 0; c < ncores; c++) { core_vpes = core_vpe_count(c); pr_cont("%c%u", c ? ',' : '{', core_vpes); @@ -62,7 +64,7 @@ static void __init cps_smp_setup(void) for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) { cpu_data[nvpes + v].core = c; -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) cpu_data[nvpes + v].vpe_id = v; #endif } @@ -91,6 +93,11 @@ static void __init cps_smp_setup(void) /* Make core 0 coherent with everything */ write_gcr_cl_coherence(0xff); + if (mips_cm_revision() >= CM_REV_CM3) { + core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry); + write_gcr_bev_base(core_entry); + } + #ifdef CONFIG_MIPS_MT_FPAFF /* If we have an FPU, enroll ourselves in the FPU-full mask */ if (cpu_has_fpu) @@ -210,6 +217,18 @@ static void boot_core(unsigned core) if (mips_cpc_present()) { /* Reset the core */ mips_cpc_lock_other(core); + + if (mips_cm_revision() >= CM_REV_CM3) { + /* Run VP0 following the reset */ + write_cpc_co_vp_run(0x1); + + /* + * Ensure that the VP_RUN register is written before the + * core leaves reset. + */ + wmb(); + } + write_cpc_co_cmd(CPC_Cx_CMD_RESET); timeout = 100; @@ -259,6 +278,7 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]); struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core]; struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id]; + unsigned long core_entry; unsigned int remote; int err; @@ -276,6 +296,13 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) goto out; } + if (cpu_has_vp) { + mips_cm_lock_other(core, vpe_id); + core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry); + write_gcr_co_reset_base(core_entry); + mips_cm_unlock_other(); + } + if (core != current_cpu_data.core) { /* Boot a VPE on another powered up core */ for (remote = 0; remote < NR_CPUS; remote++) { @@ -293,7 +320,7 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) goto out; } - BUG_ON(!cpu_has_mipsmt); + BUG_ON(!cpu_has_mipsmt && !cpu_has_vp); /* Boot a VPE on this core */ mips_cps_boot_vpes(core_cfg, vpe_id); From 7e307c7f65fa4ae8a6cd977d08c2d0e9bc6c1acf Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:34 +0000 Subject: [PATCH 104/266] UPSTREAM: MIPS: smp-cps: Add nothreads kernel parameter When debugging a new system or core it can be useful to disable the use of multithreading. Introduce a "nothreads" kernel command line parameter that can be set in order to do so. Signed-off-by: Paul Burton Cc: Matt Redfearn Cc: Rusty Russell Cc: Niklas Cassel Cc: Ezequiel Garcia Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12340/ Signed-off-by: Ralf Baechle (cherry picked from commit 6422a913856716be080dba4c2cb9d083d4e244ed) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/smp-cps.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index d353482d176b..651233e709f4 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -27,14 +27,25 @@ #include #include +static bool threads_disabled; static DECLARE_BITMAP(core_power, NR_CPUS); struct core_boot_config *mips_cps_core_bootcfg; +static int __init setup_nothreads(char *s) +{ + threads_disabled = true; + return 0; +} +early_param("nothreads", setup_nothreads); + static unsigned core_vpe_count(unsigned core) { unsigned cfg; + if (threads_disabled) + return 1; + if ((!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) && (!config_enabled(CONFIG_CPU_MIPSR6) || !cpu_has_vp)) return 1; From 79a0335b1267498e92340dc640fa786c6cab18dd Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 3 Feb 2016 03:15:35 +0000 Subject: [PATCH 105/266] UPSTREAM: MIPS: smp-cps: Stop printing EJTAG exceptions to UART When CONFIG_MIPS_CPS_NS16550 is enabled, some register state is dumped to the UART when an exception is taken via the BEV on secondary cores. EJTAG exceptions are architecturally expected to be handled by the BEV even when Status.BEV is 0. This effectively means that if userland executes an sdbbp instruction on a secondary core then the kernel dumps register state to the UART even though the exception is perfectly normal & expected. Prevent this by simply not dumping information to the UART for EJTAG exceptions. Fixes: 609cf6f2291a ("MIPS: CPS: Early debug using an ns16550-compatible UART") Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12341/ Signed-off-by: Ralf Baechle (cherry picked from commit 6609ccdc852f7bfbfa54300dd5b3cd89eb4ced6f) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/cps-vec.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index c28138d53d32..51b98dc371b3 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -223,7 +223,6 @@ LEAF(excep_intex) .org 0x480 LEAF(excep_ejtag) - DUMP_EXCEP("EJTAG") PTR_LA k0, ejtag_debug_handler jr k0 nop From 4eb22eaa8a3e4052a9f75ae6d896a521199ee43c Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 8 Feb 2016 09:46:31 -0800 Subject: [PATCH 106/266] UPSTREAM: MIPS: Fix early CM probing Commit c014d164f21d ("MIPS: Add platform callback before initializing the L2 cache") added a platform_early_l2_init function in order to allow platforms to probe for the CM before L2 initialisation is performed, so that CM GCRs are available to mips_sc_probe. That commit actually fails to do anything useful, since it checks mips_cm_revision to determine whether it should call mips_cm_probe but the result of mips_cm_revision will always be 0 until mips_cm_probe has been called. Thus the "early" mips_cm_probe call never occurs. Fix this & drop the useless weak platform_early_l2_init function by simply calling mips_cm_probe from setup_arch. For platforms that don't select CONFIG_MIPS_CM this will be a no-op, and for those that do it removes the requirement for them to call mips_cm_probe manually (although doing so isn't harmful for now). Signed-off-by: Paul Burton Reviewed-by: Alexander Sverdlin Cc: Andrzej Hajda Cc: Aaro Koskinen Cc: Masahiro Yamada Cc: Rob Herring Cc: Peter Hurley Cc: Leonid Yegoshin Cc: Jaedon Shin Cc: James Hogan Cc: Jonas Gorski Cc: Markos Chandras Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12475/ Signed-off-by: Ralf Baechle (cherry picked from commit 3af5a67c86a30f8cd8bfd6202709be21cedd2756) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/setup.c | 1 + arch/mips/mm/sc-mips.c | 10 ---------- arch/mips/mti-malta/malta-init.c | 8 -------- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 162a14e62669..34fd37e5c898 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -897,6 +897,7 @@ static inline void prefill_possible_map(void) {} void __init setup_arch(char **cmdline_p) { cpu_probe(); + mips_cm_probe(); prom_init(); setup_early_fdc_console(); diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index ddb8154610cc..91dec32c77b7 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -186,10 +186,6 @@ static int __init mips_sc_probe_cm3(void) return 0; } -void __weak platform_early_l2_init(void) -{ -} - static inline int __init mips_sc_probe(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -199,12 +195,6 @@ static inline int __init mips_sc_probe(void) /* Mark as not present until probe completed */ c->scache.flags |= MIPS_CACHE_NOT_PRESENT; - /* - * Do we need some platform specific probing before - * we configure L2? - */ - platform_early_l2_init(); - if (mips_cm_revision() >= CM_REV_CM3) return mips_sc_probe_cm3(); diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index 571148c5fd0b..dc2c5214809d 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -293,7 +293,6 @@ mips_pci_controller: console_config(); #endif /* Early detection of CMP support */ - mips_cm_probe(); mips_cpc_probe(); if (!register_cps_smp_ops()) @@ -304,10 +303,3 @@ mips_pci_controller: return; register_up_smp_ops(); } - -void platform_early_l2_init(void) -{ - /* L2 configuration lives in the CM3 */ - if (mips_cm_revision() >= CM_REV_CM3) - mips_cm_probe(); -} From 2710d8db2830098ce88648d50975513635e5e81c Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Wed, 7 Sep 2016 10:45:11 +0100 Subject: [PATCH 107/266] UPSTREAM: MIPS: pm-cps: Change FSB workaround to CPU blacklist The check for whether a CPU required the FSB flush workaround previously required every CPU not requiring it to be whitelisted. That approach does not scale well as new CPUs are introduced so change the default from a WARN and returning an error to just returning 0. Any CPUs requiring the workaround can then be added to the blacklist. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Adam Buchbinder Cc: Masahiro Yamada Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14218/ Signed-off-by: Ralf Baechle (cherry picked from commit b97d0b9099afcd5c569acaf9b0eb3f6e3b1b1f35) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/pm-cps.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 91901dbb3830..a3b602083149 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -271,14 +271,9 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, /* On older ones it's unavailable */ return -1; - /* CPUs which do not require the workaround */ - case CPU_P5600: - case CPU_I6400: - return 0; - default: - WARN_ONCE(1, "pm-cps: FSB flush unsupported for this CPU\n"); - return -1; + /* Assume that the CPU does not need this workaround */ + return 0; } /* From 0466b2e7a4d7f582580640c6fde5b06a1df9772f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 7 Aug 2017 16:01:18 -0700 Subject: [PATCH 108/266] UPSTREAM: MIPS: generic: Bump default NR_CPUS to 16 In generic_defconfig set CONFIG_NR_CPUS to 16 rather than 2, which is a rather too low limit for many modern day MIPS systems. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16949/ Signed-off-by: Ralf Baechle (cherry picked from commit c2c03291fba35dbba1712a0d9a679a43567d36a4) Signed-off-by: Greg Kroah-Hartman --- arch/mips/configs/generic_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/configs/generic_defconfig b/arch/mips/configs/generic_defconfig index c95d94c7838b..196c14d400b8 100644 --- a/arch/mips/configs/generic_defconfig +++ b/arch/mips/configs/generic_defconfig @@ -3,7 +3,7 @@ CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_MIPS_CPS=y CONFIG_CPU_HAS_MSA=y CONFIG_HIGHMEM=y -CONFIG_NR_CPUS=2 +CONFIG_NR_CPUS=16 CONFIG_MIPS_O32_FP64_SUPPORT=y CONFIG_SYSVIPC=y CONFIG_NO_HZ_IDLE=y From 63a30ac54ee77099ebeae3c524d664c602f5b730 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Thu, 7 Jul 2016 08:50:39 +0100 Subject: [PATCH 109/266] UPSTREAM: MIPS: smp-cps: Add support for CPU hotplug of MIPSr6 processors Introduce support for hotplug of Virtual Processors in MIPSr6 systems. The method is simpler than the VPE parallel from the now-deprecated MT ASE, it can now simply write the VP_STOP register with the mask of VPs to halt, and use the VP_RUNNING register to determine when the VP has halted. Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: Matt Redfearn Cc: Qais Yousef Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/13752/ Signed-off-by: Ralf Baechle (cherry picked from commit 0d2808f338c7cb0ccf6b087dd7be0e4fa0c865e0) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/smp-cps.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 651233e709f4..a211bbe82d0d 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -404,14 +404,16 @@ static enum { void play_dead(void) { - unsigned cpu, core; + unsigned int cpu, core, vpe_id; local_irq_disable(); idle_task_exit(); cpu = smp_processor_id(); cpu_death = CPU_DEATH_POWER; - if (cpu_has_mipsmt) { + pr_debug("CPU%d going offline\n", cpu); + + if (cpu_has_mipsmt || cpu_has_vp) { core = cpu_data[cpu].core; /* Look for another online VPE within the core */ @@ -432,10 +434,21 @@ void play_dead(void) complete(&cpu_death_chosen); if (cpu_death == CPU_DEATH_HALT) { - /* Halt this TC */ - write_c0_tchalt(TCHALT_H); - instruction_hazard(); + vpe_id = cpu_vpe_id(&cpu_data[cpu]); + + pr_debug("Halting core %d VP%d\n", core, vpe_id); + if (cpu_has_mipsmt) { + /* Halt this TC */ + write_c0_tchalt(TCHALT_H); + instruction_hazard(); + } else if (cpu_has_vp) { + write_cpc_cl_vp_stop(1 << vpe_id); + + /* Ensure that the VP_STOP register is written */ + wmb(); + } } else { + pr_debug("Gating power to core %d\n", core); /* Power down the core */ cps_pm_enter_state(CPS_PM_POWER_GATED); } @@ -462,6 +475,7 @@ static void wait_for_sibling_halt(void *ptr_cpu) static void cps_cpu_die(unsigned int cpu) { unsigned core = cpu_data[cpu].core; + unsigned int vpe_id = cpu_vpe_id(&cpu_data[cpu]); unsigned stat; int err; @@ -490,10 +504,12 @@ static void cps_cpu_die(unsigned int cpu) * in which case the CPC will refuse to power down the core. */ do { + mips_cm_lock_other(core, vpe_id); mips_cpc_lock_other(core); stat = read_cpc_co_stat_conf(); stat &= CPC_Cx_STAT_CONF_SEQSTATE_MSK; mips_cpc_unlock_other(); + mips_cm_unlock_other(); } while (stat != CPC_Cx_STAT_CONF_SEQSTATE_D0 && stat != CPC_Cx_STAT_CONF_SEQSTATE_D2 && stat != CPC_Cx_STAT_CONF_SEQSTATE_U2); @@ -510,6 +526,12 @@ static void cps_cpu_die(unsigned int cpu) (void *)(unsigned long)cpu, 1); if (err) panic("Failed to call remote sibling CPU\n"); + } else if (cpu_has_vp) { + do { + mips_cm_lock_other(core, vpe_id); + stat = read_cpc_co_vp_running(); + mips_cm_unlock_other(); + } while (stat & (1 << vpe_id)); } } From b4af2637b68c69878febbff5a392af838b9b57ff Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Thu, 22 Sep 2016 11:59:47 +0100 Subject: [PATCH 110/266] UPSTREAM: MIPS: smp-cps: Avoid BUG() when offlining pre-r6 CPUs Commit 0d2808f338c7 ("MIPS: smp-cps: Add support for CPU hotplug of MIPSr6 processors") added a call to mips_cm_lock_other in order to lock the CPC in CPUs containing a version 3 or higher Coherence Manager, which use the general CM core other register, where previous CMs had a dedicated core other register for the CPC. A kernel BUG() is triggered, however, if mips_cm_lock_other is called with a VP other than 0 on a CPU with CM < 3, a condition introduced by 0d2808f338c7. Avoid the BUG() by always locking VP0 when locking the CPC, since the required register, cpc_stat_conf, is shared by all vps in a core. Fixes: 0d2808f338c7 ("MIPS: smp-cps: Add support for CPU hotplug...) Signed-off-by: Matt Redfearn Cc: Qais Yousef Cc: Masahiro Yamada Cc: James Hogan Cc: Paul Burton Cc: Andrew Morton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14297/ Signed-off-by: Ralf Baechle (cherry picked from commit 6ca8ac773e97e2dfa5734ae435c40e672dd19ac4) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/smp-cps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index a211bbe82d0d..0ed4bfdaa65d 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -504,7 +504,7 @@ static void cps_cpu_die(unsigned int cpu) * in which case the CPC will refuse to power down the core. */ do { - mips_cm_lock_other(core, vpe_id); + mips_cm_lock_other(core, 0); mips_cpc_lock_other(core); stat = read_cpc_co_stat_conf(); stat &= CPC_Cx_STAT_CONF_SEQSTATE_MSK; From fb77eb94a33ddd06c52257d02f77362df4f52c70 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 14:48:50 -0700 Subject: [PATCH 111/266] UPSTREAM: MIPS: CM: Avoid per-core locking with CM3 & higher CM3 provides a GCR_CL_OTHER register per VP, rather than only per core. This means that we don't need to prevent other VPs within a core from racing with code that makes use of the core-other register region. Reduce locking overhead by demoting the per-core spinlock providing protection for CM2.5 & lower to a per-CPU/per-VP spinlock for CM3 & higher. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16193/ Signed-off-by: Ralf Baechle (cherry picked from commit 516db1c61f3fd4328361699a2c74781ab1dbf84c) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mips-cm.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 760217bbb2fa..fb70ab8229d5 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -265,15 +265,34 @@ void mips_cm_lock_other(unsigned int core, unsigned int vp) u32 val; preempt_disable(); - curr_core = current_cpu_data.core; - spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core), - per_cpu(cm_core_lock_flags, curr_core)); if (mips_cm_revision() >= CM_REV_CM3) { val = core << CM3_GCR_Cx_OTHER_CORE_SHF; val |= vp << CM3_GCR_Cx_OTHER_VP_SHF; + + /* + * We need to disable interrupts in SMP systems in order to + * ensure that we don't interrupt the caller with code which + * may modify the redirect register. We do so here in a + * slightly obscure way by using a spin lock, since this has + * the neat property of also catching any nested uses of + * mips_cm_lock_other() leading to a deadlock or a nice warning + * with lockdep enabled. + */ + spin_lock_irqsave(this_cpu_ptr(&cm_core_lock), + *this_cpu_ptr(&cm_core_lock_flags)); } else { BUG_ON(vp != 0); + + /* + * We only have a GCR_CL_OTHER per core in systems with + * CM 2.5 & older, so have to ensure other VP(E)s don't + * race with us. + */ + curr_core = current_cpu_data.core; + spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core), + per_cpu(cm_core_lock_flags, curr_core)); + val = core << CM_GCR_Cx_OTHER_CORENUM_SHF; } @@ -288,10 +307,17 @@ void mips_cm_lock_other(unsigned int core, unsigned int vp) void mips_cm_unlock_other(void) { - unsigned curr_core = current_cpu_data.core; + unsigned int curr_core; + + if (mips_cm_revision() < CM_REV_CM3) { + curr_core = current_cpu_data.core; + spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core), + per_cpu(cm_core_lock_flags, curr_core)); + } else { + spin_unlock_irqrestore(this_cpu_ptr(&cm_core_lock), + *this_cpu_ptr(&cm_core_lock_flags)); + } - spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core), - per_cpu(cm_core_lock_flags, curr_core)); preempt_enable(); } From 5ec00040d8b69a2643ad0335a22accd57bdb9513 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 14:48:51 -0700 Subject: [PATCH 112/266] UPSTREAM: MIPS: CM: WARN on attempt to lock invalid VP, not BUG Rather than using BUG_ON in the case of an invalid attempt to lock access to a non-zero VP on a pre-CM3 system, use WARN_ON so that we have even the slightest chance of recovery. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16194/ Signed-off-by: Ralf Baechle (cherry picked from commit 2f93a60c3d829da07764eafd922beb40e7317aa3) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mips-cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index fb70ab8229d5..36bd476d0760 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -282,7 +282,7 @@ void mips_cm_lock_other(unsigned int core, unsigned int vp) spin_lock_irqsave(this_cpu_ptr(&cm_core_lock), *this_cpu_ptr(&cm_core_lock_flags)); } else { - BUG_ON(vp != 0); + WARN_ON(vp != 0); /* * We only have a GCR_CL_OTHER per core in systems with From 9f251794e77fd027cf5b6f8093d9135b324bd755 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 14:48:52 -0700 Subject: [PATCH 113/266] UPSTREAM: MIPS: CPS: Select CONFIG_SYS_SUPPORTS_SCHED_SMT for MIPSr6 Prior to MIPSr6 multithreading is only supported if CONFIG_MIPS_MT_SMP is enabled, so CONFIG_MIPS_MT_SMP selects CONFIG_SYS_SUPPORTS_SCHED_SMT. With MIPSr6 the CONFIG_MIPS_CPS SMP implementation always supports multithreading, so have it select CONFIG_SYS_SUPPORTS_SCHED_SMT in order to allow the scheduler to make better informed decisions on multithreaded MIPSr6 systems (for example those using I6400 or I6500 CPUs). Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16195/ Signed-off-by: Ralf Baechle (cherry picked from commit c8b7712c34d0604e2540608731bd5e9202c1139e) Signed-off-by: Greg Kroah-Hartman --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 7b673c1cc2dc..a0383f86e230 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2336,6 +2336,7 @@ config MIPS_CPS select SMP select SYNC_R4K if (CEVT_R4K || CSRC_R4K) select SYS_SUPPORTS_HOTPLUG_CPU + select SYS_SUPPORTS_SCHED_SMT if CPU_MIPSR6 select SYS_SUPPORTS_SMP select WEAK_ORDERING help From bf48b18d3758f067a9693986f3d121fd94508e77 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 14:48:53 -0700 Subject: [PATCH 114/266] UPSTREAM: MIPS: CPS: Prevent multi-core with dcache aliasing Systems using the MIPS Coherence Manager (CM) cannot support multi-core SMP with dcache aliasing. This is because CPU caches are VIPT, but interventions in CM-based systems provide only the physical address to remote caches. This means that interventions may behave incorrectly in the presence of an aliasing dcache, since the physical address used when handling an intervention may lead to operation on an aliased cache line rather than the correct line. Prevent us from running into this issue by refusing to boot secondary cores in systems where dcache aliasing may occur. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16196/ Signed-off-by: Ralf Baechle (cherry picked from commit 5570ba2ee920de4e7760a2802b842771845b2c32) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/smp-cps.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 0ed4bfdaa65d..61ce01464913 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -140,9 +140,11 @@ static void __init cps_prepare_cpus(unsigned int max_cpus) /* Warn the user if the CCA prevents multi-core */ ncores = mips_cm_numcores(); - if (cca_unsuitable && ncores > 1) { - pr_warn("Using only one core due to unsuitable CCA 0x%x\n", - cca); + if ((cca_unsuitable || cpu_has_dc_aliases) && ncores > 1) { + pr_warn("Using only one core due to %s%s%s\n", + cca_unsuitable ? "unsuitable CCA" : "", + (cca_unsuitable && cpu_has_dc_aliases) ? " & " : "", + cpu_has_dc_aliases ? "dcache aliasing" : ""); for_each_present_cpu(c) { if (cpu_data[c].core) From 346a79c3cc3d592d4a08a1a417b55f2ebe77a57f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 14:48:54 -0700 Subject: [PATCH 115/266] UPSTREAM: MIPS: CPS: Handle cores not powering down more gracefully If we get into a state where a core that ought to power down isn't doing so then the current result is that another CPU gets stuck inside cps_cpu_die() waiting for CPU that ought to be powering down to do so. The best case scenario is that we then trigger RCU stall messages or lockup messages, but neither makes it particularly clear what's happening. Handle this more gracefully by introducing a timeout beyond which we warn the user that the core didn't power down & stop waiting for it. This at least allows the CPU running cps_cpu_die() to continue normally, and hopefully presuming the CPU that powered back up is doing nothing harmful the system will continue functioning as normal. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16197/ Signed-off-by: Ralf Baechle (cherry picked from commit 4ad755c9e39c0eeae16f96b97602f1954f582c66) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/smp-cps.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 61ce01464913..1b78309fb493 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -478,6 +478,7 @@ static void cps_cpu_die(unsigned int cpu) { unsigned core = cpu_data[cpu].core; unsigned int vpe_id = cpu_vpe_id(&cpu_data[cpu]); + ktime_t fail_time; unsigned stat; int err; @@ -505,6 +506,7 @@ static void cps_cpu_die(unsigned int cpu) * state, the latter happening when a JTAG probe is connected * in which case the CPC will refuse to power down the core. */ + fail_time = ktime_add_ms(ktime_get(), 2000); do { mips_cm_lock_other(core, 0); mips_cpc_lock_other(core); @@ -512,9 +514,28 @@ static void cps_cpu_die(unsigned int cpu) stat &= CPC_Cx_STAT_CONF_SEQSTATE_MSK; mips_cpc_unlock_other(); mips_cm_unlock_other(); - } while (stat != CPC_Cx_STAT_CONF_SEQSTATE_D0 && - stat != CPC_Cx_STAT_CONF_SEQSTATE_D2 && - stat != CPC_Cx_STAT_CONF_SEQSTATE_U2); + + if (stat == CPC_Cx_STAT_CONF_SEQSTATE_D0 || + stat == CPC_Cx_STAT_CONF_SEQSTATE_D2 || + stat == CPC_Cx_STAT_CONF_SEQSTATE_U2) + break; + + /* + * The core ought to have powered down, but didn't & + * now we don't really know what state it's in. It's + * likely that its _pwr_up pin has been wired to logic + * 1 & it powered back up as soon as we powered it + * down... + * + * The best we can do is warn the user & continue in + * the hope that the core is doing nothing harmful & + * might behave properly if we online it later. + */ + if (WARN(ktime_after(ktime_get(), fail_time), + "CPU%u hasn't powered down, seq. state %u\n", + cpu, stat >> CPC_Cx_STAT_CONF_SEQSTATE_SHF)) + break; + } while (1); /* Indicate the core is powered off */ bitmap_clear(core_power, core, 1); From b1f4d404b412b61646da1df0e97a750bdd4032b9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 14:48:55 -0700 Subject: [PATCH 116/266] UPSTREAM: MIPS: CPS: Handle spurious VP starts more gracefully On pre-r6 systems with the MT ASE the CPS SMP code included checks to halt the VPE running mips_cps_boot_vpes() if its bit in the struct core_boot_config vpe_mask field is clear. This was largely done in order to allow us to start arbitrary VPEs within a core despite the fact that hardware is typically configured to run only VPE0 after powering up a core. VPE0 would start the desired other VPEs, halt itself, and the fact that VPE0 started would be largely hidden & irrelevant. In MIPSr6 multithreading we have control over which VPs start executing when a core powers up via the cores CPC registers accessed remotely through the redirect block. For this reason the MIPSr6 multithreading path in mips_cps_boot_vpes() hasn't bothered up until now to handle halting the VP running it. However it is possible to power up cores entirely in hardware by using a pwr_up pin associated with the core. Unfortunately some systems wire this pin to a logic 1, which means that it is possible for a core to power up at a point that software doesn't expect. The result is that we generally go execute the kernel on a CPU that ought not to be running & the results can be unpredictable. Handle this case by stopping VPs that we don't expect to be running in mips_cps_boot_vpes() - with this change even if a core powers up it will do nothing useful & all VPs within it will stop running before they proceed to run general kernel code & do any damage. Ideally we would produce some sort of warning here, but given the stage of core bringup this happens at that would be non-trivial. We also will only hit this if a core starts up after being offlined via hotplug, and when that happens we will already produce a warning that the CPU didn't power down in cps_cpu_die() which seems sufficient. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16198/ Signed-off-by: Ralf Baechle (cherry picked from commit fa7a3b4a7217b40bf58c4f38e5ee573b43a8aa2f) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/cps-vec.S | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 51b98dc371b3..6829ee25af60 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -22,6 +22,7 @@ #define GCR_CL_COHERENCE_OFS 0x2008 #define GCR_CL_ID_OFS 0x2028 +#define CPC_CL_VC_STOP_OFS 0x2020 #define CPC_CL_VC_RUN_OFS 0x2028 .extern mips_cm_base @@ -376,8 +377,12 @@ LEAF(mips_cps_boot_vpes) PTR_LI t2, UNCAC_BASE PTR_ADD t1, t1, t2 - /* Set VC_RUN to the VPE mask */ + /* Start any other VPs that ought to be running */ PTR_S ta2, CPC_CL_VC_RUN_OFS(t1) + + /* Ensure this VP stops running if it shouldn't be */ + not ta2 + PTR_S ta2, CPC_CL_VC_STOP_OFS(t1) ehb #elif defined(CONFIG_MIPS_MT) From 315428718fd29e4ffac9611ba17bc4a2679a2de3 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 15:38:03 -0700 Subject: [PATCH 117/266] UPSTREAM: MIPS: Allow storing pgd in C0_CONTEXT for MIPSr6 CONFIG_MIPS_PGD_C0_CONTEXT, which allows a pointer to the page directory to be stored in the cop0 Context register when enabled, was previously only allowed for MIPSr2. MIPSr6 is just as able to make use of it, so allow it there too. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16204/ Signed-off-by: Ralf Baechle (cherry picked from commit cebf8c0f4f4e378f5e82606023b92ffbb1ad6048) Signed-off-by: Greg Kroah-Hartman --- arch/mips/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index a0383f86e230..2c93e3b7d318 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2039,7 +2039,7 @@ config CPU_SUPPORTS_UNCACHED_ACCELERATED bool config MIPS_PGD_C0_CONTEXT bool - default y if 64BIT && CPU_MIPSR2 && !CPU_XLP + default y if 64BIT && (CPU_MIPSR2 || CPU_MIPSR6) && !CPU_XLP # # Set to y for ptrace access to watch registers. From 4d143413ce843f4960fbdb5177b8aae6ab778296 Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Fri, 29 Dec 2017 16:41:45 +0100 Subject: [PATCH 118/266] UPSTREAM: dt-bindings/goldfish-pic: Add device tree binding for Goldfish PIC driver Add documentation for DT binding of Goldfish PIC driver. The compatible string used by OS for binding the driver is "google,goldfish-pic". Acked-by: Rob Herring Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Marc Zyngier (cherry picked from commit c2ba80af4805543ace4928191d877ffe706087e1) Signed-off-by: Greg Kroah-Hartman --- .../google,goldfish-pic.txt | 30 +++++++++++++++++++ MAINTAINERS | 5 ++++ 2 files changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt diff --git a/Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt b/Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt new file mode 100644 index 000000000000..35f752706e7d --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt @@ -0,0 +1,30 @@ +Android Goldfish PIC + +Android Goldfish programmable interrupt device used by Android +emulator. + +Required properties: + +- compatible : should contain "google,goldfish-pic" +- reg : +- interrupts : + +Example for mips when used in cascade mode: + + cpuintc { + #interrupt-cells = <0x1>; + #address-cells = <0>; + interrupt-controller; + compatible = "mti,cpu-interrupt-controller"; + }; + + interrupt-controller@1f000000 { + compatible = "google,goldfish-pic"; + reg = <0x1f000000 0x1000>; + + interrupt-controller; + #interrupt-cells = <0x1>; + + interrupt-parent = <&cpuintc>; + interrupts = <0x2>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 48bf18de18bb..84e5fdb02fb9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -756,6 +756,11 @@ S: Supported F: drivers/android/ F: drivers/staging/android/ +ANDROID GOLDFISH PIC DRIVER +M: Miodrag Dinic +S: Supported +F: Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt + ANDROID GOLDFISH RTC DRIVER M: Miodrag Dinic S: Supported From 0e3eb81e608af3e2bbfb8aa49f8f6ab6e7bc5df1 Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Fri, 29 Dec 2017 16:41:46 +0100 Subject: [PATCH 119/266] BACKPORT: irqchip/irq-goldfish-pic: Add Goldfish PIC driver Add device driver for a virtual programmable interrupt controller The virtual PIC is designed as a device tree-based interrupt controller. The compatible string used by OS for binding the driver is "google,goldfish-pic". Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Marc Zyngier (cherry picked from commit 4235ff50cf98dd42ba15175687570f9f03e124a1) Conflicts: drivers/irqchip/Kconfig drivers/irqchip/Makefile drivers/irqchip/irq-goldfish-pic.c Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + drivers/irqchip/Kconfig | 8 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-goldfish-pic.c | 136 +++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 drivers/irqchip/irq-goldfish-pic.c diff --git a/MAINTAINERS b/MAINTAINERS index 84e5fdb02fb9..0d2266dad653 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -760,6 +760,7 @@ ANDROID GOLDFISH PIC DRIVER M: Miodrag Dinic S: Supported F: Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt +F: drivers/irqchip/irq-goldfish-pic.c ANDROID GOLDFISH RTC DRIVER M: Miodrag Dinic diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 4d7294e5d982..9ce6fa46f00e 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -193,3 +193,11 @@ config IRQ_MXS def_bool y if MACH_ASM9260 || ARCH_MXS select IRQ_DOMAIN select STMP_DEVICE + +config GOLDFISH_PIC + bool "Goldfish programmable interrupt controller" + depends on MIPS && (GOLDFISH || COMPILE_TEST) + select IRQ_DOMAIN + help + Say yes here to enable Goldfish interrupt controller driver used + for Goldfish based virtual platforms. diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 177f78f6e6d6..616d052b65c0 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -55,3 +55,4 @@ obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o +obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o diff --git a/drivers/irqchip/irq-goldfish-pic.c b/drivers/irqchip/irq-goldfish-pic.c new file mode 100644 index 000000000000..ac18926b68b7 --- /dev/null +++ b/drivers/irqchip/irq-goldfish-pic.c @@ -0,0 +1,136 @@ +/* + * Driver for MIPS Goldfish Programmable Interrupt Controller. + * + * Author: Miodrag Dinic + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#define GFPIC_NR_IRQS 32 + +/* 8..39 Cascaded Goldfish PIC interrupts */ +#define GFPIC_IRQ_BASE 8 + +#define GFPIC_REG_IRQ_PENDING 0x04 +#define GFPIC_REG_IRQ_DISABLE_ALL 0x08 +#define GFPIC_REG_IRQ_DISABLE 0x0c +#define GFPIC_REG_IRQ_ENABLE 0x10 + +struct goldfish_pic_data { + void __iomem *base; + struct irq_domain *irq_domain; +}; + +static void goldfish_pic_cascade(struct irq_desc *desc) +{ + struct goldfish_pic_data *gfpic = irq_desc_get_handler_data(desc); + struct irq_chip *host_chip = irq_desc_get_chip(desc); + u32 pending, hwirq, virq; + + chained_irq_enter(host_chip, desc); + + pending = readl(gfpic->base + GFPIC_REG_IRQ_PENDING); + while (pending) { + hwirq = __fls(pending); + virq = irq_linear_revmap(gfpic->irq_domain, hwirq); + generic_handle_irq(virq); + pending &= ~(1 << hwirq); + } + + chained_irq_exit(host_chip, desc); +} + +static const struct irq_domain_ops goldfish_irq_domain_ops = { + .xlate = irq_domain_xlate_onecell, +}; + +static int __init goldfish_pic_of_init(struct device_node *of_node, + struct device_node *parent) +{ + struct goldfish_pic_data *gfpic; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + unsigned int parent_irq; + int ret = 0; + + gfpic = kzalloc(sizeof(*gfpic), GFP_KERNEL); + if (!gfpic) { + ret = -ENOMEM; + goto out_err; + } + + parent_irq = irq_of_parse_and_map(of_node, 0); + if (!parent_irq) { + pr_err("Failed to map parent IRQ!\n"); + ret = -EINVAL; + goto out_free; + } + + gfpic->base = of_iomap(of_node, 0); + if (!gfpic->base) { + pr_err("Failed to map base address!\n"); + ret = -ENOMEM; + goto out_unmap_irq; + } + + /* Mask interrupts. */ + writel(1, gfpic->base + GFPIC_REG_IRQ_DISABLE_ALL); + + gc = irq_alloc_generic_chip("GFPIC", 1, GFPIC_IRQ_BASE, gfpic->base, + handle_level_irq); + if (!gc) { + pr_err("Failed to allocate chip structures!\n"); + ret = -ENOMEM; + goto out_iounmap; + } + + ct = gc->chip_types; + ct->regs.enable = GFPIC_REG_IRQ_ENABLE; + ct->regs.disable = GFPIC_REG_IRQ_DISABLE; + ct->chip.irq_unmask = irq_gc_unmask_enable_reg; + ct->chip.irq_mask = irq_gc_mask_disable_reg; + + irq_setup_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS), 0, + IRQ_NOPROBE | IRQ_LEVEL, 0); + + gfpic->irq_domain = irq_domain_add_legacy(of_node, GFPIC_NR_IRQS, + GFPIC_IRQ_BASE, 0, + &goldfish_irq_domain_ops, + NULL); + if (!gfpic->irq_domain) { + pr_err("Failed to add irqdomain!\n"); + ret = -ENOMEM; + goto out_iounmap; + } + + irq_set_chained_handler_and_data(parent_irq, + goldfish_pic_cascade, gfpic); + + pr_info("Successfully registered.\n"); + return 0; + +out_iounmap: + iounmap(gfpic->base); +out_unmap_irq: + irq_dispose_mapping(parent_irq); +out_free: + kfree(gfpic); +out_err: + pr_err("Failed to initialize! (errno = %d)\n", ret); + return ret; +} + +IRQCHIP_DECLARE(google_gf_pic, "google,goldfish-pic", goldfish_pic_of_init); From 39678d21f51ce3b13f897ddbdc1b9c6d5e25f0e6 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 12:29:56 -0700 Subject: [PATCH 120/266] BACKPORT: MIPS: generic: Add a MAINTAINERS entry Add an entry to MAINTAINERS for the generic platform code, such that relevant people, starting with myself, can be CC'd on patches. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16186/ Signed-off-by: Ralf Baechle (cherry picked from commit 032a469b1e6ef02209308a5b107c10beb4b12fb6) Conflicts: MAINTAINERS Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0d2266dad653..a1ec446c3358 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7066,6 +7066,12 @@ S: Supported F: Documentation/mips/ F: arch/mips/ +MIPS GENERIC PLATFORM +M: Paul Burton +L: linux-mips@linux-mips.org +S: Supported +F: arch/mips/generic/ + MIPS RINT INSTRUCTION EMULATION M: Aleksandar Markovic L: linux-mips@linux-mips.org From 7bad331b2528a21da3c4d981904c5ffe502c3573 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 2 Aug 2016 14:07:24 -0700 Subject: [PATCH 121/266] UPSTREAM: config: add android config fragments Copy the config fragments from the AOSP common kernel android-4.4 branch. It is becoming possible to run mainline kernels with Android, but the kernel defconfigs don't work as-is and debugging missing config options is a pain. Adding the config fragments into the kernel tree, makes configuring a mainline kernel as simple as: make ARCH=arm multi_v7_defconfig android-base.config android-recommended.config The following non-upstream config options were removed: CONFIG_NETFILTER_XT_MATCH_QTAGUID CONFIG_NETFILTER_XT_MATCH_QUOTA2 CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG CONFIG_PPPOLAC CONFIG_PPPOPNS CONFIG_SECURITY_PERF_EVENTS_RESTRICT CONFIG_USB_CONFIGFS_F_MTP CONFIG_USB_CONFIGFS_F_PTP CONFIG_USB_CONFIGFS_F_ACC CONFIG_USB_CONFIGFS_F_AUDIO_SRC CONFIG_USB_CONFIGFS_UEVENT CONFIG_INPUT_KEYCHORD CONFIG_INPUT_KEYRESET Link: http://lkml.kernel.org/r/1466708235-28593-1-git-send-email-robh@kernel.org Signed-off-by: Rob Herring Cc: Amit Pundir Cc: John Stultz Cc: Dmitry Shmidt Cc: Rom Lemarchand Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 27eb6622ab67bad75814c9b7b08096cfb16be63a) Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 5 + kernel/configs/android-base.config | 152 ++++++++++++++++++++++ kernel/configs/android-recommended.config | 121 +++++++++++++++++ 3 files changed, 278 insertions(+) create mode 100644 kernel/configs/android-base.config create mode 100644 kernel/configs/android-recommended.config diff --git a/MAINTAINERS b/MAINTAINERS index a1ec446c3358..46da781dae65 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -746,6 +746,11 @@ W: http://ez.analog.com/community/linux-device-drivers S: Supported F: drivers/dma/dma-axi-dmac.c +ANDROID CONFIG FRAGMENTS +M: Rob Herring +S: Supported +F: kernel/configs/android* + ANDROID DRIVERS M: Greg Kroah-Hartman M: Arve Hjønnevåg diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config new file mode 100644 index 000000000000..9f748ed7bea8 --- /dev/null +++ b/kernel/configs/android-base.config @@ -0,0 +1,152 @@ +# KEEP ALPHABETICALLY SORTED +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +# CONFIG_INET_LRO is not set +# CONFIG_MODULES is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_SYSVIPC is not set +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_ASHMEM=y +CONFIG_AUDIT=y +CONFIG_BLK_DEV_DM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_SCHED=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_DM_CRYPT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_EMBEDDED=y +CONFIG_FB=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_INET=y +CONFIG_INET_DIAG_DESTROY=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 +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IPV6=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_NET=y +CONFIG_NETDEVICES=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_KEY=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_NAT=y +CONFIG_NO_HZ=y +CONFIG_PACKET=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PREEMPT=y +CONFIG_QUOTA=y +CONFIG_RTC_CLASS=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SETEND_EMULATION=y +CONFIG_STAGING=y +CONFIG_SWP_EMULATION=y +CONFIG_SYNC=y +CONFIG_TUN=y +CONFIG_UNIX=y +CONFIG_USB_GADGET=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_XFRM_USER=y diff --git a/kernel/configs/android-recommended.config b/kernel/configs/android-recommended.config new file mode 100644 index 000000000000..e3b953e966d2 --- /dev/null +++ b/kernel/configs/android-recommended.config @@ -0,0 +1,121 @@ +# KEEP ALPHABETICALLY SORTED +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_PM_WAKELOCKS_GC is not set +# CONFIG_VT is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_COMPACTION=y +CONFIG_DEBUG_RODATA=y +CONFIG_DM_UEVENT=y +CONFIG_DRAGONRISE_FF=y +CONFIG_ENABLE_DEFAULT_TRACERS=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FUSE_FS=y +CONFIG_GREENASIA_FF=y +CONFIG_HIDRAW=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_GYRATION=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WACOM=y +CONFIG_HID_WALTOP=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_UINPUT=y +CONFIG_ION=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KSM=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGITECH_FF=y +CONFIG_MD=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MSDOS_FS=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANTHERLORD_FF=y +CONFIG_PERF_EVENTS=y +CONFIG_PM_DEBUG=y +CONFIG_PM_RUNTIME=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_POWER_SUPPLY=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_SCHEDSTATS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_SND=y +CONFIG_SOUND=y +CONFIG_SUSPEND_TIME=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +CONFIG_TIMER_STATS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UHID=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_USBNET=y +CONFIG_VFAT_FS=y From 8ae29f24b92cb31d0dadcabf1c5ae0a810650cf6 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 11 Oct 2016 13:54:36 -0700 Subject: [PATCH 122/266] UPSTREAM: config/android: Remove CONFIG_IPV6_PRIVACY Option is long gone, see commit 5d9efa7ee99e ("ipv6: Remove privacy config option.") Link: http://lkml.kernel.org/r/20160811170340.9859-1-bp@alien8.de Signed-off-by: Borislav Petkov Cc: Rob Herring Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit a2c6a235dbf4318fc7f7981932478e6c47f093ab) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index 9f748ed7bea8..fcf2de834ee9 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -41,7 +41,6 @@ CONFIG_IPV6=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IP_ADVANCED_ROUTER=y From 258e4752645454cb63b4a3c4a1dcad402925e74b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 11 Oct 2016 13:54:38 -0700 Subject: [PATCH 123/266] UPSTREAM: config: android: move device mapper options to recommended CONFIG_MD is in recommended, but other dependent options like DM_CRYPT and DM_VERITY options are in base. The result is the options in base don't get enabled when applying both base and recommended fragments. Move all the options to recommended. Link: http://lkml.kernel.org/r/20160908185934.18098-1-robh@kernel.org Signed-off-by: Rob Herring Acked-by: John Stultz Cc: Amit Pundir Cc: Dmitry Shmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit f023a3956f273859ed36f624f75a66c272124b16) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 4 ---- kernel/configs/android-recommended.config | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index fcf2de834ee9..da8b3e9deac6 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -11,7 +11,6 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ARMV8_DEPRECATED=y CONFIG_ASHMEM=y CONFIG_AUDIT=y -CONFIG_BLK_DEV_DM=y CONFIG_BLK_DEV_INITRD=y CONFIG_CGROUPS=y CONFIG_CGROUP_CPUACCT=y @@ -19,9 +18,6 @@ CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_SCHED=y CONFIG_CP15_BARRIER_EMULATION=y -CONFIG_DM_CRYPT=y -CONFIG_DM_VERITY=y -CONFIG_DM_VERITY_FEC=y CONFIG_EMBEDDED=y CONFIG_FB=y CONFIG_HIGH_RES_TIMERS=y diff --git a/kernel/configs/android-recommended.config b/kernel/configs/android-recommended.config index e3b953e966d2..297756be369c 100644 --- a/kernel/configs/android-recommended.config +++ b/kernel/configs/android-recommended.config @@ -6,12 +6,16 @@ # CONFIG_PM_WAKELOCKS_GC is not set # CONFIG_VT is not set CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BLK_DEV_DM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_COMPACTION=y CONFIG_DEBUG_RODATA=y +CONFIG_DM_CRYPT=y CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y CONFIG_DRAGONRISE_FF=y CONFIG_ENABLE_DEFAULT_TRACERS=y CONFIG_EXT4_FS=y From d31dd9f2a24d774d18c69a7fb768bdc145a7784e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 11 Oct 2016 13:54:41 -0700 Subject: [PATCH 124/266] UPSTREAM: config: android: set SELinux as default security mode Android won't boot without SELinux enabled, so make it the default. Link: http://lkml.kernel.org/r/20160908185934.18098-2-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit d90ae51a3e7556c9f50431db43cd8190934ccf94) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index da8b3e9deac6..248070e0d61d 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -18,6 +18,7 @@ CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_SCHED=y CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_DEFAULT_SECURITY_SELINUX=y CONFIG_EMBEDDED=y CONFIG_FB=y CONFIG_HIGH_RES_TIMERS=y From 247bb900b1d96cb2696c1d0c3bcb44144a3b1000 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 11 Oct 2016 13:54:44 -0700 Subject: [PATCH 125/266] UPSTREAM: config: android: enable CONFIG_SECCOMP As of Android N, SECCOMP is required. Without it, we will get mediaextractor error: E /system/bin/mediaextractor: libminijail: prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER): Invalid argument Link: http://lkml.kernel.org/r/20160908185934.18098-3-robh@kernel.org Signed-off-by: Rob Herring Acked-by: John Stultz Cc: Amit Pundir Cc: Dmitry Shmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 2489a1771aae86062c637f0eb7a06129681208b1) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index 248070e0d61d..1a8f34f63601 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -131,6 +131,7 @@ CONFIG_PREEMPT=y CONFIG_QUOTA=y CONFIG_RTC_CLASS=y CONFIG_RT_GROUP_SCHED=y +CONFIG_SECCOMP=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y From 48303629e52617678490d99d29f03ef960a9c61a Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Mon, 27 Feb 2017 14:28:06 -0800 Subject: [PATCH 126/266] UPSTREAM: config: android-base: enable hardened usercopy and kernel ASLR Enable CONFIG_HARDENED_USERCOPY and CONFIG_RANDOMIZE_BASE in Android base config fragment. Reviewed at https://android-review.googlesource.com/#/c/283659/ Reviewed at https://android-review.googlesource.com/#/c/278133/ Link: http://lkml.kernel.org/r/1481113148-29204-2-git-send-email-amit.pundir@linaro.org Signed-off-by: Amit Pundir Cc: Rob Herring Cc: John Stultz Cc: Daniel Micay Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 0d31a194d517ce77a1c3a06cd8708184bb6e7862) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index 1a8f34f63601..26a06e09a5bd 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -21,6 +21,7 @@ CONFIG_CP15_BARRIER_EMULATION=y CONFIG_DEFAULT_SECURITY_SELINUX=y CONFIG_EMBEDDED=y CONFIG_FB=y +CONFIG_HARDENED_USERCOPY=y CONFIG_HIGH_RES_TIMERS=y CONFIG_INET6_AH=y CONFIG_INET6_ESP=y @@ -129,6 +130,7 @@ CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y CONFIG_PREEMPT=y CONFIG_QUOTA=y +CONFIG_RANDOMIZE_BASE=y CONFIG_RTC_CLASS=y CONFIG_RT_GROUP_SCHED=y CONFIG_SECCOMP=y From 4814880b1bbe171b350f02706696a4f4afe7330c Mon Sep 17 00:00:00 2001 From: Max Shi Date: Thu, 8 Jun 2017 18:09:11 +0530 Subject: [PATCH 127/266] UPSTREAM: config: android-base: disable CONFIG_USELIB and CONFIG_FHANDLE Turn off the two kernel configs to disable related system ABI. Reviewed-at: https://android-review.googlesource.com/#/c/264976/ Signed-off-by: Max Shi [AmitP: cherry-picked this change from Android common kernel] Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman (cherry picked from commit c1ebc2febdb85a73a4f91a9b9eaab6387619eaa6) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index 26a06e09a5bd..efe5ff86767e 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -1,10 +1,12 @@ # KEEP ALPHABETICALLY SORTED # CONFIG_DEVKMEM is not set # CONFIG_DEVMEM is not set +# CONFIG_FHANDLE is not set # CONFIG_INET_LRO is not set # CONFIG_MODULES is not set # CONFIG_OABI_COMPAT is not set # CONFIG_SYSVIPC is not set +# CONFIG_USELIB is not set CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y From f03dda414b4ad268b2d1d4a94cc442456eadd573 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 8 Jun 2017 18:09:13 +0530 Subject: [PATCH 128/266] UPSTREAM: config: android-base: add CONFIG_IKCONFIG option This adds CONFIG_IKCONFIG and CONFIG_IKCONFIG_PROC options, which are a requirement for the O release. Reviewed-at: https://android-review.googlesource.com/#/c/364553/ Signed-off-by: Greg Kroah-Hartman [AmitP: cherry-picked this change from Android common kernel] Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 5b89db2fa545b473dc352689ac3afe407367ea34) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index efe5ff86767e..e12cfec25758 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -25,6 +25,8 @@ CONFIG_EMBEDDED=y CONFIG_FB=y CONFIG_HARDENED_USERCOPY=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y From 54479d4f24153261adf1c78c272ba6582eb61040 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 8 Jun 2017 18:09:14 +0530 Subject: [PATCH 129/266] UPSTREAM: config: android-base: add CONFIG_MODULES option This adds CONFIG_MODULES, CONFIG_MODULE_UNLOAD, and CONFIG_MODVERSIONS which are required by the O release. Reviewed-at: https://android-review.googlesource.com/#/c/364554/ Signed-off-by: Greg Kroah-Hartman [AmitP: cherry-picked this change from Android common kernel] Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 2096e1706336d83cd66ca744e4d904af4d63e25c) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index e12cfec25758..62cb392fc34b 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -3,7 +3,6 @@ # CONFIG_DEVMEM is not set # CONFIG_FHANDLE is not set # CONFIG_INET_LRO is not set -# CONFIG_MODULES is not set # CONFIG_OABI_COMPAT is not set # CONFIG_SYSVIPC is not set # CONFIG_USELIB is not set @@ -64,6 +63,9 @@ CONFIG_IP_NF_TARGET_MASQUERADE=y CONFIG_IP_NF_TARGET_NETMAP=y CONFIG_IP_NF_TARGET_REDIRECT=y CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y CONFIG_NET=y CONFIG_NETDEVICES=y CONFIG_NETFILTER=y From b4ad83cea26d2da1463291e34fcdef223938a924 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Thu, 8 Jun 2017 18:09:15 +0530 Subject: [PATCH 130/266] UPSTREAM: config: android-base: add CGROUP_BPF Add CONFIG_CGROUP_BPF as a default configuration in android base config since it is used to replace XT_QTAGUID in future. Reviewed-at: https://android-review.googlesource.com/#/c/400374/ Signed-off-by: Chenbo Feng [AmitP: cherry-picked this change from Android common kernel] Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 2edfe6be206adc4c1055e053322d27267f8952bc) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index 62cb392fc34b..cdde5af6b332 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -14,6 +14,7 @@ CONFIG_ASHMEM=y CONFIG_AUDIT=y CONFIG_BLK_DEV_INITRD=y CONFIG_CGROUPS=y +CONFIG_CGROUP_BPF=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y From 414511978e11cf823d1c41a1756f99d008a91da8 Mon Sep 17 00:00:00 2001 From: Roberto Pereira Date: Thu, 8 Jun 2017 18:09:16 +0530 Subject: [PATCH 131/266] UPSTREAM: config: android-base: disable CONFIG_NFSD and CONFIG_NFS_FS Disable Network file system support. Reviewed-at: https://android-review.googlesource.com/#/c/409559/ Signed-off-by: Roberto Pereira [AmitP: cherry-picked this change from Android common kernel and updated commit message] Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 9e69dd0179c346dfb5d08b8d46d5f5c9c81ab1b7) Signed-off-by: Greg Kroah-Hartman --- kernel/configs/android-base.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config index cdde5af6b332..d70829033bb7 100644 --- a/kernel/configs/android-base.config +++ b/kernel/configs/android-base.config @@ -3,6 +3,8 @@ # CONFIG_DEVMEM is not set # CONFIG_FHANDLE is not set # CONFIG_INET_LRO is not set +# CONFIG_NFSD is not set +# CONFIG_NFS_FS is not set # CONFIG_OABI_COMPAT is not set # CONFIG_SYSVIPC is not set # CONFIG_USELIB is not set From a6f6fe171a593b7cc650ef8b6051e1b84fe35cd2 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Thu, 7 Jan 2016 11:03:14 -0800 Subject: [PATCH 132/266] UPSTREAM: dtc: create tool to diff device trees Create script to diff device trees. The device tree can be in any of the forms recognized by the dtc compiler: - source - binary blob - file system tree (from /proc/devicetree) If the device tree is a source file, then it is pre-processed in the same way as it would be when built in the linux kernel source tree before diffing. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring (cherry picked from commit 10eadc253ddf8325bc6daafdbed67438cfede84c) Signed-off-by: Greg Kroah-Hartman --- scripts/dtc/dtx_diff | 343 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100755 scripts/dtc/dtx_diff diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff new file mode 100755 index 000000000000..f1160053d75e --- /dev/null +++ b/scripts/dtc/dtx_diff @@ -0,0 +1,343 @@ +#! /bin/bash + +# Copyright (C) 2015 Frank Rowand +# +# 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; version 2 of the License. + + +usage() { + + # use spaces instead of tabs in the usage message + cat >&2 <tmp_dtx_1.dts + `basename $0` ARCH=arch_of_dtx_2 DTx_2 >tmp_dtx_2.dts + `basename $0` tmp_dtx_1.dts tmp_dtx_2.dts + rm tmp_dtx_1.dts tmp_dtx_2.dts + + If DTx_1 and DTx_2 are in different directories, then this script will + add the path of DTx_1 and DTx_2 to the include paths. If DTx_2 includes + a local file that exists in both the path of DTx_1 and DTx_2 then the + file in the path of DTx_1 will incorrectly be included. Possible + workaround: + + `basename $0` DTx_1 >tmp_dtx_1.dts + `basename $0` DTx_2 >tmp_dtx_2.dts + `basename $0` tmp_dtx_1.dts tmp_dtx_2.dts + rm tmp_dtx_1.dts tmp_dtx_2.dts + +eod +} + + +compile_to_dts() { + + dtx="$1" + + if [ -d "${dtx}" ] ; then + + # ----- input is file tree + + if ( ! ${DTC} -I fs ${dtx} ) ; then + exit 3 + fi + + elif [ -f "${dtx}" ] && [ -r "${dtx}" ] ; then + + magic=`hexdump -n 4 -e '/1 "%02x"' ${dtx}` + if [ "${magic}" = "d00dfeed" ] ; then + + # ----- input is FDT (binary blob) + + if ( ! ${DTC} -I dtb ${dtx} ) ; then + exit 3 + fi + + return + + fi + + # ----- input is DTS (source) + + if ( cpp ${cpp_flags} -x assembler-with-cpp ${dtx} \ + | ${DTC} -I dts ) ; then + return + fi + + echo "" >&2 + echo "Possible hints to resolve the above error:" >&2 + echo " (hints might not fix the problem)" >&2 + + hint_given=0 + + if [ "${ARCH}" = "" ] ; then + hint_given=1 + echo "" >&2 + echo " shell variable \$ARCH not set" >&2 + fi + + dtx_arch=`echo "/${dtx}" | sed -e 's|.*/arch/||' -e 's|/.*||'` + + if [ "${dtx_arch}" != "" -a "${dtx_arch}" != "${ARCH}" ] ; then + hint_given=1 + echo "" >&2 + echo " architecture ${dtx_arch} is in file path," >&2 + echo " but does not match shell variable \$ARCH" >&2 + echo " (${ARCH}) does not match shell variable" >&2 + echo " \$ARCH (${ARCH})" >&2 + fi + + if [ ! -d ${srctree}/arch/${ARCH} ] ; then + hint_given=1 + echo "" >&2 + echo " ${srctree}/arch/${ARCH}/ does not exist" >&2 + echo " Is \$ARCH='${ARCH}' correct?" >&2 + echo " Possible fix: use '-s' option" >&2 + + git_root=`git rev-parse --show-toplevel 2>/dev/null` + if [ -d ${git_root}/arch/ ] ; then + echo " Possible fix: use '-S' option" >&2 + fi + fi + + if [ $hint_given = 0 ] ; then + echo "" >&2 + echo " No hints available." >&2 + fi + + echo "" >&2 + + exit 3 + + else + echo "" >&2 + echo "ERROR: ${dtx} does not exist or is not readable" >&2 + echo "" >&2 + exit 2 + fi + +} + + +# ----- start of script + +cmd_diff=0 +diff_flags="-u" +dtx_file_1="" +dtx_file_2="" +dtc_sort="-s" +help=0 +srctree="" + + +while [ $# -gt 0 ] ; do + + case $1 in + + -f ) + diff_flags="--unified=999999" + shift + ;; + + -h | -help | --help ) + help=1 + shift + ;; + + -s ) + srctree="$2" + shift 2 + ;; + + -S ) + git_root=`git rev-parse --show-toplevel 2>/dev/null` + srctree="${git_root}" + shift + ;; + + -u ) + dtc_sort="" + shift + ;; + + *) + if [ "${dtx_file_1}" = "" ] ; then + dtx_file_1="$1" + elif [ "${dtx_file_2}" = "" ] ; then + dtx_file_2="$1" + else + echo "" >&2 + echo "ERROR: Unexpected parameter: $1" >&2 + echo "" >&2 + exit 2 + fi + shift + ;; + + esac + +done + +if [ "${srctree}" = "" ] ; then + srctree="." +fi + +if [ "${dtx_file_2}" != "" ]; then + cmd_diff=1 +fi + +if (( ${help} )) ; then + usage + exit 1 +fi + +# this must follow check for ${help} +if [ "${dtx_file_1}" = "" ]; then + echo "" >&2 + echo "ERROR: parameter DTx required" >&2 + echo "" >&2 + exit 2 +fi + + +# ----- prefer dtc from linux kernel, allow fallback to dtc in $PATH + +if [ "${KBUILD_OUTPUT:0:2}" = ".." ] ; then + __KBUILD_OUTPUT="${srctree}/${KBUILD_OUTPUT}" +elif [ "${KBUILD_OUTPUT}" = "" ] ; then + __KBUILD_OUTPUT="." +else + __KBUILD_OUTPUT="${KBUILD_OUTPUT}" +fi + +DTC="${__KBUILD_OUTPUT}/scripts/dtc/dtc" + +if [ ! -x ${DTC} ] ; then + __DTC="dtc" + if ( ! which ${__DTC} >/dev/null ) ; then + + # use spaces instead of tabs in the error message + cat >&2 < Date: Tue, 2 Feb 2016 11:02:35 -0800 Subject: [PATCH 133/266] UPSTREAM: scripts/dtc: dtx_diff - add info to error message If kernel config options are not properly set, "make scripts" will not compile dtc. Update the unable to find dtc error message to check the kernel config and give better advice on how to create dtc. Reword another error message to increase clarity. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring (cherry picked from commit 60c7f4cb1fa4df62b7ba07e9b087728ca7ce5bc8) Signed-off-by: Greg Kroah-Hartman --- scripts/dtc/dtx_diff | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff index f1160053d75e..959ab2646d38 100755 --- a/scripts/dtc/dtx_diff +++ b/scripts/dtc/dtx_diff @@ -136,8 +136,7 @@ compile_to_dts() { echo "" >&2 echo " architecture ${dtx_arch} is in file path," >&2 echo " but does not match shell variable \$ARCH" >&2 - echo " (${ARCH}) does not match shell variable" >&2 - echo " \$ARCH (${ARCH})" >&2 + echo " >>\$ARCH<< is: >>${ARCH}<<" >&2 fi if [ ! -d ${srctree}/arch/${ARCH} ] ; then @@ -267,6 +266,14 @@ DTC="${__KBUILD_OUTPUT}/scripts/dtc/dtc" if [ ! -x ${DTC} ] ; then __DTC="dtc" + if grep -q "^CONFIG_DTC=y" ${__KBUILD_OUTPUT}/.config ; then + make_command=' + make scripts' + else + make_command=' + Enable CONFIG_DTC in the kernel configuration + make scripts' + fi if ( ! which ${__DTC} >/dev/null ) ; then # use spaces instead of tabs in the error message @@ -280,8 +287,7 @@ ERROR: unable to find a 'dtc' program 'dtc' is: ${DTC} If it does not exist, create it from the root of the Linux source tree: - - 'make scripts'. +${make_command} If not at the root of the Linux kernel source tree -s SRCTREE or -S may need to be specified to find 'dtc'. From 8b8ef6794bdba4b5805596c0933bfa0be224b457 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 26 Jan 2016 09:04:11 -0600 Subject: [PATCH 134/266] UPSTREAM: scripts/dtc: Update to upstream commit b06e55c88b9b Sync to upstream dtc commit b06e55c88b9b ("Prevent crash on modulo by zero"). This adds the following commits from upstream: b06e55c Prevent crash on modulo by zero b433450 Fix some bugs in processing of line directives d728ad5 Fix crash on nul character in string escape sequence 1ab2205 Gracefully handle bad octal literals 1937095 Prevent crash on division by zero d0b3ab0 libfdt: Fix undefined behaviour in fdt_offset_ptr() d4c7c25 libfdt: check for potential overrun in _fdt_splice() f58799b libfdt: Add some missing symbols to version.lds af9f26d Remove duplicated -Werror in dtc Makefile 604e61e fdt: Add functions to retrieve strings 8702bd1 fdt: Add a function to get the index of a string 2218387 fdt: Add a function to count strings 554fde2 libfdt: fix comment block of fdt_get_property_namelen() e5e6df7 fdtdump: Fix bug printing bytestrings with negative values 067829e Remove redundant fdtdump test code 897a429 Move fdt_path_offset alias tests to right tests section 2d1417c Add simple .travis.yml f6dbc6c guess output file format 5e78dff guess input file format based on file content or file name 8b927bf tests: convert `echo -n` to `printf` 64c46b0 Fix crash with poorly defined #size-cells Cc: Grant Likely Tested-by: Frank Rowand Reviewed-by: Frank Rowand Signed-off-by: Rob Herring (cherry picked from commit 91feabc2e2240ee80dc8ac08103cb83f497e4d12) Signed-off-by: Greg Kroah-Hartman --- scripts/dtc/checks.c | 2 +- scripts/dtc/dtc-lexer.l | 39 ++++++---- scripts/dtc/dtc-lexer.lex.c_shipped | 101 ++++++++++++++------------ scripts/dtc/dtc-parser.tab.c_shipped | 102 +++++++++++++++------------ scripts/dtc/dtc-parser.y | 20 +++++- scripts/dtc/dtc.c | 62 +++++++++++++++- scripts/dtc/libfdt/fdt.c | 13 ++-- scripts/dtc/libfdt/fdt_ro.c | 100 ++++++++++++++++++++++++++ scripts/dtc/libfdt/fdt_rw.c | 2 + scripts/dtc/libfdt/libfdt.h | 73 ++++++++++++++++++- scripts/dtc/util.c | 3 +- scripts/dtc/version_gen.h | 2 +- 12 files changed, 399 insertions(+), 120 deletions(-) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index e81a8c74b8d2..0c03ac9159c1 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -560,7 +560,7 @@ static void check_reg_format(struct check *c, struct node *dt, size_cells = node_size_cells(node->parent); entrylen = (addr_cells + size_cells) * sizeof(cell_t); - if ((prop->val.len % entrylen) != 0) + if (!entrylen || (prop->val.len % entrylen) != 0) FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) " "(#address-cells == %d, #size-cells == %d)", node->fullpath, prop->val.len, addr_cells, size_cells); diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index 0ee1caf03dd0..790fbf6cf2d7 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -73,24 +73,32 @@ static void lexical_error(const char *fmt, ...); } <*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { - char *line, *tmp, *fn; + char *line, *fnstart, *fnend; + struct data fn; /* skip text before line # */ line = yytext; while (!isdigit((unsigned char)*line)) line++; - /* skip digits in line # */ - tmp = line; - while (!isspace((unsigned char)*tmp)) - tmp++; - /* "NULL"-terminate line # */ - *tmp = '\0'; - /* start of filename */ - fn = strchr(tmp + 1, '"') + 1; - /* strip trailing " from filename */ - tmp = strchr(fn, '"'); - *tmp = 0; + + /* regexp ensures that first and list " + * in the whole yytext are those at + * beginning and end of the filename string */ + fnstart = memchr(yytext, '"', yyleng); + for (fnend = yytext + yyleng - 1; + *fnend != '"'; fnend--) + ; + assert(fnstart && fnend && (fnend > fnstart)); + + fn = data_copy_escape_string(fnstart + 1, + fnend - fnstart - 1); + + /* Don't allow nuls in filenames */ + if (memchr(fn.val, '\0', fn.len - 1)) + lexical_error("nul in line number directive"); + /* -1 since #line is the number of the next line */ - srcpos_set_line(xstrdup(fn), atoi(line) - 1); + srcpos_set_line(xstrdup(fn.val), atoi(line) - 1); + data_free(fn); } <*><> { @@ -153,7 +161,10 @@ static void lexical_error(const char *fmt, ...); errno = 0; yylval.integer = strtoull(yytext, &e, 0); - assert(!(*e) || !e[strspn(e, "UL")]); + if (*e && e[strspn(e, "UL")]) { + lexical_error("Bad integer literal '%s'", + yytext); + } if (errno == ERANGE) lexical_error("Integer literal '%s' out of range", diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index 11cd78e72305..ba525c2f9fc2 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -951,31 +951,39 @@ case 2: YY_RULE_SETUP #line 75 "dtc-lexer.l" { - char *line, *tmp, *fn; + char *line, *fnstart, *fnend; + struct data fn; /* skip text before line # */ line = yytext; while (!isdigit((unsigned char)*line)) line++; - /* skip digits in line # */ - tmp = line; - while (!isspace((unsigned char)*tmp)) - tmp++; - /* "NULL"-terminate line # */ - *tmp = '\0'; - /* start of filename */ - fn = strchr(tmp + 1, '"') + 1; - /* strip trailing " from filename */ - tmp = strchr(fn, '"'); - *tmp = 0; + + /* regexp ensures that first and list " + * in the whole yytext are those at + * beginning and end of the filename string */ + fnstart = memchr(yytext, '"', yyleng); + for (fnend = yytext + yyleng - 1; + *fnend != '"'; fnend--) + ; + assert(fnstart && fnend && (fnend > fnstart)); + + fn = data_copy_escape_string(fnstart + 1, + fnend - fnstart - 1); + + /* Don't allow nuls in filenames */ + if (memchr(fn.val, '\0', fn.len - 1)) + lexical_error("nul in line number directive"); + /* -1 since #line is the number of the next line */ - srcpos_set_line(xstrdup(fn), atoi(line) - 1); + srcpos_set_line(xstrdup(fn.val), atoi(line) - 1); + data_free(fn); } YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(BYTESTRING): case YY_STATE_EOF(PROPNODENAME): case YY_STATE_EOF(V1): -#line 96 "dtc-lexer.l" +#line 104 "dtc-lexer.l" { if (!pop_input_file()) { yyterminate(); @@ -985,7 +993,7 @@ case YY_STATE_EOF(V1): case 3: /* rule 3 can match eol */ YY_RULE_SETUP -#line 102 "dtc-lexer.l" +#line 110 "dtc-lexer.l" { DPRINT("String: %s\n", yytext); yylval.data = data_copy_escape_string(yytext+1, @@ -995,7 +1003,7 @@ YY_RULE_SETUP YY_BREAK case 4: YY_RULE_SETUP -#line 109 "dtc-lexer.l" +#line 117 "dtc-lexer.l" { DPRINT("Keyword: /dts-v1/\n"); dts_version = 1; @@ -1005,7 +1013,7 @@ YY_RULE_SETUP YY_BREAK case 5: YY_RULE_SETUP -#line 116 "dtc-lexer.l" +#line 124 "dtc-lexer.l" { DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); @@ -1014,7 +1022,7 @@ YY_RULE_SETUP YY_BREAK case 6: YY_RULE_SETUP -#line 122 "dtc-lexer.l" +#line 130 "dtc-lexer.l" { DPRINT("Keyword: /bits/\n"); BEGIN_DEFAULT(); @@ -1023,7 +1031,7 @@ YY_RULE_SETUP YY_BREAK case 7: YY_RULE_SETUP -#line 128 "dtc-lexer.l" +#line 136 "dtc-lexer.l" { DPRINT("Keyword: /delete-property/\n"); DPRINT("\n"); @@ -1033,7 +1041,7 @@ YY_RULE_SETUP YY_BREAK case 8: YY_RULE_SETUP -#line 135 "dtc-lexer.l" +#line 143 "dtc-lexer.l" { DPRINT("Keyword: /delete-node/\n"); DPRINT("\n"); @@ -1043,7 +1051,7 @@ YY_RULE_SETUP YY_BREAK case 9: YY_RULE_SETUP -#line 142 "dtc-lexer.l" +#line 150 "dtc-lexer.l" { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); @@ -1053,7 +1061,7 @@ YY_RULE_SETUP YY_BREAK case 10: YY_RULE_SETUP -#line 149 "dtc-lexer.l" +#line 157 "dtc-lexer.l" { char *e; DPRINT("Integer Literal: '%s'\n", yytext); @@ -1061,7 +1069,10 @@ YY_RULE_SETUP errno = 0; yylval.integer = strtoull(yytext, &e, 0); - assert(!(*e) || !e[strspn(e, "UL")]); + if (*e && e[strspn(e, "UL")]) { + lexical_error("Bad integer literal '%s'", + yytext); + } if (errno == ERANGE) lexical_error("Integer literal '%s' out of range", @@ -1076,7 +1087,7 @@ YY_RULE_SETUP case 11: /* rule 11 can match eol */ YY_RULE_SETUP -#line 168 "dtc-lexer.l" +#line 179 "dtc-lexer.l" { struct data d; DPRINT("Character literal: %s\n", yytext); @@ -1100,7 +1111,7 @@ YY_RULE_SETUP YY_BREAK case 12: YY_RULE_SETUP -#line 189 "dtc-lexer.l" +#line 200 "dtc-lexer.l" { /* label reference */ DPRINT("Ref: %s\n", yytext+1); yylval.labelref = xstrdup(yytext+1); @@ -1109,7 +1120,7 @@ YY_RULE_SETUP YY_BREAK case 13: YY_RULE_SETUP -#line 195 "dtc-lexer.l" +#line 206 "dtc-lexer.l" { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); @@ -1119,7 +1130,7 @@ YY_RULE_SETUP YY_BREAK case 14: YY_RULE_SETUP -#line 202 "dtc-lexer.l" +#line 213 "dtc-lexer.l" { yylval.byte = strtol(yytext, NULL, 16); DPRINT("Byte: %02x\n", (int)yylval.byte); @@ -1128,7 +1139,7 @@ YY_RULE_SETUP YY_BREAK case 15: YY_RULE_SETUP -#line 208 "dtc-lexer.l" +#line 219 "dtc-lexer.l" { DPRINT("/BYTESTRING\n"); BEGIN_DEFAULT(); @@ -1137,7 +1148,7 @@ YY_RULE_SETUP YY_BREAK case 16: YY_RULE_SETUP -#line 214 "dtc-lexer.l" +#line 225 "dtc-lexer.l" { DPRINT("PropNodeName: %s\n", yytext); yylval.propnodename = xstrdup((yytext[0] == '\\') ? @@ -1148,7 +1159,7 @@ YY_RULE_SETUP YY_BREAK case 17: YY_RULE_SETUP -#line 222 "dtc-lexer.l" +#line 233 "dtc-lexer.l" { DPRINT("Binary Include\n"); return DT_INCBIN; @@ -1157,64 +1168,64 @@ YY_RULE_SETUP case 18: /* rule 18 can match eol */ YY_RULE_SETUP -#line 227 "dtc-lexer.l" +#line 238 "dtc-lexer.l" /* eat whitespace */ YY_BREAK case 19: /* rule 19 can match eol */ YY_RULE_SETUP -#line 228 "dtc-lexer.l" +#line 239 "dtc-lexer.l" /* eat C-style comments */ YY_BREAK case 20: /* rule 20 can match eol */ YY_RULE_SETUP -#line 229 "dtc-lexer.l" +#line 240 "dtc-lexer.l" /* eat C++-style comments */ YY_BREAK case 21: YY_RULE_SETUP -#line 231 "dtc-lexer.l" +#line 242 "dtc-lexer.l" { return DT_LSHIFT; }; YY_BREAK case 22: YY_RULE_SETUP -#line 232 "dtc-lexer.l" +#line 243 "dtc-lexer.l" { return DT_RSHIFT; }; YY_BREAK case 23: YY_RULE_SETUP -#line 233 "dtc-lexer.l" +#line 244 "dtc-lexer.l" { return DT_LE; }; YY_BREAK case 24: YY_RULE_SETUP -#line 234 "dtc-lexer.l" +#line 245 "dtc-lexer.l" { return DT_GE; }; YY_BREAK case 25: YY_RULE_SETUP -#line 235 "dtc-lexer.l" +#line 246 "dtc-lexer.l" { return DT_EQ; }; YY_BREAK case 26: YY_RULE_SETUP -#line 236 "dtc-lexer.l" +#line 247 "dtc-lexer.l" { return DT_NE; }; YY_BREAK case 27: YY_RULE_SETUP -#line 237 "dtc-lexer.l" +#line 248 "dtc-lexer.l" { return DT_AND; }; YY_BREAK case 28: YY_RULE_SETUP -#line 238 "dtc-lexer.l" +#line 249 "dtc-lexer.l" { return DT_OR; }; YY_BREAK case 29: YY_RULE_SETUP -#line 240 "dtc-lexer.l" +#line 251 "dtc-lexer.l" { DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); @@ -1232,10 +1243,10 @@ YY_RULE_SETUP YY_BREAK case 30: YY_RULE_SETUP -#line 255 "dtc-lexer.l" +#line 266 "dtc-lexer.l" ECHO; YY_BREAK -#line 1239 "dtc-lexer.lex.c" +#line 1250 "dtc-lexer.lex.c" case YY_END_OF_BUFFER: { @@ -2195,7 +2206,7 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" -#line 254 "dtc-lexer.l" +#line 265 "dtc-lexer.l" diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped index 116458c8dfc4..31cec50a1265 100644 --- a/scripts/dtc/dtc-parser.tab.c_shipped +++ b/scripts/dtc/dtc-parser.tab.c_shipped @@ -499,9 +499,9 @@ static const yytype_uint16 yyrline[] = 298, 303, 322, 336, 343, 344, 345, 352, 356, 357, 361, 362, 366, 367, 371, 372, 376, 377, 381, 382, 386, 387, 388, 392, 393, 394, 395, 396, 400, 401, - 402, 406, 407, 408, 412, 413, 414, 415, 419, 420, - 421, 422, 427, 430, 434, 442, 445, 449, 457, 461, - 465 + 402, 406, 407, 408, 412, 413, 422, 431, 435, 436, + 437, 438, 443, 446, 450, 458, 461, 465, 473, 477, + 481 }; #endif @@ -1909,111 +1909,125 @@ yyreduce: break; case 65: -#line 413 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); } -#line 1915 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 414 "dtc-parser.y" /* yacc.c:1646 */ + { + if ((yyvsp[0].integer) != 0) { + (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); + } else { + ERROR(&(yyloc), "Division by zero"); + (yyval.integer) = 0; + } + } +#line 1922 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 66: -#line 414 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); } -#line 1921 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 423 "dtc-parser.y" /* yacc.c:1646 */ + { + if ((yyvsp[0].integer) != 0) { + (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); + } else { + ERROR(&(yyloc), "Division by zero"); + (yyval.integer) = 0; + } + } +#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 69: -#line 420 "dtc-parser.y" /* yacc.c:1646 */ +#line 436 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = -(yyvsp[0].integer); } -#line 1927 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 70: -#line 421 "dtc-parser.y" /* yacc.c:1646 */ +#line 437 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = ~(yyvsp[0].integer); } -#line 1933 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 71: -#line 422 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = !(yyvsp[0].integer); } -#line 1939 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 72: -#line 427 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.data) = empty_data; - } #line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */ break; + case 71: +#line 438 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = !(yyvsp[0].integer); } +#line 1953 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 72: +#line 443 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = empty_data; + } +#line 1961 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + case 73: -#line 431 "dtc-parser.y" /* yacc.c:1646 */ +#line 447 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte)); } -#line 1955 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1969 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 74: -#line 435 "dtc-parser.y" /* yacc.c:1646 */ +#line 451 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); } -#line 1963 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1977 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 75: -#line 442 "dtc-parser.y" /* yacc.c:1646 */ +#line 458 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.nodelist) = NULL; } -#line 1971 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1985 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 76: -#line 446 "dtc-parser.y" /* yacc.c:1646 */ +#line 462 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist)); } -#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1993 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 77: -#line 450 "dtc-parser.y" /* yacc.c:1646 */ +#line 466 "dtc-parser.y" /* yacc.c:1646 */ { ERROR(&(yylsp[0]), "Properties must precede subnodes"); YYERROR; } -#line 1988 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2002 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 78: -#line 458 "dtc-parser.y" /* yacc.c:1646 */ +#line 474 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename)); } -#line 1996 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2010 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 79: -#line 462 "dtc-parser.y" /* yacc.c:1646 */ +#line 478 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename)); } -#line 2004 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2018 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 80: -#line 466 "dtc-parser.y" /* yacc.c:1646 */ +#line 482 "dtc-parser.y" /* yacc.c:1646 */ { add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref)); (yyval.node) = (yyvsp[0].node); } -#line 2013 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2027 "dtc-parser.tab.c" /* yacc.c:1646 */ break; -#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2031 "dtc-parser.tab.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -2248,7 +2262,7 @@ yyreturn: #endif return yyresult; } -#line 472 "dtc-parser.y" /* yacc.c:1906 */ +#line 488 "dtc-parser.y" /* yacc.c:1906 */ void yyerror(char const *s) diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 5a897e36562d..000873f070fd 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -410,8 +410,24 @@ integer_add: integer_mul: integer_mul '*' integer_unary { $$ = $1 * $3; } - | integer_mul '/' integer_unary { $$ = $1 / $3; } - | integer_mul '%' integer_unary { $$ = $1 % $3; } + | integer_mul '/' integer_unary + { + if ($3 != 0) { + $$ = $1 / $3; + } else { + ERROR(&@$, "Division by zero"); + $$ = 0; + } + } + | integer_mul '%' integer_unary + { + if ($3 != 0) { + $$ = $1 % $3; + } else { + ERROR(&@$, "Division by zero"); + $$ = 0; + } + } | integer_unary ; diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index 8c4add69a765..5fa23c406266 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -18,6 +18,8 @@ * USA */ +#include + #include "dtc.h" #include "srcpos.h" @@ -104,11 +106,56 @@ static const char * const usage_opts_help[] = { NULL, }; +static const char *guess_type_by_name(const char *fname, const char *fallback) +{ + const char *s; + + s = strrchr(fname, '.'); + if (s == NULL) + return fallback; + if (!strcasecmp(s, ".dts")) + return "dts"; + if (!strcasecmp(s, ".dtb")) + return "dtb"; + return fallback; +} + +static const char *guess_input_format(const char *fname, const char *fallback) +{ + struct stat statbuf; + uint32_t magic; + FILE *f; + + if (stat(fname, &statbuf) != 0) + return fallback; + + if (S_ISDIR(statbuf.st_mode)) + return "fs"; + + if (!S_ISREG(statbuf.st_mode)) + return fallback; + + f = fopen(fname, "r"); + if (f == NULL) + return fallback; + if (fread(&magic, 4, 1, f) != 1) { + fclose(f); + return fallback; + } + fclose(f); + + magic = fdt32_to_cpu(magic); + if (magic == FDT_MAGIC) + return "dtb"; + + return guess_type_by_name(fname, fallback); +} + int main(int argc, char *argv[]) { struct boot_info *bi; - const char *inform = "dts"; - const char *outform = "dts"; + const char *inform = NULL; + const char *outform = NULL; const char *outname = "-"; const char *depname = NULL; bool force = false, sort = false; @@ -213,6 +260,17 @@ int main(int argc, char *argv[]) fprintf(depfile, "%s:", outname); } + if (inform == NULL) + inform = guess_input_format(arg, "dts"); + if (outform == NULL) { + outform = guess_type_by_name(outname, NULL); + if (outform == NULL) { + if (streq(inform, "dts")) + outform = "dtb"; + else + outform = "dts"; + } + } if (streq(inform, "dts")) bi = dt_from_source(arg); else if (streq(inform, "fs")) diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index 2ce6a44179de..22286a1aaeaf 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -76,18 +76,19 @@ int fdt_check_header(const void *fdt) const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { - const char *p; + unsigned absoffset = offset + fdt_off_dt_struct(fdt); + + if ((absoffset < offset) + || ((absoffset + len) < absoffset) + || (absoffset + len) > fdt_totalsize(fdt)) + return NULL; if (fdt_version(fdt) >= 0x11) if (((offset + len) < offset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; - p = _fdt_offset_ptr(fdt, offset); - - if (p + len < p) - return NULL; - return p; + return _fdt_offset_ptr(fdt, offset); } uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index a65e4b5b72b6..e5b313682007 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -538,6 +538,106 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) return 0; } +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) +{ + const char *list, *end; + int length, count = 0; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return -length; + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + list += length; + count++; + } + + return count; +} + +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string) +{ + int length, len, idx = 0; + const char *list, *end; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return -length; + + len = strlen(string) + 1; + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + if (length == len && memcmp(list, string, length) == 0) + return idx; + + list += length; + idx++; + } + + return -FDT_ERR_NOTFOUND; +} + +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int idx, + int *lenp) +{ + const char *list, *end; + int length; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) { + if (lenp) + *lenp = length; + + return NULL; + } + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) { + if (lenp) + *lenp = -FDT_ERR_BADVALUE; + + return NULL; + } + + if (idx == 0) { + if (lenp) + *lenp = length - 1; + + return list; + } + + list += length; + idx--; + } + + if (lenp) + *lenp = -FDT_ERR_NOTFOUND; + + return NULL; +} + int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible) { diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 70adec6c371b..8be02b1f68f3 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -101,6 +101,8 @@ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) if (((p + oldlen) < p) || ((p + oldlen) > end)) return -FDT_ERR_BADOFFSET; + if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) + return -FDT_ERR_BADOFFSET; if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) return -FDT_ERR_NOSPACE; memmove(p + newlen, p + oldlen, end - p - oldlen); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index ea35ac3c9be4..59ca33976e56 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -121,7 +121,12 @@ /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells * or similar property with a bad format or value */ -#define FDT_ERR_MAX 14 +#define FDT_ERR_BADVALUE 15 + /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected + * value. For example: a property expected to contain a string list + * is not NUL-terminated within the length of its value. */ + +#define FDT_ERR_MAX 15 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ @@ -457,8 +462,8 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, * @namelen: number of characters of name to consider * @lenp: pointer to an integer variable (will be overwritten) or NULL * - * Identical to fdt_get_property_namelen(), but only examine the first - * namelen characters of name for matching the property name. + * Identical to fdt_get_property(), but only examine the first namelen + * characters of name for matching the property name. */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, int nodeoffset, @@ -868,6 +873,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, */ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); +/** + * fdt_stringlist_count - count the number of strings in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @return: + * the number of strings in the given property + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); + +/** + * fdt_stringlist_search - find a string in a string list and return its index + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @string: string to look up in the string list + * + * Note that it is possible for this function to succeed on property values + * that are not NUL-terminated. That's because the function will stop after + * finding the first occurrence of @string. This can for example happen with + * small-valued cell properties, such as #address-cells, when searching for + * the empty string. + * + * @return: + * the index of the string in the list of strings + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist or does not contain + * the given string + */ +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string); + +/** + * fdt_stringlist_get() - obtain the string at a given index in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @index: index of the string to return + * @lenp: return location for the string length or an error code on failure + * + * Note that this will successfully extract strings from properties with + * non-NUL-terminated values. For example on small-valued cell properties + * this function will return the empty string. + * + * If non-NULL, the length of the string (on success) or a negative error-code + * (on failure) will be stored in the integer pointer to by lenp. + * + * @return: + * A pointer to the string at the given index in the string list or NULL on + * failure. On success the length of the string will be stored in the memory + * location pointed to by the lenp parameter, if non-NULL. On failure one of + * the following negative error codes will be returned in the lenp parameter + * (if non-NULL): + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int index, + int *lenp); + /**********************************************************************/ /* Read-only functions (addressing related) */ /**********************************************************************/ diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index 9d65226df9e4..fb124eea4919 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -152,7 +152,6 @@ char get_escape_char(const char *s, int *i) int j = *i + 1; char val; - assert(c); switch (c) { case 'a': val = '\a'; @@ -349,7 +348,6 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) void utilfdt_print_data(const char *data, int len) { int i; - const char *p = data; const char *s; /* no data, don't print */ @@ -376,6 +374,7 @@ void utilfdt_print_data(const char *data, int len) i < (len - 1) ? " " : ""); printf(">"); } else { + const unsigned char *p = (const unsigned char *)data; printf(" = ["); for (i = 0; i < len; i++) printf("%02x%s", *p++, i < len - 1 ? " " : ""); diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index 5b8c7d53d608..11d93e6d8220 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.4.1-g9d3649bd" +#define DTC_VERSION "DTC 1.4.1-gb06e55c8" From 4d8ea865394ee408d2c5e5c8e317fd952dc0e46f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 4 Mar 2016 08:56:58 -0600 Subject: [PATCH 135/266] UPSTREAM: scripts/dtc: Update to upstream version 53bf130b1cdd Sync to upstream dtc commit 53bf130b1cdd ("libfdt: simplify fdt_node_check_compatible()"). This adds the following commits from upstream: 53bf130 libfdt: simplify fdt_node_check_compatible() c9d9121 Warn on node name unit-address presence/absence mismatch 2e53f9d Catch unsigned 32bit overflow when parsing flattened device tree offsets Signed-off-by: Rob Herring (cherry picked from commit b993734718c0106418e068f21c7be01afc12306c) Signed-off-by: Greg Kroah-Hartman --- scripts/dtc/checks.c | 26 ++++++++++++++++++++++++++ scripts/dtc/flattree.c | 4 ++-- scripts/dtc/libfdt/fdt_ro.c | 6 ++---- scripts/dtc/version_gen.h | 2 +- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index 0c03ac9159c1..386f9563313f 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -294,6 +294,30 @@ static void check_node_name_format(struct check *c, struct node *dt, } NODE_ERROR(node_name_format, NULL, &node_name_chars); +static void check_unit_address_vs_reg(struct check *c, struct node *dt, + struct node *node) +{ + const char *unitname = get_unitname(node); + struct property *prop = get_property(node, "reg"); + + if (!prop) { + prop = get_property(node, "ranges"); + if (prop && !prop->val.len) + prop = NULL; + } + + if (prop) { + if (!unitname[0]) + FAIL(c, "Node %s has a reg or ranges property, but no unit name", + node->fullpath); + } else { + if (unitname[0]) + FAIL(c, "Node %s has a unit name, but no reg property", + node->fullpath); + } +} +NODE_WARNING(unit_address_vs_reg, NULL); + static void check_property_name_chars(struct check *c, struct node *dt, struct node *node, struct property *prop) { @@ -667,6 +691,8 @@ static struct check *check_table[] = { &addr_size_cells, ®_format, &ranges_format, + &unit_address_vs_reg, + &avoid_default_addr_size, &obsolete_chosen_interrupt_controller, diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index bd99fa2d33b8..ec14954f5810 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -889,7 +889,7 @@ struct boot_info *dt_from_blob(const char *fname) if (version >= 3) { uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings); - if (off_str+size_str > totalsize) + if ((off_str+size_str < off_str) || (off_str+size_str > totalsize)) die("String table extends past total size\n"); inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str); } else { @@ -898,7 +898,7 @@ struct boot_info *dt_from_blob(const char *fname) if (version >= 17) { size_dt = fdt32_to_cpu(fdt->size_dt_struct); - if (off_dt+size_dt > totalsize) + if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize)) die("Structure block extends past total size\n"); } diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index e5b313682007..50cce864283c 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -647,10 +647,8 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; - if (fdt_stringlist_contains(prop, len, compatible)) - return 0; - else - return 1; + + return !fdt_stringlist_contains(prop, len, compatible); } int fdt_node_offset_by_compatible(const void *fdt, int startoffset, diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index 11d93e6d8220..ad9b05ae698b 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.4.1-gb06e55c8" +#define DTC_VERSION "DTC 1.4.1-g53bf130b" From 68b6a5ccf304d7e02e3593bf73daedb82b6e0051 Mon Sep 17 00:00:00 2001 From: Gaurav Minocha Date: Tue, 19 Jul 2016 19:37:44 -0700 Subject: [PATCH 136/266] UPSTREAM: scripts/dtc: dt_to_config - kernel config options for a devicetree Determining which kernel config options need to be enabled for a given devicetree can be a painful process. Create a new tool to find the drivers that may match a devicetree node compatible, find the kernel config options that enable the driver, and optionally report whether the kernel config option is enabled. Signed-off-by: Gaurav Minocha Signed-off-by: Frank Rowand Signed-off-by: Rob Herring (cherry picked from commit ca0cd118a15f9a1e25fa6086543ab49ddd96df99) Signed-off-by: Greg Kroah-Hartman --- scripts/dtc/dt_to_config | 1213 ++++++++++++++++++++++++++++++++++++++ scripts/dtc/dtx_diff | 2 +- 2 files changed, 1214 insertions(+), 1 deletion(-) create mode 100755 scripts/dtc/dt_to_config diff --git a/scripts/dtc/dt_to_config b/scripts/dtc/dt_to_config new file mode 100755 index 000000000000..9a248b505c58 --- /dev/null +++ b/scripts/dtc/dt_to_config @@ -0,0 +1,1213 @@ +#!/usr/bin/perl + +# Copyright 2016 by Frank Rowand +# Copyright 2016 by Gaurav Minocha +# +# This file is subject to the terms and conditions of the GNU General Public +# License v2. + +use strict 'refs'; +use strict subs; + +use Getopt::Long; + +$VUFX = "160610a"; + +$script_name = $0; +$script_name =~ s|^.*/||; + + +# ----- constants for print_flags() + +# Position in string $pr_flags. Range of 0..($num_pr_flags - 1). +$pr_flag_pos_mcompatible = 0; +$pr_flag_pos_driver = 1; +$pr_flag_pos_mdriver = 2; +$pr_flag_pos_config = 3; +$pr_flag_pos_mconfig = 4; +$pr_flag_pos_node_not_enabled = 5; +$pr_flag_pos_white_list = 6; +$pr_flag_pos_hard_coded = 7; +$pr_flag_pos_config_hard_coded = 8; +$pr_flag_pos_config_none = 9; +$pr_flag_pos_config_m = 10; +$pr_flag_pos_config_y = 11; +$pr_flag_pos_config_test_fail = 12; + +$num_pr_flags = $pr_flag_pos_config_test_fail + 1; + +# flags in @pr_flag_value must be unique values to allow simple regular +# expessions to work for --include_flags and --exclude_flags. +# Convention: use upper case letters for potential issues or problems. + +@pr_flag_value = ('M', 'd', 'D', 'c', 'C', 'E', 'W', 'H', 'x', 'n', 'm', 'y', 'F'); + +@pr_flag_help = ( + "multiple compatibles found for this node", + "driver found for this compatible", + "multiple drivers found for this compatible", + "kernel config found for this driver", + "multiple config options found for this driver", + "node is not enabled", + "compatible is white listed", + "matching driver and/or kernel config is hard coded", + "kernel config hard coded in Makefile", + "one or more kernel config file options is not set", + "one or more kernel config file options is set to 'm'", + "one or more kernel config file options is set to 'y'", + "one of more kernel config file options fails to have correct value" +); + + +# ----- + +%driver_config = (); # driver config array, indexed by driver source file +%driver_count = (); # driver_cnt, indexed by compatible +%compat_driver = (); # compatible driver array, indexed by compatible +%existing_config = (); # existing config symbols present in given config file + # expected values are: "y", "m", a decimal number, a + # hex number, or a string + +# ----- magic compatibles, do not have a driver +# +# Will not search for drivers for these compatibles. + +%compat_white_list = ( + 'none' => '1', + 'pci' => '1', + 'simple-bus' => '1', +); + +# Will not search for drivers for these compatibles. +# +# These compatibles have a very large number of false positives. +# +# 'hardcoded_no_driver' is a magic value. Other code knows this +# magic value. Do not use 'no_driver' here! +# +# Revisit each 'hardcoded_no_driver' to see how the compatible +# is used. Are there drivers that can be provided? + +%driver_hard_code_list = ( + 'cache' => ['hardcoded_no_driver'], + 'eeprom' => ['hardcoded_no_driver'], + 'gpio' => ['hardcoded_no_driver'], + 'gpio-keys' => ['drivers/input/keyboard/gpio_keys.c'], + 'i2c-gpio' => ['drivers/i2c/busses/i2c-gpio.c'], + 'isa' => ['arch/mips/mti-malta/malta-dt.c', + 'arch/x86/kernel/devicetree.c'], + 'led' => ['hardcoded_no_driver'], + 'm25p32' => ['hardcoded_no_driver'], + 'm25p64' => ['hardcoded_no_driver'], + 'm25p80' => ['hardcoded_no_driver'], + 'mtd-ram' => ['drivers/mtd/maps/physmap_of.c'], + 'pwm-backlight' => ['drivers/video/backlight/pwm_bl.c'], + 'spidev' => ['hardcoded_no_driver'], + 'syscon' => ['drivers/mfd/syscon.c'], + 'tlv320aic23' => ['hardcoded_no_driver'], + 'wm8731' => ['hardcoded_no_driver'], +); + +# Use these config options instead of searching makefiles + +%driver_config_hard_code_list = ( + + # this one needed even if %driver_hard_code_list is empty + 'no_driver' => ['no_config'], + 'hardcoded_no_driver' => ['no_config'], + + # drivers/usb/host/ehci-ppc-of.c + # drivers/usb/host/ehci-xilinx-of.c + # are included from: + # drivers/usb/host/ehci-hcd.c + # thus the search of Makefile for the included .c files is incorrect + # ehci-hcd.c wraps the includes with ifdef CONFIG_USB_EHCI_HCD_..._OF + # + # similar model for ohci-hcd.c (but no ohci-xilinx-of.c) + # + # similarly, uhci-hcd.c includes uhci-platform.c + + 'drivers/usb/host/ehci-ppc-of.c' => ['CONFIG_USB_EHCI_HCD', + 'CONFIG_USB_EHCI_HCD_PPC_OF'], + 'drivers/usb/host/ohci-ppc-of.c' => ['CONFIG_USB_OHCI_HCD', + 'CONFIG_USB_OHCI_HCD_PPC_OF'], + + 'drivers/usb/host/ehci-xilinx-of.c' => ['CONFIG_USB_EHCI_HCD', + 'CONFIG_USB_EHCI_HCD_XILINX'], + + 'drivers/usb/host/uhci-platform.c' => ['CONFIG_USB_UHCI_HCD', + 'CONFIG_USB_UHCI_PLATFORM'], + + # scan_makefile will find only one of these config options: + # ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),) + 'arch/arm/mach-imx/platsmp.c' => ['CONFIG_SOC_IMX6 && CONFIG_SMP', + 'CONFIG_SOC_LS1021A && CONFIG_SMP'], +); + + +# 'virt/kvm/arm/.*' are controlled by makefiles in other directories, +# using relative paths, such as 'KVM := ../../../virt/kvm'. Do not +# add complexity to find_kconfig() to deal with this. There is a long +# term intent to change the kvm related makefiles to the normal kernel +# style. After that is done, this entry can be removed from the +# black_list_driver. + +@black_list_driver = ( + # kvm no longer a problem after commit 503a62862e8f in 4.7-rc1 + # 'virt/kvm/arm/.*', +); + + +sub usage() +{ + print +" +Usage: $script_name [options] device-tree... + + device_tree is: dts_file | dtb_file | proc_device-tree + + +Valid options: + -c FILE Read kernel config options from FILE + --config FILE synonym for 'c' + --config-format config file friendly output format + --exclude-flag FLAG exclude entries with a matching flag + -h Display this message and exit + --help synonym for 'h' + --black-list-driver use driver black list + --white-list-config use config white list + --white-list-driver use driver white list + --include-flag FLAG include only entries with a matching flag + --include-suspect include only entries with an uppercase flag + --short-name do not show the path portion of the node name + --show-lists report of white and black lists + --version Display program version and exit + + + Report driver source files that match the compatibles in the device + tree file and the kernel config options that enable the driver source + files. + + This program must be run in the root directory of a Linux kernel + source tree. + + The default format is a report that is intended to be easily human + scannable. + + An alternate format can be selected by --config-format. This will + create output that can easily be edited to create a fragment that can + be appended to the existing kernel config file. Each entry consists of + multiple lines. The first line reports flags, the node path, compatible + value, driver file matching the compatible, configuration options, and + current values of the configuration options. For each configuration + option, the following lines report the current value and the value that + is required for the driver file to be included in the kernel. + + If a large number of drivers or config options is listed for a node, + and the '$pr_flag_value[$pr_flag_pos_hard_coded]' flag is set consider using --white-list-config and/or + --white-list-driver. If the white list option suppresses the correct + entry please report that as a bug. + + CAUTION: + This program uses heuristics to guess which driver(s) support each + compatible string and which config option(s) enables the driver(s). + Do not believe that the reported information is fully correct. + This program is intended to aid the process of determining the + proper kernel configuration for a device tree, but this is not + a fully automated process -- human involvement may still be + required! + + The driver match heuristic used is to search for source files + containing the compatible string enclosed in quotes. + + This program might not be able to find all drivers matching a + compatible string. + + Some makefiles are overly clever. This program was not made + complex enough to handle them. If no config option is listed + for a driver, look at the makefile for the driver source file. + Even if a config option is listed for a driver, some other + available config options may not be listed. + + FLAG values: +"; + + for ($k = 0; $k < $num_pr_flags; $k++) { + printf " %s %s\n", $pr_flag_value[$k], $pr_flag_help[$k]; + } + + print +" + Upper case letters indicate potential issues or problems. + + The flag: + +"; + + $k = $pr_flag_pos_hard_coded; + printf " %s %s\n", $pr_flag_value[$k], $pr_flag_help[$k]; + + print +" + will be set if the config or driver is in the white lists, even if + --white-list-config and --white-list-driver are not specified. + This is a hint that 1) many of these reported lines are likely to + be incorrect, and 2) using those options will reduce the number of + drivers and/or config options reported. + + --white-list-config and --white-list-driver may not be accurate if this + program is not well maintained. Use them with appropriate skepticism. + Use the --show-lists option to report the values in the list. + + Return value: + 0 if no error + 1 error processing command line + 2 unable to open or read kernel config file + 3 unable to open or process input device tree file(s) + + EXAMPLES: + + dt_to_config arch/arm/boot/dts/my_dts_file.dts + + Basic report. + + dt_to_config \\ + --config \${KBUILD_OUTPUT}/.config \\ + arch/\${ARCH}/boot/dts/my_dts_file.dts + + Full report, with config file issues noted. + + dt_to_config --include-suspect \\ + --config \${KBUILD_OUTPUT}/.config \\ + arch/\${ARCH}/boot/dts/my_dts_file.dts + + Report of node / compatible string / driver tuples that should + be further investigated. A node may have multiple compatible + strings. A compatible string may be matched by multiple drivers. + A driver may have config file issues noted. The compatible string + and/or driver may be in the white lists. + + dt_to_config --include-suspect --config-format \\ + --config ${KBUILD_OUTPUT}/.config \\ + arch/\${ARCH}/boot/dts/my_dts_file.dts + + Report of node / compatible string / driver tuples that should + be further investigated. The report can be edited to uncomment + the config options to select the desired tuple for a given node. + A node may have multiple compatible strings. A compatible string + may be matched by multiple drivers. A driver may have config file + issues noted. The compatible string and/or driver may be in the + white lists. + +"; +} + +sub set_flag() +{ + # pr_flags_ref is a reference to $pr_flags + + my $pr_flags_ref = shift; + my $pos = shift; + + substr $$pr_flags_ref, $pos, 1, $pr_flag_value[$pos]; + + return $pr_flags; +} + +sub print_flags() +{ + # return 1 if anything printed, else 0 + + # some fields of pn_arg_ref might not be used in this function, but + # extract all of them anyway. + my $pn_arg_ref = shift; + + my $compat = $pn_arg_ref->{compat}; + my $compatible_cnt = $pn_arg_ref->{compatible_cnt}; + my $config = $pn_arg_ref->{config}; + my $config_cnt = $pn_arg_ref->{config_cnt}; + my $driver = $pn_arg_ref->{driver}; + my $driver_cnt = $pn_arg_ref->{driver_cnt}; + my $full_node = $pn_arg_ref->{full_node}; + my $node = $pn_arg_ref->{node}; + my $node_enabled = $pn_arg_ref->{node_enabled}; + my $white_list = $pn_arg_ref->{white_list}; + + my $pr_flags = '-' x $num_pr_flags; + + + # ----- set flags in $pr_flags + + if ($compatible_cnt > 1) { + &set_flag(\$pr_flags, $pr_flag_pos_mcompatible); + } + + if ($config_cnt > 1) { + &set_flag(\$pr_flags, $pr_flag_pos_mconfig); + } + + if ($driver_cnt >= 1) { + &set_flag(\$pr_flags, $pr_flag_pos_driver); + } + + if ($driver_cnt > 1) { + &set_flag(\$pr_flags, $pr_flag_pos_mdriver); + } + + # These strings are the same way the linux kernel tests. + # The ePapr lists of values is slightly different. + if (!( + ($node_enabled eq "") || + ($node_enabled eq "ok") || + ($node_enabled eq "okay") + )) { + &set_flag(\$pr_flags, $pr_flag_pos_node_not_enabled); + } + + if ($white_list) { + &set_flag(\$pr_flags, $pr_flag_pos_white_list); + } + + if (exists($driver_hard_code_list{$compat}) || + (exists($driver_config_hard_code_list{$driver}) && + ($driver ne "no_driver"))) { + &set_flag(\$pr_flags, $pr_flag_pos_hard_coded); + } + + my @configs = split(' && ', $config); + for $configs (@configs) { + $not = $configs =~ /^!/; + $configs =~ s/^!//; + + if (($configs ne "no_config") && ($configs ne "no_makefile")) { + &set_flag(\$pr_flags, $pr_flag_pos_config); + } + + if (($config_cnt >= 1) && + ($configs !~ /CONFIG_/) && + (($configs ne "no_config") && ($configs ne "no_makefile"))) { + &set_flag(\$pr_flags, $pr_flag_pos_config_hard_coded); + } + + my $existing_config = $existing_config{$configs}; + if ($existing_config eq "m") { + &set_flag(\$pr_flags, $pr_flag_pos_config_m); + # Possible fail, depends on whether built in or + # module is desired. + &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail); + } elsif ($existing_config eq "y") { + &set_flag(\$pr_flags, $pr_flag_pos_config_y); + if ($not) { + &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail); + } + } elsif (($config_file) && ($configs =~ /CONFIG_/)) { + &set_flag(\$pr_flags, $pr_flag_pos_config_none); + if (!$not) { + &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail); + } + } + } + + # ----- include / exclude filters + + if ($include_flag_pattern && ($pr_flags !~ m/$include_flag_pattern/)) { + return 0; + } + + if ($exclude_flag_pattern && ($pr_flags =~ m/$exclude_flag_pattern/)) { + return 0; + } + + if ($config_format) { + print "# "; + } + print "$pr_flags : "; + + return 1; +} + + +sub print_node() +{ + # return number of lines printed + + # some fields of pn_arg_ref might not be used in this function, but + # extract all of them anyway. + my $pn_arg_ref = shift; + + my $compat = $pn_arg_ref->{compat}; + my $compatible_cnt = $pn_arg_ref->{compatible_cnt}; + my $config = $pn_arg_ref->{config}; + my $config_cnt = $pn_arg_ref->{config_cnt}; + my $driver = $pn_arg_ref->{driver}; + my $driver_cnt = $pn_arg_ref->{driver_cnt}; + my $full_node = $pn_arg_ref->{full_node}; + my $node = $pn_arg_ref->{node}; + my $node_enabled = $pn_arg_ref->{node_enabled}; + my $white_list = $pn_arg_ref->{white_list}; + + my $separator; + + if (! &print_flags($pn_arg_ref)) { + return 0; + } + + + if ($short_name) { + print "$node"; + } else { + print "$full_node"; + } + print " : $compat : $driver : $config : "; + + my @configs = split(' && ', $config); + + if ($config_file) { + for $configs (@configs) { + $configs =~ s/^!//; + my $existing_config = $existing_config{$configs}; + if (!$existing_config) { + # check for /-m/, /-y/, or /-objs/ + if ($configs !~ /CONFIG_/) { + $existing_config = "x"; + }; + }; + if ($existing_config) { + print "$separator", "$existing_config"; + $separator = ", "; + } else { + print "$separator", "n"; + $separator = ", "; + } + } + } else { + print "none"; + } + + print "\n"; + + if ($config_format) { + for $configs (@configs) { + $not = $configs =~ /^!/; + $configs =~ s/^!//; + my $existing_config = $existing_config{$configs}; + + if ($not) { + if ($configs !~ /CONFIG_/) { + print "# $configs\n"; + } elsif ($existing_config eq "m") { + print "# $configs is m\n"; + print "# $configs=n\n"; + } elsif ($existing_config eq "y") { + print "# $configs is set\n"; + print "# $configs=n\n"; + } else { + print "# $configs is not set\n"; + print "# $configs=n\n"; + } + + } else { + if ($configs !~ /CONFIG_/) { + print "# $configs\n"; + } elsif ($existing_config eq "m") { + print "# $configs is m\n"; + print "# $configs=y\n"; + } elsif ($existing_config eq "y") { + print "# $configs is set\n"; + print "# $configs=y\n"; + } else { + print "# $configs is not set\n"; + print "# $configs=y\n"; + } + } + } + } + + return 1; +} + + +sub scan_makefile +{ + my $pn_arg_ref = shift; + my $driver = shift; + + # ----- Find Kconfig symbols that enable driver + + my ($dir, $base) = $driver =~ m{(.*)/(.*).c}; + + my $makefile = $dir . "/Makefile"; + if (! -r $makefile) { + $makefile = $dir . "/Kbuild"; + } + if (! -r $makefile) { + my $config; + + $config = 'no_makefile'; + push @{ $driver_config{$driver} }, $config; + return; + } + + if (!open(MAKEFILE_FILE, "<", "$makefile")) { + return; + } + + my $line; + my @config; + my @if_config; + my @make_var; + + NEXT_LINE: + while ($next_line = ) { + my $config; + my $if_config; + my $ifdef; + my $ifeq; + my $ifndef; + my $ifneq; + my $ifdef_config; + my $ifeq_config; + my $ifndef_config; + my $ifneq_config; + + chomp($next_line); + $line = $line . $next_line; + if ($next_line =~ /\\$/) { + $line =~ s/\\$/ /; + next NEXT_LINE; + } + if ($line =~ /^\s*#/) { + $line = ""; + next NEXT_LINE; + } + + # ----- condition ... else ... endif + + if ($line =~ /^([ ]\s*|)else\b/) { + $if_config = "!" . pop @if_config; + $if_config =~ s/^!!//; + push @if_config, $if_config; + $line =~ s/^([ ]\s*|)else\b//; + } + + ($null, $ifeq_config, $ifeq_config_val ) = $line =~ /^([ ]\s*|)ifeq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/; + ($null, $ifneq_config, $ifneq_config_val) = $line =~ /^([ ]\s*|)ifneq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/; + ($null, $ifdef_config) = $line =~ /^([ ]\s*|)ifdef\b.*\b(CONFIG_[A-Za-z0-9_]*)/; + ($null, $ifndef_config) = $line =~ /^([ ]\s*|)ifndef\b.*\b(CONFIG_[A-Za-z0-9_]*)/; + + ($null, $ifeq) = $line =~ /^([ ]\s*|)ifeq\b\s*(.*)/; + ($null, $ifneq) = $line =~ /^([ ]\s*|)ifneq\b\s*(.*)/; + ($null, $ifdef) = $line =~ /^([ ]\s*|)ifdef\b\s*(.*)/; + ($null, $ifndef) = $line =~ /^([ ]\s*|)ifndef\b\s*(.*)/; + + # Order of tests is important. Prefer "CONFIG_*" regex match over + # less specific regex match. + if ($ifdef_config) { + $if_config = $ifdef_config; + } elsif ($ifeq_config) { + if ($ifeq_config_val =~ /y/) { + $if_config = $ifeq_config; + } else { + $if_config = "!" . $ifeq_config; + } + } elsif ($ifndef_config) { + $if_config = "!" . $ifndef_config; + } elsif ($ifneq_config) { + if ($ifneq_config_val =~ /y/) { + $if_config = "!" . $ifneq_config; + } else { + $if_config = $ifneq_config; + } + } elsif ($ifdef) { + $if_config = $ifdef; + } elsif ($ifeq) { + $if_config = $ifeq; + } elsif ($ifndef) { + $if_config = "!" . $ifndef; + } elsif ($ifneq) { + $if_config = "!" . $ifneq; + } else { + $if_config = ""; + } + $if_config =~ s/^!!//; + + if ($if_config) { + push @if_config, $if_config; + $line = ""; + next NEXT_LINE; + } + + if ($line =~ /^([ ]\s*|)endif\b/) { + pop @if_config; + $line = ""; + next NEXT_LINE; + } + + # ----- simple CONFIG_* = *.[co] or xxx [+:?]*= *.[co] + # Most makefiles select on *.o, but + # arch/powerpc/boot/Makefile selects on *.c + + ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$base.[co]\b/; + + # ----- match a make variable instead of *.[co] + # Recursively expanded variables are not handled. + + if (!$config) { + my $make_var; + ($make_var) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$base.[co]\b/; + if ($make_var) { + if ($make_var =~ /[a-zA-Z0-9]+-[ym]/) { + $config = $make_var; + } elsif ($make_var =~ /[a-zA-Z0-9]+-objs/) { + $config = $make_var; + } else { + push @make_var, $make_var; + } + } + } + + if (!$config) { + for $make_var (@make_var) { + ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$make_var\b/; + last if ($config); + } + } + + if (!$config) { + for $make_var (@make_var) { + ($config) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$make_var\b/; + last if ($config); + } + } + + # ----- next if no config found + + if (!$config) { + $line = ""; + next NEXT_LINE; + } + + for $if_config (@if_config) { + $config = $if_config . " && " . $config; + } + + push @{ $driver_config{$driver} }, $config; + + $line = ""; + } + + close(MAKEFILE_FILE); + +} + + +sub find_kconfig +{ + my $pn_arg_ref = shift; + my $driver = shift; + + my $lines_printed = 0; + my @configs; + + if (!@{ $driver_config{$driver} }) { + &scan_makefile($pn_arg_ref, $driver); + if (!@{ $driver_config{$driver} }) { + push @{ $driver_config{$driver} }, "no_config"; + } + } + + @configs = @{ $driver_config{$driver} }; + + $$pn_arg_ref{config_cnt} = $#configs + 1; + for my $config (@configs) { + $$pn_arg_ref{config} = $config; + $lines_printed += &print_node($pn_arg_ref); + } + + return $lines_printed; +} + + +sub handle_compatible() +{ + my $full_node = shift; + my $node = shift; + my $compatible = shift; + my $node_enabled = shift; + + my $compat; + my $lines_printed = 0; + my %pn_arg = (); + + return if (!$node or !$compatible); + + # Do not process compatible property of root node, + # it is used to match board, not to bind a driver. + return if ($node eq "/"); + + $pn_arg{full_node} = $full_node; + $pn_arg{node} = $node; + $pn_arg{node_enabled} = $node_enabled; + + my @compatibles = split('", "', $compatible); + + $compatibles[0] =~ s/^"//; + $compatibles[$#compatibles] =~ s/"$//; + + $pn_arg{compatible_cnt} = $#compatibles + 1; + + COMPAT: + for $compat (@compatibles) { + + $pn_arg{compat} = $compat; + $pn_arg{driver_cnt} = 0; + $pn_arg{white_list} = 0; + + if (exists($compat_white_list{$compat})) { + $pn_arg{white_list} = 1; + $pn_arg{driver} = "no_driver"; + $pn_arg{config_cnt} = 1; + $pn_arg{config} = "no_config"; + $lines_printed += &print_node(\%pn_arg); + next COMPAT; + } + + # ----- if compat previously seen, use cached info + + if (exists($compat_driver{$compat})) { + for my $driver (@{ $compat_driver{$compat} }) { + $pn_arg{driver} = $driver; + $pn_arg{driver_cnt} = $driver_count{$compat}; + $pn_arg{config_cnt} = $#{ $driver_config{$driver}} + 1; + + for my $config (@{ $driver_config{$driver} }) { + $pn_arg{config} = $config; + $lines_printed += &print_node(\%pn_arg); + } + + if (!@{ $driver_config{$driver} }) { + # no config cached yet + # $driver in %driver_hard_code_list + # but not %driver_config_hard_code_list + $lines_printed += &find_kconfig(\%pn_arg, $driver); + } + } + next COMPAT; + } + + + # ----- Find drivers (source files that contain compatible) + + # this will miss arch/sparc/include/asm/parport.h + # It is better to move the compatible out of the .h + # than to add *.h. to the files list, because *.h generates + # a lot of false negatives. + my $files = '"*.c"'; + my $drivers = `git grep -l '"$compat"' -- $files`; + chomp($drivers); + if ($drivers eq "") { + $pn_arg{driver} = "no_driver"; + $pn_arg{config_cnt} = 1; + $pn_arg{config} = "no_config"; + push @{ $compat_driver{$compat} }, "no_driver"; + $lines_printed += &print_node(\%pn_arg); + next COMPAT; + } + + my @drivers = split("\n", $drivers); + $driver_count{$compat} = $#drivers + 1; + $pn_arg{driver_cnt} = $#drivers + 1; + + DRIVER: + for my $driver (@drivers) { + push @{ $compat_driver{$compat} }, $driver; + $pn_arg{driver} = $driver; + + # ----- if driver previously seen, use cached info + + $pn_arg{config_cnt} = $#{ $driver_config{$driver} } + 1; + for my $config (@{ $driver_config{$driver} }) { + $pn_arg{config} = $config; + $lines_printed += &print_node(\%pn_arg); + } + if (@{ $driver_config{$driver} }) { + next DRIVER; + } + + if ($black_list_driver) { + for $black (@black_list_driver) { + next DRIVER if ($driver =~ /^$black$/); + } + } + + + # ----- Find Kconfig symbols that enable driver + + $lines_printed += &find_kconfig(\%pn_arg, $driver); + + } + } + + # White space (line) between nodes for readability. + # Each node may report several compatibles. + # For each compatible, multiple drivers may be reported. + # For each driver, multiple CONFIG_ options may be reported. + if ($lines_printed) { + print "\n"; + } +} + +sub read_dts() +{ + my $file = shift; + + my $compatible = ""; + my $line; + my $node = ""; + my $node_enabled = ""; + + if (! -r $file) { + print STDERR "file '$file' is not readable or does not exist\n"; + exit 3; + } + + if (!open(DT_FILE, "-|", "$dtx_diff $file")) { + print STDERR "\n"; + print STDERR "shell command failed:\n"; + print STDERR " $dtx_diff $file\n"; + print STDERR "\n"; + exit 3; + } + + FILE: + while ($line = ) { + chomp($line); + + if ($line =~ /{/) { + + &handle_compatible($full_node, $node, $compatible, + $node_enabled); + + while ($end_node_count-- > 0) { + pop @full_node; + }; + $end_node_count = 0; + $full_node = @full_node[-1]; + + $node = $line; + $node =~ s/^\s*(.*)\s+\{.*/$1/; + $node =~ s/.*: //; + if ($node eq '/' ) { + $full_node = '/'; + } elsif ($full_node ne '/') { + $full_node = $full_node . '/' . $node; + } else { + $full_node = '/' . $node; + } + push @full_node, $full_node; + + $compatible = ""; + $node_enabled = ""; + next FILE; + } + + if ($line =~ /}/) { + $end_node_count++; + } + + if ($line =~ /(\s+|^)status =/) { + $node_enabled = $line; + $node_enabled =~ s/^\t*//; + $node_enabled =~ s/^status = "//; + $node_enabled =~ s/";$//; + next FILE; + } + + if ($line =~ /(\s+|^)compatible =/) { + # Extract all compatible entries for this device + # White space matching here and in handle_compatible() is + # precise, because input format is the output of dtc, + # which is invoked by dtx_diff. + $compatible = $line; + $compatible =~ s/^\t*//; + $compatible =~ s/^compatible = //; + $compatible =~ s/;$//; + } + } + + &handle_compatible($full_node, $node, $compatible, $node_enabled); + + close(DT_FILE); +} + + +sub read_config_file() +{ + if (! -r $config_file) { + print STDERR "file '$config_file' is not readable or does not exist\n"; + exit 2; + } + + if (!open(CONFIG_FILE, "<", "$config_file")) { + print STDERR "open $config_file failed\n"; + exit 2; + } + + my @line; + + LINE: + while ($line = ) { + chomp($line); + next LINE if ($line =~ /^\s*#/); + next LINE if ($line =~ /^\s*$/); + @line = split /=/, $line; + $existing_config{@line[0]} = @line[1]; + } + + close(CONFIG_FILE); +} + + +sub cmd_line_err() +{ + my $msg = shift; + + print STDERR "\n"; + print STDERR " ERROR processing command line options\n"; + print STDERR " $msg\n" if ($msg ne ""); + print STDERR "\n"; + print STDERR " For help, type '$script_name --help'\n"; + print STDERR "\n"; +} + + +# ----------------------------------------------------------------------------- +# program entry point + +Getopt::Long::Configure("no_ignore_case", "bundling"); + +if (!GetOptions( + "c=s" => \$config_file, + "config=s" => \$config_file, + "config-format" => \$config_format, + "exclude-flag=s" => \@exclude_flag, + "h" => \$help, + "help" => \$help, + "black-list-driver" => \$black_list_driver, + "white-list-config" => \$white_list_config, + "white-list-driver" => \$white_list_driver, + "include-flag=s" => \@include_flag, + "include-suspect" => \$include_suspect, + "short-name" => \$short_name, + "show-lists" => \$show_lists, + "version" => \$version, + )) { + + &cmd_line_err(); + + exit 1; +} + + +my $exit_after_messages = 0; + +if ($version) { + print STDERR "\n$script_name $VUFX\n\n"; + $exit_after_messages = 1; +} + + +if ($help) { + &usage; + $exit_after_messages = 1; +} + + +if ($show_lists) { + + print "\n"; + print "These compatibles are hard coded to have no driver.\n"; + print "\n"; + for my $compat (sort keys %compat_white_list) { + print " $compat\n"; + } + + + print "\n\n"; + print "The driver for these compatibles is hard coded (white list).\n"; + print "\n"; + my $max_compat_len = 0; + for my $compat (sort keys %driver_hard_code_list) { + if (length $compat > $max_compat_len) { + $max_compat_len = length $compat; + } + } + for my $compat (sort keys %driver_hard_code_list) { + if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) { + my $first = 1; + for my $driver (@{ $driver_hard_code_list{$compat} }) { + if ($first) { + print " $compat"; + print " " x ($max_compat_len - length $compat); + $first = 0; + } else { + print " ", " " x $max_compat_len; + } + print " $driver\n"; + } + } + } + + + print "\n\n"; + print "The configuration option for these drivers is hard coded (white list).\n"; + print "\n"; + my $max_driver_len = 0; + for my $driver (sort keys %driver_config_hard_code_list) { + if (length $driver > $max_driver_len) { + $max_driver_len = length $driver; + } + } + for my $driver (sort keys %driver_config_hard_code_list) { + if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) { + my $first = 1; + for my $config (@{ $driver_config_hard_code_list{$driver} }) { + if ($first) { + print " $driver"; + print " " x ($max_driver_len - length $driver); + $first = 0; + } else { + print " ", " " x $max_driver_len; + } + print " $config\n"; + } + } + } + + + print "\n\n"; + print "These drivers are black listed.\n"; + print "\n"; + for my $driver (@black_list_driver) { + print " $driver\n"; + } + + print "\n"; + + $exit_after_messages = 1; +} + + +if ($exit_after_messages) { + exit 0; +} + + +$exclude_flag_pattern = "["; +for my $exclude_flag (@exclude_flag) { + $exclude_flag_pattern = $exclude_flag_pattern . $exclude_flag; +} +$exclude_flag_pattern = $exclude_flag_pattern . "]"; +# clean up if empty +$exclude_flag_pattern =~ s/^\[\]$//; + + +$include_flag_pattern = "["; +for my $include_flag (@include_flag) { + $include_flag_pattern = $include_flag_pattern . $include_flag; +} +$include_flag_pattern = $include_flag_pattern . "]"; +# clean up if empty +$include_flag_pattern =~ s/^\[\]$//; + + +if ($exclude_flag_pattern) { + my $found = 0; + for $pr_flag_value (@pr_flag_value) { + if ($exclude_flag_pattern =~ m/$pr_flag_value/) { + $found = 1; + } + } + if (!$found) { + &cmd_line_err("invalid value for FLAG in --exclude-flag\n"); + exit 1 + } +} + +if ($include_flag_pattern) { + my $found = 0; + for $pr_flag_value (@pr_flag_value) { + if ($include_flag_pattern =~ m/$pr_flag_value/) { + $found = 1; + } + } + if (!$found) { + &cmd_line_err("invalid value for FLAG in --include-flag\n"); + exit 1 + } +} + +if ($include_suspect) { + $include_flag_pattern =~ s/\[//; + $include_flag_pattern =~ s/\]//; + $include_flag_pattern = "[" . $include_flag_pattern . "A-Z]"; +} + +if ($exclude_flag_pattern =~ m/$include_flag_pattern/) { + &cmd_line_err("the same flag appears in both --exclude-flag and --include-flag or --include-suspect\n"); + exit 1 +} + + +# ($#ARGV < 0) is valid for --help, --version +if ($#ARGV < 0) { + &cmd_line_err("device-tree... is required"); + exit 1 +} + + +if ($config_file) { + &read_config_file(); +} + + +# avoid pushing duplicates for this value +$driver = "hardcoded_no_driver"; +for $config ( @{ $driver_config_hard_code_list{$driver} } ) { + push @{ $driver_config{$driver} }, $config; +} + +if ($white_list_driver) { + for my $compat (keys %driver_hard_code_list) { + for my $driver (@{ $driver_hard_code_list{$compat} }) { + push @{ $compat_driver{$compat} }, $driver; + if ($driver ne "hardcoded_no_driver") { + $driver_count{$compat} = scalar @{ $compat_driver{$compat} }; + } + } + } +} + +if ($white_list_config) { + for my $driver (keys %driver_config_hard_code_list) { + if ($driver ne "hardcoded_no_driver") { + for $config ( @{ $driver_config_hard_code_list{$driver} } ) { + push @{ $driver_config{$driver} }, $config; + } + } + } +} + +if (-x "scripts/dtc/dtx_diff") { + $dtx_diff = "scripts/dtc/dtx_diff"; +} else { + + print STDERR "\n"; + print STDERR "$script_name must be run from the root directory of a Linux kernel tree\n"; + print STDERR "\n"; + exit 3; +} + +for $file (@ARGV) { + &read_dts($file); +} diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff index 959ab2646d38..ec47f95991a3 100755 --- a/scripts/dtc/dtx_diff +++ b/scripts/dtc/dtx_diff @@ -266,7 +266,7 @@ DTC="${__KBUILD_OUTPUT}/scripts/dtc/dtc" if [ ! -x ${DTC} ] ; then __DTC="dtc" - if grep -q "^CONFIG_DTC=y" ${__KBUILD_OUTPUT}/.config ; then + if grep -q "^CONFIG_DTC=y" ${__KBUILD_OUTPUT}/.config 2>/dev/null; then make_command=' make scripts' else From 90b7079af2cd25a8c1b3c03a3f840dae5f5bca2e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 4 Jan 2017 10:45:20 -0600 Subject: [PATCH 137/266] UPSTREAM: scripts/dtc: Update to upstream version 0931cea3ba20 Sync to upstream dtc commit 0931cea3ba20 ("dtc: fdtdump: check fdt if not in scanning mode"). In particular, this pulls in dtc overlay support. This adds the following commits from upstream: f88865469b65 dtc: Fix memory leak in character literal parsing 00fbb8696b66 Rename boot_info 1ef86ad2c24f dtc: Clean up /dts-v1/ and /plugin/ handling in grammar e3c769aa9c16 dtc: Don't always generate __symbols__ for plugins c96cb3c0169e tests: Don't use -@ on plugin de/recompile tests 66381538ce24 tests: Remove "suppression of fixups" tests ba765b273f0f tests: Clarify dtc overlay tests 6ea8cd944fcd tests: More thorough tests of libfdt overlay application without dtc 7d8ef6e1db97 tests: Correct fdt handling of overlays without fixups and base trees without symbols b4dc0ed8b127 tests: Fix double expansion bugs in test code 3ea879dc0c8f tests: Split overlay tests into those with do/don't exercise dtc plugin generation 47b4d66a2f11 tests: Test auto-alias generation on base tree, not overlay 72e1ad811523 tests: Make overlay/plugin tests unconditional e7b3c3b5951b tests: Add overlay tests 9637e3f772a9 tests: Add check_path test 20f29d8d41f6 dtc: Plugin and fixup support a2c92cac53f8 dtc: Document the dynamic plugin internals 8f70ac39801d checks: Pass boot_info instead of root node ea10f953878f libfdt: add missing errors to fdt_strerror() daa75e8fa594 libfdt: fix fdt_stringlist_search() e28eff5b787a libfdt: fix fdt_stringlist_count() ae97c7722840 tests: overlay: Rename the device tree blobs to be more explicit 96162d2bd9cb tests: overlay: Add test suffix to the compiled blobs 5ce8634733b7 libfdt: Add fdt_overlay_apply to the exported symbols 804a9db90ad2 fdt: strerr: Remove spurious BADOVERLAY e8c3a1a493fa tests: overlay: Move back the bad fixup tests 7a72d89d3f81 libfdt: overlay: Fix symbols and fixups nodes condition cabbaa972cdd libfdt: overlay: Report a bad overlay for mismatching local fixups deb0a5c1aeaa libfdt: Add BADPHANDLE error string 7b7a6be9ba15 libfdt: Don't use 'index' as a local variable name aea8860d831e tests: Add tests cases for the overlay code 0cdd06c5135b libfdt: Add overlay application function 39240cc865cf libfdt: Extend the reach of FDT_ERR_BADPHANDLE 4aa3a6f5e6d9 libfdt: Add new errors for the overlay code 6d1832c9e64b dtc: Remove "home page" link 45fd440a9561 Fix some typing errors in libfdt.h and livetree.c a59be4939c13 Merge tag 'v1.4.2' a34bb721caca dtc: Fix assorted problems in the testcases for the -a option 874f40588d3e Implement the -a option to pad dtb aligned ec02b34c05be dtc: Makefile improvements for release uploading 1ed45d40a137 dtc: Bump version to 1.4.2 36fd7331fb11 libfdt: simplify fdt_del_mem_rsv() d877364e4a0f libfdt: Add fdt_setprop_inplace_namelen_partial 3e9037aaad44 libfdt: Add fdt_getprop_namelen_w 84e0e1346c68 libfdt: Add max phandle retrieval function d29126c90acb libfdt: Add iterator over properties 902d0f0953d0 libfdt: Add a subnodes iterator macro c539075ba8ba fdtput.c: Fix memory leak. f79ddb83e185 fdtget.c: Fix memory leak 1074ee54b63f convert-dtsv0-lexer.l: fix memory leak e24d39a024e6 fdtdump.c: make sure size_t argument to memchr is always unsigned. 44a59713cf05 Remove unused srcpos_dump() function cb9241ae3453 DTC: Fix memory leak on flatname. 1ee0ae24ea09 Simplify check field and macro names 9d97527a8621 Remove property check functions 2e709d158e11 Remove tree check functions c4cb12e193e3 Alter grammar to allow multiple /dts-v1/ tags d71d25d76012 Use xasprintf() in srcpos 9dc404958e9c util: Add xasprintf portable asprintf variant beef80b8b55f Correct a missing space in a fdt_header cast 68d43cec1253 Correct line lengths in libfdt.h b0dbceafd49a Correct space-after-tab in libfdt.h Signed-off-by: Rob Herring (cherry picked from commit 6f05afcbb031722ec1eff77dde188ff2edf8940e) Signed-off-by: Greg Kroah-Hartman --- scripts/dtc/checks.c | 351 ++++++----- scripts/dtc/dtc-lexer.l | 21 +- scripts/dtc/dtc-lexer.lex.c_shipped | 632 ++++++++++--------- scripts/dtc/dtc-parser.tab.c_shipped | 910 ++++++++++++++------------- scripts/dtc/dtc-parser.tab.h_shipped | 54 +- scripts/dtc/dtc-parser.y | 34 +- scripts/dtc/dtc.c | 69 +- scripts/dtc/dtc.h | 39 +- scripts/dtc/flattree.c | 41 +- scripts/dtc/fstree.c | 5 +- scripts/dtc/libfdt/Makefile.libfdt | 2 +- scripts/dtc/libfdt/fdt_ro.c | 30 +- scripts/dtc/libfdt/fdt_rw.c | 6 +- scripts/dtc/libfdt/fdt_strerror.c | 6 + scripts/dtc/libfdt/fdt_wip.c | 31 +- scripts/dtc/libfdt/libfdt.h | 210 ++++++- scripts/dtc/libfdt/libfdt_env.h | 1 + scripts/dtc/livetree.c | 299 ++++++++- scripts/dtc/srcpos.c | 35 +- scripts/dtc/srcpos.h | 1 - scripts/dtc/treesource.c | 14 +- scripts/dtc/util.c | 30 + scripts/dtc/util.h | 1 + scripts/dtc/version_gen.h | 2 +- 24 files changed, 1733 insertions(+), 1091 deletions(-) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index 386f9563313f..3d18e45374c8 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -40,16 +40,11 @@ enum checkstatus { struct check; -typedef void (*tree_check_fn)(struct check *c, struct node *dt); -typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); -typedef void (*prop_check_fn)(struct check *c, struct node *dt, - struct node *node, struct property *prop); +typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node); struct check { const char *name; - tree_check_fn tree_fn; - node_check_fn node_fn; - prop_check_fn prop_fn; + check_fn fn; void *data; bool warn, error; enum checkstatus status; @@ -58,45 +53,24 @@ struct check { struct check **prereq; }; -#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \ - static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ - static struct check nm = { \ - .name = #nm, \ - .tree_fn = (tfn), \ - .node_fn = (nfn), \ - .prop_fn = (pfn), \ - .data = (d), \ - .warn = (w), \ - .error = (e), \ +#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \ + static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \ + static struct check _nm = { \ + .name = #_nm, \ + .fn = (_fn), \ + .data = (_d), \ + .warn = (_w), \ + .error = (_e), \ .status = UNCHECKED, \ - .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ - .prereq = nm##_prereqs, \ + .num_prereqs = ARRAY_SIZE(_nm##_prereqs), \ + .prereq = _nm##_prereqs, \ }; -#define WARNING(nm, tfn, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__) -#define ERROR(nm, tfn, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__) -#define CHECK(nm, tfn, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__) - -#define TREE_WARNING(nm, d, ...) \ - WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) -#define TREE_ERROR(nm, d, ...) \ - ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) -#define TREE_CHECK(nm, d, ...) \ - CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) -#define NODE_WARNING(nm, d, ...) \ - WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) -#define NODE_ERROR(nm, d, ...) \ - ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) -#define NODE_CHECK(nm, d, ...) \ - CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) -#define PROP_WARNING(nm, d, ...) \ - WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) -#define PROP_ERROR(nm, d, ...) \ - ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) -#define PROP_CHECK(nm, d, ...) \ - CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) +#define WARNING(_nm, _fn, _d, ...) \ + CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__) +#define ERROR(_nm, _fn, _d, ...) \ + CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__) +#define CHECK(_nm, _fn, _d, ...) \ + CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__) #ifdef __GNUC__ static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); @@ -123,27 +97,21 @@ static inline void check_msg(struct check *c, const char *fmt, ...) check_msg((c), __VA_ARGS__); \ } while (0) -static void check_nodes_props(struct check *c, struct node *dt, struct node *node) +static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node) { struct node *child; - struct property *prop; TRACE(c, "%s", node->fullpath); - if (c->node_fn) - c->node_fn(c, dt, node); - - if (c->prop_fn) - for_each_property(node, prop) { - TRACE(c, "%s\t'%s'", node->fullpath, prop->name); - c->prop_fn(c, dt, node, prop); - } + if (c->fn) + c->fn(c, dti, node); for_each_child(node, child) - check_nodes_props(c, dt, child); + check_nodes_props(c, dti, child); } -static bool run_check(struct check *c, struct node *dt) +static bool run_check(struct check *c, struct dt_info *dti) { + struct node *dt = dti->dt; bool error = false; int i; @@ -156,7 +124,7 @@ static bool run_check(struct check *c, struct node *dt) for (i = 0; i < c->num_prereqs; i++) { struct check *prq = c->prereq[i]; - error = error || run_check(prq, dt); + error = error || run_check(prq, dti); if (prq->status != PASSED) { c->status = PREREQ; check_msg(c, "Failed prerequisite '%s'", @@ -167,11 +135,8 @@ static bool run_check(struct check *c, struct node *dt) if (c->status != UNCHECKED) goto out; - if (c->node_fn || c->prop_fn) - check_nodes_props(c, dt, dt); + check_nodes_props(c, dti, dt); - if (c->tree_fn) - c->tree_fn(c, dt); if (c->status == UNCHECKED) c->status = PASSED; @@ -189,13 +154,14 @@ out: */ /* A check which always fails, for testing purposes only */ -static inline void check_always_fail(struct check *c, struct node *dt) +static inline void check_always_fail(struct check *c, struct dt_info *dti, + struct node *node) { FAIL(c, "always_fail check"); } -TREE_CHECK(always_fail, NULL); +CHECK(always_fail, check_always_fail, NULL); -static void check_is_string(struct check *c, struct node *root, +static void check_is_string(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -210,11 +176,11 @@ static void check_is_string(struct check *c, struct node *root, propname, node->fullpath); } #define WARNING_IF_NOT_STRING(nm, propname) \ - WARNING(nm, NULL, check_is_string, NULL, (propname)) + WARNING(nm, check_is_string, (propname)) #define ERROR_IF_NOT_STRING(nm, propname) \ - ERROR(nm, NULL, check_is_string, NULL, (propname)) + ERROR(nm, check_is_string, (propname)) -static void check_is_cell(struct check *c, struct node *root, +static void check_is_cell(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -229,15 +195,15 @@ static void check_is_cell(struct check *c, struct node *root, propname, node->fullpath); } #define WARNING_IF_NOT_CELL(nm, propname) \ - WARNING(nm, NULL, check_is_cell, NULL, (propname)) + WARNING(nm, check_is_cell, (propname)) #define ERROR_IF_NOT_CELL(nm, propname) \ - ERROR(nm, NULL, check_is_cell, NULL, (propname)) + ERROR(nm, check_is_cell, (propname)) /* * Structural check functions */ -static void check_duplicate_node_names(struct check *c, struct node *dt, +static void check_duplicate_node_names(struct check *c, struct dt_info *dti, struct node *node) { struct node *child, *child2; @@ -250,9 +216,9 @@ static void check_duplicate_node_names(struct check *c, struct node *dt, FAIL(c, "Duplicate node name %s", child->fullpath); } -NODE_ERROR(duplicate_node_names, NULL); +ERROR(duplicate_node_names, check_duplicate_node_names, NULL); -static void check_duplicate_property_names(struct check *c, struct node *dt, +static void check_duplicate_property_names(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop, *prop2; @@ -267,14 +233,14 @@ static void check_duplicate_property_names(struct check *c, struct node *dt, } } } -NODE_ERROR(duplicate_property_names, NULL); +ERROR(duplicate_property_names, check_duplicate_property_names, NULL); #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define DIGITS "0123456789" #define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" -static void check_node_name_chars(struct check *c, struct node *dt, +static void check_node_name_chars(struct check *c, struct dt_info *dti, struct node *node) { int n = strspn(node->name, c->data); @@ -283,19 +249,19 @@ static void check_node_name_chars(struct check *c, struct node *dt, FAIL(c, "Bad character '%c' in node %s", node->name[n], node->fullpath); } -NODE_ERROR(node_name_chars, PROPNODECHARS "@"); +ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); -static void check_node_name_format(struct check *c, struct node *dt, +static void check_node_name_format(struct check *c, struct dt_info *dti, struct node *node) { if (strchr(get_unitname(node), '@')) FAIL(c, "Node %s has multiple '@' characters in name", node->fullpath); } -NODE_ERROR(node_name_format, NULL, &node_name_chars); +ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); -static void check_unit_address_vs_reg(struct check *c, struct node *dt, - struct node *node) +static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, + struct node *node) { const char *unitname = get_unitname(node); struct property *prop = get_property(node, "reg"); @@ -316,18 +282,22 @@ static void check_unit_address_vs_reg(struct check *c, struct node *dt, node->fullpath); } } -NODE_WARNING(unit_address_vs_reg, NULL); +WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); -static void check_property_name_chars(struct check *c, struct node *dt, - struct node *node, struct property *prop) +static void check_property_name_chars(struct check *c, struct dt_info *dti, + struct node *node) { - int n = strspn(prop->name, c->data); + struct property *prop; - if (n < strlen(prop->name)) - FAIL(c, "Bad character '%c' in property name \"%s\", node %s", - prop->name[n], prop->name, node->fullpath); + for_each_property(node, prop) { + int n = strspn(prop->name, c->data); + + if (n < strlen(prop->name)) + FAIL(c, "Bad character '%c' in property name \"%s\", node %s", + prop->name[n], prop->name, node->fullpath); + } } -PROP_ERROR(property_name_chars, PROPNODECHARS); +ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); #define DESCLABEL_FMT "%s%s%s%s%s" #define DESCLABEL_ARGS(node,prop,mark) \ @@ -336,10 +306,11 @@ PROP_ERROR(property_name_chars, PROPNODECHARS); ((prop) ? (prop)->name : ""), \ ((prop) ? "' in " : ""), (node)->fullpath -static void check_duplicate_label(struct check *c, struct node *dt, +static void check_duplicate_label(struct check *c, struct dt_info *dti, const char *label, struct node *node, struct property *prop, struct marker *mark) { + struct node *dt = dti->dt; struct node *othernode = NULL; struct property *otherprop = NULL; struct marker *othermark = NULL; @@ -362,44 +333,43 @@ static void check_duplicate_label(struct check *c, struct node *dt, DESCLABEL_ARGS(othernode, otherprop, othermark)); } -static void check_duplicate_label_node(struct check *c, struct node *dt, +static void check_duplicate_label_node(struct check *c, struct dt_info *dti, struct node *node) { struct label *l; + struct property *prop; for_each_label(node->labels, l) - check_duplicate_label(c, dt, l->label, node, NULL, NULL); + check_duplicate_label(c, dti, l->label, node, NULL, NULL); + + for_each_property(node, prop) { + struct marker *m = prop->val.markers; + + for_each_label(prop->labels, l) + check_duplicate_label(c, dti, l->label, node, prop, NULL); + + for_each_marker_of_type(m, LABEL) + check_duplicate_label(c, dti, m->ref, node, prop, m); + } } -static void check_duplicate_label_prop(struct check *c, struct node *dt, - struct node *node, struct property *prop) -{ - struct marker *m = prop->val.markers; - struct label *l; - - for_each_label(prop->labels, l) - check_duplicate_label(c, dt, l->label, node, prop, NULL); - - for_each_marker_of_type(m, LABEL) - check_duplicate_label(c, dt, m->ref, node, prop, m); -} -ERROR(duplicate_label, NULL, check_duplicate_label_node, - check_duplicate_label_prop, NULL); - -static void check_explicit_phandles(struct check *c, struct node *root, - struct node *node, struct property *prop) +ERROR(duplicate_label, check_duplicate_label_node, NULL); + +static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, + struct node *node, const char *propname) { + struct node *root = dti->dt; + struct property *prop; struct marker *m; - struct node *other; cell_t phandle; - if (!streq(prop->name, "phandle") - && !streq(prop->name, "linux,phandle")) - return; + prop = get_property(node, propname); + if (!prop) + return 0; if (prop->val.len != sizeof(cell_t)) { FAIL(c, "%s has bad length (%d) %s property", node->fullpath, prop->val.len, prop->name); - return; + return 0; } m = prop->val.markers; @@ -411,14 +381,13 @@ static void check_explicit_phandles(struct check *c, struct node *root, * by construction. */ { FAIL(c, "%s in %s is a reference to another node", prop->name, node->fullpath); - return; } /* But setting this node's phandle equal to its own * phandle is allowed - that means allocate a unique * phandle for this node, even if it's not otherwise * referenced. The value will be filled in later, so - * no further checking for now. */ - return; + * we treat it as having no phandle data for now. */ + return 0; } phandle = propval_cell(prop); @@ -426,12 +395,36 @@ static void check_explicit_phandles(struct check *c, struct node *root, if ((phandle == 0) || (phandle == -1)) { FAIL(c, "%s has bad value (0x%x) in %s property", node->fullpath, phandle, prop->name); - return; + return 0; } - if (node->phandle && (node->phandle != phandle)) - FAIL(c, "%s has %s property which replaces existing phandle information", - node->fullpath, prop->name); + return phandle; +} + +static void check_explicit_phandles(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct node *root = dti->dt; + struct node *other; + cell_t phandle, linux_phandle; + + /* Nothing should have assigned phandles yet */ + assert(!node->phandle); + + phandle = check_phandle_prop(c, dti, node, "phandle"); + + linux_phandle = check_phandle_prop(c, dti, node, "linux,phandle"); + + if (!phandle && !linux_phandle) + /* No valid phandles; nothing further to check */ + return; + + if (linux_phandle && phandle && (phandle != linux_phandle)) + FAIL(c, "%s has mismatching 'phandle' and 'linux,phandle'" + " properties", node->fullpath); + + if (linux_phandle && !phandle) + phandle = linux_phandle; other = get_node_by_phandle(root, phandle); if (other && (other != node)) { @@ -442,9 +435,9 @@ static void check_explicit_phandles(struct check *c, struct node *root, node->phandle = phandle; } -PROP_ERROR(explicit_phandles, NULL); +ERROR(explicit_phandles, check_explicit_phandles, NULL); -static void check_name_properties(struct check *c, struct node *root, +static void check_name_properties(struct check *c, struct dt_info *dti, struct node *node) { struct property **pp, *prop = NULL; @@ -472,60 +465,73 @@ static void check_name_properties(struct check *c, struct node *root, } } ERROR_IF_NOT_STRING(name_is_string, "name"); -NODE_ERROR(name_properties, NULL, &name_is_string); +ERROR(name_properties, check_name_properties, NULL, &name_is_string); /* * Reference fixup functions */ -static void fixup_phandle_references(struct check *c, struct node *dt, - struct node *node, struct property *prop) +static void fixup_phandle_references(struct check *c, struct dt_info *dti, + struct node *node) { - struct marker *m = prop->val.markers; - struct node *refnode; - cell_t phandle; + struct node *dt = dti->dt; + struct property *prop; - for_each_marker_of_type(m, REF_PHANDLE) { - assert(m->offset + sizeof(cell_t) <= prop->val.len); + for_each_property(node, prop) { + struct marker *m = prop->val.markers; + struct node *refnode; + cell_t phandle; - refnode = get_node_by_ref(dt, m->ref); - if (! refnode) { - FAIL(c, "Reference to non-existent node or label \"%s\"\n", - m->ref); - continue; + for_each_marker_of_type(m, REF_PHANDLE) { + assert(m->offset + sizeof(cell_t) <= prop->val.len); + + refnode = get_node_by_ref(dt, m->ref); + if (! refnode) { + if (!(dti->dtsflags & DTSF_PLUGIN)) + FAIL(c, "Reference to non-existent node or " + "label \"%s\"\n", m->ref); + else /* mark the entry as unresolved */ + *((cell_t *)(prop->val.val + m->offset)) = + cpu_to_fdt32(0xffffffff); + continue; + } + + phandle = get_node_phandle(dt, refnode); + *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } - - phandle = get_node_phandle(dt, refnode); - *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } } -ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, +ERROR(phandle_references, fixup_phandle_references, NULL, &duplicate_node_names, &explicit_phandles); -static void fixup_path_references(struct check *c, struct node *dt, - struct node *node, struct property *prop) +static void fixup_path_references(struct check *c, struct dt_info *dti, + struct node *node) { - struct marker *m = prop->val.markers; - struct node *refnode; - char *path; + struct node *dt = dti->dt; + struct property *prop; - for_each_marker_of_type(m, REF_PATH) { - assert(m->offset <= prop->val.len); + for_each_property(node, prop) { + struct marker *m = prop->val.markers; + struct node *refnode; + char *path; - refnode = get_node_by_ref(dt, m->ref); - if (!refnode) { - FAIL(c, "Reference to non-existent node or label \"%s\"\n", - m->ref); - continue; + for_each_marker_of_type(m, REF_PATH) { + assert(m->offset <= prop->val.len); + + refnode = get_node_by_ref(dt, m->ref); + if (!refnode) { + FAIL(c, "Reference to non-existent node or label \"%s\"\n", + m->ref); + continue; + } + + path = refnode->fullpath; + prop->val = data_insert_at_marker(prop->val, m, path, + strlen(path) + 1); } - - path = refnode->fullpath; - prop->val = data_insert_at_marker(prop->val, m, path, - strlen(path) + 1); } } -ERROR(path_references, NULL, NULL, fixup_path_references, NULL, - &duplicate_node_names); +ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names); /* * Semantic checks @@ -538,7 +544,7 @@ WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); WARNING_IF_NOT_STRING(model_is_string, "model"); WARNING_IF_NOT_STRING(status_is_string, "status"); -static void fixup_addr_size_cells(struct check *c, struct node *dt, +static void fixup_addr_size_cells(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -554,7 +560,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt, if (prop) node->size_cells = propval_cell(prop); } -WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, +WARNING(addr_size_cells, fixup_addr_size_cells, NULL, &address_cells_is_cell, &size_cells_is_cell); #define node_addr_cells(n) \ @@ -562,7 +568,7 @@ WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, #define node_size_cells(n) \ (((n)->size_cells == -1) ? 1 : (n)->size_cells) -static void check_reg_format(struct check *c, struct node *dt, +static void check_reg_format(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -589,9 +595,9 @@ static void check_reg_format(struct check *c, struct node *dt, "(#address-cells == %d, #size-cells == %d)", node->fullpath, prop->val.len, addr_cells, size_cells); } -NODE_WARNING(reg_format, NULL, &addr_size_cells); +WARNING(reg_format, check_reg_format, NULL, &addr_size_cells); -static void check_ranges_format(struct check *c, struct node *dt, +static void check_ranges_format(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -630,12 +636,12 @@ static void check_ranges_format(struct check *c, struct node *dt, p_addr_cells, c_addr_cells, c_size_cells); } } -NODE_WARNING(ranges_format, NULL, &addr_size_cells); +WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); /* * Style checks */ -static void check_avoid_default_addr_size(struct check *c, struct node *dt, +static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti, struct node *node) { struct property *reg, *ranges; @@ -657,14 +663,21 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt, FAIL(c, "Relying on default #size-cells value for %s", node->fullpath); } -NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); +WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, + &addr_size_cells); static void check_obsolete_chosen_interrupt_controller(struct check *c, - struct node *dt) + struct dt_info *dti, + struct node *node) { + struct node *dt = dti->dt; struct node *chosen; struct property *prop; + if (node != dt) + return; + + chosen = get_node_by_path(dt, "/chosen"); if (!chosen) return; @@ -674,7 +687,8 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, FAIL(c, "/chosen has obsolete \"interrupt-controller\" " "property"); } -TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); +WARNING(obsolete_chosen_interrupt_controller, + check_obsolete_chosen_interrupt_controller, NULL); static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, @@ -760,9 +774,8 @@ void parse_checks_option(bool warn, bool error, const char *arg) die("Unrecognized check name \"%s\"\n", name); } -void process_checks(bool force, struct boot_info *bi) +void process_checks(bool force, struct dt_info *dti) { - struct node *dt = bi->dt; int i; int error = 0; @@ -770,7 +783,7 @@ void process_checks(bool force, struct boot_info *bi) struct check *c = check_table[i]; if (c->warn || c->error) - error = error || run_check(c, dt); + error = error || run_check(c, dti); } if (error) { diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index 790fbf6cf2d7..c600603044f3 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...); return DT_V1; } +<*>"/plugin/" { + DPRINT("Keyword: /plugin/\n"); + return DT_PLUGIN; + } + <*>"/memreserve/" { DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); @@ -184,16 +189,16 @@ static void lexical_error(const char *fmt, ...); if (d.len == 1) { lexical_error("Empty character literal"); yylval.integer = 0; - return DT_CHAR_LITERAL; + } else { + yylval.integer = (unsigned char)d.val[0]; + + if (d.len > 2) + lexical_error("Character literal has %d" + " characters instead of 1", + d.len - 1); } - yylval.integer = (unsigned char)d.val[0]; - - if (d.len > 2) - lexical_error("Character literal has %d" - " characters instead of 1", - d.len - 1); - + data_free(d); return DT_CHAR_LITERAL; } diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index ba525c2f9fc2..2c862bc86ad0 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -8,8 +8,8 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 39 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 1 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -88,25 +88,13 @@ typedef unsigned int flex_uint32_t; #endif /* ! FLEXINT_H */ -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST +/* TODO: this is always defined, so inline it */ #define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) #else -#define yyconst +#define yynoreturn #endif /* Returned upon end-of-file. */ @@ -167,7 +155,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE; typedef size_t yy_size_t; #endif -extern yy_size_t yyleng; +extern int yyleng; extern FILE *yyin, *yyout; @@ -206,12 +194,12 @@ struct yy_buffer_state /* Size of input buffer in bytes, not including room for EOB * characters. */ - yy_size_t yy_buf_size; + int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - yy_size_t yy_n_chars; + int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -234,7 +222,7 @@ struct yy_buffer_state int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ - + /* Whether to try to fill the input buffer when we reach the * end of it. */ @@ -262,7 +250,7 @@ struct yy_buffer_state /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ -static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general @@ -281,11 +269,11 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; -static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ -yy_size_t yyleng; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; /* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; +static char *yy_c_buf_p = NULL; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ @@ -310,7 +298,7 @@ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); -YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); @@ -342,12 +330,12 @@ void yyfree (void * ); /* Begin user sect3 */ -#define yywrap() 1 +#define yywrap() (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +FILE *yyin = NULL, *yyout = NULL; typedef int yy_state_type; @@ -356,25 +344,28 @@ extern int yylineno; int yylineno = 1; extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); -static void yy_fatal_error (yyconst char msg[] ); +static void yynoreturn yy_fatal_error (yyconst char* msg ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ - yyleng = (size_t) (yy_cp - yy_bp); \ + yyleng = (int) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 30 -#define YY_END_OF_BUFFER 31 +#define YY_NUM_RULES 31 +#define YY_END_OF_BUFFER 32 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -382,28 +373,29 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[159] = +static yyconst flex_int16_t yy_accept[166] = { 0, - 0, 0, 0, 0, 0, 0, 0, 0, 31, 29, - 18, 18, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 15, 16, 16, 29, - 16, 10, 10, 18, 26, 0, 3, 0, 27, 12, - 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, - 21, 23, 25, 24, 22, 0, 9, 28, 0, 0, - 0, 14, 14, 16, 16, 16, 10, 10, 10, 0, - 12, 0, 11, 0, 0, 0, 20, 0, 0, 0, - 0, 0, 0, 0, 0, 16, 10, 10, 10, 0, - 13, 19, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 32, 30, + 19, 19, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 16, 17, 17, 30, + 17, 11, 11, 19, 27, 0, 3, 0, 28, 13, + 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 22, 24, 26, 25, 23, 0, 10, 29, 0, + 0, 0, 15, 15, 17, 17, 17, 11, 11, 11, + 0, 13, 0, 12, 0, 0, 0, 21, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 11, 11, + 11, 0, 14, 20, 0, 0, 0, 0, 0, 0, - 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 16, 6, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 4, 17, - 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 5, 8, 0, 0, 0, 0, 7, 0 + 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 7, 0, 0, 0, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 18, 0, 0, 5, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 6, 9, 0, + 0, 0, 0, 8, 0 } ; -static yyconst flex_int32_t yy_ec[256] = +static yyconst YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, @@ -416,9 +408,9 @@ static yyconst flex_int32_t yy_ec[256] = 22, 22, 22, 22, 24, 22, 22, 25, 22, 22, 1, 26, 27, 1, 22, 1, 21, 28, 29, 30, - 31, 21, 22, 22, 32, 22, 22, 33, 34, 35, - 36, 37, 22, 38, 39, 40, 41, 42, 22, 25, - 43, 22, 44, 45, 46, 1, 1, 1, 1, 1, + 31, 21, 32, 22, 33, 22, 22, 34, 35, 36, + 37, 38, 22, 39, 40, 41, 42, 43, 22, 25, + 44, 22, 45, 46, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -435,163 +427,165 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[47] = +static yyconst YY_CHAR yy_meta[48] = { 0, 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, 2, 2, 4, 5, 5, 5, 6, 1, 1, 1, 7, 8, 8, 8, 8, 1, 1, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 3, 1, 4 + 8, 8, 8, 8, 3, 1, 4 } ; -static yyconst flex_int16_t yy_base[173] = +static yyconst flex_uint16_t yy_base[180] = { 0, - 0, 383, 34, 382, 65, 381, 37, 105, 387, 391, - 54, 111, 367, 110, 109, 109, 112, 41, 366, 104, - 367, 338, 124, 117, 0, 144, 391, 0, 121, 0, - 135, 155, 140, 179, 391, 160, 391, 379, 391, 0, - 368, 141, 391, 167, 370, 376, 346, 103, 342, 345, - 391, 391, 391, 391, 391, 358, 391, 391, 175, 342, - 338, 391, 355, 0, 185, 339, 184, 347, 346, 0, - 0, 322, 175, 357, 175, 363, 352, 324, 330, 323, - 332, 326, 201, 324, 329, 322, 391, 333, 181, 309, - 391, 341, 340, 313, 320, 338, 178, 311, 146, 317, + 0, 393, 35, 392, 66, 391, 38, 107, 397, 401, + 55, 113, 377, 112, 111, 111, 114, 42, 376, 106, + 377, 347, 126, 120, 0, 147, 401, 0, 124, 0, + 137, 158, 170, 163, 401, 153, 401, 389, 401, 0, + 378, 120, 401, 131, 380, 386, 355, 139, 351, 355, + 351, 401, 401, 401, 401, 401, 367, 401, 401, 185, + 350, 346, 401, 364, 0, 185, 347, 189, 356, 355, + 0, 0, 330, 180, 366, 141, 372, 361, 332, 338, + 331, 341, 334, 326, 205, 331, 337, 329, 401, 341, + 167, 316, 401, 349, 348, 320, 328, 346, 180, 318, - 314, 315, 335, 331, 303, 300, 309, 299, 308, 188, - 336, 335, 391, 305, 320, 281, 283, 271, 203, 288, - 281, 271, 266, 264, 245, 242, 208, 104, 391, 391, - 244, 218, 204, 219, 206, 224, 201, 212, 204, 229, - 215, 208, 207, 200, 219, 391, 233, 221, 200, 181, - 391, 391, 149, 122, 86, 41, 391, 391, 245, 251, - 259, 263, 267, 273, 280, 284, 292, 300, 304, 310, - 318, 326 + 324, 209, 324, 320, 322, 342, 338, 309, 306, 315, + 305, 315, 312, 192, 342, 341, 401, 293, 306, 282, + 268, 252, 255, 203, 285, 282, 272, 268, 252, 233, + 232, 239, 208, 107, 401, 401, 238, 211, 401, 211, + 212, 208, 228, 203, 215, 207, 233, 222, 212, 211, + 203, 227, 401, 237, 225, 204, 185, 401, 401, 149, + 128, 88, 42, 401, 401, 253, 259, 267, 271, 275, + 281, 288, 292, 300, 308, 312, 318, 326, 334 } ; -static yyconst flex_int16_t yy_def[173] = +static yyconst flex_int16_t yy_def[180] = { 0, - 158, 1, 1, 3, 158, 5, 1, 1, 158, 158, - 158, 158, 158, 159, 160, 161, 158, 158, 158, 158, - 162, 158, 158, 158, 163, 162, 158, 164, 165, 164, - 164, 158, 158, 158, 158, 159, 158, 159, 158, 166, - 158, 161, 158, 161, 167, 168, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 162, 158, 158, 158, 158, - 158, 158, 162, 164, 165, 164, 158, 158, 158, 169, - 166, 170, 161, 167, 167, 168, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 164, 158, 158, 169, 170, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, + 165, 1, 1, 3, 165, 5, 1, 1, 165, 165, + 165, 165, 165, 166, 167, 168, 165, 165, 165, 165, + 169, 165, 165, 165, 170, 169, 165, 171, 172, 171, + 171, 165, 165, 165, 165, 166, 165, 166, 165, 173, + 165, 168, 165, 168, 174, 175, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 169, 165, 165, 165, + 165, 165, 165, 169, 171, 172, 171, 165, 165, 165, + 176, 173, 177, 168, 174, 174, 175, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 171, 165, 165, + 176, 177, 165, 165, 165, 165, 165, 165, 165, 165, - 158, 164, 158, 158, 158, 158, 158, 158, 158, 171, - 158, 164, 158, 158, 158, 158, 158, 158, 171, 158, - 171, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 172, 158, 158, 158, 172, 158, 172, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 0, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158 + 165, 165, 165, 165, 171, 165, 165, 165, 165, 165, + 165, 165, 165, 178, 165, 171, 165, 165, 165, 165, + 165, 165, 165, 178, 165, 178, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 179, 165, 165, + 165, 179, 165, 179, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 0, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165 } ; -static yyconst flex_int16_t yy_nxt[438] = +static yyconst flex_uint16_t yy_nxt[449] = { 0, 10, 11, 12, 11, 13, 14, 10, 15, 16, 10, 10, 10, 17, 10, 10, 10, 10, 18, 19, 20, 21, 21, 21, 21, 21, 10, 10, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 10, 22, 10, 24, 25, 25, 25, - 32, 33, 33, 157, 26, 34, 34, 34, 51, 52, - 27, 26, 26, 26, 26, 10, 11, 12, 11, 13, - 14, 28, 15, 16, 28, 28, 28, 24, 28, 28, - 28, 10, 18, 19, 20, 29, 29, 29, 29, 29, - 30, 10, 29, 29, 29, 29, 29, 29, 29, 29, + 21, 21, 21, 21, 10, 22, 10, 24, 25, 25, + 25, 32, 33, 33, 164, 26, 34, 34, 34, 52, + 53, 27, 26, 26, 26, 26, 10, 11, 12, 11, + 13, 14, 28, 15, 16, 28, 28, 28, 24, 28, + 28, 28, 10, 18, 19, 20, 29, 29, 29, 29, + 29, 30, 10, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 10, 22, - 10, 23, 34, 34, 34, 37, 39, 43, 32, 33, - 33, 45, 54, 55, 46, 59, 45, 64, 156, 46, - 64, 64, 64, 79, 44, 38, 59, 57, 134, 47, - 135, 48, 80, 49, 47, 50, 48, 99, 61, 43, - 50, 110, 41, 67, 67, 67, 60, 63, 63, 63, - 57, 155, 68, 69, 63, 37, 44, 66, 67, 67, - 67, 63, 63, 63, 63, 73, 59, 68, 69, 70, - 34, 34, 34, 43, 75, 38, 154, 92, 83, 83, - 83, 64, 44, 120, 64, 64, 64, 67, 67, 67, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 10, 22, 10, 23, 34, 34, 34, 37, 39, 43, + 32, 33, 33, 45, 55, 56, 46, 60, 43, 45, + 65, 163, 46, 65, 65, 65, 44, 38, 60, 74, + 58, 47, 141, 48, 142, 44, 49, 47, 50, 48, + 76, 51, 62, 94, 50, 41, 44, 51, 37, 61, + 64, 64, 64, 58, 34, 34, 34, 64, 162, 80, + 67, 68, 68, 68, 64, 64, 64, 64, 38, 81, + 69, 70, 71, 68, 68, 68, 60, 161, 43, 69, + 70, 65, 69, 70, 65, 65, 65, 125, 85, 85, - 44, 57, 99, 68, 69, 107, 68, 69, 120, 127, - 108, 153, 152, 121, 83, 83, 83, 133, 133, 133, - 146, 133, 133, 133, 146, 140, 140, 140, 121, 141, - 140, 140, 140, 151, 141, 158, 150, 149, 148, 144, - 147, 143, 142, 139, 147, 36, 36, 36, 36, 36, - 36, 36, 36, 40, 138, 137, 136, 40, 40, 42, - 42, 42, 42, 42, 42, 42, 42, 56, 56, 56, - 56, 62, 132, 62, 64, 131, 130, 64, 129, 64, - 64, 65, 128, 158, 65, 65, 65, 65, 71, 127, - 71, 71, 74, 74, 74, 74, 74, 74, 74, 74, + 85, 58, 68, 68, 68, 44, 102, 110, 125, 133, + 102, 69, 70, 111, 114, 160, 159, 126, 85, 85, + 85, 140, 140, 140, 140, 140, 140, 153, 126, 147, + 147, 147, 153, 148, 147, 147, 147, 158, 148, 165, + 157, 156, 155, 151, 150, 149, 146, 154, 145, 144, + 143, 139, 154, 36, 36, 36, 36, 36, 36, 36, + 36, 40, 138, 137, 136, 40, 40, 42, 42, 42, + 42, 42, 42, 42, 42, 57, 57, 57, 57, 63, + 135, 63, 65, 134, 165, 65, 133, 65, 65, 66, + 132, 131, 66, 66, 66, 66, 72, 130, 72, 72, - 76, 76, 76, 76, 76, 76, 76, 76, 89, 126, - 89, 90, 125, 90, 90, 124, 90, 90, 119, 119, - 119, 119, 119, 119, 119, 119, 145, 145, 145, 145, - 145, 145, 145, 145, 123, 122, 59, 59, 118, 117, - 116, 115, 114, 113, 45, 112, 108, 111, 109, 106, - 105, 104, 46, 103, 91, 87, 102, 101, 100, 98, - 97, 96, 95, 94, 93, 77, 75, 91, 88, 87, - 86, 57, 85, 84, 57, 82, 81, 78, 77, 75, - 72, 158, 58, 57, 53, 35, 158, 31, 23, 23, - 9, 158, 158, 158, 158, 158, 158, 158, 158, 158, + 75, 75, 75, 75, 75, 75, 75, 75, 77, 77, + 77, 77, 77, 77, 77, 77, 91, 129, 91, 92, + 128, 92, 92, 127, 92, 92, 124, 124, 124, 124, + 124, 124, 124, 124, 152, 152, 152, 152, 152, 152, + 152, 152, 60, 60, 123, 122, 121, 120, 119, 118, + 117, 45, 116, 111, 115, 113, 112, 109, 108, 107, + 46, 106, 93, 89, 105, 104, 103, 101, 100, 99, + 98, 97, 96, 95, 78, 76, 93, 90, 89, 88, + 58, 87, 86, 58, 84, 83, 82, 79, 78, 76, + 73, 165, 59, 58, 54, 35, 165, 31, 23, 23, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158 + 9, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165 } ; -static yyconst flex_int16_t yy_chk[438] = +static yyconst flex_int16_t yy_chk[449] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, - 7, 7, 7, 156, 3, 11, 11, 11, 18, 18, - 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, + 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, + 3, 7, 7, 7, 163, 3, 11, 11, 11, 18, + 18, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 8, 12, 12, 12, 14, 15, 16, 8, 8, - 8, 17, 20, 20, 17, 23, 24, 29, 155, 24, - 29, 29, 29, 48, 16, 14, 31, 29, 128, 17, - 128, 17, 48, 17, 24, 17, 24, 99, 24, 42, - 24, 99, 15, 33, 33, 33, 23, 26, 26, 26, - 26, 154, 33, 33, 26, 36, 42, 31, 32, 32, - 32, 26, 26, 26, 26, 44, 59, 32, 32, 32, - 34, 34, 34, 73, 75, 36, 153, 75, 59, 59, - 59, 65, 44, 110, 65, 65, 65, 67, 67, 67, + 5, 5, 5, 8, 12, 12, 12, 14, 15, 16, + 8, 8, 8, 17, 20, 20, 17, 23, 42, 24, + 29, 162, 24, 29, 29, 29, 16, 14, 31, 44, + 29, 17, 134, 17, 134, 42, 17, 24, 17, 24, + 76, 17, 24, 76, 24, 15, 44, 24, 36, 23, + 26, 26, 26, 26, 34, 34, 34, 26, 161, 48, + 31, 32, 32, 32, 26, 26, 26, 26, 36, 48, + 32, 32, 32, 33, 33, 33, 60, 160, 74, 91, + 91, 66, 33, 33, 66, 66, 66, 114, 60, 60, - 73, 65, 83, 89, 89, 97, 67, 67, 119, 127, - 97, 150, 149, 110, 83, 83, 83, 133, 133, 133, - 141, 127, 127, 127, 145, 136, 136, 136, 119, 136, - 140, 140, 140, 148, 140, 147, 144, 143, 142, 139, - 141, 138, 137, 135, 145, 159, 159, 159, 159, 159, - 159, 159, 159, 160, 134, 132, 131, 160, 160, 161, - 161, 161, 161, 161, 161, 161, 161, 162, 162, 162, - 162, 163, 126, 163, 164, 125, 124, 164, 123, 164, - 164, 165, 122, 121, 165, 165, 165, 165, 166, 120, - 166, 166, 167, 167, 167, 167, 167, 167, 167, 167, + 60, 66, 68, 68, 68, 74, 85, 99, 124, 133, + 102, 68, 68, 99, 102, 157, 156, 114, 85, 85, + 85, 133, 133, 133, 140, 140, 140, 148, 124, 143, + 143, 143, 152, 143, 147, 147, 147, 155, 147, 154, + 151, 150, 149, 146, 145, 144, 142, 148, 141, 138, + 137, 132, 152, 166, 166, 166, 166, 166, 166, 166, + 166, 167, 131, 130, 129, 167, 167, 168, 168, 168, + 168, 168, 168, 168, 168, 169, 169, 169, 169, 170, + 128, 170, 171, 127, 126, 171, 125, 171, 171, 172, + 123, 122, 172, 172, 172, 172, 173, 121, 173, 173, - 168, 168, 168, 168, 168, 168, 168, 168, 169, 118, - 169, 170, 117, 170, 170, 116, 170, 170, 171, 171, - 171, 171, 171, 171, 171, 171, 172, 172, 172, 172, - 172, 172, 172, 172, 115, 114, 112, 111, 109, 108, - 107, 106, 105, 104, 103, 102, 101, 100, 98, 96, - 95, 94, 93, 92, 90, 88, 86, 85, 84, 82, - 81, 80, 79, 78, 77, 76, 74, 72, 69, 68, - 66, 63, 61, 60, 56, 50, 49, 47, 46, 45, + 174, 174, 174, 174, 174, 174, 174, 174, 175, 175, + 175, 175, 175, 175, 175, 175, 176, 120, 176, 177, + 119, 177, 177, 118, 177, 177, 178, 178, 178, 178, + 178, 178, 178, 178, 179, 179, 179, 179, 179, 179, + 179, 179, 116, 115, 113, 112, 111, 110, 109, 108, + 107, 106, 105, 104, 103, 101, 100, 98, 97, 96, + 95, 94, 92, 90, 88, 87, 86, 84, 83, 82, + 81, 80, 79, 78, 77, 75, 73, 70, 69, 67, + 64, 62, 61, 57, 51, 50, 49, 47, 46, 45, 41, 38, 22, 21, 19, 13, 9, 6, 4, 2, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158 + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165 } ; static yy_state_type yy_last_accepting_state; @@ -662,7 +656,7 @@ static int dts_version = 1; static void push_input_file(const char *filename); static bool pop_input_file(void); static void lexical_error(const char *fmt, ...); -#line 666 "dtc-lexer.lex.c" +#line 660 "dtc-lexer.lex.c" #define INITIAL 0 #define BYTESTRING 1 @@ -698,19 +692,19 @@ void yyset_extra (YY_EXTRA_TYPE user_defined ); FILE *yyget_in (void ); -void yyset_in (FILE * in_str ); +void yyset_in (FILE * _in_str ); FILE *yyget_out (void ); -void yyset_out (FILE * out_str ); +void yyset_out (FILE * _out_str ); -yy_size_t yyget_leng (void ); + int yyget_leng (void ); char *yyget_text (void ); int yyget_lineno (void ); -void yyset_lineno (int line_number ); +void yyset_lineno (int _line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. @@ -724,6 +718,10 @@ extern int yywrap (void ); #endif #endif +#ifndef YY_NO_UNPUT + +#endif + #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif @@ -757,7 +755,7 @@ static int input (void ); /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -781,7 +779,7 @@ static int input (void ); else \ { \ errno=0; \ - while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + while ( (result = (int) fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ @@ -836,7 +834,7 @@ extern int yylex (void); /* Code executed at the end of each rule. */ #ifndef YY_BREAK -#define YY_BREAK break; +#define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ @@ -849,9 +847,9 @@ extern int yylex (void); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; if ( !(yy_init) ) { @@ -882,9 +880,9 @@ YY_DECL { #line 68 "dtc-lexer.l" -#line 886 "dtc-lexer.lex.c" +#line 884 "dtc-lexer.lex.c" - while ( 1 ) /* loops until end-of-file is reached */ + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); @@ -901,7 +899,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -910,13 +908,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 159 ) + if ( yy_current_state >= 166 ) yy_c = yy_meta[(unsigned int) yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; ++yy_cp; } - while ( yy_current_state != 158 ); + while ( yy_current_state != 165 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); @@ -1014,24 +1012,32 @@ YY_RULE_SETUP case 5: YY_RULE_SETUP #line 124 "dtc-lexer.l" +{ + DPRINT("Keyword: /plugin/\n"); + return DT_PLUGIN; + } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 129 "dtc-lexer.l" { DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); return DT_MEMRESERVE; } YY_BREAK -case 6: +case 7: YY_RULE_SETUP -#line 130 "dtc-lexer.l" +#line 135 "dtc-lexer.l" { DPRINT("Keyword: /bits/\n"); BEGIN_DEFAULT(); return DT_BITS; } YY_BREAK -case 7: +case 8: YY_RULE_SETUP -#line 136 "dtc-lexer.l" +#line 141 "dtc-lexer.l" { DPRINT("Keyword: /delete-property/\n"); DPRINT("\n"); @@ -1039,9 +1045,9 @@ YY_RULE_SETUP return DT_DEL_PROP; } YY_BREAK -case 8: +case 9: YY_RULE_SETUP -#line 143 "dtc-lexer.l" +#line 148 "dtc-lexer.l" { DPRINT("Keyword: /delete-node/\n"); DPRINT("\n"); @@ -1049,9 +1055,9 @@ YY_RULE_SETUP return DT_DEL_NODE; } YY_BREAK -case 9: +case 10: YY_RULE_SETUP -#line 150 "dtc-lexer.l" +#line 155 "dtc-lexer.l" { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); @@ -1059,9 +1065,9 @@ YY_RULE_SETUP return DT_LABEL; } YY_BREAK -case 10: +case 11: YY_RULE_SETUP -#line 157 "dtc-lexer.l" +#line 162 "dtc-lexer.l" { char *e; DPRINT("Integer Literal: '%s'\n", yytext); @@ -1084,10 +1090,10 @@ YY_RULE_SETUP return DT_LITERAL; } YY_BREAK -case 11: -/* rule 11 can match eol */ +case 12: +/* rule 12 can match eol */ YY_RULE_SETUP -#line 179 "dtc-lexer.l" +#line 184 "dtc-lexer.l" { struct data d; DPRINT("Character literal: %s\n", yytext); @@ -1096,31 +1102,31 @@ YY_RULE_SETUP if (d.len == 1) { lexical_error("Empty character literal"); yylval.integer = 0; - return DT_CHAR_LITERAL; + } else { + yylval.integer = (unsigned char)d.val[0]; + + if (d.len > 2) + lexical_error("Character literal has %d" + " characters instead of 1", + d.len - 1); } - yylval.integer = (unsigned char)d.val[0]; - - if (d.len > 2) - lexical_error("Character literal has %d" - " characters instead of 1", - d.len - 1); - + data_free(d); return DT_CHAR_LITERAL; } YY_BREAK -case 12: +case 13: YY_RULE_SETUP -#line 200 "dtc-lexer.l" +#line 205 "dtc-lexer.l" { /* label reference */ DPRINT("Ref: %s\n", yytext+1); yylval.labelref = xstrdup(yytext+1); return DT_REF; } YY_BREAK -case 13: +case 14: YY_RULE_SETUP -#line 206 "dtc-lexer.l" +#line 211 "dtc-lexer.l" { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); @@ -1128,27 +1134,27 @@ YY_RULE_SETUP return DT_REF; } YY_BREAK -case 14: +case 15: YY_RULE_SETUP -#line 213 "dtc-lexer.l" +#line 218 "dtc-lexer.l" { yylval.byte = strtol(yytext, NULL, 16); DPRINT("Byte: %02x\n", (int)yylval.byte); return DT_BYTE; } YY_BREAK -case 15: +case 16: YY_RULE_SETUP -#line 219 "dtc-lexer.l" +#line 224 "dtc-lexer.l" { DPRINT("/BYTESTRING\n"); BEGIN_DEFAULT(); return ']'; } YY_BREAK -case 16: +case 17: YY_RULE_SETUP -#line 225 "dtc-lexer.l" +#line 230 "dtc-lexer.l" { DPRINT("PropNodeName: %s\n", yytext); yylval.propnodename = xstrdup((yytext[0] == '\\') ? @@ -1157,75 +1163,75 @@ YY_RULE_SETUP return DT_PROPNODENAME; } YY_BREAK -case 17: +case 18: YY_RULE_SETUP -#line 233 "dtc-lexer.l" +#line 238 "dtc-lexer.l" { DPRINT("Binary Include\n"); return DT_INCBIN; } YY_BREAK -case 18: -/* rule 18 can match eol */ -YY_RULE_SETUP -#line 238 "dtc-lexer.l" -/* eat whitespace */ - YY_BREAK case 19: /* rule 19 can match eol */ YY_RULE_SETUP -#line 239 "dtc-lexer.l" -/* eat C-style comments */ +#line 243 "dtc-lexer.l" +/* eat whitespace */ YY_BREAK case 20: /* rule 20 can match eol */ YY_RULE_SETUP -#line 240 "dtc-lexer.l" -/* eat C++-style comments */ +#line 244 "dtc-lexer.l" +/* eat C-style comments */ YY_BREAK case 21: +/* rule 21 can match eol */ YY_RULE_SETUP -#line 242 "dtc-lexer.l" -{ return DT_LSHIFT; }; +#line 245 "dtc-lexer.l" +/* eat C++-style comments */ YY_BREAK case 22: YY_RULE_SETUP -#line 243 "dtc-lexer.l" -{ return DT_RSHIFT; }; +#line 247 "dtc-lexer.l" +{ return DT_LSHIFT; }; YY_BREAK case 23: YY_RULE_SETUP -#line 244 "dtc-lexer.l" -{ return DT_LE; }; +#line 248 "dtc-lexer.l" +{ return DT_RSHIFT; }; YY_BREAK case 24: YY_RULE_SETUP -#line 245 "dtc-lexer.l" -{ return DT_GE; }; +#line 249 "dtc-lexer.l" +{ return DT_LE; }; YY_BREAK case 25: YY_RULE_SETUP -#line 246 "dtc-lexer.l" -{ return DT_EQ; }; +#line 250 "dtc-lexer.l" +{ return DT_GE; }; YY_BREAK case 26: YY_RULE_SETUP -#line 247 "dtc-lexer.l" -{ return DT_NE; }; +#line 251 "dtc-lexer.l" +{ return DT_EQ; }; YY_BREAK case 27: YY_RULE_SETUP -#line 248 "dtc-lexer.l" -{ return DT_AND; }; +#line 252 "dtc-lexer.l" +{ return DT_NE; }; YY_BREAK case 28: YY_RULE_SETUP -#line 249 "dtc-lexer.l" -{ return DT_OR; }; +#line 253 "dtc-lexer.l" +{ return DT_AND; }; YY_BREAK case 29: YY_RULE_SETUP -#line 251 "dtc-lexer.l" +#line 254 "dtc-lexer.l" +{ return DT_OR; }; + YY_BREAK +case 30: +YY_RULE_SETUP +#line 256 "dtc-lexer.l" { DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); @@ -1241,12 +1247,12 @@ YY_RULE_SETUP return yytext[0]; } YY_BREAK -case 30: +case 31: YY_RULE_SETUP -#line 266 "dtc-lexer.l" +#line 271 "dtc-lexer.l" ECHO; YY_BREAK -#line 1250 "dtc-lexer.lex.c" +#line 1256 "dtc-lexer.lex.c" case YY_END_OF_BUFFER: { @@ -1388,9 +1394,9 @@ ECHO; */ static int yy_get_next_buffer (void) { - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = (yytext_ptr); - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + yy_size_t number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) @@ -1419,7 +1425,7 @@ static int yy_get_next_buffer (void) /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); @@ -1432,7 +1438,7 @@ static int yy_get_next_buffer (void) else { - yy_size_t num_to_read = + int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) @@ -1446,7 +1452,7 @@ static int yy_get_next_buffer (void) if ( b->yy_is_our_buffer ) { - yy_size_t new_size = b->yy_buf_size * 2; + int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; @@ -1459,7 +1465,7 @@ static int yy_get_next_buffer (void) } else /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; + b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( @@ -1501,9 +1507,9 @@ static int yy_get_next_buffer (void) else ret_val = EOB_ACT_CONTINUE_SCAN; - if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); @@ -1522,15 +1528,15 @@ static int yy_get_next_buffer (void) static yy_state_type yy_get_previous_state (void) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -1539,10 +1545,10 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 159 ) + if ( yy_current_state >= 166 ) yy_c = yy_meta[(unsigned int) yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; } return yy_current_state; @@ -1555,10 +1561,10 @@ static int yy_get_next_buffer (void) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { - register int yy_is_jam; - register char *yy_cp = (yy_c_buf_p); + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -1567,15 +1573,19 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 159 ) + if ( yy_current_state >= 166 ) yy_c = yy_meta[(unsigned int) yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 158); + yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; + yy_is_jam = (yy_current_state == 165); return yy_is_jam ? 0 : yy_current_state; } +#ifndef YY_NO_UNPUT + +#endif + #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) @@ -1600,7 +1610,7 @@ static int yy_get_next_buffer (void) else { /* need more input */ - yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); + int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) @@ -1624,7 +1634,7 @@ static int yy_get_next_buffer (void) case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) - return EOF; + return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; @@ -1727,7 +1737,7 @@ static void yy_load_buffer_state (void) if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - b->yy_buf_size = size; + b->yy_buf_size = (yy_size_t)size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. @@ -1874,7 +1884,7 @@ void yypop_buffer_state (void) */ static void yyensure_buffer_stack (void) { - yy_size_t num_to_alloc; + int num_to_alloc; if (!(yy_buffer_stack)) { @@ -1882,15 +1892,15 @@ static void yyensure_buffer_stack (void) * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ - num_to_alloc = 1; + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - + (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; @@ -1899,7 +1909,7 @@ static void yyensure_buffer_stack (void) if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; + yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc @@ -1919,7 +1929,7 @@ static void yyensure_buffer_stack (void) * @param base the character buffer * @param size the size in bytes of the character buffer * - * @return the newly allocated buffer state object. + * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { @@ -1929,7 +1939,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ - return 0; + return NULL; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) @@ -1938,7 +1948,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; - b->yy_input_file = 0; + b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; @@ -1961,7 +1971,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) { - return yy_scan_bytes(yystr,strlen(yystr) ); + return yy_scan_bytes(yystr,(int) strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will @@ -1971,7 +1981,7 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) * * @return the newly allocated buffer state object. */ -YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; @@ -1979,7 +1989,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ - n = _yybytes_len + 2; + n = (yy_size_t) _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); @@ -2005,9 +2015,9 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len #define YY_EXIT_FAILURE 2 #endif -static void yy_fatal_error (yyconst char* msg ) +static void yynoreturn yy_fatal_error (yyconst char* msg ) { - (void) fprintf( stderr, "%s\n", msg ); + (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } @@ -2035,7 +2045,7 @@ static void yy_fatal_error (yyconst char* msg ) */ int yyget_lineno (void) { - + return yylineno; } @@ -2058,7 +2068,7 @@ FILE *yyget_out (void) /** Get the length of the current token. * */ -yy_size_t yyget_leng (void) +int yyget_leng (void) { return yyleng; } @@ -2073,29 +2083,29 @@ char *yyget_text (void) } /** Set the current line number. - * @param line_number + * @param _line_number line number * */ -void yyset_lineno (int line_number ) +void yyset_lineno (int _line_number ) { - yylineno = line_number; + yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. - * @param in_str A readable stream. + * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ -void yyset_in (FILE * in_str ) +void yyset_in (FILE * _in_str ) { - yyin = in_str ; + yyin = _in_str ; } -void yyset_out (FILE * out_str ) +void yyset_out (FILE * _out_str ) { - yyout = out_str ; + yyout = _out_str ; } int yyget_debug (void) @@ -2103,9 +2113,9 @@ int yyget_debug (void) return yy_flex_debug; } -void yyset_debug (int bdebug ) +void yyset_debug (int _bdebug ) { - yy_flex_debug = bdebug ; + yy_flex_debug = _bdebug ; } static int yy_init_globals (void) @@ -2114,10 +2124,10 @@ static int yy_init_globals (void) * This function is called from yylex_destroy(), so don't allocate here. */ - (yy_buffer_stack) = 0; + (yy_buffer_stack) = NULL; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; - (yy_c_buf_p) = (char *) 0; + (yy_c_buf_p) = NULL; (yy_init) = 0; (yy_start) = 0; @@ -2126,8 +2136,8 @@ static int yy_init_globals (void) yyin = stdin; yyout = stdout; #else - yyin = (FILE *) 0; - yyout = (FILE *) 0; + yyin = NULL; + yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by @@ -2165,7 +2175,8 @@ int yylex_destroy (void) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { - register int i; + + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -2174,7 +2185,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { - register int n; + int n; for ( n = 0; s[n]; ++n ) ; @@ -2184,11 +2195,12 @@ static int yy_flex_strlen (yyconst char * s ) void *yyalloc (yy_size_t size ) { - return (void *) malloc( size ); + return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size ) { + /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter @@ -2196,17 +2208,17 @@ void *yyrealloc (void * ptr, yy_size_t size ) * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ - return (void *) realloc( (char *) ptr, size ); + return realloc(ptr, size); } void yyfree (void * ptr ) { - free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" -#line 265 "dtc-lexer.l" +#line 271 "dtc-lexer.l" diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped index 31cec50a1265..2965227a1b4a 100644 --- a/scripts/dtc/dtc-parser.tab.c_shipped +++ b/scripts/dtc/dtc-parser.tab.c_shipped @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.2. */ +/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. 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 @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.0.2" +#define YYBISON_VERSION "3.0.4" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -65,6 +65,7 @@ #line 20 "dtc-parser.y" /* yacc.c:339 */ #include +#include #include "dtc.h" #include "srcpos.h" @@ -77,10 +78,10 @@ extern void yyerror(char const *s); treesource_error = true; \ } while (0) -extern struct boot_info *the_boot_info; +extern struct dt_info *parser_output; extern bool treesource_error; -#line 84 "dtc-parser.tab.c" /* yacc.c:339 */ +#line 85 "dtc-parser.tab.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus @@ -116,35 +117,36 @@ extern int yydebug; enum yytokentype { DT_V1 = 258, - DT_MEMRESERVE = 259, - DT_LSHIFT = 260, - DT_RSHIFT = 261, - DT_LE = 262, - DT_GE = 263, - DT_EQ = 264, - DT_NE = 265, - DT_AND = 266, - DT_OR = 267, - DT_BITS = 268, - DT_DEL_PROP = 269, - DT_DEL_NODE = 270, - DT_PROPNODENAME = 271, - DT_LITERAL = 272, - DT_CHAR_LITERAL = 273, - DT_BYTE = 274, - DT_STRING = 275, - DT_LABEL = 276, - DT_REF = 277, - DT_INCBIN = 278 + DT_PLUGIN = 259, + DT_MEMRESERVE = 260, + DT_LSHIFT = 261, + DT_RSHIFT = 262, + DT_LE = 263, + DT_GE = 264, + DT_EQ = 265, + DT_NE = 266, + DT_AND = 267, + DT_OR = 268, + DT_BITS = 269, + DT_DEL_PROP = 270, + DT_DEL_NODE = 271, + DT_PROPNODENAME = 272, + DT_LITERAL = 273, + DT_CHAR_LITERAL = 274, + DT_BYTE = 275, + DT_STRING = 276, + DT_LABEL = 277, + DT_REF = 278, + DT_INCBIN = 279 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE YYSTYPE; + union YYSTYPE { -#line 38 "dtc-parser.y" /* yacc.c:355 */ +#line 39 "dtc-parser.y" /* yacc.c:355 */ char *propnodename; char *labelref; @@ -162,9 +164,12 @@ union YYSTYPE struct node *nodelist; struct reserve_info *re; uint64_t integer; + unsigned int flags; -#line 167 "dtc-parser.tab.c" /* yacc.c:355 */ +#line 170 "dtc-parser.tab.c" /* yacc.c:355 */ }; + +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif @@ -192,7 +197,7 @@ int yyparse (void); /* Copy the second part of user declarations. */ -#line 196 "dtc-parser.tab.c" /* yacc.c:358 */ +#line 201 "dtc-parser.tab.c" /* yacc.c:358 */ #ifdef short # undef short @@ -434,23 +439,23 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 4 +#define YYFINAL 6 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 136 +#define YYLAST 138 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 47 +#define YYNTOKENS 48 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 28 +#define YYNNTS 30 /* YYNRULES -- Number of rules. */ -#define YYNRULES 80 +#define YYNRULES 84 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 144 +#define YYNSTATES 149 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 278 +#define YYMAXUTOK 279 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -462,16 +467,16 @@ static const yytype_uint8 yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 46, 2, 2, 2, 44, 40, 2, - 32, 34, 43, 41, 33, 42, 2, 25, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 37, 24, - 35, 28, 29, 36, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 47, 2, 2, 2, 45, 41, 2, + 33, 35, 44, 42, 34, 43, 2, 26, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 38, 25, + 36, 29, 30, 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 30, 2, 31, 39, 2, 2, 2, 2, 2, + 2, 31, 2, 32, 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 26, 38, 27, 45, 2, 2, 2, + 2, 2, 2, 27, 39, 28, 46, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -486,22 +491,22 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 104, 104, 113, 116, 123, 127, 135, 139, 144, - 155, 165, 180, 188, 191, 198, 202, 206, 210, 218, - 222, 226, 230, 234, 250, 260, 268, 271, 275, 282, - 298, 303, 322, 336, 343, 344, 345, 352, 356, 357, - 361, 362, 366, 367, 371, 372, 376, 377, 381, 382, - 386, 387, 388, 392, 393, 394, 395, 396, 400, 401, - 402, 406, 407, 408, 412, 413, 422, 431, 435, 436, - 437, 438, 443, 446, 450, 458, 461, 465, 473, 477, - 481 + 0, 109, 109, 117, 121, 128, 129, 139, 142, 149, + 153, 161, 165, 170, 181, 191, 206, 214, 217, 224, + 228, 232, 236, 244, 248, 252, 256, 260, 276, 286, + 294, 297, 301, 308, 324, 329, 348, 362, 369, 370, + 371, 378, 382, 383, 387, 388, 392, 393, 397, 398, + 402, 403, 407, 408, 412, 413, 414, 418, 419, 420, + 421, 422, 426, 427, 428, 432, 433, 434, 438, 439, + 448, 457, 461, 462, 463, 464, 469, 472, 476, 484, + 487, 491, 499, 503, 507 }; #endif @@ -510,19 +515,20 @@ static const yytype_uint16 yyrline[] = First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { - "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT", - "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR", - "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL", - "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", - "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'", - "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'", - "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile", - "memreserves", "memreserve", "devicetree", "nodedef", "proplist", - "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim", - "integer_expr", "integer_trinary", "integer_or", "integer_and", - "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq", - "integer_rela", "integer_shift", "integer_add", "integer_mul", - "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR + "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE", + "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", + "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", + "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", + "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", + "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", + "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile", + "header", "headers", "memreserves", "memreserve", "devicetree", + "nodedef", "proplist", "propdef", "propdata", "propdataprefix", + "arrayprefix", "integer_prim", "integer_expr", "integer_trinary", + "integer_or", "integer_and", "integer_bitor", "integer_bitxor", + "integer_bitand", "integer_eq", "integer_rela", "integer_shift", + "integer_add", "integer_mul", "integer_unary", "bytestring", "subnodes", + "subnode", YY_NULLPTR }; #endif @@ -533,16 +539,16 @@ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 59, 47, 123, 125, 61, 62, - 91, 93, 40, 44, 41, 60, 63, 58, 124, 94, - 38, 43, 45, 42, 37, 126, 33 + 275, 276, 277, 278, 279, 59, 47, 123, 125, 61, + 62, 91, 93, 40, 44, 41, 60, 63, 58, 124, + 94, 38, 43, 45, 42, 37, 126, 33 }; # endif -#define YYPACT_NINF -81 +#define YYPACT_NINF -44 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-81))) + (!!((Yystate) == (-44))) #define YYTABLE_NINF -1 @@ -553,21 +559,21 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int8 yypact[] = { - 16, -11, 21, 10, -81, 25, 10, 19, 10, -81, - -81, -9, 25, -81, 2, 51, -81, -9, -9, -9, - -81, 1, -81, -6, 50, 14, 28, 29, 36, 3, - 58, 44, -3, -81, 47, -81, -81, 65, 68, 2, - 2, -81, -81, -81, -81, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -81, 63, 69, 2, -81, -81, - 50, 57, 14, 28, 29, 36, 3, 3, 58, 58, - 58, 58, 44, 44, -3, -3, -81, -81, -81, 79, - 80, -8, 63, -81, 72, 63, -81, -81, -9, 76, - 77, -81, -81, -81, -81, -81, 78, -81, -81, -81, - -81, -81, 35, 4, -81, -81, -81, -81, 86, -81, - -81, -81, 73, -81, -81, 33, 71, 84, 39, -81, - -81, -81, -81, -81, 41, -81, -81, -81, 25, -81, - 74, 25, 75, -81 + 14, 27, 61, 14, 8, 18, -44, -44, 37, 8, + 40, 8, 64, -44, -44, -12, 37, -44, 50, 52, + -44, -44, -12, -12, -12, -44, 51, -44, -4, 78, + 53, 54, 55, 17, 2, 30, 38, -3, -44, 66, + -44, -44, 70, 72, 50, 50, -44, -44, -44, -44, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -44, + 3, 73, 50, -44, -44, 78, 59, 53, 54, 55, + 17, 2, 2, 30, 30, 30, 30, 38, 38, -3, + -3, -44, -44, -44, 82, 83, 44, 3, -44, 74, + 3, -44, -44, -12, 76, 79, -44, -44, -44, -44, + -44, 80, -44, -44, -44, -44, -44, -10, 36, -44, + -44, -44, -44, 85, -44, -44, -44, 75, -44, -44, + 21, 71, 88, -6, -44, -44, -44, -44, -44, 11, + -44, -44, -44, 37, -44, 77, 37, 81, -44 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -575,37 +581,37 @@ static const yytype_int8 yypact[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 0, 0, 0, 3, 1, 0, 0, 0, 3, 34, - 35, 0, 0, 6, 0, 2, 4, 0, 0, 0, - 68, 0, 37, 38, 40, 42, 44, 46, 48, 50, - 53, 60, 63, 67, 0, 13, 7, 0, 0, 0, - 0, 69, 70, 71, 36, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 7, 3, 1, 6, 0, 0, + 0, 7, 0, 38, 39, 0, 0, 10, 0, 2, + 8, 4, 0, 0, 0, 72, 0, 41, 42, 44, + 46, 48, 50, 52, 54, 57, 64, 67, 71, 0, + 17, 11, 0, 0, 0, 0, 73, 74, 75, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 5, 75, 0, 0, 10, 8, - 41, 0, 43, 45, 47, 49, 51, 52, 56, 57, - 55, 54, 58, 59, 61, 62, 65, 64, 66, 0, - 0, 0, 0, 14, 0, 75, 11, 9, 0, 0, - 0, 16, 26, 78, 18, 80, 0, 77, 76, 39, - 17, 79, 0, 0, 12, 25, 15, 27, 0, 19, - 28, 22, 0, 72, 30, 0, 0, 0, 0, 33, - 32, 20, 31, 29, 0, 73, 74, 21, 0, 24, - 0, 0, 0, 23 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 79, 0, 0, 14, 12, 45, 0, 47, 49, 51, + 53, 55, 56, 60, 61, 59, 58, 62, 63, 65, + 66, 69, 68, 70, 0, 0, 0, 0, 18, 0, + 79, 15, 13, 0, 0, 0, 20, 30, 82, 22, + 84, 0, 81, 80, 43, 21, 83, 0, 0, 16, + 29, 19, 31, 0, 23, 32, 26, 0, 76, 34, + 0, 0, 0, 0, 37, 36, 24, 35, 33, 0, + 77, 78, 25, 0, 28, 0, 0, 0, 27 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -81, -81, 100, 104, -81, -38, -81, -80, -81, -81, - -81, -5, 66, 13, -81, 70, 67, 81, 64, 82, - 37, 27, 34, 38, -14, -81, 22, 24 + -44, -44, -44, 103, 99, 104, -44, -43, -44, -21, + -44, -44, -44, -8, 63, 9, -44, 65, 67, 68, + 69, 62, 26, 4, 22, 23, -19, -44, 20, 28 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 2, 7, 8, 15, 36, 65, 93, 112, 113, - 125, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 128, 94, 95 + -1, 2, 3, 4, 10, 11, 19, 41, 70, 98, + 117, 118, 130, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 133, 99, 100 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -613,87 +619,87 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { - 12, 68, 69, 41, 42, 43, 45, 34, 9, 10, - 53, 54, 104, 3, 5, 107, 101, 118, 35, 1, - 102, 4, 61, 11, 119, 120, 121, 122, 35, 97, - 46, 6, 55, 17, 123, 44, 18, 19, 56, 124, - 62, 63, 9, 10, 14, 51, 52, 86, 87, 88, - 9, 10, 48, 103, 129, 130, 115, 11, 135, 116, - 136, 47, 131, 57, 58, 11, 37, 49, 117, 50, - 137, 64, 38, 39, 138, 139, 40, 89, 90, 91, - 78, 79, 80, 81, 92, 59, 60, 66, 76, 77, - 67, 82, 83, 96, 98, 99, 100, 84, 85, 106, - 110, 111, 114, 126, 134, 127, 133, 141, 16, 143, - 13, 109, 71, 74, 72, 70, 105, 108, 0, 0, - 132, 0, 0, 0, 0, 0, 0, 0, 0, 73, - 0, 0, 75, 140, 0, 0, 142 + 16, 73, 74, 46, 47, 48, 13, 14, 39, 50, + 58, 59, 120, 8, 140, 121, 141, 1, 94, 95, + 96, 15, 12, 66, 122, 97, 142, 56, 57, 102, + 9, 22, 60, 51, 23, 24, 62, 63, 61, 13, + 14, 67, 68, 134, 135, 143, 144, 91, 92, 93, + 123, 136, 5, 108, 15, 13, 14, 124, 125, 126, + 127, 6, 83, 84, 85, 86, 18, 128, 42, 106, + 15, 40, 129, 107, 43, 44, 109, 40, 45, 112, + 64, 65, 81, 82, 87, 88, 49, 89, 90, 21, + 52, 69, 53, 71, 54, 72, 55, 103, 101, 104, + 105, 115, 111, 131, 116, 119, 7, 138, 132, 139, + 20, 146, 114, 17, 76, 75, 148, 80, 0, 77, + 113, 78, 137, 79, 0, 110, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 145, 0, 0, 147 }; static const yytype_int16 yycheck[] = { - 5, 39, 40, 17, 18, 19, 12, 12, 17, 18, - 7, 8, 92, 24, 4, 95, 24, 13, 26, 3, - 28, 0, 25, 32, 20, 21, 22, 23, 26, 67, - 36, 21, 29, 42, 30, 34, 45, 46, 35, 35, - 43, 44, 17, 18, 25, 9, 10, 61, 62, 63, - 17, 18, 38, 91, 21, 22, 21, 32, 19, 24, - 21, 11, 29, 5, 6, 32, 15, 39, 33, 40, - 31, 24, 21, 22, 33, 34, 25, 14, 15, 16, - 53, 54, 55, 56, 21, 41, 42, 22, 51, 52, - 22, 57, 58, 24, 37, 16, 16, 59, 60, 27, - 24, 24, 24, 17, 20, 32, 35, 33, 8, 34, - 6, 98, 46, 49, 47, 45, 92, 95, -1, -1, - 125, -1, -1, -1, -1, -1, -1, -1, -1, 48, - -1, -1, 50, 138, -1, -1, 141 + 8, 44, 45, 22, 23, 24, 18, 19, 16, 13, + 8, 9, 22, 5, 20, 25, 22, 3, 15, 16, + 17, 33, 4, 26, 34, 22, 32, 10, 11, 72, + 22, 43, 30, 37, 46, 47, 6, 7, 36, 18, + 19, 44, 45, 22, 23, 34, 35, 66, 67, 68, + 14, 30, 25, 96, 33, 18, 19, 21, 22, 23, + 24, 0, 58, 59, 60, 61, 26, 31, 16, 25, + 33, 27, 36, 29, 22, 23, 97, 27, 26, 100, + 42, 43, 56, 57, 62, 63, 35, 64, 65, 25, + 12, 25, 39, 23, 40, 23, 41, 38, 25, 17, + 17, 25, 28, 18, 25, 25, 3, 36, 33, 21, + 11, 34, 103, 9, 51, 50, 35, 55, -1, 52, + 100, 53, 130, 54, -1, 97, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 143, -1, -1, 146 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 3, 48, 24, 0, 4, 21, 49, 50, 17, - 18, 32, 58, 50, 25, 51, 49, 42, 45, 46, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 58, 26, 52, 15, 21, 22, - 25, 71, 71, 71, 34, 12, 36, 11, 38, 39, - 40, 9, 10, 7, 8, 29, 35, 5, 6, 41, - 42, 25, 43, 44, 24, 53, 22, 22, 52, 52, - 62, 59, 63, 64, 65, 66, 67, 67, 68, 68, - 68, 68, 69, 69, 70, 70, 71, 71, 71, 14, - 15, 16, 21, 54, 73, 74, 24, 52, 37, 16, - 16, 24, 28, 52, 54, 74, 27, 54, 73, 60, - 24, 24, 55, 56, 24, 21, 24, 33, 13, 20, - 21, 22, 23, 30, 35, 57, 17, 32, 72, 21, - 22, 29, 58, 35, 20, 19, 21, 31, 33, 34, - 58, 33, 58, 34 + 0, 3, 49, 50, 51, 25, 0, 51, 5, 22, + 52, 53, 4, 18, 19, 33, 61, 53, 26, 54, + 52, 25, 43, 46, 47, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 61, + 27, 55, 16, 22, 23, 26, 74, 74, 74, 35, + 13, 37, 12, 39, 40, 41, 10, 11, 8, 9, + 30, 36, 6, 7, 42, 43, 26, 44, 45, 25, + 56, 23, 23, 55, 55, 65, 62, 66, 67, 68, + 69, 70, 70, 71, 71, 71, 71, 72, 72, 73, + 73, 74, 74, 74, 15, 16, 17, 22, 57, 76, + 77, 25, 55, 38, 17, 17, 25, 29, 55, 57, + 77, 28, 57, 76, 63, 25, 25, 58, 59, 25, + 22, 25, 34, 14, 21, 22, 23, 24, 31, 36, + 60, 18, 33, 75, 22, 23, 30, 61, 36, 21, + 20, 22, 32, 34, 35, 61, 34, 61, 35 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 47, 48, 49, 49, 50, 50, 51, 51, 51, - 51, 51, 52, 53, 53, 54, 54, 54, 54, 55, - 55, 55, 55, 55, 55, 55, 56, 56, 56, 57, - 57, 57, 57, 57, 58, 58, 58, 59, 60, 60, - 61, 61, 62, 62, 63, 63, 64, 64, 65, 65, - 66, 66, 66, 67, 67, 67, 67, 67, 68, 68, - 68, 69, 69, 69, 70, 70, 70, 70, 71, 71, - 71, 71, 72, 72, 72, 73, 73, 73, 74, 74, - 74 + 0, 48, 49, 50, 50, 51, 51, 52, 52, 53, + 53, 54, 54, 54, 54, 54, 55, 56, 56, 57, + 57, 57, 57, 58, 58, 58, 58, 58, 58, 58, + 59, 59, 59, 60, 60, 60, 60, 60, 61, 61, + 61, 62, 63, 63, 64, 64, 65, 65, 66, 66, + 67, 67, 68, 68, 69, 69, 69, 70, 70, 70, + 70, 70, 71, 71, 71, 72, 72, 72, 73, 73, + 73, 73, 74, 74, 74, 74, 75, 75, 75, 76, + 76, 76, 77, 77, 77 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 4, 0, 2, 4, 2, 2, 3, 4, - 3, 4, 5, 0, 2, 4, 2, 3, 2, 2, - 3, 4, 2, 9, 5, 2, 0, 2, 2, 3, - 1, 2, 2, 2, 1, 1, 3, 1, 1, 5, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, - 1, 3, 3, 1, 3, 3, 3, 1, 1, 2, - 2, 2, 0, 2, 2, 0, 2, 2, 2, 3, - 2 + 0, 2, 3, 2, 4, 1, 2, 0, 2, 4, + 2, 2, 3, 4, 3, 4, 5, 0, 2, 4, + 2, 3, 2, 2, 3, 4, 2, 9, 5, 2, + 0, 2, 2, 3, 1, 2, 2, 2, 1, 1, + 3, 1, 1, 5, 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, 3, 1, 3, 3, + 3, 3, 3, 3, 1, 3, 3, 1, 3, 3, + 3, 1, 1, 2, 2, 2, 0, 2, 2, 0, + 2, 2, 2, 3, 2 }; @@ -1463,65 +1469,91 @@ yyreduce: switch (yyn) { case 2: -#line 105 "dtc-parser.y" /* yacc.c:1646 */ +#line 110 "dtc-parser.y" /* yacc.c:1646 */ { - the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node), - guess_boot_cpuid((yyvsp[0].node))); + parser_output = build_dt_info((yyvsp[-2].flags), (yyvsp[-1].re), (yyvsp[0].node), + guess_boot_cpuid((yyvsp[0].node))); } -#line 1472 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1478 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 3: -#line 113 "dtc-parser.y" /* yacc.c:1646 */ +#line 118 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.re) = NULL; + (yyval.flags) = DTSF_V1; } -#line 1480 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1486 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 4: -#line 117 "dtc-parser.y" /* yacc.c:1646 */ +#line 122 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re)); + (yyval.flags) = DTSF_V1 | DTSF_PLUGIN; } -#line 1488 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 5: -#line 124 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer)); - } -#line 1496 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1494 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 6: -#line 128 "dtc-parser.y" /* yacc.c:1646 */ +#line 130 "dtc-parser.y" /* yacc.c:1646 */ + { + if ((yyvsp[0].flags) != (yyvsp[-1].flags)) + ERROR(&(yylsp[0]), "Header flags don't match earlier ones"); + (yyval.flags) = (yyvsp[-1].flags); + } +#line 1504 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 7: +#line 139 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.re) = NULL; + } +#line 1512 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 8: +#line 143 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re)); + } +#line 1520 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 9: +#line 150 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer)); + } +#line 1528 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 10: +#line 154 "dtc-parser.y" /* yacc.c:1646 */ { add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref)); (yyval.re) = (yyvsp[0].re); } -#line 1505 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1537 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 7: -#line 136 "dtc-parser.y" /* yacc.c:1646 */ + case 11: +#line 162 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node((yyvsp[0].node), ""); } -#line 1513 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1545 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 8: -#line 140 "dtc-parser.y" /* yacc.c:1646 */ + case 12: +#line 166 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node)); } -#line 1521 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1553 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 9: -#line 145 "dtc-parser.y" /* yacc.c:1646 */ + case 13: +#line 171 "dtc-parser.y" /* yacc.c:1646 */ { struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref)); @@ -1532,11 +1564,11 @@ yyreduce: ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref)); (yyval.node) = (yyvsp[-3].node); } -#line 1536 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1568 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 10: -#line 156 "dtc-parser.y" /* yacc.c:1646 */ + case 14: +#line 182 "dtc-parser.y" /* yacc.c:1646 */ { struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref)); @@ -1546,11 +1578,11 @@ yyreduce: ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref)); (yyval.node) = (yyvsp[-2].node); } -#line 1550 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 11: -#line 166 "dtc-parser.y" /* yacc.c:1646 */ + case 15: +#line 192 "dtc-parser.y" /* yacc.c:1646 */ { struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref)); @@ -1562,100 +1594,100 @@ yyreduce: (yyval.node) = (yyvsp[-3].node); } -#line 1566 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 12: -#line 181 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist)); - } -#line 1574 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 13: -#line 188 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.proplist) = NULL; - } -#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 14: -#line 192 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist)); - } -#line 1590 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 15: -#line 199 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data)); - } #line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 16: -#line 203 "dtc-parser.y" /* yacc.c:1646 */ +#line 207 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data); + (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist)); } #line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 17: -#line 207 "dtc-parser.y" /* yacc.c:1646 */ +#line 214 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.prop) = build_property_delete((yyvsp[-1].propnodename)); + (yyval.proplist) = NULL; } #line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 18: -#line 211 "dtc-parser.y" /* yacc.c:1646 */ +#line 218 "dtc-parser.y" /* yacc.c:1646 */ { - add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref)); - (yyval.prop) = (yyvsp[0].prop); + (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist)); } -#line 1623 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1622 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 19: -#line 219 "dtc-parser.y" /* yacc.c:1646 */ +#line 225 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data)); + (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data)); } -#line 1631 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1630 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 20: -#line 223 "dtc-parser.y" /* yacc.c:1646 */ +#line 229 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data); + (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data); } -#line 1639 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1638 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 21: -#line 227 "dtc-parser.y" /* yacc.c:1646 */ +#line 233 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data)); + (yyval.prop) = build_property_delete((yyvsp[-1].propnodename)); } -#line 1647 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1646 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 22: -#line 231 "dtc-parser.y" /* yacc.c:1646 */ +#line 237 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref)); + add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref)); + (yyval.prop) = (yyvsp[0].prop); } #line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 23: -#line 235 "dtc-parser.y" /* yacc.c:1646 */ +#line 245 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data)); + } +#line 1663 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 24: +#line 249 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data); + } +#line 1671 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 25: +#line 253 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data)); + } +#line 1679 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 26: +#line 257 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref)); + } +#line 1687 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 27: +#line 261 "dtc-parser.y" /* yacc.c:1646 */ { FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL); struct data d; @@ -1671,11 +1703,11 @@ yyreduce: (yyval.data) = data_merge((yyvsp[-8].data), d); fclose(f); } -#line 1675 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1707 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 24: -#line 251 "dtc-parser.y" /* yacc.c:1646 */ + case 28: +#line 277 "dtc-parser.y" /* yacc.c:1646 */ { FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL); struct data d = empty_data; @@ -1685,43 +1717,43 @@ yyreduce: (yyval.data) = data_merge((yyvsp[-4].data), d); fclose(f); } -#line 1689 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 25: -#line 261 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); - } -#line 1697 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 26: -#line 268 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.data) = empty_data; - } -#line 1705 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 27: -#line 272 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.data) = (yyvsp[-1].data); - } -#line 1713 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 28: -#line 276 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); - } #line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 29: -#line 283 "dtc-parser.y" /* yacc.c:1646 */ +#line 287 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); + } +#line 1729 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 30: +#line 294 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = empty_data; + } +#line 1737 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 31: +#line 298 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = (yyvsp[-1].data); + } +#line 1745 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 32: +#line 302 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); + } +#line 1753 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 33: +#line 309 "dtc-parser.y" /* yacc.c:1646 */ { unsigned long long bits; @@ -1737,20 +1769,20 @@ yyreduce: (yyval.array).data = empty_data; (yyval.array).bits = bits; } -#line 1741 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 30: -#line 299 "dtc-parser.y" /* yacc.c:1646 */ + case 34: +#line 325 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.array).data = empty_data; (yyval.array).bits = 32; } -#line 1750 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1782 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 31: -#line 304 "dtc-parser.y" /* yacc.c:1646 */ + case 35: +#line 330 "dtc-parser.y" /* yacc.c:1646 */ { if ((yyvsp[-1].array).bits < 64) { uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1; @@ -1769,11 +1801,11 @@ yyreduce: (yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits); } -#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1805 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 32: -#line 323 "dtc-parser.y" /* yacc.c:1646 */ + case 36: +#line 349 "dtc-parser.y" /* yacc.c:1646 */ { uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits); @@ -1787,129 +1819,129 @@ yyreduce: (yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits); } -#line 1791 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1823 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 33: -#line 337 "dtc-parser.y" /* yacc.c:1646 */ + case 37: +#line 363 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref)); } -#line 1799 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 36: -#line 346 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.integer) = (yyvsp[-1].integer); - } -#line 1807 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 39: -#line 357 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); } -#line 1813 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 41: -#line 362 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); } -#line 1819 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 43: -#line 367 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); } -#line 1825 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 45: -#line 372 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); } #line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */ break; + case 40: +#line 372 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.integer) = (yyvsp[-1].integer); + } +#line 1839 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 43: +#line 383 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); } +#line 1845 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 45: +#line 388 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); } +#line 1851 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + case 47: -#line 377 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); } -#line 1837 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 393 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); } +#line 1857 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 49: -#line 382 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); } -#line 1843 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 398 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); } +#line 1863 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 51: -#line 387 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); } -#line 1849 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 403 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); } +#line 1869 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 52: -#line 388 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); } -#line 1855 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 54: -#line 393 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); } -#line 1861 "dtc-parser.tab.c" /* yacc.c:1646 */ + case 53: +#line 408 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); } +#line 1875 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 55: -#line 394 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); } -#line 1867 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 413 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); } +#line 1881 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 56: -#line 395 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); } -#line 1873 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 57: -#line 396 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); } -#line 1879 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 414 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); } +#line 1887 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 58: -#line 400 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); } -#line 1885 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 419 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); } +#line 1893 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 59: -#line 401 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); } -#line 1891 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 420 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); } +#line 1899 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 60: +#line 421 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); } +#line 1905 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 61: -#line 406 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); } -#line 1897 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 422 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); } +#line 1911 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 62: -#line 407 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); } -#line 1903 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 426 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); } +#line 1917 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 64: -#line 412 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); } -#line 1909 "dtc-parser.tab.c" /* yacc.c:1646 */ + case 63: +#line 427 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); } +#line 1923 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 65: -#line 414 "dtc-parser.y" /* yacc.c:1646 */ +#line 432 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); } +#line 1929 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 66: +#line 433 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); } +#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 68: +#line 438 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); } +#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 69: +#line 440 "dtc-parser.y" /* yacc.c:1646 */ { if ((yyvsp[0].integer) != 0) { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); @@ -1918,11 +1950,11 @@ yyreduce: (yyval.integer) = 0; } } -#line 1922 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1954 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 66: -#line 423 "dtc-parser.y" /* yacc.c:1646 */ + case 70: +#line 449 "dtc-parser.y" /* yacc.c:1646 */ { if ((yyvsp[0].integer) != 0) { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); @@ -1931,103 +1963,103 @@ yyreduce: (yyval.integer) = 0; } } -#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 69: -#line 436 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = -(yyvsp[0].integer); } -#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 70: -#line 437 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = ~(yyvsp[0].integer); } -#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 71: -#line 438 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = !(yyvsp[0].integer); } -#line 1953 "dtc-parser.tab.c" /* yacc.c:1646 */ - break; - - case 72: -#line 443 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.data) = empty_data; - } -#line 1961 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1967 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 73: -#line 447 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte)); - } -#line 1969 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 462 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = -(yyvsp[0].integer); } +#line 1973 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 74: -#line 451 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); - } -#line 1977 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 463 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = ~(yyvsp[0].integer); } +#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 75: -#line 458 "dtc-parser.y" /* yacc.c:1646 */ - { - (yyval.nodelist) = NULL; - } +#line 464 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = !(yyvsp[0].integer); } #line 1985 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 76: -#line 462 "dtc-parser.y" /* yacc.c:1646 */ +#line 469 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist)); + (yyval.data) = empty_data; } #line 1993 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 77: -#line 466 "dtc-parser.y" /* yacc.c:1646 */ +#line 473 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte)); + } +#line 2001 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 78: +#line 477 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); + } +#line 2009 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 79: +#line 484 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.nodelist) = NULL; + } +#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 80: +#line 488 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist)); + } +#line 2025 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 81: +#line 492 "dtc-parser.y" /* yacc.c:1646 */ { ERROR(&(yylsp[0]), "Properties must precede subnodes"); YYERROR; } -#line 2002 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2034 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 78: -#line 474 "dtc-parser.y" /* yacc.c:1646 */ + case 82: +#line 500 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename)); } -#line 2010 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2042 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 79: -#line 478 "dtc-parser.y" /* yacc.c:1646 */ + case 83: +#line 504 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename)); } -#line 2018 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2050 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 80: -#line 482 "dtc-parser.y" /* yacc.c:1646 */ + case 84: +#line 508 "dtc-parser.y" /* yacc.c:1646 */ { add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref)); (yyval.node) = (yyvsp[0].node); } -#line 2027 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2059 "dtc-parser.tab.c" /* yacc.c:1646 */ break; -#line 2031 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2063 "dtc-parser.tab.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -2262,7 +2294,7 @@ yyreturn: #endif return yyresult; } -#line 488 "dtc-parser.y" /* yacc.c:1906 */ +#line 514 "dtc-parser.y" /* yacc.c:1906 */ void yyerror(char const *s) diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped index 30867c688300..6aa512c1b337 100644 --- a/scripts/dtc/dtc-parser.tab.h_shipped +++ b/scripts/dtc/dtc-parser.tab.h_shipped @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.2. */ +/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. 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 @@ -46,35 +46,36 @@ extern int yydebug; enum yytokentype { DT_V1 = 258, - DT_MEMRESERVE = 259, - DT_LSHIFT = 260, - DT_RSHIFT = 261, - DT_LE = 262, - DT_GE = 263, - DT_EQ = 264, - DT_NE = 265, - DT_AND = 266, - DT_OR = 267, - DT_BITS = 268, - DT_DEL_PROP = 269, - DT_DEL_NODE = 270, - DT_PROPNODENAME = 271, - DT_LITERAL = 272, - DT_CHAR_LITERAL = 273, - DT_BYTE = 274, - DT_STRING = 275, - DT_LABEL = 276, - DT_REF = 277, - DT_INCBIN = 278 + DT_PLUGIN = 259, + DT_MEMRESERVE = 260, + DT_LSHIFT = 261, + DT_RSHIFT = 262, + DT_LE = 263, + DT_GE = 264, + DT_EQ = 265, + DT_NE = 266, + DT_AND = 267, + DT_OR = 268, + DT_BITS = 269, + DT_DEL_PROP = 270, + DT_DEL_NODE = 271, + DT_PROPNODENAME = 272, + DT_LITERAL = 273, + DT_CHAR_LITERAL = 274, + DT_BYTE = 275, + DT_STRING = 276, + DT_LABEL = 277, + DT_REF = 278, + DT_INCBIN = 279 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE YYSTYPE; + union YYSTYPE { -#line 38 "dtc-parser.y" /* yacc.c:1909 */ +#line 39 "dtc-parser.y" /* yacc.c:1909 */ char *propnodename; char *labelref; @@ -92,9 +93,12 @@ union YYSTYPE struct node *nodelist; struct reserve_info *re; uint64_t integer; + unsigned int flags; -#line 97 "dtc-parser.tab.h" /* yacc.c:1909 */ +#line 99 "dtc-parser.tab.h" /* yacc.c:1909 */ }; + +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 000873f070fd..b2fd4d155839 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -19,6 +19,7 @@ */ %{ #include +#include #include "dtc.h" #include "srcpos.h" @@ -31,7 +32,7 @@ extern void yyerror(char const *s); treesource_error = true; \ } while (0) -extern struct boot_info *the_boot_info; +extern struct dt_info *parser_output; extern bool treesource_error; %} @@ -52,9 +53,11 @@ extern bool treesource_error; struct node *nodelist; struct reserve_info *re; uint64_t integer; + unsigned int flags; } %token DT_V1 +%token DT_PLUGIN %token DT_MEMRESERVE %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR %token DT_BITS @@ -71,6 +74,8 @@ extern bool treesource_error; %type propdata %type propdataprefix +%type header +%type headers %type memreserve %type memreserves %type arrayprefix @@ -101,10 +106,31 @@ extern bool treesource_error; %% sourcefile: - DT_V1 ';' memreserves devicetree + headers memreserves devicetree { - the_boot_info = build_boot_info($3, $4, - guess_boot_cpuid($4)); + parser_output = build_dt_info($1, $2, $3, + guess_boot_cpuid($3)); + } + ; + +header: + DT_V1 ';' + { + $$ = DTSF_V1; + } + | DT_V1 ';' DT_PLUGIN ';' + { + $$ = DTSF_V1 | DTSF_PLUGIN; + } + ; + +headers: + header + | header headers + { + if ($2 != $1) + ERROR(&@2, "Header flags don't match earlier ones"); + $$ = $1; } ; diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index 5fa23c406266..a4edf4c7aebf 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -30,7 +30,16 @@ int quiet; /* Level of quietness */ int reservenum; /* Number of memory reservation slots */ int minsize; /* Minimum blob size */ int padsize; /* Additional padding to blob */ +int alignsize; /* Additional padding to blob accroding to the alignsize */ int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */ +int generate_symbols; /* enable symbols & fixup support */ +int generate_fixups; /* suppress generation of fixups on symbol support */ +int auto_label_aliases; /* auto generate labels -> aliases */ + +static int is_power_of_2(int x) +{ + return (x > 0) && ((x & (x - 1)) == 0); +} static void fill_fullpaths(struct node *tree, const char *prefix) { @@ -53,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix) #define FDT_VERSION(version) _FDT_VERSION(version) #define _FDT_VERSION(version) #version static const char usage_synopsis[] = "dtc [options] "; -static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv"; +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv"; static struct option const usage_long_opts[] = { {"quiet", no_argument, NULL, 'q'}, {"in-format", a_argument, NULL, 'I'}, @@ -64,6 +73,7 @@ static struct option const usage_long_opts[] = { {"reserve", a_argument, NULL, 'R'}, {"space", a_argument, NULL, 'S'}, {"pad", a_argument, NULL, 'p'}, + {"align", a_argument, NULL, 'a'}, {"boot-cpu", a_argument, NULL, 'b'}, {"force", no_argument, NULL, 'f'}, {"include", a_argument, NULL, 'i'}, @@ -71,6 +81,8 @@ static struct option const usage_long_opts[] = { {"phandle", a_argument, NULL, 'H'}, {"warning", a_argument, NULL, 'W'}, {"error", a_argument, NULL, 'E'}, + {"symbols", no_argument, NULL, '@'}, + {"auto-alias", no_argument, NULL, 'A'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, {NULL, no_argument, NULL, 0x0}, @@ -91,6 +103,7 @@ static const char * const usage_opts_help[] = { "\n\tMake space for reserve map entries (for dtb and asm output)", "\n\tMake the blob at least long (extra space)", "\n\tAdd padding to the blob of long (extra space)", + "\n\tMake the blob align to the (extra space)", "\n\tSet the physical boot cpu", "\n\tTry to produce output even if the input tree has errors", "\n\tAdd a path to search for include files", @@ -101,6 +114,8 @@ static const char * const usage_opts_help[] = { "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties", "\n\tEnable/disable warnings (prefix with \"no-\")", "\n\tEnable/disable errors (prefix with \"no-\")", + "\n\tEnable generation of symbols", + "\n\tEnable auto-alias of labels", "\n\tPrint this help and exit", "\n\tPrint version and exit", NULL, @@ -153,7 +168,7 @@ static const char *guess_input_format(const char *fname, const char *fallback) int main(int argc, char *argv[]) { - struct boot_info *bi; + struct dt_info *dti; const char *inform = NULL; const char *outform = NULL; const char *outname = "-"; @@ -169,6 +184,7 @@ int main(int argc, char *argv[]) reservenum = 0; minsize = 0; padsize = 0; + alignsize = 0; while ((opt = util_getopt_long()) != EOF) { switch (opt) { @@ -196,6 +212,12 @@ int main(int argc, char *argv[]) case 'p': padsize = strtol(optarg, NULL, 0); break; + case 'a': + alignsize = strtol(optarg, NULL, 0); + if (!is_power_of_2(alignsize)) + die("Invalid argument \"%d\" to -a option\n", + optarg); + break; case 'f': force = true; break; @@ -234,6 +256,13 @@ int main(int argc, char *argv[]) parse_checks_option(false, true, optarg); break; + case '@': + generate_symbols = 1; + break; + case 'A': + auto_label_aliases = 1; + break; + case 'h': usage(NULL); default: @@ -272,11 +301,11 @@ int main(int argc, char *argv[]) } } if (streq(inform, "dts")) - bi = dt_from_source(arg); + dti = dt_from_source(arg); else if (streq(inform, "fs")) - bi = dt_from_fs(arg); + dti = dt_from_fs(arg); else if(streq(inform, "dtb")) - bi = dt_from_blob(arg); + dti = dt_from_blob(arg); else die("Unknown input format \"%s\"\n", inform); @@ -286,13 +315,29 @@ int main(int argc, char *argv[]) } if (cmdline_boot_cpuid != -1) - bi->boot_cpuid_phys = cmdline_boot_cpuid; + dti->boot_cpuid_phys = cmdline_boot_cpuid; - fill_fullpaths(bi->dt, ""); - process_checks(force, bi); + fill_fullpaths(dti->dt, ""); + process_checks(force, dti); + + /* on a plugin, generate by default */ + if (dti->dtsflags & DTSF_PLUGIN) { + generate_fixups = 1; + } + + if (auto_label_aliases) + generate_label_tree(dti, "aliases", false); + + if (generate_symbols) + generate_label_tree(dti, "__symbols__", true); + + if (generate_fixups) { + generate_fixups_tree(dti, "__fixups__"); + generate_local_fixups_tree(dti, "__local_fixups__"); + } if (sort) - sort_tree(bi); + sort_tree(dti); if (streq(outname, "-")) { outf = stdout; @@ -304,11 +349,11 @@ int main(int argc, char *argv[]) } if (streq(outform, "dts")) { - dt_to_source(outf, bi); + dt_to_source(outf, dti); } else if (streq(outform, "dtb")) { - dt_to_blob(outf, bi, outversion); + dt_to_blob(outf, dti, outversion); } else if (streq(outform, "asm")) { - dt_to_asm(outf, bi, outversion); + dt_to_asm(outf, dti, outversion); } else if (streq(outform, "null")) { /* do nothing */ } else { diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 56212c8df660..c6f125c68ba8 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -53,7 +53,11 @@ extern int quiet; /* Level of quietness */ extern int reservenum; /* Number of memory reservation slots */ extern int minsize; /* Minimum blob size */ extern int padsize; /* Additional padding to blob */ +extern int alignsize; /* Additional padding to blob accroding to the alignsize */ extern int phandle_format; /* Use linux,phandle or phandle properties */ +extern int generate_symbols; /* generate symbols for nodes with labels */ +extern int generate_fixups; /* generate fixups */ +extern int auto_label_aliases; /* auto generate labels -> aliases */ #define PHANDLE_LEGACY 0x1 #define PHANDLE_EPAPR 0x2 @@ -201,6 +205,8 @@ void delete_property(struct property *prop); void add_child(struct node *parent, struct node *child); void delete_node_by_name(struct node *parent, char *name); void delete_node(struct node *node); +void append_to_property(struct node *node, + char *name, const void *data, int len); const char *get_unitname(struct node *node); struct property *get_property(struct node *node, const char *propname); @@ -235,35 +241,44 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, struct reserve_info *new); -struct boot_info { +struct dt_info { + unsigned int dtsflags; struct reserve_info *reservelist; - struct node *dt; /* the device tree */ uint32_t boot_cpuid_phys; + struct node *dt; /* the device tree */ }; -struct boot_info *build_boot_info(struct reserve_info *reservelist, - struct node *tree, uint32_t boot_cpuid_phys); -void sort_tree(struct boot_info *bi); +/* DTS version flags definitions */ +#define DTSF_V1 0x0001 /* /dts-v1/ */ +#define DTSF_PLUGIN 0x0002 /* /plugin/ */ + +struct dt_info *build_dt_info(unsigned int dtsflags, + struct reserve_info *reservelist, + struct node *tree, uint32_t boot_cpuid_phys); +void sort_tree(struct dt_info *dti); +void generate_label_tree(struct dt_info *dti, char *name, bool allocph); +void generate_fixups_tree(struct dt_info *dti, char *name); +void generate_local_fixups_tree(struct dt_info *dti, char *name); /* Checks */ void parse_checks_option(bool warn, bool error, const char *arg); -void process_checks(bool force, struct boot_info *bi); +void process_checks(bool force, struct dt_info *dti); /* Flattened trees */ -void dt_to_blob(FILE *f, struct boot_info *bi, int version); -void dt_to_asm(FILE *f, struct boot_info *bi, int version); +void dt_to_blob(FILE *f, struct dt_info *dti, int version); +void dt_to_asm(FILE *f, struct dt_info *dti, int version); -struct boot_info *dt_from_blob(const char *fname); +struct dt_info *dt_from_blob(const char *fname); /* Tree source */ -void dt_to_source(FILE *f, struct boot_info *bi); -struct boot_info *dt_from_source(const char *f); +void dt_to_source(FILE *f, struct dt_info *dti); +struct dt_info *dt_from_source(const char *f); /* FS trees */ -struct boot_info *dt_from_fs(const char *dirname); +struct dt_info *dt_from_fs(const char *dirname); #endif /* _DTC_H */ diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index ec14954f5810..ebac548b3fa8 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -366,7 +366,7 @@ static void make_fdt_header(struct fdt_header *fdt, fdt->size_dt_struct = cpu_to_fdt32(dtsize); } -void dt_to_blob(FILE *f, struct boot_info *bi, int version) +void dt_to_blob(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; int i; @@ -384,29 +384,36 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version) if (!vi) die("Unknown device tree blob version %d\n", version); - flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi); + flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi); bin_emit_cell(&dtbuf, FDT_END); - reservebuf = flatten_reserve_list(bi->reservelist, vi); + reservebuf = flatten_reserve_list(dti->reservelist, vi); /* Make header */ make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len, - bi->boot_cpuid_phys); + dti->boot_cpuid_phys); /* * If the user asked for more space than is used, adjust the totalsize. */ if (minsize > 0) { padlen = minsize - fdt32_to_cpu(fdt.totalsize); - if ((padlen < 0) && (quiet < 1)) - fprintf(stderr, - "Warning: blob size %d >= minimum size %d\n", - fdt32_to_cpu(fdt.totalsize), minsize); + if (padlen < 0) { + padlen = 0; + if (quiet < 1) + fprintf(stderr, + "Warning: blob size %d >= minimum size %d\n", + fdt32_to_cpu(fdt.totalsize), minsize); + } } if (padsize > 0) padlen = padsize; + if (alignsize > 0) + padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize) + - fdt32_to_cpu(fdt.totalsize); + if (padlen > 0) { int tsize = fdt32_to_cpu(fdt.totalsize); tsize += padlen; @@ -460,7 +467,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) } } -void dt_to_asm(FILE *f, struct boot_info *bi, int version) +void dt_to_asm(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; int i; @@ -500,7 +507,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) if (vi->flags & FTF_BOOTCPUID) { fprintf(f, "\t/* boot_cpuid_phys */\n"); - asm_emit_cell(f, bi->boot_cpuid_phys); + asm_emit_cell(f, dti->boot_cpuid_phys); } if (vi->flags & FTF_STRTABSIZE) { @@ -530,7 +537,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) * Use .long on high and low halfs of u64s to avoid .quad * as it appears .quad isn't available in some assemblers. */ - for (re = bi->reservelist; re; re = re->next) { + for (re = dti->reservelist; re; re = re->next) { struct label *l; for_each_label(re->labels, l) { @@ -550,7 +557,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n"); emit_label(f, symprefix, "struct_start"); - flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi); + flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi); fprintf(f, "\t/* FDT_END */\n"); asm_emit_cell(f, FDT_END); @@ -572,6 +579,8 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) if (padsize > 0) { fprintf(f, "\t.space\t%d, 0\n", padsize); } + if (alignsize > 0) + asm_emit_align(f, alignsize); emit_label(f, symprefix, "blob_abs_end"); data_free(strbuf); @@ -797,11 +806,15 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, } } while (val != FDT_END_NODE); + if (node->name != flatname) { + free(flatname); + } + return node; } -struct boot_info *dt_from_blob(const char *fname) +struct dt_info *dt_from_blob(const char *fname) { FILE *f; uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys; @@ -929,5 +942,5 @@ struct boot_info *dt_from_blob(const char *fname) fclose(f); - return build_boot_info(reservelist, tree, boot_cpuid_phys); + return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys); } diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c index 6d1beec9581d..ae7d06c3c492 100644 --- a/scripts/dtc/fstree.c +++ b/scripts/dtc/fstree.c @@ -79,13 +79,12 @@ static struct node *read_fstree(const char *dirname) return tree; } -struct boot_info *dt_from_fs(const char *dirname) +struct dt_info *dt_from_fs(const char *dirname) { struct node *tree; tree = read_fstree(dirname); tree = name_node(tree, ""); - return build_boot_info(NULL, tree, guess_boot_cpuid(tree)); + return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree)); } - diff --git a/scripts/dtc/libfdt/Makefile.libfdt b/scripts/dtc/libfdt/Makefile.libfdt index 09c322ed82ba..098b3f36e668 100644 --- a/scripts/dtc/libfdt/Makefile.libfdt +++ b/scripts/dtc/libfdt/Makefile.libfdt @@ -7,5 +7,5 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h LIBFDT_VERSION = version.lds LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \ - fdt_addresses.c + fdt_addresses.c fdt_overlay.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index 50cce864283c..3d00d2eee0e3 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -88,6 +88,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset, return (strlen(p) == len) && (memcmp(p, s, len) == 0); } +uint32_t fdt_get_max_phandle(const void *fdt) +{ + uint32_t max_phandle = 0; + int offset; + + for (offset = fdt_next_node(fdt, -1, NULL);; + offset = fdt_next_node(fdt, offset, NULL)) { + uint32_t phandle; + + if (offset == -FDT_ERR_NOTFOUND) + return max_phandle; + + if (offset < 0) + return (uint32_t)-1; + + phandle = fdt_get_phandle(fdt, offset); + if (phandle == (uint32_t)-1) + continue; + + if (phandle > max_phandle) + max_phandle = phandle; + } + + return 0; +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); @@ -545,7 +571,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) - return -length; + return length; end = list + length; @@ -571,7 +597,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) - return -length; + return length; len = strlen(string) + 1; end = list + length; diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 8be02b1f68f3..2eed4f58387c 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -191,17 +191,13 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) int fdt_del_mem_rsv(void *fdt, int n) { struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); - int err; FDT_RW_CHECK_HEADER(fdt); if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; - err = _fdt_splice_mem_rsv(fdt, re, 1, 0); - if (err) - return err; - return 0; + return _fdt_splice_mem_rsv(fdt, re, 1, 0); } static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, diff --git a/scripts/dtc/libfdt/fdt_strerror.c b/scripts/dtc/libfdt/fdt_strerror.c index e6c3ceee8c58..9677a1887e57 100644 --- a/scripts/dtc/libfdt/fdt_strerror.c +++ b/scripts/dtc/libfdt/fdt_strerror.c @@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADOFFSET), FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADPHANDLE), FDT_ERRTABENT(FDT_ERR_BADSTATE), FDT_ERRTABENT(FDT_ERR_TRUNCATED), @@ -76,6 +77,11 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADVERSION), FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_INTERNAL), + FDT_ERRTABENT(FDT_ERR_BADNCELLS), + FDT_ERRTABENT(FDT_ERR_BADVALUE), + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_NOPHANDLES), }; #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c index c5bbb68d3273..6aaab399929c 100644 --- a/scripts/dtc/libfdt/fdt_wip.c +++ b/scripts/dtc/libfdt/fdt_wip.c @@ -55,21 +55,42 @@ #include "libfdt_internal.h" -int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, - const void *val, int len) +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len) { void *propval; int proplen; - propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); + propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, + &proplen); + if (!propval) + return proplen; + + if (proplen < (len + idx)) + return -FDT_ERR_NOSPACE; + + memcpy((char *)propval + idx, val, len); + return 0; +} + +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + const void *propval; + int proplen; + + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); if (! propval) return proplen; if (proplen != len) return -FDT_ERR_NOSPACE; - memcpy(propval, val, len); - return 0; + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), 0, + val, len); } static void _fdt_nop_region(void *start, int len) diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index 59ca33976e56..b842b156fa17 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -61,7 +61,7 @@ #define FDT_ERR_NOTFOUND 1 /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ #define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attemped to create a node or property which + /* FDT_ERR_EXISTS: Attempted to create a node or property which * already exists */ #define FDT_ERR_NOSPACE 3 /* FDT_ERR_NOSPACE: Operation needed to expand the device @@ -79,8 +79,10 @@ * (e.g. missing a leading / for a function which requires an * absolute path) */ #define FDT_ERR_BADPHANDLE 6 - /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle - * value. phandle values of 0 and -1 are not permitted. */ + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. + * This can be caused either by an invalid phandle property + * length, or the phandle value was either 0 or -1, which are + * not permitted. */ #define FDT_ERR_BADSTATE 7 /* FDT_ERR_BADSTATE: Function was passed an incomplete device * tree created by the sequential-write functions, which is @@ -126,7 +128,16 @@ * value. For example: a property expected to contain a string list * is not NUL-terminated within the length of its value. */ -#define FDT_ERR_MAX 15 +#define FDT_ERR_BADOVERLAY 16 + /* FDT_ERR_BADOVERLAY: The device tree overlay, while + * correctly structured, cannot be applied due to some + * unexpected or missing value, property or node. */ + +#define FDT_ERR_NOPHANDLES 17 + /* FDT_ERR_NOPHANDLES: The device tree doesn't have any + * phandle available anymore without causing an overflow */ + +#define FDT_ERR_MAX 17 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ @@ -168,27 +179,55 @@ int fdt_first_subnode(const void *fdt, int offset); */ int fdt_next_subnode(const void *fdt, int offset); +/** + * fdt_for_each_subnode - iterate over all subnodes of a parent + * + * @node: child node (int, lvalue) + * @fdt: FDT blob (const void *) + * @parent: parent node (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_subnode(node, fdt, parent) { + * Use node + * ... + * } + * + * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and @node is used as + * iterator in the loop. The parent variable be constant or even a + * literal. + * + */ +#define fdt_for_each_subnode(node, fdt, parent) \ + for (node = fdt_first_subnode(fdt, parent); \ + node >= 0; \ + node = fdt_next_subnode(fdt, node)) + /**********************************************************************/ /* General functions */ /**********************************************************************/ #define fdt_get_header(fdt, field) \ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) #define fdt_version(fdt) (fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) #define __fdt_set_hdr(name) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \ { \ - struct fdt_header *fdth = (struct fdt_header*)fdt; \ + struct fdt_header *fdth = (struct fdt_header *)fdt; \ fdth->name = cpu_to_fdt32(val); \ } __fdt_set_hdr(magic); @@ -258,6 +297,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize); */ const char *fdt_string(const void *fdt, int stroffset); +/** + * fdt_get_max_phandle - retrieves the highest phandle in a tree + * @fdt: pointer to the device tree blob + * + * fdt_get_max_phandle retrieves the highest phandle in the given + * device tree. This will ignore badly formatted phandles, or phandles + * with a value of 0 or -1. + * + * returns: + * the highest phandle on success + * 0, if no phandle was found in the device tree + * -1, if an error occurred + */ +uint32_t fdt_get_max_phandle(const void *fdt); + /** * fdt_num_mem_rsv - retrieve the number of memory reserve map entries * @fdt: pointer to the device tree blob @@ -318,8 +372,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, * returns: * structure block offset of the requested subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -351,7 +406,8 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); * address). * * returns: - * structure block offset of the node with the requested path (>=0), on success + * structure block offset of the node with the requested path (>=0), on + * success * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid * -FDT_ERR_NOTFOUND, if the requested node does not exist * -FDT_ERR_BADMAGIC, @@ -375,10 +431,12 @@ int fdt_path_offset(const void *fdt, const char *path); * * returns: * pointer to the node's name, on success - * If lenp is non-NULL, *lenp contains the length of that name (>=0) + * If lenp is non-NULL, *lenp contains the length of that name + * (>=0) * NULL, on error * if lenp is non-NULL *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings @@ -426,6 +484,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset); */ int fdt_next_property_offset(const void *fdt, int offset); +/** + * fdt_for_each_property_offset - iterate over all properties of a node + * + * @property_offset: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_property_offset(property, fdt, node) { + * Use property + * ... + * } + * + * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and property is used as + * iterator in the loop. The node variable can be constant or even a + * literal. + */ +#define fdt_for_each_property_offset(property, fdt, node) \ + for (property = fdt_first_property_offset(fdt, node); \ + property >= 0; \ + property = fdt_next_property_offset(fdt, property)) + /** * fdt_get_property_by_offset - retrieve the property at a given offset * @fdt: pointer to the device tree blob @@ -490,7 +575,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -554,6 +640,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); +static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, + const char *name, int namelen, + int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, + namelen, lenp); +} /** * fdt_getprop - retrieve the value of a given property @@ -575,7 +668,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -617,7 +711,7 @@ const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen); /** - * fdt_get_alias - retreive the path referenced by a given alias + * fdt_get_alias - retrieve the path referenced by a given alias * @fdt: pointer to the device tree blob * @name: name of the alias th look up * @@ -647,7 +741,7 @@ const char *fdt_get_alias(const void *fdt, const char *name); * 0, on success * buf contains the absolute path of the node at * nodeoffset, as a NUL-terminated string. - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) * characters and will not fit in the given buffer. * -FDT_ERR_BADMAGIC, @@ -677,11 +771,11 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); * structure from the start to nodeoffset. * * returns: - * structure block offset of the node at node offset's ancestor * of depth supernodedepth (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag -* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of + * nodeoffset * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -703,7 +797,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, * * returns: * depth of the node at nodeoffset (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -726,7 +820,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset); * returns: * structure block offset of the parent of the node at nodeoffset * (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -766,7 +860,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset); * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -813,7 +907,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); * 1, if the node has a 'compatible' property, but it does not list * the given string * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property - * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -850,7 +944,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -960,7 +1054,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #address-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -980,7 +1075,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #size-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -994,6 +1090,27 @@ int fdt_size_cells(const void *fdt, int nodeoffset); /* Write-in-place functions */ /**********************************************************************/ +/** + * fdt_setprop_inplace_namelen_partial - change a property's value, + * but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: number of characters of name to consider + * @idx: index of the property to change in the array + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * Identical to fdt_setprop_inplace(), but modifies the given property + * starting from the given index, and using only the first characters + * of the name. It is useful when you want to manipulate only one value of + * an array and you have a string that doesn't end with \0. + */ +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len); + /** * fdt_setprop_inplace - change a property's value, but not its size * @fdt: pointer to the device tree blob @@ -1604,9 +1721,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * change the offsets of some existing nodes. * returns: - * structure block offset of the created nodeequested subnode (>=0), on success + * structure block offset of the created nodeequested subnode (>=0), on + * success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of * the given name * -FDT_ERR_NOSPACE, if there is insufficient free space in the @@ -1644,6 +1763,37 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); */ int fdt_del_node(void *fdt, int nodeoffset); +/** + * fdt_overlay_apply - Applies a DT overlay on a base DT + * @fdt: pointer to the base device tree blob + * @fdto: pointer to the device tree overlay blob + * + * fdt_overlay_apply() will apply the given device tree overlay on the + * given base device tree. + * + * Expect the base device tree to be modified, even if the function + * returns an error. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there's not enough space in the base device tree + * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or + * properties in the base DT + * -FDT_ERR_BADPHANDLE, + * -FDT_ERR_BADOVERLAY, + * -FDT_ERR_NOPHANDLES, + * -FDT_ERR_INTERNAL, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, + * -FDT_ERR_BADPATH, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_overlay_apply(void *fdt, void *fdto); + /**********************************************************************/ /* Debugging / informational functions */ /**********************************************************************/ diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h index 9dea97dfff81..99f936dacc60 100644 --- a/scripts/dtc/libfdt/libfdt_env.h +++ b/scripts/dtc/libfdt/libfdt_env.h @@ -54,6 +54,7 @@ #include #include +#include #include #ifdef __CHECKER__ diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index e229b84432f9..afa2f67b142a 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -204,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) } } - /* if no collision occured, add child to the old node. */ + /* if no collision occurred, add child to the old node. */ if (new_child) add_child(old_node, new_child); } @@ -296,6 +296,23 @@ void delete_node(struct node *node) delete_labels(&node->labels); } +void append_to_property(struct node *node, + char *name, const void *data, int len) +{ + struct data d; + struct property *p; + + p = get_property(node, name); + if (p) { + d = data_append_data(p->val, data, len); + p->val = d; + } else { + d = data_append_data(empty_data, data, len); + p = build_property(name, d); + add_property(node, p); + } +} + struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) { struct reserve_info *new = xmalloc(sizeof(*new)); @@ -335,17 +352,19 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, return list; } -struct boot_info *build_boot_info(struct reserve_info *reservelist, - struct node *tree, uint32_t boot_cpuid_phys) +struct dt_info *build_dt_info(unsigned int dtsflags, + struct reserve_info *reservelist, + struct node *tree, uint32_t boot_cpuid_phys) { - struct boot_info *bi; + struct dt_info *dti; - bi = xmalloc(sizeof(*bi)); - bi->reservelist = reservelist; - bi->dt = tree; - bi->boot_cpuid_phys = boot_cpuid_phys; + dti = xmalloc(sizeof(*dti)); + dti->dtsflags = dtsflags; + dti->reservelist = reservelist; + dti->dt = tree; + dti->boot_cpuid_phys = boot_cpuid_phys; - return bi; + return dti; } /* @@ -592,12 +611,12 @@ static int cmp_reserve_info(const void *ax, const void *bx) return 0; } -static void sort_reserve_entries(struct boot_info *bi) +static void sort_reserve_entries(struct dt_info *dti) { struct reserve_info *ri, **tbl; int n = 0, i = 0; - for (ri = bi->reservelist; + for (ri = dti->reservelist; ri; ri = ri->next) n++; @@ -607,14 +626,14 @@ static void sort_reserve_entries(struct boot_info *bi) tbl = xmalloc(n * sizeof(*tbl)); - for (ri = bi->reservelist; + for (ri = dti->reservelist; ri; ri = ri->next) tbl[i++] = ri; qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); - bi->reservelist = tbl[0]; + dti->reservelist = tbl[0]; for (i = 0; i < (n-1); i++) tbl[i]->next = tbl[i+1]; tbl[n-1]->next = NULL; @@ -704,8 +723,256 @@ static void sort_node(struct node *node) sort_node(c); } -void sort_tree(struct boot_info *bi) +void sort_tree(struct dt_info *dti) { - sort_reserve_entries(bi); - sort_node(bi->dt); + sort_reserve_entries(dti); + sort_node(dti->dt); +} + +/* utility helper to avoid code duplication */ +static struct node *build_and_name_child_node(struct node *parent, char *name) +{ + struct node *node; + + node = build_node(NULL, NULL); + name_node(node, xstrdup(name)); + add_child(parent, node); + + return node; +} + +static struct node *build_root_node(struct node *dt, char *name) +{ + struct node *an; + + an = get_subnode(dt, name); + if (!an) + an = build_and_name_child_node(dt, name); + + if (!an) + die("Could not build root node /%s\n", name); + + return an; +} + +static bool any_label_tree(struct dt_info *dti, struct node *node) +{ + struct node *c; + + if (node->labels) + return true; + + for_each_child(node, c) + if (any_label_tree(dti, c)) + return true; + + return false; +} + +static void generate_label_tree_internal(struct dt_info *dti, + struct node *an, struct node *node, + bool allocph) +{ + struct node *dt = dti->dt; + struct node *c; + struct property *p; + struct label *l; + + /* if there are labels */ + if (node->labels) { + + /* now add the label in the node */ + for_each_label(node->labels, l) { + + /* check whether the label already exists */ + p = get_property(an, l->label); + if (p) { + fprintf(stderr, "WARNING: label %s already" + " exists in /%s", l->label, + an->name); + continue; + } + + /* insert it */ + p = build_property(l->label, + data_copy_mem(node->fullpath, + strlen(node->fullpath) + 1)); + add_property(an, p); + } + + /* force allocation of a phandle for this node */ + if (allocph) + (void)get_node_phandle(dt, node); + } + + for_each_child(node, c) + generate_label_tree_internal(dti, an, c, allocph); +} + +static bool any_fixup_tree(struct dt_info *dti, struct node *node) +{ + struct node *c; + struct property *prop; + struct marker *m; + + for_each_property(node, prop) { + m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + if (!get_node_by_ref(dti->dt, m->ref)) + return true; + } + } + + for_each_child(node, c) { + if (any_fixup_tree(dti, c)) + return true; + } + + return false; +} + +static void add_fixup_entry(struct dt_info *dti, struct node *fn, + struct node *node, struct property *prop, + struct marker *m) +{ + char *entry; + + /* m->ref can only be a REF_PHANDLE, but check anyway */ + assert(m->type == REF_PHANDLE); + + /* there shouldn't be any ':' in the arguments */ + if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) + die("arguments should not contain ':'\n"); + + xasprintf(&entry, "%s:%s:%u", + node->fullpath, prop->name, m->offset); + append_to_property(fn, m->ref, entry, strlen(entry) + 1); +} + +static void generate_fixups_tree_internal(struct dt_info *dti, + struct node *fn, + struct node *node) +{ + struct node *dt = dti->dt; + struct node *c; + struct property *prop; + struct marker *m; + struct node *refnode; + + for_each_property(node, prop) { + m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + refnode = get_node_by_ref(dt, m->ref); + if (!refnode) + add_fixup_entry(dti, fn, node, prop, m); + } + } + + for_each_child(node, c) + generate_fixups_tree_internal(dti, fn, c); +} + +static bool any_local_fixup_tree(struct dt_info *dti, struct node *node) +{ + struct node *c; + struct property *prop; + struct marker *m; + + for_each_property(node, prop) { + m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + if (get_node_by_ref(dti->dt, m->ref)) + return true; + } + } + + for_each_child(node, c) { + if (any_local_fixup_tree(dti, c)) + return true; + } + + return false; +} + +static void add_local_fixup_entry(struct dt_info *dti, + struct node *lfn, struct node *node, + struct property *prop, struct marker *m, + struct node *refnode) +{ + struct node *wn, *nwn; /* local fixup node, walk node, new */ + uint32_t value_32; + char **compp; + int i, depth; + + /* walk back retreiving depth */ + depth = 0; + for (wn = node; wn; wn = wn->parent) + depth++; + + /* allocate name array */ + compp = xmalloc(sizeof(*compp) * depth); + + /* store names in the array */ + for (wn = node, i = depth - 1; wn; wn = wn->parent, i--) + compp[i] = wn->name; + + /* walk the path components creating nodes if they don't exist */ + for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { + /* if no node exists, create it */ + nwn = get_subnode(wn, compp[i]); + if (!nwn) + nwn = build_and_name_child_node(wn, compp[i]); + } + + free(compp); + + value_32 = cpu_to_fdt32(m->offset); + append_to_property(wn, prop->name, &value_32, sizeof(value_32)); +} + +static void generate_local_fixups_tree_internal(struct dt_info *dti, + struct node *lfn, + struct node *node) +{ + struct node *dt = dti->dt; + struct node *c; + struct property *prop; + struct marker *m; + struct node *refnode; + + for_each_property(node, prop) { + m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + refnode = get_node_by_ref(dt, m->ref); + if (refnode) + add_local_fixup_entry(dti, lfn, node, prop, m, refnode); + } + } + + for_each_child(node, c) + generate_local_fixups_tree_internal(dti, lfn, c); +} + +void generate_label_tree(struct dt_info *dti, char *name, bool allocph) +{ + if (!any_label_tree(dti, dti->dt)) + return; + generate_label_tree_internal(dti, build_root_node(dti->dt, name), + dti->dt, allocph); +} + +void generate_fixups_tree(struct dt_info *dti, char *name) +{ + if (!any_fixup_tree(dti, dti->dt)) + return; + generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), + dti->dt); +} + +void generate_local_fixups_tree(struct dt_info *dti, char *name) +{ + if (!any_local_fixup_tree(dti, dti->dt)) + return; + generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), + dti->dt); } diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index f534c22a888d..aa3aad04cec4 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -246,46 +246,27 @@ srcpos_copy(struct srcpos *pos) return pos_new; } - - -void -srcpos_dump(struct srcpos *pos) -{ - printf("file : \"%s\"\n", - pos->file ? (char *) pos->file : ""); - printf("first_line : %d\n", pos->first_line); - printf("first_column: %d\n", pos->first_column); - printf("last_line : %d\n", pos->last_line); - printf("last_column : %d\n", pos->last_column); - printf("file : %s\n", pos->file->name); -} - - char * srcpos_string(struct srcpos *pos) { const char *fname = ""; char *pos_str; - int rc; if (pos) fname = pos->file->name; if (pos->first_line != pos->last_line) - rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname, - pos->first_line, pos->first_column, - pos->last_line, pos->last_column); + xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname, + pos->first_line, pos->first_column, + pos->last_line, pos->last_column); else if (pos->first_column != pos->last_column) - rc = asprintf(&pos_str, "%s:%d.%d-%d", fname, - pos->first_line, pos->first_column, - pos->last_column); + xasprintf(&pos_str, "%s:%d.%d-%d", fname, + pos->first_line, pos->first_column, + pos->last_column); else - rc = asprintf(&pos_str, "%s:%d.%d", fname, - pos->first_line, pos->first_column); - - if (rc == -1) - die("Couldn't allocate in srcpos string"); + xasprintf(&pos_str, "%s:%d.%d", fname, + pos->first_line, pos->first_column); return pos_str; } diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h index f81827bd684a..2cdfcd82e95e 100644 --- a/scripts/dtc/srcpos.h +++ b/scripts/dtc/srcpos.h @@ -105,7 +105,6 @@ extern struct srcpos srcpos_empty; extern void srcpos_update(struct srcpos *pos, const char *text, int len); extern struct srcpos *srcpos_copy(struct srcpos *pos); extern char *srcpos_string(struct srcpos *pos); -extern void srcpos_dump(struct srcpos *pos); extern void srcpos_verror(struct srcpos *pos, const char *prefix, const char *fmt, va_list va) diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index a55d1d128cce..c9d8967969f9 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -25,12 +25,12 @@ extern FILE *yyin; extern int yyparse(void); extern YYLTYPE yylloc; -struct boot_info *the_boot_info; +struct dt_info *parser_output; bool treesource_error; -struct boot_info *dt_from_source(const char *fname) +struct dt_info *dt_from_source(const char *fname) { - the_boot_info = NULL; + parser_output = NULL; treesource_error = false; srcfile_push(fname); @@ -43,7 +43,7 @@ struct boot_info *dt_from_source(const char *fname) if (treesource_error) die("Syntax error parsing input tree\n"); - return the_boot_info; + return parser_output; } static void write_prefix(FILE *f, int level) @@ -263,13 +263,13 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level) } -void dt_to_source(FILE *f, struct boot_info *bi) +void dt_to_source(FILE *f, struct dt_info *dti) { struct reserve_info *re; fprintf(f, "/dts-v1/;\n\n"); - for (re = bi->reservelist; re; re = re->next) { + for (re = dti->reservelist; re; re = re->next) { struct label *l; for_each_label(re->labels, l) @@ -279,6 +279,6 @@ void dt_to_source(FILE *f, struct boot_info *bi) (unsigned long long)re->re.size); } - write_tree_source_node(f, bi->dt, 0); + write_tree_source_node(f, dti->dt, 0); } diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index fb124eea4919..3550f86bd6df 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -46,6 +46,36 @@ char *xstrdup(const char *s) return d; } +/* based in part from (3) vsnprintf */ +int xasprintf(char **strp, const char *fmt, ...) +{ + int n, size = 128; /* start with 128 bytes */ + char *p; + va_list ap; + + /* initial pointer is NULL making the fist realloc to be malloc */ + p = NULL; + while (1) { + p = xrealloc(p, size); + + /* Try to print in the allocated space. */ + va_start(ap, fmt); + n = vsnprintf(p, size, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (n > -1 && n < size) + break; + /* Else try again with more space. */ + if (n > -1) /* glibc 2.1 */ + size = n + 1; /* precisely what is needed */ + else /* glibc 2.0 */ + size *= 2; /* twice the old size */ + } + *strp = p; + return strlen(p); +} + char *join_path(const char *path, const char *name) { int lenp = strlen(path); diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index f800b6011fb1..f5c4f1b50d30 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -59,6 +59,7 @@ static inline void *xrealloc(void *p, size_t len) } extern char *xstrdup(const char *s); +extern int xasprintf(char **strp, const char *fmt, ...); extern char *join_path(const char *path, const char *name); /** diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index ad9b05ae698b..16c2e53a85e3 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.4.1-g53bf130b" +#define DTC_VERSION "DTC 1.4.2-g0931cea3" From e59efd01149a6368ce0196761eee892e2ef5df48 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 2 Nov 2017 12:14:00 +0100 Subject: [PATCH 138/266] FROMLIST: MIPS: math-emu: Remove an unnecessary header inclusion Remove an unnecessary header inclusion of "ieee754dp.h". Signed-off-by: Aleksandar Markovic (cherry picked from: https://patchwork.linux-mips.org/patch/17583/) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/sp_tlong.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/math-emu/sp_tlong.c b/arch/mips/math-emu/sp_tlong.c index a2450c7e452a..bca5ac995801 100644 --- a/arch/mips/math-emu/sp_tlong.c +++ b/arch/mips/math-emu/sp_tlong.c @@ -20,7 +20,6 @@ */ #include "ieee754sp.h" -#include "ieee754dp.h" s64 ieee754sp_tlong(union ieee754sp x) { From c18976613cf09e54cb85314e0402e63fc74d3161 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 2 Nov 2017 12:14:01 +0100 Subject: [PATCH 139/266] FROMLIST: MIPS: math-emu: Avoid definition duplication for macro DPXMULT() Avoid duplicate definition of macro DPXMULT(). Move its definition to a header. Signed-off-by: Aleksandar Markovic (cherry picked from: https://patchwork.linux-mips.org/patch/17584/) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 3 --- arch/mips/math-emu/dp_mul.c | 3 --- arch/mips/math-emu/ieee754dp.h | 3 +++ 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 7ad79ed411f5..28b90fd3e093 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -201,9 +201,6 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, * Multiply 64 bits xm and ym to give 128 bits result in hrm:lrm. */ - /* 32 * 32 => 64 */ -#define DPXMULT(x, y) ((u64)(x) * (u64)y) - lxm = xm; hxm = xm >> 32; lym = ym; diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index 60c8bfe40947..7bc5dde8e746 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c @@ -128,9 +128,6 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) * Multiply 64 bits xm, ym to give high 64 bits rm with stickness. */ - /* 32 * 32 => 64 */ -#define DPXMULT(x, y) ((u64)(x) * (u64)y) - lxm = xm; hxm = xm >> 32; lym = ym; diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h index 9ba023004eb6..a56707b75282 100644 --- a/arch/mips/math-emu/ieee754dp.h +++ b/arch/mips/math-emu/ieee754dp.h @@ -55,6 +55,9 @@ static inline int ieee754dp_finite(union ieee754dp x) #define XDPSRS1(v) \ (((v) >> 1) | ((v) & 1)) +/* 32bit * 32bit => 64bit unsigned integer multiplication */ +#define DPXMULT(x, y) ((u64)(x) * (u64)y) + /* convert denormal to normalized with extended exponent */ #define DPDNORMx(m,e) \ while ((m >> DP_FBITS) == 0) { m <<= 1; e--; } From 0d0e0871fd4f7fb4a6feeb00ac9993c83504c384 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 2 Nov 2017 12:14:02 +0100 Subject: [PATCH 140/266] FROMLIST: MIPS: math-emu: Declare function srl128() as static Declare function srl128() as static, since it it used just locally to the source file. This also removes a sparse warning for corresponding file. Signed-off-by: Aleksandar Markovic (cherry picked from: https://patchwork.linux-mips.org/patch/17585/) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/dp_maddf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 28b90fd3e093..5c4ad8e32fcb 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -16,7 +16,7 @@ /* 128 bits shift right logical with rounding. */ -void srl128(u64 *hptr, u64 *lptr, int count) +static void srl128(u64 *hptr, u64 *lptr, int count) { u64 low; From 7ac185315bf0b2a42b70ad55e5030667bd81ce91 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 2 Nov 2017 12:14:03 +0100 Subject: [PATCH 141/266] FROMLIST: MIPS: math-emu: Avoid an assignment within if statement condition Move invocation of fpu_emu() to be out of if statement condition. This makes code easier to follow and debug, and fixes a checkpatch warning. Signed-off-by: Aleksandar Markovic (cherry picked from: https://patchwork.linux-mips.org/patch/17586/) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index cd0f6c06147c..18ea0b076818 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1354,7 +1354,8 @@ branch_common: return SIGILL; /* a real fpu computation instruction */ - if ((sig = fpu_emu(xcp, ctx, ir))) + sig = fpu_emu(xcp, ctx, ir); + if (sig) return sig; } break; From 4ca35deb836b3b6879016d864266932abe9dc704 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 2 Nov 2017 12:14:04 +0100 Subject: [PATCH 142/266] FROMLIST: MIPS: math-emu: Avoid multiple assignment Replace several instances of multiple assignment with individual assignments. Signed-off-by: Aleksandar Markovic (cherry picked from: https://patchwork.linux-mips.org/patch/17587/) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 3 ++- arch/mips/math-emu/dp_sqrt.c | 6 ++++-- arch/mips/math-emu/sp_sqrt.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 18ea0b076818..42947a16adb9 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1191,7 +1191,8 @@ emul: if (!cpu_has_mips_r6 || delay_slot(xcp)) return SIGILL; - cond = likely = 0; + likely = 0; + cond = 0; fpr = ¤t->thread.fpu.fpr[MIPSInst_RT(ir)]; bit0 = get_fpr32(fpr, 0) & 0x1; switch (MIPSInst_RS(ir)) { diff --git a/arch/mips/math-emu/dp_sqrt.c b/arch/mips/math-emu/dp_sqrt.c index cea907b83146..fa39eb84ba8b 100644 --- a/arch/mips/math-emu/dp_sqrt.c +++ b/arch/mips/math-emu/dp_sqrt.c @@ -91,7 +91,8 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x) scalx -= 256; } - y = x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); + x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); + y = x; /* magic initial approximation to almost 8 sig. bits */ yh = y.bits >> 32; @@ -108,7 +109,8 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x) /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */ /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */ - z = t = ieee754dp_mul(y, y); + t = ieee754dp_mul(y, y); + z = t; t.bexp += 0x001; t = ieee754dp_add(t, z); z = ieee754dp_mul(ieee754dp_sub(x, z), y); diff --git a/arch/mips/math-emu/sp_sqrt.c b/arch/mips/math-emu/sp_sqrt.c index 67059c33a250..9cc83f012342 100644 --- a/arch/mips/math-emu/sp_sqrt.c +++ b/arch/mips/math-emu/sp_sqrt.c @@ -82,7 +82,8 @@ union ieee754sp ieee754sp_sqrt(union ieee754sp x) /* generate sqrt(x) bit by bit */ ix += ix; - q = s = 0; /* q = sqrt(x) */ + s = 0; + q = 0; /* q = sqrt(x) */ r = 0x01000000; /* r = moving bit from right to left */ while (r != 0) { From fcc1a32d69d5fc0e62583bf47ceaa8668d9911d6 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 2 Nov 2017 12:14:05 +0100 Subject: [PATCH 143/266] FROMLIST: MIPS: math-emu: Mark fall throughs in switch statements with a comment Mark intentional fall throughs in switch statements with a consistent comment. In most of the cases, a new comment line containing text "fall through" is inserted. In some of the cases, existing comment contained a variation of the text "fall through" (for example, "FALL THROUGH" or "drop through"). In such cases, the existing comment is modified to contain "fall through". Lastly, in two cases, code segments were described in comments as "fall througs", but were in reality "breaks out" of switch statement. In such cases, existing comments are accordingly modified. Apart from making code easier to follow and debug, this change enables some static code analysers to interpret newly inserted comments as their annotations (and, therefore, not issue warnings of type "fall through in switch statement", which is desireable, since marked fallthroughs are intentional). Signed-off-by: Aleksandar Markovic (cherry picked from: https://patchwork.linux-mips.org/patch/17588/) Signed-off-by: Greg Kroah-Hartman --- arch/mips/math-emu/cp1emu.c | 22 +++++++++++++++------- arch/mips/math-emu/dp_add.c | 3 +-- arch/mips/math-emu/dp_div.c | 1 + arch/mips/math-emu/dp_fmax.c | 2 ++ arch/mips/math-emu/dp_fmin.c | 2 ++ arch/mips/math-emu/dp_maddf.c | 3 ++- arch/mips/math-emu/dp_mul.c | 1 + arch/mips/math-emu/dp_sqrt.c | 2 +- arch/mips/math-emu/dp_sub.c | 2 +- arch/mips/math-emu/sp_add.c | 3 +-- arch/mips/math-emu/sp_div.c | 1 + arch/mips/math-emu/sp_fdp.c | 3 ++- arch/mips/math-emu/sp_fmax.c | 2 ++ arch/mips/math-emu/sp_fmin.c | 2 ++ arch/mips/math-emu/sp_maddf.c | 3 ++- arch/mips/math-emu/sp_mul.c | 1 + arch/mips/math-emu/sp_sub.c | 1 + 17 files changed, 38 insertions(+), 16 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 42947a16adb9..ebb5e3bfe12a 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -452,7 +452,7 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, regs->cp0_epc + dec_insn.pc_inc + dec_insn.next_pc_inc; } - /* Fall through */ + /* fall through */ case jr_op: /* For R6, JR already emulated in jalr_op */ if (NO_R6EMU && insn.r_format.func == jr_op) @@ -472,10 +472,11 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, regs->regs[31] = regs->cp0_epc + dec_insn.pc_inc + dec_insn.next_pc_inc; - /* Fall through */ + /* fall through */ case bltzl_op: if (NO_R6EMU) break; + /* fall through */ case bltz_op: if ((long)regs->regs[insn.i_format.rs] < 0) *contpc = regs->cp0_epc + @@ -495,10 +496,11 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, regs->regs[31] = regs->cp0_epc + dec_insn.pc_inc + dec_insn.next_pc_inc; - /* Fall through */ + /* fall through */ case bgezl_op: if (NO_R6EMU) break; + /* fall through */ case bgez_op: if ((long)regs->regs[insn.i_format.rs] >= 0) *contpc = regs->cp0_epc + @@ -513,11 +515,12 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, break; case jalx_op: set_isa16_mode(bit); + /* fall through */ case jal_op: regs->regs[31] = regs->cp0_epc + dec_insn.pc_inc + dec_insn.next_pc_inc; - /* Fall through */ + /* fall through */ case j_op: *contpc = regs->cp0_epc + dec_insn.pc_inc; *contpc >>= 28; @@ -529,6 +532,7 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case beql_op: if (NO_R6EMU) break; + /* fall through */ case beq_op: if (regs->regs[insn.i_format.rs] == regs->regs[insn.i_format.rt]) @@ -543,6 +547,7 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case bnel_op: if (NO_R6EMU) break; + /* fall through */ case bne_op: if (regs->regs[insn.i_format.rs] != regs->regs[insn.i_format.rt]) @@ -557,6 +562,7 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case blezl_op: if (!insn.i_format.rt && NO_R6EMU) break; + /* fall through */ case blez_op: /* @@ -594,6 +600,7 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case bgtzl_op: if (!insn.i_format.rt && NO_R6EMU) break; + /* fall through */ case bgtz_op: /* * Compact branches for R6 for the @@ -730,7 +737,8 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, return 1; } - /* R2/R6 compatible cop1 instruction. Fall through */ + /* R2/R6 compatible cop1 instruction */ + /* fall through */ case cop2_op: case cop1x_op: if (insn.i_format.rs == bc_op) { @@ -1222,14 +1230,14 @@ emul: case bcfl_op: if (cpu_has_mips_2_3_4_5_r) likely = 1; - /* Fall through */ + /* fall through */ case bcf_op: cond = !cond; break; case bctl_op: if (cpu_has_mips_2_3_4_5_r) likely = 1; - /* Fall through */ + /* fall through */ case bct_op: break; } diff --git a/arch/mips/math-emu/dp_add.c b/arch/mips/math-emu/dp_add.c index 8954ef031f84..678de20e4cb1 100644 --- a/arch/mips/math-emu/dp_add.c +++ b/arch/mips/math-emu/dp_add.c @@ -104,8 +104,7 @@ union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; - - /* FALL THROUGH */ + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): DPDNORMY; diff --git a/arch/mips/math-emu/dp_div.c b/arch/mips/math-emu/dp_div.c index f4746f7c5f63..3063ae3ab3b9 100644 --- a/arch/mips/math-emu/dp_div.c +++ b/arch/mips/math-emu/dp_div.c @@ -103,6 +103,7 @@ union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): DPDNORMY; diff --git a/arch/mips/math-emu/dp_fmax.c b/arch/mips/math-emu/dp_fmax.c index 5bec64f2884e..d1f984b40344 100644 --- a/arch/mips/math-emu/dp_fmax.c +++ b/arch/mips/math-emu/dp_fmax.c @@ -96,6 +96,7 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): DPDNORMY; @@ -224,6 +225,7 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): DPDNORMY; diff --git a/arch/mips/math-emu/dp_fmin.c b/arch/mips/math-emu/dp_fmin.c index a287b23818d8..f98b96135c8d 100644 --- a/arch/mips/math-emu/dp_fmin.c +++ b/arch/mips/math-emu/dp_fmin.c @@ -96,6 +96,7 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): DPDNORMY; @@ -224,6 +225,7 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): DPDNORMY; diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 5c4ad8e32fcb..7ea2f8222026 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -157,6 +157,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): if (zc == IEEE754_CLASS_INF) @@ -173,7 +174,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): if (zc == IEEE754_CLASS_INF) return ieee754dp_inf(zs); - /* fall through to real computations */ + /* continue to real computations */ } /* Finally get to do some computation */ diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index 7bc5dde8e746..c34a6cdf1b25 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c @@ -101,6 +101,7 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): DPDNORMY; diff --git a/arch/mips/math-emu/dp_sqrt.c b/arch/mips/math-emu/dp_sqrt.c index fa39eb84ba8b..1d26c92e5295 100644 --- a/arch/mips/math-emu/dp_sqrt.c +++ b/arch/mips/math-emu/dp_sqrt.c @@ -142,7 +142,7 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x) switch (oldcsr.rm) { case FPU_CSR_RU: y.bits += 1; - /* drop through */ + /* fall through */ case FPU_CSR_RN: t.bits += 1; break; diff --git a/arch/mips/math-emu/dp_sub.c b/arch/mips/math-emu/dp_sub.c index fc17a781b9ae..3cc48b86519b 100644 --- a/arch/mips/math-emu/dp_sub.c +++ b/arch/mips/math-emu/dp_sub.c @@ -106,7 +106,7 @@ union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; - /* FALL THROUGH */ + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): /* normalize ym,ye */ diff --git a/arch/mips/math-emu/sp_add.c b/arch/mips/math-emu/sp_add.c index c55c0c00bca8..51dced9fbdaf 100644 --- a/arch/mips/math-emu/sp_add.c +++ b/arch/mips/math-emu/sp_add.c @@ -104,8 +104,7 @@ union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; - - /* FALL THROUGH */ + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): SPDNORMY; diff --git a/arch/mips/math-emu/sp_div.c b/arch/mips/math-emu/sp_div.c index 23587b31ca87..5d2904960eb8 100644 --- a/arch/mips/math-emu/sp_div.c +++ b/arch/mips/math-emu/sp_div.c @@ -103,6 +103,7 @@ union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): SPDNORMY; diff --git a/arch/mips/math-emu/sp_fdp.c b/arch/mips/math-emu/sp_fdp.c index 5060e8fdcb0b..36a50f9082d1 100644 --- a/arch/mips/math-emu/sp_fdp.c +++ b/arch/mips/math-emu/sp_fdp.c @@ -46,7 +46,8 @@ union ieee754sp ieee754sp_fdp(union ieee754dp x) case IEEE754_CLASS_SNAN: x = ieee754dp_nanxcpt(x); EXPLODEXDP; - /* Fall through. */ + /* fall through */ + case IEEE754_CLASS_QNAN: y = ieee754sp_nan_fdp(xs, xm); if (!ieee754_csr.nan2008) { diff --git a/arch/mips/math-emu/sp_fmax.c b/arch/mips/math-emu/sp_fmax.c index 74a5a00d2f22..22019ed691df 100644 --- a/arch/mips/math-emu/sp_fmax.c +++ b/arch/mips/math-emu/sp_fmax.c @@ -96,6 +96,7 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): SPDNORMY; @@ -224,6 +225,7 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): SPDNORMY; diff --git a/arch/mips/math-emu/sp_fmin.c b/arch/mips/math-emu/sp_fmin.c index c51385f46b09..feaec3985cca 100644 --- a/arch/mips/math-emu/sp_fmin.c +++ b/arch/mips/math-emu/sp_fmin.c @@ -96,6 +96,7 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): SPDNORMY; @@ -224,6 +225,7 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): SPDNORMY; diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index f823338dbb65..07ba675401e2 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -126,6 +126,7 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): if (zc == IEEE754_CLASS_INF) @@ -142,7 +143,7 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): if (zc == IEEE754_CLASS_INF) return ieee754sp_inf(zs); - /* fall through to real computations */ + /* continue to real computations */ } /* Finally get to do some computation */ diff --git a/arch/mips/math-emu/sp_mul.c b/arch/mips/math-emu/sp_mul.c index 4015101fbc37..fde71e293ec4 100644 --- a/arch/mips/math-emu/sp_mul.c +++ b/arch/mips/math-emu/sp_mul.c @@ -101,6 +101,7 @@ union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): SPDNORMY; diff --git a/arch/mips/math-emu/sp_sub.c b/arch/mips/math-emu/sp_sub.c index dc998ed47295..9f2ff72c3d6b 100644 --- a/arch/mips/math-emu/sp_sub.c +++ b/arch/mips/math-emu/sp_sub.c @@ -106,6 +106,7 @@ union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; + /* fall through */ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): SPDNORMY; From 22904b58933d0d2cfe3e9c0014d02a198320a5c9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 19 Jan 2018 16:40:48 +0100 Subject: [PATCH 144/266] FROMLIST: dt-bindings: Document mti,mips-cpc binding Document a binding for the MIPS Cluster Power Controller (CPC) that allows the device tree to specify where the CPC registers are located. Signed-off-by: Paul Burton Signed-off-by: Aleksandar Markovic Reviewed-by: Rob Herring (cherry picked from: https://patchwork.linux-mips.org/patch/18512/) Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/power/mti,mips-cpc.txt | 8 ++++++++ MAINTAINERS | 1 + 2 files changed, 9 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/mti,mips-cpc.txt diff --git a/Documentation/devicetree/bindings/power/mti,mips-cpc.txt b/Documentation/devicetree/bindings/power/mti,mips-cpc.txt new file mode 100644 index 000000000000..c6b82511ae8a --- /dev/null +++ b/Documentation/devicetree/bindings/power/mti,mips-cpc.txt @@ -0,0 +1,8 @@ +Binding for MIPS Cluster Power Controller (CPC). + +This binding allows a system to specify where the CPC registers are +located. + +Required properties: +compatible : Should be "mti,mips-cpc". +regs: Should describe the address & size of the CPC register region. diff --git a/MAINTAINERS b/MAINTAINERS index 46da781dae65..f5e6e92ec41b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7075,6 +7075,7 @@ MIPS GENERIC PLATFORM M: Paul Burton L: linux-mips@linux-mips.org S: Supported +F: Documentation/devicetree/bindings/power/mti,mips-cpc.txt F: arch/mips/generic/ MIPS RINT INSTRUCTION EMULATION From 5bf8bba0f178a4687035494a3ab995548df2e792 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 19 Jan 2018 16:40:49 +0100 Subject: [PATCH 145/266] FROMLIST: MIPS: CPC: Map registers using DT in mips_cpc_default_phys_base() Reading mips_cpc_base value from the DT allows each platform to define it according to its needs. This is especially convenient for MIPS_GENERIC kernel where this kind of information should be determined in runtime. Use mti,mips-cpc compatible string with just a reg property to specify the register location for your platform. Signed-off-by: Paul Burton Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic (cherry picked from: https://patchwork.linux-mips.org/patch/18513/) Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mips-cpc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index b232caf4d53c..3491ee05737c 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -23,6 +25,17 @@ static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); phys_addr_t __weak mips_cpc_default_phys_base(void) { + struct device_node *cpc_node; + struct resource res; + int err; + + cpc_node = of_find_compatible_node(of_root, NULL, "mti,mips-cpc"); + if (cpc_node) { + err = of_address_to_resource(cpc_node, 0, &res); + if (!err) + return res.start; + } + return 0; } From d4d732cfa4afe151563662e7ec9ef99e08ebd5a3 Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Tue, 9 Jan 2018 12:57:16 +0100 Subject: [PATCH 146/266] FROMLIST: MIPS: Add noexec=on|off kernel parameter Add a new kernel parameter to override the default behavior related to the decision whether to indicate stack as non-executable or executable (regardless of PT_GNU_STACK entry or CPU RIXI support) in function mips_elf_read_implies_exec(). Allowed values: noexec=on: force indicating non-exec stack & heap noexec=off: force indicating executable stack & heap If this parameter is omitted, kernel behavior remains the same as it was before this patch is applied. This functionality is convenient during debugging and is especially useful for Android development where indication of non-executable stack is required. NOTE: Using noexec=on on a system without CPU XI support is not recommended since there is no actual HW support that provide non-executable stack and heap. Use only for debugging purposes and not in a production environment. Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic (cherry picked from: https://patchwork.linux-mips.org/patch/18218/) Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 19 ++++++++++++ arch/mips/kernel/elf.c | 48 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e2072d12693b..6ae512fb4488 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2470,6 +2470,25 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noexec=on: enable non-executable mappings (default) noexec=off: disable non-executable mappings + noexec [MIPS] + Force indicating stack and heap as non-executable or + executable regardless of PT_GNU_STACK entry or CPU XI + (execute inhibit) support. Valid valuess are: on, off. + noexec=on: force indicating non-executable + stack and heap + noexec=off: force indicating executable + stack and heap + If this parameter is omitted, stack and heap will be + indicated non-executable or executable as they are + actually set up, which depends on PT_GNU_STACK entry + and possibly other factors (for instance, CPU XI + support). + NOTE: Using noexec=on on a system without CPU XI + support is not recommended since there is no actual + HW support that provide non-executable stack/heap. + Use only for debugging purposes and not in a + production environment. + nosmap [X86] Disable SMAP (Supervisor Mode Access Prevention) even if it is supported by processor. diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 2aaa0825e56d..624e15dbd405 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -330,8 +330,56 @@ void mips_set_personality_nan(struct arch_elf_state *state) } } +static int noexec = EXSTACK_DEFAULT; + +/* + * kernel parameter: noexec=on|off + * + * Force indicating stack and heap as non-executable or + * executable regardless of PT_GNU_STACK entry or CPU XI + * (execute inhibit) support. Valid valuess are: on, off. + * + * noexec=on: force indicating non-executable + * stack and heap + * noexec=off: force indicating executable + * stack and heap + * + * If this parameter is omitted, stack and heap will be + * indicated non-executable or executable as they are + * actually set up, which depends on PT_GNU_STACK entry + * and possibly other factors (for instance, CPU XI + * support). + * + * NOTE: Using noexec=on on a system without CPU XI + * support is not recommended since there is no actual + * HW support that provide non-executable stack/heap. + * Use only for debugging purposes and not in a + * production environment. + */ +static int __init noexec_setup(char *str) +{ + if (!strcmp(str, "on")) + noexec = EXSTACK_DISABLE_X; + else if (!strcmp(str, "off")) + noexec = EXSTACK_ENABLE_X; + else + pr_err("Malformed noexec format! noexec=on|off\n"); + + return 1; +} +__setup("noexec=", noexec_setup); + int mips_elf_read_implies_exec(void *elf_ex, int exstack) { + switch (noexec) { + case EXSTACK_DISABLE_X: + return 0; + case EXSTACK_ENABLE_X: + return 1; + default: + break; + } + if (exstack != EXSTACK_DISABLE_X) { /* The binary doesn't request a non-executable stack */ return 1; From 0bc65cbcc33545f1718ea8a98272be931780271b Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Fri, 29 Dec 2017 16:41:47 +0100 Subject: [PATCH 147/266] FROMLIST: MIPS: ranchu: Add Ranchu as a new generic-based board Provide amendments to the MIPS generic platform framework so that the new generic-based board Ranchu can be chosen to be built. The Ranchu board is intended to be used by Android emulator. The name "Ranchu" originates from Android development community. "Goldfish" and "Ranchu" are terms used for two generations of virtual boards used by Android emulator. The name "Ranchu" is a newer one among the two, and this patch deals with Ranchu. However, for historical reasons, some devices/drivers still contain the name "Goldfish". MIPS Ranchu machine includes a number of Goldfish devices. The support for Virtio devices is also included. Ranchu board supports up to 16 Virtio devices which can be attached using Virtio MMIO Bus. This is summarized in the following picture: ABUS ||----MIPS CPU || | IRQs ||----Goldfish PIC------------(32)-------- || | | | | | | | | | ||----Goldfish TTY------ | | | | | | | | || | | | | | | | | ||----Goldfish RTC-------- | | | | | | | || | | | | | | | ||----Goldfish FB----------- | | | | | | || | | | | | | ||----Goldfish Events--------- | | | | | || | | | | | ||----Goldfish Audio------------ | | | | || | | | | ||----Goldfish Battery------------ | | | || | | | ||----Android PIPE------------------ | | || | | ||----Virtio MMIO Bus | | || | | | | | || | | (virtio-block)--------- | || (16) | | || | (virtio-net)------------------ Device Tree is created on the QEMU side based on the information about devices IO map and IRQ numbers. Kernel will load this DTB using UHI boot protocol DTB handover mode. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Reviewed-by: James Hogan (cherry picked from: https://patchwork.linux-mips.org/patch/18138/) Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 7 ++ arch/mips/configs/generic/board-ranchu.config | 30 ++++++ arch/mips/generic/Kconfig | 10 ++ arch/mips/generic/Makefile | 2 + arch/mips/generic/board-ranchu.c | 92 +++++++++++++++++++ 5 files changed, 141 insertions(+) create mode 100644 arch/mips/configs/generic/board-ranchu.config create mode 100644 arch/mips/generic/board-ranchu.c diff --git a/MAINTAINERS b/MAINTAINERS index f5e6e92ec41b..8368ad504c57 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8887,6 +8887,13 @@ S: Maintained F: Documentation/blockdev/ramdisk.txt F: drivers/block/brd.c +RANCHU VIRTUAL BOARD FOR MIPS +M: Miodrag Dinic +L: linux-mips@linux-mips.org +S: Supported +F: arch/mips/generic/board-ranchu.c +F: arch/mips/configs/generic/board-ranchu.config + RANDOM NUMBER DRIVER M: "Theodore Ts'o" S: Maintained diff --git a/arch/mips/configs/generic/board-ranchu.config b/arch/mips/configs/generic/board-ranchu.config new file mode 100644 index 000000000000..fee9ad4c5598 --- /dev/null +++ b/arch/mips/configs/generic/board-ranchu.config @@ -0,0 +1,30 @@ +CONFIG_VIRT_BOARD_RANCHU=y + +CONFIG_BATTERY_GOLDFISH=y +CONFIG_FB=y +CONFIG_FB_GOLDFISH=y +CONFIG_GOLDFISH=y +CONFIG_STAGING=y +CONFIG_GOLDFISH_AUDIO=y +CONFIG_GOLDFISH_PIC=y +CONFIG_GOLDFISH_PIPE=y +CONFIG_GOLDFISH_TTY=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_GOLDFISH=y + +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_GOLDFISH_EVENTS=y + +CONFIG_MAGIC_SYSRQ=y +CONFIG_POWER_SUPPLY=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y + +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_NETDEVICES=y +CONFIG_VIRTIO_NET=y diff --git a/arch/mips/generic/Kconfig b/arch/mips/generic/Kconfig index baddb0646b23..80e1c72dfd50 100644 --- a/arch/mips/generic/Kconfig +++ b/arch/mips/generic/Kconfig @@ -9,4 +9,14 @@ config LEGACY_BOARDS kernel is booted without being provided with an FDT via the UHI boot protocol. +config VIRT_BOARD_RANCHU + bool "Support Ranchu platform for Android emulator" + help + This enables support for the platform used by Android emulator. + + Ranchu platform consists of a set of virtual devices. This platform + enables emulation of variety of virtual configurations while using + Android emulator. Android emulator is based on Qemu, and contains + the support for the same set of virtual devices. + endif diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile index 26e64207f7ad..bdaa5b22dc36 100644 --- a/arch/mips/generic/Makefile +++ b/arch/mips/generic/Makefile @@ -11,3 +11,5 @@ obj-y += init.o obj-y += irq.o obj-y += proc.o + +obj-$(CONFIG_VIRT_BOARD_RANCHU) += board-ranchu.o diff --git a/arch/mips/generic/board-ranchu.c b/arch/mips/generic/board-ranchu.c new file mode 100644 index 000000000000..ea451b89bb53 --- /dev/null +++ b/arch/mips/generic/board-ranchu.c @@ -0,0 +1,92 @@ +/* + * Support code for virtual Ranchu board for MIPS. + * + * Author: Miodrag Dinic + * + * 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 +#include + +#include +#include +#include + +#define GOLDFISH_TIMER_LOW 0x00 +#define GOLDFISH_TIMER_HIGH 0x04 + +static __init u64 read_rtc_time(void __iomem *base) +{ + u32 time_low; + u32 time_high; + + /* + * Reading the low address latches the high value + * as well so there is no fear that we may read + * inaccurate high value. + */ + time_low = readl(base + GOLDFISH_TIMER_LOW); + time_high = readl(base + GOLDFISH_TIMER_HIGH); + + return ((u64)time_high << 32) | time_low; +} + +static __init unsigned int ranchu_measure_hpt_freq(void) +{ + u64 rtc_start, rtc_current, rtc_delta; + unsigned int start, count; + struct device_node *np; + void __iomem *rtc_base; + + np = of_find_compatible_node(NULL, NULL, "google,goldfish-rtc"); + if (!np) + panic("%s(): Failed to find 'google,goldfish-rtc' dt node!", + __func__); + + rtc_base = of_iomap(np, 0); + if (!rtc_base) + panic("%s(): Failed to ioremap Goldfish RTC base!", __func__); + + /* + * Poll the nanosecond resolution RTC for one + * second to calibrate the CPU frequency. + */ + rtc_start = read_rtc_time(rtc_base); + start = read_c0_count(); + + do { + rtc_current = read_rtc_time(rtc_base); + rtc_delta = rtc_current - rtc_start; + } while (rtc_delta < NSEC_PER_SEC); + + count = read_c0_count() - start; + + /* + * Make sure the frequency will be a round number. + * Without this correction, the returned value may vary + * between subsequent emulation executions. + * + * TODO: Set this value using device tree. + */ + count += 5000; + count -= count % 10000; + + iounmap(rtc_base); + + return count; +} + +static const struct of_device_id ranchu_of_match[] __initconst = { + { + .compatible = "mti,ranchu", + }, +}; + +MIPS_MACHINE(ranchu) = { + .matches = ranchu_of_match, + .measure_hpt_freq = ranchu_measure_hpt_freq, +}; From 8c74f4c80eb5e8cbc0a985a46353d57d2bab36a8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 30 Nov 2017 09:16:31 +0100 Subject: [PATCH 148/266] FROMLIST: tty: goldfish: Enable 'earlycon' only if built-in Commit 3840ed9548f7 ("tty: goldfish: Implement support for kernel 'earlycon' parameter") breaks an allmodconfig config on x86: | LD vmlinux.o | MODPOST vmlinux.o |drivers/tty/serial/earlycon.o: In function `parse_options': |drivers/tty/serial/earlycon.c:97: undefined reference to `uart_parse_earlycon' |Makefile:1005: recipe for target 'vmlinux' failed earlycon.c::parse_options() invokes uart_parse_earlycon() from serial_core.c which is compiled=m because GOLDFISH_TTY itself (and most others) are =m. To avoid that, I'm adding the _CONSOLE config option which is selected if the GOLDFISH module itself is =y since it doesn't need the early bits for the =m case (other drivers do the same dance). The alternative would be to move uart_parse_earlycon() from serial_core.c to earlycon.c (we don't have that many users of that function). Fixes: 3840ed9548f7 ("tty: goldfish: Implement support for kernel 'earlycon' parameter") Signed-off-by: Sebastian Andrzej Siewior (cherry picked from: https://patchwork.kernel.org/patch/10084429/) Signed-off-by: Greg Kroah-Hartman --- drivers/tty/Kconfig | 6 +++++- drivers/tty/goldfish.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index cadfc5f370f1..331bfc4fbd80 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -405,10 +405,14 @@ config GOLDFISH_TTY depends on GOLDFISH select SERIAL_CORE select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON help Console and system TTY driver for the Goldfish virtual platform. +config GOLDFISH_TTY_EARLY_CONSOLE + bool + default y if GOLDFISH_TTY=y + select SERIAL_EARLYCON + config DA_TTY bool "DA TTY" depends on METAG_DA diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 41c701401f71..c6ec9e64451b 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -442,6 +442,7 @@ static int goldfish_tty_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE static void gf_early_console_putchar(struct uart_port *port, int ch) { __raw_writel(ch, port->membase); @@ -465,6 +466,7 @@ static int __init gf_earlycon_setup(struct earlycon_device *device, } OF_EARLYCON_DECLARE(early_gf_tty, "google,goldfish-tty", gf_earlycon_setup); +#endif static const struct of_device_id goldfish_tty_of_match[] = { { .compatible = "google,goldfish-tty", }, From 938ae27ff3ddd142f1a97bc9a0404cfc2b17ff94 Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Mon, 5 Feb 2018 10:29:37 +0100 Subject: [PATCH 149/266] ANDROID: MIPS: Add ranchu[32r5|32r6|64]_defconfig Change-Id: I6faf54a3c0ebd1dbb97494b0f6e96202460ee648 Signed-off-by: Miodrag Dinic Signed-off-by: Greg Kroah-Hartman --- arch/mips/configs/ranchu32r5_defconfig | 314 ++++++++++++++++++++++++ arch/mips/configs/ranchu32r6_defconfig | 313 ++++++++++++++++++++++++ arch/mips/configs/ranchu64_defconfig | 315 +++++++++++++++++++++++++ arch/mips/configs/ranchu_defconfig | 312 ++++++++++++++++++++++++ 4 files changed, 1254 insertions(+) create mode 100644 arch/mips/configs/ranchu32r5_defconfig create mode 100644 arch/mips/configs/ranchu32r6_defconfig create mode 100644 arch/mips/configs/ranchu64_defconfig create mode 100644 arch/mips/configs/ranchu_defconfig diff --git a/arch/mips/configs/ranchu32r5_defconfig b/arch/mips/configs/ranchu32r5_defconfig new file mode 100644 index 000000000000..62287a910a12 --- /dev/null +++ b/arch/mips/configs/ranchu32r5_defconfig @@ -0,0 +1,314 @@ +CONFIG_MIPS_GENERIC=y +CONFIG_VIRT_BOARD_RANCHU=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_CPU_MIPS32_R2=y +CONFIG_MIPS_CPS=y +CONFIG_CPU_HAS_MSA=y +CONFIG_HIGHMEM=y +CONFIG_KSM=y +CONFIG_CMA=y +CONFIG_NR_CPUS=16 +CONFIG_PREEMPT=y +CONFIG_MIPS_O32_FP64_SUPPORT=y +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_CGROUP=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_USERFAULTFD=y +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_INET_ESP=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_DNS_RESOLVER=y +CONFIG_CFG80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_VIRTIO_BLK=y +CONFIG_SCSI=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_TUN=y +CONFIG_VIRTIO_NET=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GOLDFISH_EVENTS=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_GOLDFISH_TTY=y +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_BATTERY_GOLDFISH=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +# CONFIG_HWMON is not set +CONFIG_MEDIA_SUPPORT=y +CONFIG_FB=y +CONFIG_FB_GOLDFISH=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_SUPPORT is not set +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_GOLDFISH=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_SYNC=y +CONFIG_ION=y +CONFIG_GOLDFISH_AUDIO=y +CONFIG_GOLDFISH_SYNC=y +# CONFIG_MIPS_PLATFORM_DEVICES is not set +CONFIG_GOLDFISH=y +CONFIG_GOLDFISH_PIPE=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_GOLDFISH_PIC=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_FANOTIFY=y +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y +CONFIG_SDCARD_FS=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_REDUCED=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_FTRACE is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon" +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set diff --git a/arch/mips/configs/ranchu32r6_defconfig b/arch/mips/configs/ranchu32r6_defconfig new file mode 100644 index 000000000000..4df031b26a5d --- /dev/null +++ b/arch/mips/configs/ranchu32r6_defconfig @@ -0,0 +1,313 @@ +CONFIG_MIPS_GENERIC=y +CONFIG_VIRT_BOARD_RANCHU=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_CPU_MIPS32_R6=y +CONFIG_MIPS_CPS=y +CONFIG_CPU_HAS_MSA=y +CONFIG_HIGHMEM=y +CONFIG_KSM=y +CONFIG_CMA=y +CONFIG_NR_CPUS=16 +CONFIG_PREEMPT=y +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_CGROUP=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_USERFAULTFD=y +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_INET_ESP=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_DNS_RESOLVER=y +CONFIG_CFG80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_VIRTIO_BLK=y +CONFIG_SCSI=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_TUN=y +CONFIG_VIRTIO_NET=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GOLDFISH_EVENTS=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_GOLDFISH_TTY=y +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_BATTERY_GOLDFISH=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +# CONFIG_HWMON is not set +CONFIG_MEDIA_SUPPORT=y +CONFIG_FB=y +CONFIG_FB_GOLDFISH=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_SUPPORT is not set +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_GOLDFISH=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_SYNC=y +CONFIG_ION=y +CONFIG_GOLDFISH_AUDIO=y +CONFIG_GOLDFISH_SYNC=y +# CONFIG_MIPS_PLATFORM_DEVICES is not set +CONFIG_GOLDFISH=y +CONFIG_GOLDFISH_PIPE=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_GOLDFISH_PIC=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_FANOTIFY=y +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y +CONFIG_SDCARD_FS=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_REDUCED=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_FTRACE is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon" +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set diff --git a/arch/mips/configs/ranchu64_defconfig b/arch/mips/configs/ranchu64_defconfig new file mode 100644 index 000000000000..35ff3534441c --- /dev/null +++ b/arch/mips/configs/ranchu64_defconfig @@ -0,0 +1,315 @@ +CONFIG_MIPS_GENERIC=y +CONFIG_VIRT_BOARD_RANCHU=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_CPU_MIPS64_R6=y +CONFIG_64BIT=y +CONFIG_MIPS_CPS=y +CONFIG_CPU_HAS_MSA=y +CONFIG_KSM=y +CONFIG_CMA=y +CONFIG_NR_CPUS=16 +CONFIG_PREEMPT=y +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_CGROUP=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_USERFAULTFD=y +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_MIPS32_O32=y +CONFIG_MIPS32_N32=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_INET_ESP=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_DNS_RESOLVER=y +CONFIG_CFG80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_VIRTIO_BLK=y +CONFIG_SCSI=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_TUN=y +CONFIG_VIRTIO_NET=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GOLDFISH_EVENTS=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_GOLDFISH_TTY=y +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_BATTERY_GOLDFISH=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +# CONFIG_HWMON is not set +CONFIG_MEDIA_SUPPORT=y +CONFIG_FB=y +CONFIG_FB_GOLDFISH=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_SUPPORT is not set +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_GOLDFISH=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_SYNC=y +CONFIG_ION=y +CONFIG_GOLDFISH_AUDIO=y +CONFIG_GOLDFISH_SYNC=y +# CONFIG_MIPS_PLATFORM_DEVICES is not set +CONFIG_GOLDFISH=y +CONFIG_GOLDFISH_PIPE=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_GOLDFISH_PIC=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_FANOTIFY=y +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y +CONFIG_SDCARD_FS=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_REDUCED=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_FTRACE is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon" +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set diff --git a/arch/mips/configs/ranchu_defconfig b/arch/mips/configs/ranchu_defconfig new file mode 100644 index 000000000000..266a11b66c78 --- /dev/null +++ b/arch/mips/configs/ranchu_defconfig @@ -0,0 +1,312 @@ +CONFIG_MIPS_GENERIC=y +CONFIG_VIRT_BOARD_RANCHU=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_MIPS_CPS=y +CONFIG_HIGHMEM=y +CONFIG_KSM=y +CONFIG_CMA=y +CONFIG_NR_CPUS=16 +CONFIG_PREEMPT=y +CONFIG_MIPS_O32_FP64_SUPPORT=y +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_CGROUP=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_USERFAULTFD=y +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_INET_ESP=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_DNS_RESOLVER=y +CONFIG_CFG80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_VIRTIO_BLK=y +CONFIG_SCSI=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_TUN=y +CONFIG_VIRTIO_NET=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GOLDFISH_EVENTS=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_GOLDFISH_TTY=y +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_BATTERY_GOLDFISH=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +# CONFIG_HWMON is not set +CONFIG_MEDIA_SUPPORT=y +CONFIG_FB=y +CONFIG_FB_GOLDFISH=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_SUPPORT is not set +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_GOLDFISH=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_SYNC=y +CONFIG_ION=y +CONFIG_GOLDFISH_AUDIO=y +CONFIG_GOLDFISH_SYNC=y +# CONFIG_MIPS_PLATFORM_DEVICES is not set +CONFIG_GOLDFISH=y +CONFIG_GOLDFISH_PIPE=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_GOLDFISH_PIC=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_FANOTIFY=y +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y +CONFIG_SDCARD_FS=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_REDUCED=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_FTRACE is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon noexec=on" +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set From 756df204117ba96c5f27be61caff2164fe05f015 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 11 Feb 2016 16:59:12 -0600 Subject: [PATCH 150/266] UPSTREAM: ARM: boot: Add an implementation of strnlen for libfdt Recent versions of libfdt add a dependency on strnlen. Copy the implementation in lib/string.c here, so we can update libfdt. Acked-by: Russell King Signed-off-by: Rob Herring Change-Id: I18ac2af16d541f99a3b0b39e51baa60fa57dd537 (cherry picked from commit 76df69806b7fafea013e2f4f82b0bd54498f3406) Signed-off-by: Amit Pundir --- arch/arm/boot/compressed/string.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/compressed/string.c b/arch/arm/boot/compressed/string.c index 36e53ef9200f..689467448736 100644 --- a/arch/arm/boot/compressed/string.c +++ b/arch/arm/boot/compressed/string.c @@ -65,6 +65,15 @@ size_t strlen(const char *s) return sc - s; } +size_t strnlen(const char *s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + int memcmp(const void *cs, const void *ct, size_t count) { const unsigned char *su1 = cs, *su2 = ct, *end = su1 + count; From 037d2374ce3ee79b7d1f8bed64dddbde0e18fc08 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 16 Feb 2016 11:16:31 +0100 Subject: [PATCH 151/266] UPSTREAM: arm64/efi: Make strnlen() available to the EFI namespace Changes introduced in the upstream version of libfdt pulled in by commit 91feabc2e224 ("scripts/dtc: Update to upstream commit b06e55c88b9b") use the strnlen() function, which isn't currently available to the EFI name- space. Add it to the EFI namespace to avoid a linker error. Cc: Catalin Marinas Cc: Rob Herring Reviewed-by: Ard Biesheuvel Signed-off-by: Thierry Reding Signed-off-by: Will Deacon (cherry picked from commit 7f4e346263f59ff50b531dda94609fb13ca12401) Signed-off-by: Amit Pundir --- arch/arm64/kernel/image.h | 1 + arch/arm64/lib/strnlen.S | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h index db1bf57948f1..5e360ce88f10 100644 --- a/arch/arm64/kernel/image.h +++ b/arch/arm64/kernel/image.h @@ -98,6 +98,7 @@ __efistub_memcpy = KALLSYMS_HIDE(__pi_memcpy); __efistub_memmove = KALLSYMS_HIDE(__pi_memmove); __efistub_memset = KALLSYMS_HIDE(__pi_memset); __efistub_strlen = KALLSYMS_HIDE(__pi_strlen); +__efistub_strnlen = KALLSYMS_HIDE(__pi_strnlen); __efistub_strcmp = KALLSYMS_HIDE(__pi_strcmp); __efistub_strncmp = KALLSYMS_HIDE(__pi_strncmp); __efistub___flush_dcache_area = KALLSYMS_HIDE(__pi___flush_dcache_area); diff --git a/arch/arm64/lib/strnlen.S b/arch/arm64/lib/strnlen.S index 2ca665711bf2..eae38da6e0bb 100644 --- a/arch/arm64/lib/strnlen.S +++ b/arch/arm64/lib/strnlen.S @@ -168,4 +168,4 @@ CPU_LE( lsr tmp2, tmp2, tmp4 ) /* Shift (tmp1 & 63). */ .Lhit_limit: mov len, limit ret -ENDPROC(strnlen) +ENDPIPROC(strnlen) From 810bdaf1dd747016fea5d5256530cf9ade05a4c9 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 5 Jan 2018 11:27:07 +0100 Subject: [PATCH 152/266] UPSTREAM: ANDROID: binder: remove waitqueue when thread exits. binder_poll() passes the thread->wait waitqueue that can be slept on for work. When a thread that uses epoll explicitly exits using BINDER_THREAD_EXIT, the waitqueue is freed, but it is never removed from the corresponding epoll data structure. When the process subsequently exits, the epoll cleanup code tries to access the waitlist, which results in a use-after-free. Prevent this by using POLLFREE when the thread exits. (cherry picked from commit f5cb779ba16334b45ba8946d6bfa6d9834d1527f) Change-Id: Ib34b1cbb8ab2192d78c3d9956b2f963a66ecad2e Signed-off-by: Martijn Coenen Reported-by: syzbot Cc: stable # 4.14 Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index b4a958e20c44..297b61689250 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4536,6 +4536,18 @@ static int binder_thread_release(struct binder_proc *proc, if (t) spin_lock(&t->lock); } + + /* + * If this thread used poll, make sure we remove the waitqueue + * from any epoll data structures holding it with POLLFREE. + * waitqueue_active() is safe to use here because we're holding + * the inner lock. + */ + if ((thread->looper & BINDER_LOOPER_STATE_POLL) && + waitqueue_active(&thread->wait)) { + wake_up_poll(&thread->wait, POLLHUP | POLLFREE); + } + binder_inner_proc_unlock(thread->proc); if (send_reply) From 6b8924e4899fbc1093f499338688ad446bd0a4c8 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Tue, 28 Nov 2017 18:22:11 -0800 Subject: [PATCH 153/266] ANDROID: qtaguid: Fix the UAF probelm with tag_ref_tree When multiple threads is trying to tag/delete the same socket at the same time, there is a chance the tag_ref_entry of the target socket to be null before the uid_tag_data entry is freed. It is caused by the ctrl_cmd_tag function where it doesn't correctly grab the spinlocks when tagging a socket. Signed-off-by: Chenbo Feng Bug: 65853158 Change-Id: I5d89885918054cf835370a52bff2d693362ac5f0 --- net/netfilter/xt_qtaguid.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index 6f5cdc5b505f..148c2917285c 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -519,13 +519,11 @@ static struct tag_ref *get_tag_ref(tag_t full_tag, DR_DEBUG("qtaguid: get_tag_ref(0x%llx)\n", full_tag); - spin_lock_bh(&uid_tag_data_tree_lock); tr_entry = lookup_tag_ref(full_tag, &utd_entry); BUG_ON(IS_ERR_OR_NULL(utd_entry)); if (!tr_entry) tr_entry = new_tag_ref(full_tag, utd_entry); - spin_unlock_bh(&uid_tag_data_tree_lock); if (utd_res) *utd_res = utd_entry; DR_DEBUG("qtaguid: get_tag_ref(0x%llx) utd=%p tr=%p\n", @@ -2021,6 +2019,7 @@ static int ctrl_cmd_delete(const char *input) /* Delete socket tags */ spin_lock_bh(&sock_tag_list_lock); + spin_lock_bh(&uid_tag_data_tree_lock); node = rb_first(&sock_tag_tree); while (node) { st_entry = rb_entry(node, struct sock_tag, sock_node); @@ -2050,6 +2049,7 @@ static int ctrl_cmd_delete(const char *input) list_del(&st_entry->list); } } + spin_unlock_bh(&uid_tag_data_tree_lock); spin_unlock_bh(&sock_tag_list_lock); sock_tag_tree_erase(&st_to_free_tree); @@ -2259,10 +2259,12 @@ static int ctrl_cmd_tag(const char *input) full_tag = combine_atag_with_uid(acct_tag, uid_int); spin_lock_bh(&sock_tag_list_lock); + spin_lock_bh(&uid_tag_data_tree_lock); sock_tag_entry = get_sock_stat_nl(el_socket->sk); tag_ref_entry = get_tag_ref(full_tag, &uid_tag_data_entry); if (IS_ERR(tag_ref_entry)) { res = PTR_ERR(tag_ref_entry); + spin_unlock_bh(&uid_tag_data_tree_lock); spin_unlock_bh(&sock_tag_list_lock); goto err_put; } @@ -2289,9 +2291,14 @@ static int ctrl_cmd_tag(const char *input) pr_err("qtaguid: ctrl_tag(%s): " "socket tag alloc failed\n", input); + BUG_ON(tag_ref_entry->num_sock_tags <= 0); + tag_ref_entry->num_sock_tags--; + free_tag_ref_from_utd_entry(tag_ref_entry, + uid_tag_data_entry); + spin_unlock_bh(&uid_tag_data_tree_lock); spin_unlock_bh(&sock_tag_list_lock); res = -ENOMEM; - goto err_tag_unref_put; + goto err_put; } /* * Hold the sk refcount here to make sure the sk pointer cannot @@ -2301,7 +2308,6 @@ static int ctrl_cmd_tag(const char *input) sock_tag_entry->sk = el_socket->sk; sock_tag_entry->pid = current->tgid; 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); /* @@ -2319,11 +2325,11 @@ static int ctrl_cmd_tag(const char *input) else list_add(&sock_tag_entry->list, &pqd_entry->sock_tag_list); - spin_unlock_bh(&uid_tag_data_tree_lock); sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree); atomic64_inc(&qtu_events.sockets_tagged); } + spin_unlock_bh(&uid_tag_data_tree_lock); spin_unlock_bh(&sock_tag_list_lock); /* We keep the ref to the sk until it is untagged */ CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->sk_refcnt=%d\n", @@ -2332,10 +2338,6 @@ static int ctrl_cmd_tag(const char *input) sockfd_put(el_socket); return 0; -err_tag_unref_put: - BUG_ON(tag_ref_entry->num_sock_tags <= 0); - tag_ref_entry->num_sock_tags--; - free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry); err_put: CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->sk_refcnt=%d\n", input, atomic_read(&el_socket->sk->sk_refcnt) - 1); From 0e9bcc1e0a16cde2514e19b744401f8d7c110cc9 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 17 Oct 2016 10:09:39 +0100 Subject: [PATCH 154/266] UPSTREAM: MIPS: Fix build of compressed image Changes introduced to arch/mips/Makefile for the generic kernel resulted in build errors when making a compressed image if platform-y has multiple values, like this: make[2]: *** No rule to make target `alchemy/'. make[1]: *** [vmlinuz] Error 2 make[1]: Target `_all' not remade because of errors. make: *** [sub-make] Error 2 make: Target `_all' not remade because of errors. Fix this by quoting $(platform-y) as it is passed to the Makefile in arch/mips/boot/compressed/Makefile Reported-by: kernelci.org bot Link: https://storage.kernelci.org/next/next-20161017/mips-gpr_defconfig/build.log Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14405/ Signed-off-by: Ralf Baechle (cherry picked from commit 818f38c5b7c4482abd71c64ac4d49911fbefaf9e) --- arch/mips/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index a13dc908224d..0e4516d631a6 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -264,7 +264,7 @@ KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0) bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) \ VMLINUX_ENTRY_ADDRESS=$(entry-y) \ - PLATFORM=$(platform-y) + PLATFORM="$(platform-y)" ifdef CONFIG_32BIT bootvars-y += ADDR_BITS=32 endif From 78d59f1aea624e2ac110773ac7bedd9d44b343b8 Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Wed, 24 Jan 2018 09:25:24 +0000 Subject: [PATCH 155/266] sched/fair: prevent possible infinite loop in sched_group_energy There is a race between hotplug and energy_diff which might result in endless loop in sched_group_energy. When this happens, the end condition cannot be detected. We can store how many CPUs we need to visit at the beginning, and bail out of the energy calculation if we visit more cpus than expected. Bug: 72311797 72202633 Change-Id: I8dda75468ee1570da4071cd8165ef5131a8205d8 Signed-off-by: Chris Redpath --- kernel/sched/fair.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 06e77d60a510..61f88665baf3 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5447,10 +5447,22 @@ static int sched_group_energy(struct energy_env *eenv) { struct cpumask visit_cpus; u64 total_energy = 0; + int cpu_count; WARN_ON(!eenv->sg_top->sge); cpumask_copy(&visit_cpus, sched_group_cpus(eenv->sg_top)); + /* If a cpu is hotplugged in while we are in this function, + * it does not appear in the existing visit_cpus mask + * which came from the sched_group pointer of the + * sched_domain pointed at by sd_ea for either the prev + * or next cpu and was dereferenced in __energy_diff. + * Since we will dereference sd_scs later as we iterate + * through the CPUs we expect to visit, new CPUs can + * be present which are not in the visit_cpus mask. + * Guard this with cpu_count. + */ + cpu_count = cpumask_weight(&visit_cpus); while (!cpumask_empty(&visit_cpus)) { struct sched_group *sg_shared_cap = NULL; @@ -5460,6 +5472,8 @@ static int sched_group_energy(struct energy_env *eenv) /* * Is the group utilization affected by cpus outside this * sched_group? + * This sd may have groups with cpus which were not present + * when we took visit_cpus. */ sd = rcu_dereference(per_cpu(sd_scs, cpu)); @@ -5509,8 +5523,24 @@ static int sched_group_energy(struct energy_env *eenv) total_energy += sg_busy_energy + sg_idle_energy; - if (!sd->child) + if (!sd->child) { + /* + * cpu_count here is the number of + * cpus we expect to visit in this + * calculation. If we race against + * hotplug, we can have extra cpus + * added to the groups we are + * iterating which do not appear in + * the visit_cpus mask. In that case + * we are not able to calculate energy + * without restarting so we will bail + * out and use prev_cpu this time. + */ + if (!cpu_count) + return -EINVAL; cpumask_xor(&visit_cpus, &visit_cpus, sched_group_cpus(sg)); + cpu_count--; + } if (cpumask_equal(sched_group_cpus(sg), sched_group_cpus(eenv->sg_top))) goto next_cpu; @@ -5522,6 +5552,9 @@ static int sched_group_energy(struct energy_env *eenv) * If we raced with hotplug and got an sd NULL-pointer; * returning a wrong energy estimation is better than * entering an infinite loop. + * Specifically: If a cpu is unplugged after we took + * the visit_cpus mask, it no longer has an sd_scs + * pointer, so when we dereference it, we get NULL. */ if (cpumask_test_cpu(cpu, &visit_cpus)) return -EINVAL; From 5e56f242721e98a18abc2436561a0e7ce44b4c85 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 25 Aug 2017 15:57:04 -0700 Subject: [PATCH 156/266] time: Fix ktime_get_raw() incorrect base accumulation In comqit fc6eead7c1e2 ("time: Clean up CLOCK_MONOTONIC_RAW time handling"), the following code got mistakenly added to the update of the raw timekeeper: /* Update the monotonic raw base */ seconds = tk->raw_sec; nsec = (u32)(tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift); tk->tkr_raw.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); Which adds the raw_sec value and the shifted down raw xtime_nsec to the base value. But the read function adds the shifted down tk->tkr_raw.xtime_nsec value another time, The result of this is that ktime_get_raw() users (which are all internal users) see the raw time move faster then it should (the rate at which can vary with the current size of tkr_raw.xtime_nsec), which has resulted in at least problems with graphics rendering performance. The change tried to match the monotonic base update logic: seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec); nsec = (u32) tk->wall_to_monotonic.tv_nsec; tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); Which adds the wall_to_monotonic.tv_nsec value, but not the tk->tkr_mono.xtime_nsec value to the base. To fix this, simplify the tkr_raw.base accumulation to only accumulate the raw_sec portion, and do not include the tkr_raw.xtime_nsec portion, which will be added at read time. Fixes: fc6eead7c1e2 ("time: Clean up CLOCK_MONOTONIC_RAW time handling") Reported-and-tested-by: Chris Wilson Signed-off-by: John Stultz Signed-off-by: Thomas Gleixner Cc: Prarit Bhargava Cc: Kevin Brodsky Cc: Richard Cochran Cc: Stephen Boyd Cc: Will Deacon Cc: Miroslav Lichvar Cc: Daniel Mentz Link: http://lkml.kernel.org/r/1503701824-1645-1-git-send-email-john.stultz@linaro.org (cherry picked from commit 0bcdc0987cce9880436b70836c6a92bb8e744fd1) Change-Id: I91d552bef42005d954f77963beafdca3cb6eb246 --- kernel/time/timekeeping.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index fc86fdcce932..7902ecbce8ec 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -633,9 +633,7 @@ static inline void tk_update_ktime_data(struct timekeeper *tk) tk->ktime_sec = seconds; /* Update the monotonic raw base */ - seconds = tk->raw_sec; - nsec = (u32)(tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift); - tk->tkr_raw.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); + tk->tkr_raw.base = ns_to_ktime(tk->raw_sec * NSEC_PER_SEC); } /* must hold timekeeper_lock */ From 55a36659621564511040e8e27391219a9117565d Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Thu, 31 Aug 2017 10:37:00 +0200 Subject: [PATCH 157/266] BACKPORT: xfrm: Fix return value check of copy_sec_ctx. commit 8598112d04af21cf6c895670e72dcb8a9f58e74f upstream. A recent commit added an output_mark. When copying this output_mark, the return value of copy_sec_ctx is overwitten without a check. Fix this by copying the output_mark before the security context. Fixes: 077fbac405bf ("net: xfrm: support setting an output mark.") Signed-off-by: Steffen Klassert Change-Id: I25e9ac6cf79dc8d0ee599bbd23e9d5b5f34a4284 Fixes: Change-Id: I76120fba036e21780ced31ad390faf491ea81e52 ("BACKPORT: net: xfrm: support setting an output mark.") Signed-off-by: Amit Pundir --- net/xfrm/xfrm_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 8b71b09e5ab6..6905de41c5d4 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -868,13 +868,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x, &x->replay); if (ret) goto out; - if (x->security) - ret = copy_sec_ctx(x->security, skb); if (x->props.output_mark) { ret = nla_put_u32(skb, XFRMA_OUTPUT_MARK, x->props.output_mark); if (ret) goto out; } + if (x->security) + ret = copy_sec_ctx(x->security, skb); out: return ret; } From 98c977e62ecee701efe1ba8135747358a2cfba72 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Wed, 22 Jun 2016 21:55:01 +0530 Subject: [PATCH 158/266] powerpc/bpf/jit: Disable classic BPF JIT on ppc64le commit 844e3be47693f92a108cb1fb3b0606bf25e9c7a6 upstream. Classic BPF JIT was never ported completely to work on little endian powerpc. However, it can be enabled and will crash the system when used. As such, disable use of BPF JIT on ppc64le. Fixes: 7c105b63bd98 ("powerpc: Add CONFIG_CPU_LITTLE_ENDIAN kernel config option.") Reported-by: Thadeu Lima de Souza Cascardo Signed-off-by: Naveen N. Rao Acked-by: Thadeu Lima de Souza Cascardo Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index dfb1ee8c3e06..0c26025e18f9 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -129,7 +129,7 @@ config PPC select IRQ_FORCED_THREADING select HAVE_RCU_TABLE_FREE if SMP select HAVE_SYSCALL_TRACEPOINTS - select HAVE_BPF_JIT + select HAVE_BPF_JIT if CPU_BIG_ENDIAN select HAVE_ARCH_JUMP_LABEL select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_HAS_GCOV_PROFILE_ALL From 1f67581356f7797696806c948d4e126f9b2a880f Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Mon, 3 Apr 2017 13:25:12 +1000 Subject: [PATCH 159/266] powerpc/64: Fix flush_(d|i)cache_range() called from modules commit 8f5f525d5b83f7d76a6baf9c4e94d4bf312ea7f6 upstream. When the kernel is compiled to use 64bit ABIv2 the _GLOBAL() macro does not include a global entry point. A function's global entry point is used when the function is called from a different TOC context and in the kernel this typically means a call from a module into the vmlinux (or vice-versa). There are a few exported asm functions declared with _GLOBAL() and calling them from a module will likely crash the kernel since any TOC relative load will yield garbage. flush_icache_range() and flush_dcache_range() are both exported to modules, and use the TOC, so must use _GLOBAL_TOC(). Fixes: 721aeaa9fdf3 ("powerpc: Build little endian ppc64 kernel with ABIv2") Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/ppc_asm.h | 12 ++++++++++++ arch/powerpc/kernel/misc_64.S | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index dd0fc18d8103..160bb2311bbb 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -224,6 +224,16 @@ name: \ .globl name; \ name: +#define _KPROBE_TOC(name) \ + .section ".kprobes.text","a"; \ + .align 2 ; \ + .type name,@function; \ + .globl name; \ +name: \ +0: addis r2,r12,(.TOC.-0b)@ha; \ + addi r2,r2,(.TOC.-0b)@l; \ + .localentry name,.-name + #define DOTSYM(a) a #else @@ -261,6 +271,8 @@ name: \ .type GLUE(.,name),@function; \ GLUE(.,name): +#define _KPROBE_TOC(n) _KPROBE(n) + #define DOTSYM(a) GLUE(.,a) #endif diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index db475d41b57a..415e58565745 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -66,7 +66,7 @@ PPC64_CACHES: * flush all bytes from start through stop-1 inclusive */ -_KPROBE(flush_icache_range) +_KPROBE_TOC(flush_icache_range) BEGIN_FTR_SECTION PURGE_PREFETCHED_INS blr @@ -117,7 +117,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) * * flush all bytes from start to stop-1 inclusive */ -_GLOBAL(flush_dcache_range) +_GLOBAL_TOC(flush_dcache_range) /* * Flush the data cache to memory From e13972478e99666787867628fa3ff1b87ce3cd82 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 16 Aug 2017 16:01:14 +1000 Subject: [PATCH 160/266] powerpc: Fix VSX enabling/flushing to also test MSR_FP and MSR_VEC commit 5a69aec945d27e78abac9fd032533d3aaebf7c1e upstream. VSX uses a combination of the old vector registers, the old FP registers and new "second halves" of the FP registers. Thus when we need to see the VSX state in the thread struct (flush_vsx_to_thread()) or when we'll use the VSX in the kernel (enable_kernel_vsx()) we need to ensure they are all flushed into the thread struct if either of them is individually enabled. Unfortunately we only tested if the whole VSX was enabled, not if they were individually enabled. Fixes: 72cd7b44bc99 ("powerpc: Uncomment and make enable_kernel_vsx() routine available") Signed-off-by: Benjamin Herrenschmidt [mpe: Backported due to changed context] Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/process.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index cf788d7d7e56..a9b10812cbfd 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -209,7 +209,8 @@ void enable_kernel_vsx(void) WARN_ON(preemptible()); #ifdef CONFIG_SMP - if (current->thread.regs && (current->thread.regs->msr & MSR_VSX)) + if (current->thread.regs && + (current->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP))) giveup_vsx(current); else giveup_vsx(NULL); /* just enable vsx for kernel - force */ @@ -231,7 +232,7 @@ void flush_vsx_to_thread(struct task_struct *tsk) { if (tsk->thread.regs) { preempt_disable(); - if (tsk->thread.regs->msr & MSR_VSX) { + if (tsk->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)) { #ifdef CONFIG_SMP BUG_ON(tsk != current); #endif From fa34303532dcd4c609729cd0cc8aa2c53b3eb4fd Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 15 Jan 2016 20:52:22 +1100 Subject: [PATCH 161/266] powerpc: Simplify module TOC handling commit c153693d7eb9eeb28478aa2deaaf0b4e7b5ff5e9 upstream. PowerPC64 uses the symbol .TOC. much as other targets use _GLOBAL_OFFSET_TABLE_. It identifies the value of the GOT pointer (or in powerpc parlance, the TOC pointer). Global offset tables are generally local to an executable or shared library, or in the kernel, module. Thus it does not make sense for a module to resolve a relocation against .TOC. to the kernel's .TOC. value. A module has its own .TOC., and indeed the powerpc64 module relocation processing ignores the kernel value of .TOC. and instead calculates a module-local value. This patch removes code involved in exporting the kernel .TOC., tweaks modpost to ignore an undefined .TOC., and the module loader to twiddle the section symbol so that .TOC. isn't seen as undefined. Note that if the kernel was compiled with -msingle-pic-base then ELFv2 would not have function global entry code setting up r2. In that case the module call stubs would need to be modified to set up r2 using the kernel .TOC. value, requiring some of this code to be reinstated. mpe: Furthermore a change in binutils master (not yet released) causes the current way we handle the TOC to no longer work when building with MODVERSIONS=y and RELOCATABLE=n. The symptom is that modules can not be loaded due to there being no version found for TOC. Signed-off-by: Alan Modra Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/misc_64.S | 28 ---------------------------- arch/powerpc/kernel/module_64.c | 12 +++++++++--- scripts/mod/modpost.c | 3 ++- 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 415e58565745..107588295b39 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -701,31 +701,3 @@ _GLOBAL(kexec_sequence) li r5,0 blr /* image->start(physid, image->start, 0); */ #endif /* CONFIG_KEXEC */ - -#ifdef CONFIG_MODULES -#if defined(_CALL_ELF) && _CALL_ELF == 2 - -#ifdef CONFIG_MODVERSIONS -.weak __crc_TOC. -.section "___kcrctab+TOC.","a" -.globl __kcrctab_TOC. -__kcrctab_TOC.: - .llong __crc_TOC. -#endif - -/* - * Export a fake .TOC. since both modpost and depmod will complain otherwise. - * Both modpost and depmod strip the leading . so we do the same here. - */ -.section "__ksymtab_strings","a" -__kstrtab_TOC.: - .asciz "TOC." - -.section "___ksymtab+TOC.","a" -/* This symbol name is important: it's used by modpost to find exported syms */ -.globl __ksymtab_TOC. -__ksymtab_TOC.: - .llong 0 /* .value */ - .llong __kstrtab_TOC. -#endif /* ELFv2 */ -#endif /* MODULES */ diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index e4f7d4eed20c..08b7a40de5f8 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -326,7 +326,10 @@ static void dedotify_versions(struct modversion_info *vers, } } -/* Undefined symbols which refer to .funcname, hack to funcname (or .TOC.) */ +/* + * Undefined symbols which refer to .funcname, hack to funcname. Make .TOC. + * seem to be defined (value set later). + */ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) { unsigned int i; @@ -334,8 +337,11 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) for (i = 1; i < numsyms; i++) { if (syms[i].st_shndx == SHN_UNDEF) { char *name = strtab + syms[i].st_name; - if (name[0] == '.') + if (name[0] == '.') { + if (strcmp(name+1, "TOC.") == 0) + syms[i].st_shndx = SHN_ABS; syms[i].st_name++; + } } } } @@ -351,7 +357,7 @@ static Elf64_Sym *find_dot_toc(Elf64_Shdr *sechdrs, numsyms = sechdrs[symindex].sh_size / sizeof(Elf64_Sym); for (i = 1; i < numsyms; i++) { - if (syms[i].st_shndx == SHN_UNDEF + if (syms[i].st_shndx == SHN_ABS && strcmp(strtab + syms[i].st_name, "TOC.") == 0) return &syms[i]; } diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index e080746e1a6b..48958d3cec9e 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -594,7 +594,8 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname) if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 || strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 || strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || - strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) + strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0 || + strcmp(symname, ".TOC.") == 0) return 1; /* Do not ignore this symbol */ return 0; From e1c1144053753341f6767555d1e0fa043aa71e6b Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 9 Jan 2018 03:52:05 +1100 Subject: [PATCH 162/266] powerpc/pseries: Add H_GET_CPU_CHARACTERISTICS flags & wrapper commit 191eccb1580939fb0d47deb405b82a85b0379070 upstream. A new hypervisor call has been defined to communicate various characteristics of the CPU to guests. Add definitions for the hcall number, flags and a wrapper function. Signed-off-by: Michael Neuling Signed-off-by: Michael Ellerman [Balbir fixed conflicts in backport] Signed-off-by: Balbir Singh Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/hvcall.h | 17 +++++++++++++++++ arch/powerpc/include/asm/plpar_wrappers.h | 14 ++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 85bc8c0d257b..51adbde09845 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -239,6 +239,7 @@ #define H_GET_HCA_INFO 0x1B8 #define H_GET_PERF_COUNT 0x1BC #define H_MANAGE_TRACE 0x1C0 +#define H_GET_CPU_CHARACTERISTICS 0x1C8 #define H_FREE_LOGICAL_LAN_BUFFER 0x1D4 #define H_QUERY_INT_STATE 0x1E4 #define H_POLL_PENDING 0x1D8 @@ -285,6 +286,17 @@ #define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3 #define H_SET_MODE_RESOURCE_LE 4 +/* H_GET_CPU_CHARACTERISTICS return values */ +#define H_CPU_CHAR_SPEC_BAR_ORI31 (1ull << 63) // IBM bit 0 +#define H_CPU_CHAR_BCCTRL_SERIALISED (1ull << 62) // IBM bit 1 +#define H_CPU_CHAR_L1D_FLUSH_ORI30 (1ull << 61) // IBM bit 2 +#define H_CPU_CHAR_L1D_FLUSH_TRIG2 (1ull << 60) // IBM bit 3 +#define H_CPU_CHAR_L1D_THREAD_PRIV (1ull << 59) // IBM bit 4 + +#define H_CPU_BEHAV_FAVOUR_SECURITY (1ull << 63) // IBM bit 0 +#define H_CPU_BEHAV_L1D_FLUSH_PR (1ull << 62) // IBM bit 1 +#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR (1ull << 61) // IBM bit 2 + #ifndef __ASSEMBLY__ /** @@ -423,6 +435,11 @@ extern long pseries_big_endian_exceptions(void); #endif /* CONFIG_PPC_PSERIES */ +struct h_cpu_char_result { + u64 character; + u64 behaviour; +}; + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_HVCALL_H */ diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h index 67859edbf8fd..6e05cb397a5c 100644 --- a/arch/powerpc/include/asm/plpar_wrappers.h +++ b/arch/powerpc/include/asm/plpar_wrappers.h @@ -323,4 +323,18 @@ static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawr return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR, dawr0, dawrx0); } +static inline long plpar_get_cpu_characteristics(struct h_cpu_char_result *p) +{ + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + long rc; + + rc = plpar_hcall(H_GET_CPU_CHARACTERISTICS, retbuf); + if (rc == H_SUCCESS) { + p->character = retbuf[0]; + p->behaviour = retbuf[1]; + } + + return rc; +} + #endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */ From a8a9925f01e1bda46f059a66c218d536bb1462ef Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 10 Jan 2018 03:07:15 +1100 Subject: [PATCH 163/266] powerpc/64: Add macros for annotating the destination of rfid/hrfid commit 50e51c13b3822d14ff6df4279423e4b7b2269bc3 upstream. The rfid/hrfid ((Hypervisor) Return From Interrupt) instruction is used for switching from the kernel to userspace, and from the hypervisor to the guest kernel. However it can and is also used for other transitions, eg. from real mode kernel code to virtual mode kernel code, and it's not always clear from the code what the destination context is. To make it clearer when reading the code, add macros which encode the expected destination context. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/exception-64e.h | 6 +++++ arch/powerpc/include/asm/exception-64s.h | 29 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h index a703452d67b6..555e22d5e07f 100644 --- a/arch/powerpc/include/asm/exception-64e.h +++ b/arch/powerpc/include/asm/exception-64e.h @@ -209,5 +209,11 @@ exc_##label##_book3e: ori r3,r3,vector_offset@l; \ mtspr SPRN_IVOR##vector_number,r3; +#define RFI_TO_KERNEL \ + rfi + +#define RFI_TO_USER \ + rfi + #endif /* _ASM_POWERPC_EXCEPTION_64E_H */ diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 77f52b26dad6..c8c8a81e3976 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -50,6 +50,35 @@ #define EX_PPR 88 /* SMT thread status register (priority) */ #define EX_CTR 96 +/* Macros for annotating the expected destination of (h)rfid */ + +#define RFI_TO_KERNEL \ + rfid + +#define RFI_TO_USER \ + rfid + +#define RFI_TO_USER_OR_KERNEL \ + rfid + +#define RFI_TO_GUEST \ + rfid + +#define HRFI_TO_KERNEL \ + hrfid + +#define HRFI_TO_USER \ + hrfid + +#define HRFI_TO_USER_OR_KERNEL \ + hrfid + +#define HRFI_TO_GUEST \ + hrfid + +#define HRFI_TO_UNKNOWN \ + hrfid + #ifdef CONFIG_RELOCATABLE #define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \ ld r12,PACAKBASE(r13); /* get high part of &label */ \ From 7ca8316cb94f394999f0d512f30984b512f64958 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 10 Jan 2018 03:07:15 +1100 Subject: [PATCH 164/266] powerpc/64s: Simple RFI macro conversions commit 222f20f140623ef6033491d0103ee0875fe87d35 upstream. This commit does simple conversions of rfi/rfid to the new macros that include the expected destination context. By simple we mean cases where there is a single well known destination context, and it's simply a matter of substituting the instruction for the appropriate macro. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman [Balbir fixed issues with backporting to stable] Signed-off-by: Balbir Singh Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/exception-64s.h | 2 +- arch/powerpc/kernel/entry_64.S | 14 +++++++++----- arch/powerpc/kernel/exceptions-64s.S | 18 +++++++++--------- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 7 +++---- arch/powerpc/kvm/book3s_rmhandlers.S | 7 +++++-- arch/powerpc/kvm/book3s_segment.S | 4 ++-- 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index c8c8a81e3976..6dfb6e928f81 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -220,7 +220,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) mtspr SPRN_##h##SRR0,r12; \ mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ mtspr SPRN_##h##SRR1,r10; \ - h##rfid; \ + h##RFI_TO_KERNEL; \ b . /* prevent speculative execution */ #define EXCEPTION_PROLOG_PSERIES_1(label, h) \ __EXCEPTION_PROLOG_PSERIES_1(label, h) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index f6fd0332c3a2..fb2da020e0ee 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -36,6 +36,11 @@ #include #include #include +#ifdef CONFIG_PPC_BOOK3S +#include +#else +#include +#endif /* * System calls. @@ -353,8 +358,7 @@ tabort_syscall: mtmsrd r10, 1 mtspr SPRN_SRR0, r11 mtspr SPRN_SRR1, r12 - - rfid + RFI_TO_USER b . /* prevent speculative execution */ #endif @@ -1077,7 +1081,7 @@ _GLOBAL(enter_rtas) mtspr SPRN_SRR0,r5 mtspr SPRN_SRR1,r6 - rfid + RFI_TO_KERNEL b . /* prevent speculative execution */ rtas_return_loc: @@ -1102,7 +1106,7 @@ rtas_return_loc: mtspr SPRN_SRR0,r3 mtspr SPRN_SRR1,r4 - rfid + RFI_TO_KERNEL b . /* prevent speculative execution */ .align 3 @@ -1173,7 +1177,7 @@ _GLOBAL(enter_prom) LOAD_REG_IMMEDIATE(r12, MSR_SF | MSR_ISF | MSR_LE) andc r11,r11,r12 mtsrr1 r11 - rfid + RFI_TO_KERNEL #endif /* CONFIG_PPC_BOOK3E */ 1: /* Return from OF */ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index b81ccc5fb32d..e3a3b81df363 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -46,7 +46,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ mtspr SPRN_SRR0,r10 ; \ ld r10,PACAKMSR(r13) ; \ mtspr SPRN_SRR1,r10 ; \ - rfid ; \ + RFI_TO_KERNEL ; \ b . ; /* prevent speculative execution */ #define SYSCALL_PSERIES_3 \ @@ -54,7 +54,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ 1: mfspr r12,SPRN_SRR1 ; \ xori r12,r12,MSR_LE ; \ mtspr SPRN_SRR1,r12 ; \ - rfid ; /* return to userspace */ \ + RFI_TO_USER ; /* return to userspace */ \ b . ; /* prevent speculative execution */ #if defined(CONFIG_RELOCATABLE) @@ -507,7 +507,7 @@ BEGIN_FTR_SECTION LOAD_HANDLER(r12, machine_check_handle_early) 1: mtspr SPRN_SRR0,r12 mtspr SPRN_SRR1,r11 - rfid + RFI_TO_KERNEL b . /* prevent speculative execution */ 2: /* Stack overflow. Stay on emergency stack and panic. @@ -601,7 +601,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) ld r11,PACA_EXGEN+EX_R11(r13) ld r12,PACA_EXGEN+EX_R12(r13) ld r13,PACA_EXGEN+EX_R13(r13) - HRFID + HRFI_TO_UNKNOWN b . #endif @@ -666,7 +666,7 @@ masked_##_H##interrupt: \ ld r10,PACA_EXGEN+EX_R10(r13); \ ld r11,PACA_EXGEN+EX_R11(r13); \ GET_SCRATCH0(r13); \ - ##_H##rfid; \ + ##_H##RFI_TO_KERNEL; \ b . MASKED_INTERRUPT() @@ -756,7 +756,7 @@ kvmppc_skip_interrupt: addi r13, r13, 4 mtspr SPRN_SRR0, r13 GET_SCRATCH0(r13) - rfid + RFI_TO_KERNEL b . kvmppc_skip_Hinterrupt: @@ -768,7 +768,7 @@ kvmppc_skip_Hinterrupt: addi r13, r13, 4 mtspr SPRN_HSRR0, r13 GET_SCRATCH0(r13) - hrfid + HRFI_TO_KERNEL b . #endif @@ -1439,7 +1439,7 @@ machine_check_handle_early: li r3,MSR_ME andc r10,r10,r3 /* Turn off MSR_ME */ mtspr SPRN_SRR1,r10 - rfid + RFI_TO_KERNEL b . 2: /* @@ -1457,7 +1457,7 @@ machine_check_handle_early: */ bl machine_check_queue_event MACHINE_CHECK_HANDLER_WINDUP - rfid + RFI_TO_USER_OR_KERNEL 9: /* Deliver the machine check to host kernel in V mode. */ MACHINE_CHECK_HANDLER_WINDUP diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index ffab9269bfe4..4463718ae614 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -64,7 +64,7 @@ _GLOBAL_TOC(kvmppc_hv_entry_trampoline) mtmsrd r0,1 /* clear RI in MSR */ mtsrr0 r5 mtsrr1 r6 - RFI + RFI_TO_KERNEL kvmppc_call_hv_entry: ld r4, HSTATE_KVM_VCPU(r13) @@ -170,7 +170,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) mtsrr0 r8 mtsrr1 r7 beq cr1, 13f /* machine check */ - RFI + RFI_TO_KERNEL /* On POWER7, we have external interrupts set to use HSRR0/1 */ 11: mtspr SPRN_HSRR0, r8 @@ -965,8 +965,7 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ld r0, VCPU_GPR(R0)(r4) ld r4, VCPU_GPR(R4)(r4) - - hrfid + HRFI_TO_GUEST b . secondary_too_late: diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index 16c4d88ba27d..a328f99a887c 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -46,6 +46,9 @@ #define FUNC(name) name +#define RFI_TO_KERNEL RFI +#define RFI_TO_GUEST RFI + .macro INTERRUPT_TRAMPOLINE intno .global kvmppc_trampoline_\intno @@ -141,7 +144,7 @@ kvmppc_handler_skip_ins: GET_SCRATCH0(r13) /* And get back into the code */ - RFI + RFI_TO_KERNEL #endif /* @@ -164,6 +167,6 @@ _GLOBAL_TOC(kvmppc_entry_trampoline) ori r5, r5, MSR_EE mtsrr0 r7 mtsrr1 r6 - RFI + RFI_TO_KERNEL #include "book3s_segment.S" diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S index ca8f174289bb..7c982956d709 100644 --- a/arch/powerpc/kvm/book3s_segment.S +++ b/arch/powerpc/kvm/book3s_segment.S @@ -156,7 +156,7 @@ no_dcbz32_on: PPC_LL r9, SVCPU_R9(r3) PPC_LL r3, (SVCPU_R3)(r3) - RFI + RFI_TO_GUEST kvmppc_handler_trampoline_enter_end: @@ -389,5 +389,5 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) cmpwi r12, BOOK3S_INTERRUPT_DOORBELL beqa BOOK3S_INTERRUPT_DOORBELL - RFI + RFI_TO_KERNEL kvmppc_handler_trampoline_exit_end: From 9bfecafe84e628c5dff9cbeaa4b6e73560adb925 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 10 Jan 2018 03:07:15 +1100 Subject: [PATCH 165/266] powerpc/64: Convert fast_exception_return to use RFI_TO_USER/KERNEL commit a08f828cf47e6c605af21d2cdec68f84e799c318 upstream. Similar to the syscall return path, in fast_exception_return we may be returning to user or kernel context. We already have a test for that, because we conditionally restore r13. So use that existing test and branch, and bifurcate the return based on that. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/entry_64.S | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index fb2da020e0ee..8efd8c402cf7 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -891,7 +891,7 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ACCOUNT_CPU_USER_EXIT(r2, r4) REST_GPR(13, r1) -1: + mtspr SPRN_SRR1,r3 ld r2,_CCR(r1) @@ -904,8 +904,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ld r3,GPR3(r1) ld r4,GPR4(r1) ld r1,GPR1(r1) + RFI_TO_USER + b . /* prevent speculative execution */ - rfid +1: mtspr SPRN_SRR1,r3 + + ld r2,_CCR(r1) + mtcrf 0xFF,r2 + ld r2,_NIP(r1) + mtspr SPRN_SRR0,r2 + + ld r0,GPR0(r1) + ld r2,GPR2(r1) + ld r3,GPR3(r1) + ld r4,GPR4(r1) + ld r1,GPR1(r1) + RFI_TO_KERNEL b . /* prevent speculative execution */ #endif /* CONFIG_PPC_BOOK3E */ From 8dd311f1ec740b05c851d65bab9cfdde26e35a8a Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 10 Jan 2018 03:07:15 +1100 Subject: [PATCH 166/266] powerpc/64: Convert the syscall exit path to use RFI_TO_USER/KERNEL commit b8e90cb7bc04a509e821e82ab6ed7a8ef11ba333 upstream. In the syscall exit path we may be returning to user or kernel context. We already have a test for that, because we conditionally restore r13. So use that existing test and branch, and bifurcate the return based on that. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/entry_64.S | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 8efd8c402cf7..2837232bbffb 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -230,13 +230,23 @@ END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) ACCOUNT_CPU_USER_EXIT(r11, r12) HMT_MEDIUM_LOW_HAS_PPR ld r13,GPR13(r1) /* only restore r13 if returning to usermode */ + ld r2,GPR2(r1) + ld r1,GPR1(r1) + mtlr r4 + mtcr r5 + mtspr SPRN_SRR0,r7 + mtspr SPRN_SRR1,r8 + RFI_TO_USER + b . /* prevent speculative execution */ + + /* exit to kernel */ 1: ld r2,GPR2(r1) ld r1,GPR1(r1) mtlr r4 mtcr r5 mtspr SPRN_SRR0,r7 mtspr SPRN_SRR1,r8 - RFI + RFI_TO_KERNEL b . /* prevent speculative execution */ syscall_error: From 973439da1137a066f6b3f478c930edff1879dee2 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 10 Jan 2018 03:07:15 +1100 Subject: [PATCH 167/266] powerpc/64s: Convert slb_miss_common to use RFI_TO_USER/KERNEL commit c7305645eb0c1621351cfc104038831ae87c0053 upstream. In the SLB miss handler we may be returning to user or kernel. We need to add a check early on and save the result in the cr4 register, and then we bifurcate the return path based on that. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Nicholas Piggin [mpe: Backport to 4.4 based on patch from Balbir] Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/exceptions-64s.S | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index e3a3b81df363..2c6494351604 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1503,6 +1503,8 @@ slb_miss_realmode: andi. r10,r12,MSR_RI /* check for unrecoverable exception */ beq- 2f + andi. r10,r12,MSR_PR /* check for user mode (PR != 0) */ + bne 1f .machine push .machine "power4" @@ -1516,7 +1518,23 @@ slb_miss_realmode: ld r11,PACA_EXSLB+EX_R11(r13) ld r12,PACA_EXSLB+EX_R12(r13) ld r13,PACA_EXSLB+EX_R13(r13) - rfid + RFI_TO_KERNEL + b . /* prevent speculative execution */ + +1: +.machine push +.machine "power4" + mtcrf 0x80,r9 + mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ +.machine pop + + RESTORE_PPR_PACA(PACA_EXSLB, r9) + ld r9,PACA_EXSLB+EX_R9(r13) + ld r10,PACA_EXSLB+EX_R10(r13) + ld r11,PACA_EXSLB+EX_R11(r13) + ld r12,PACA_EXSLB+EX_R12(r13) + ld r13,PACA_EXSLB+EX_R13(r13) + RFI_TO_USER b . /* prevent speculative execution */ 2: mfspr r11,SPRN_SRR0 @@ -1525,7 +1543,7 @@ slb_miss_realmode: mtspr SPRN_SRR0,r10 ld r10,PACAKMSR(r13) mtspr SPRN_SRR1,r10 - rfid + RFI_TO_KERNEL b . unrecov_slb: From c3892946315effa323954134c2f8aeda51e9e68b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 10 Jan 2018 03:07:15 +1100 Subject: [PATCH 168/266] powerpc/64s: Add support for RFI flush of L1-D cache commit aa8a5e0062ac940f7659394f4817c948dc8c0667 upstream. On some CPUs we can prevent the Meltdown vulnerability by flushing the L1-D cache on exit from kernel to user mode, and from hypervisor to guest. This is known to be the case on at least Power7, Power8 and Power9. At this time we do not know the status of the vulnerability on other CPUs such as the 970 (Apple G5), pasemi CPUs (AmigaOne X1000) or Freescale CPUs. As more information comes to light we can enable this, or other mechanisms on those CPUs. The vulnerability occurs when the load of an architecturally inaccessible memory region (eg. userspace load of kernel memory) is speculatively executed to the point where its result can influence the address of a subsequent speculatively executed load. In order for that to happen, the first load must hit in the L1, because before the load is sent to the L2 the permission check is performed. Therefore if no kernel addresses hit in the L1 the vulnerability can not occur. We can ensure that is the case by flushing the L1 whenever we return to userspace. Similarly for hypervisor vs guest. In order to flush the L1-D cache on exit, we add a section of nops at each (h)rfi location that returns to a lower privileged context, and patch that with some sequence. Newer firmwares are able to advertise to us that there is a special nop instruction that flushes the L1-D. If we do not see that advertised, we fall back to doing a displacement flush in software. For guest kernels we support migration between some CPU versions, and different CPUs may use different flush instructions. So that we are prepared to migrate to a machine with a different flush instruction activated, we may have to patch more than one flush instruction at boot if the hypervisor tells us to. In the end this patch is mostly the work of Nicholas Piggin and Michael Ellerman. However a cast of thousands contributed to analysis of the issue, earlier versions of the patch, back ports testing etc. Many thanks to all of them. Tested-by: Jon Masters Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman [Balbir - back ported to stable with changes] Signed-off-by: Balbir Singh Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/exception-64s.h | 40 ++++++++--- arch/powerpc/include/asm/feature-fixups.h | 15 ++++ arch/powerpc/include/asm/paca.h | 10 +++ arch/powerpc/include/asm/setup.h | 13 ++++ arch/powerpc/kernel/asm-offsets.c | 4 ++ arch/powerpc/kernel/exceptions-64s.S | 86 +++++++++++++++++++++++ arch/powerpc/kernel/setup_64.c | 79 +++++++++++++++++++++ arch/powerpc/kernel/vmlinux.lds.S | 9 +++ arch/powerpc/lib/feature-fixups.c | 42 +++++++++++ 9 files changed, 290 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 6dfb6e928f81..9bddbec441b8 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -50,34 +50,58 @@ #define EX_PPR 88 /* SMT thread status register (priority) */ #define EX_CTR 96 -/* Macros for annotating the expected destination of (h)rfid */ +/* + * Macros for annotating the expected destination of (h)rfid + * + * The nop instructions allow us to insert one or more instructions to flush the + * L1-D cache when returning to userspace or a guest. + */ +#define RFI_FLUSH_SLOT \ + RFI_FLUSH_FIXUP_SECTION; \ + nop; \ + nop; \ + nop #define RFI_TO_KERNEL \ rfid #define RFI_TO_USER \ - rfid + RFI_FLUSH_SLOT; \ + rfid; \ + b rfi_flush_fallback #define RFI_TO_USER_OR_KERNEL \ - rfid + RFI_FLUSH_SLOT; \ + rfid; \ + b rfi_flush_fallback #define RFI_TO_GUEST \ - rfid + RFI_FLUSH_SLOT; \ + rfid; \ + b rfi_flush_fallback #define HRFI_TO_KERNEL \ hrfid #define HRFI_TO_USER \ - hrfid + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback #define HRFI_TO_USER_OR_KERNEL \ - hrfid + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback #define HRFI_TO_GUEST \ - hrfid + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback #define HRFI_TO_UNKNOWN \ - hrfid + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback #ifdef CONFIG_RELOCATABLE #define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \ diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h index 9a67a38bf7b9..7068bafbb2d6 100644 --- a/arch/powerpc/include/asm/feature-fixups.h +++ b/arch/powerpc/include/asm/feature-fixups.h @@ -184,4 +184,19 @@ label##3: \ FTR_ENTRY_OFFSET label##1b-label##3b; \ .popsection; +#define RFI_FLUSH_FIXUP_SECTION \ +951: \ + .pushsection __rfi_flush_fixup,"a"; \ + .align 2; \ +952: \ + FTR_ENTRY_OFFSET 951b-952b; \ + .popsection; + + +#ifndef __ASSEMBLY__ + +extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup; + +#endif + #endif /* __ASM_POWERPC_FEATURE_FIXUPS_H */ diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 70bd4381f8e6..45e2aefece16 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -192,6 +192,16 @@ struct paca_struct { #endif struct kvmppc_host_state kvm_hstate; #endif +#ifdef CONFIG_PPC_BOOK3S_64 + /* + * rfi fallback flush must be in its own cacheline to prevent + * other paca data leaking into the L1d + */ + u64 exrfi[13] __aligned(0x80); + void *rfi_flush_fallback_area; + u64 l1d_flush_congruence; + u64 l1d_flush_sets; +#endif }; extern struct paca_struct *paca; diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h index e9d384cbd021..7916b56f2e60 100644 --- a/arch/powerpc/include/asm/setup.h +++ b/arch/powerpc/include/asm/setup.h @@ -26,6 +26,19 @@ void initmem_init(void); void setup_panic(void); #define ARCH_PANIC_TIMEOUT 180 +void rfi_flush_enable(bool enable); + +/* These are bit flags */ +enum l1d_flush_type { + L1D_FLUSH_NONE = 0x1, + L1D_FLUSH_FALLBACK = 0x2, + L1D_FLUSH_ORI = 0x4, + L1D_FLUSH_MTTRIG = 0x8, +}; + +void __init setup_rfi_flush(enum l1d_flush_type, bool enable); +void do_rfi_flush_fixups(enum l1d_flush_type types); + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_POWERPC_SETUP_H */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 40da69163d51..d92705e3a0c1 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -243,6 +243,10 @@ int main(void) #ifdef CONFIG_PPC_BOOK3S_64 DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp)); DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce)); + DEFINE(PACA_RFI_FLUSH_FALLBACK_AREA, offsetof(struct paca_struct, rfi_flush_fallback_area)); + DEFINE(PACA_EXRFI, offsetof(struct paca_struct, exrfi)); + DEFINE(PACA_L1D_FLUSH_CONGRUENCE, offsetof(struct paca_struct, l1d_flush_congruence)); + DEFINE(PACA_L1D_FLUSH_SETS, offsetof(struct paca_struct, l1d_flush_sets)); #endif DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state)); diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 2c6494351604..938a30fef031 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1564,6 +1564,92 @@ power4_fixup_nap: blr #endif + .globl rfi_flush_fallback +rfi_flush_fallback: + SET_SCRATCH0(r13); + GET_PACA(r13); + std r9,PACA_EXRFI+EX_R9(r13) + std r10,PACA_EXRFI+EX_R10(r13) + std r11,PACA_EXRFI+EX_R11(r13) + std r12,PACA_EXRFI+EX_R12(r13) + std r8,PACA_EXRFI+EX_R13(r13) + mfctr r9 + ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13) + ld r11,PACA_L1D_FLUSH_SETS(r13) + ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13) + /* + * The load adresses are at staggered offsets within cachelines, + * which suits some pipelines better (on others it should not + * hurt). + */ + addi r12,r12,8 + mtctr r11 + DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */ + + /* order ld/st prior to dcbt stop all streams with flushing */ + sync +1: li r8,0 + .rept 8 /* 8-way set associative */ + ldx r11,r10,r8 + add r8,r8,r12 + xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not + add r8,r8,r11 // Add 0, this creates a dependency on the ldx + .endr + addi r10,r10,128 /* 128 byte cache line */ + bdnz 1b + + mtctr r9 + ld r9,PACA_EXRFI+EX_R9(r13) + ld r10,PACA_EXRFI+EX_R10(r13) + ld r11,PACA_EXRFI+EX_R11(r13) + ld r12,PACA_EXRFI+EX_R12(r13) + ld r8,PACA_EXRFI+EX_R13(r13) + GET_SCRATCH0(r13); + rfid + + .globl hrfi_flush_fallback +hrfi_flush_fallback: + SET_SCRATCH0(r13); + GET_PACA(r13); + std r9,PACA_EXRFI+EX_R9(r13) + std r10,PACA_EXRFI+EX_R10(r13) + std r11,PACA_EXRFI+EX_R11(r13) + std r12,PACA_EXRFI+EX_R12(r13) + std r8,PACA_EXRFI+EX_R13(r13) + mfctr r9 + ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13) + ld r11,PACA_L1D_FLUSH_SETS(r13) + ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13) + /* + * The load adresses are at staggered offsets within cachelines, + * which suits some pipelines better (on others it should not + * hurt). + */ + addi r12,r12,8 + mtctr r11 + DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */ + + /* order ld/st prior to dcbt stop all streams with flushing */ + sync +1: li r8,0 + .rept 8 /* 8-way set associative */ + ldx r11,r10,r8 + add r8,r8,r12 + xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not + add r8,r8,r11 // Add 0, this creates a dependency on the ldx + .endr + addi r10,r10,128 /* 128 byte cache line */ + bdnz 1b + + mtctr r9 + ld r9,PACA_EXRFI+EX_R9(r13) + ld r10,PACA_EXRFI+EX_R10(r13) + ld r11,PACA_EXRFI+EX_R11(r13) + ld r12,PACA_EXRFI+EX_R12(r13) + ld r8,PACA_EXRFI+EX_R13(r13) + GET_SCRATCH0(r13); + hrfid + /* * Hash table stuff */ diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index a20823210ac0..1a3bd6a35c44 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -834,4 +834,83 @@ static int __init disable_hardlockup_detector(void) return 0; } early_initcall(disable_hardlockup_detector); + +#ifdef CONFIG_PPC_BOOK3S_64 +static enum l1d_flush_type enabled_flush_types; +static void *l1d_flush_fallback_area; +bool rfi_flush; + +static void do_nothing(void *unused) +{ + /* + * We don't need to do the flush explicitly, just enter+exit kernel is + * sufficient, the RFI exit handlers will do the right thing. + */ +} + +void rfi_flush_enable(bool enable) +{ + if (rfi_flush == enable) + return; + + if (enable) { + do_rfi_flush_fixups(enabled_flush_types); + on_each_cpu(do_nothing, NULL, 1); + } else + do_rfi_flush_fixups(L1D_FLUSH_NONE); + + rfi_flush = enable; +} + +static void init_fallback_flush(void) +{ + u64 l1d_size, limit; + int cpu; + + l1d_size = ppc64_caches.dsize; + limit = min(safe_stack_limit(), ppc64_rma_size); + + /* + * Align to L1d size, and size it at 2x L1d size, to catch possible + * hardware prefetch runoff. We don't have a recipe for load patterns to + * reliably avoid the prefetcher. + */ + l1d_flush_fallback_area = __va(memblock_alloc_base(l1d_size * 2, l1d_size, limit)); + memset(l1d_flush_fallback_area, 0, l1d_size * 2); + + for_each_possible_cpu(cpu) { + /* + * The fallback flush is currently coded for 8-way + * associativity. Different associativity is possible, but it + * will be treated as 8-way and may not evict the lines as + * effectively. + * + * 128 byte lines are mandatory. + */ + u64 c = l1d_size / 8; + + paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area; + paca[cpu].l1d_flush_congruence = c; + paca[cpu].l1d_flush_sets = c / 128; + } +} + +void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) +{ + if (types & L1D_FLUSH_FALLBACK) { + pr_info("rfi-flush: Using fallback displacement flush\n"); + init_fallback_flush(); + } + + if (types & L1D_FLUSH_ORI) + pr_info("rfi-flush: Using ori type flush\n"); + + if (types & L1D_FLUSH_MTTRIG) + pr_info("rfi-flush: Using mttrig type flush\n"); + + enabled_flush_types = types; + + rfi_flush_enable(enable); +} +#endif /* CONFIG_PPC_BOOK3S_64 */ #endif diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index d41fd0af8980..072a23a17350 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -72,6 +72,15 @@ SECTIONS /* Read-only data */ RODATA +#ifdef CONFIG_PPC64 + . = ALIGN(8); + __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) { + __start___rfi_flush_fixup = .; + *(__rfi_flush_fixup) + __stop___rfi_flush_fixup = .; + } +#endif + EXCEPTION_TABLE(0) NOTES :kernel :notes diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index 7ce3870d7ddd..a18d648d31a6 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -20,6 +20,7 @@ #include #include #include +#include struct fixup_entry { @@ -113,6 +114,47 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) } } +#ifdef CONFIG_PPC_BOOK3S_64 +void do_rfi_flush_fixups(enum l1d_flush_type types) +{ + unsigned int instrs[3], *dest; + long *start, *end; + int i; + + start = PTRRELOC(&__start___rfi_flush_fixup), + end = PTRRELOC(&__stop___rfi_flush_fixup); + + instrs[0] = 0x60000000; /* nop */ + instrs[1] = 0x60000000; /* nop */ + instrs[2] = 0x60000000; /* nop */ + + if (types & L1D_FLUSH_FALLBACK) + /* b .+16 to fallback flush */ + instrs[0] = 0x48000010; + + i = 0; + if (types & L1D_FLUSH_ORI) { + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ + instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/ + } + + if (types & L1D_FLUSH_MTTRIG) + instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */ + + for (i = 0; start < end; start++, i++) { + dest = (void *)start + *start; + + pr_devel("patching dest %lx\n", (unsigned long)dest); + + patch_instruction(dest, instrs[0]); + patch_instruction(dest + 1, instrs[1]); + patch_instruction(dest + 2, instrs[2]); + } + + printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i); +} +#endif /* CONFIG_PPC_BOOK3S_64 */ + void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end) { long *start, *end; From 11c76e64332f0f6f10ea8c2e2612fd4601a3e0d7 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 10 Jan 2018 03:07:15 +1100 Subject: [PATCH 169/266] powerpc/64s: Support disabling RFI flush with no_rfi_flush and nopti commit bc9c9304a45480797e13a8e1df96ffcf44fb62fe upstream. Because there may be some performance overhead of the RFI flush, add kernel command line options to disable it. We add a sensibly named 'no_rfi_flush' option, but we also hijack the x86 option 'nopti'. The RFI flush is not the same as KPTI, but if we see 'nopti' we can guess that the user is trying to avoid any overhead of Meltdown mitigations, and it means we don't have to educate every one about a different command line option. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/setup_64.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 1a3bd6a35c44..7db464c2b129 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -838,8 +838,29 @@ early_initcall(disable_hardlockup_detector); #ifdef CONFIG_PPC_BOOK3S_64 static enum l1d_flush_type enabled_flush_types; static void *l1d_flush_fallback_area; +static bool no_rfi_flush; bool rfi_flush; +static int __init handle_no_rfi_flush(char *p) +{ + pr_info("rfi-flush: disabled on command line."); + no_rfi_flush = true; + return 0; +} +early_param("no_rfi_flush", handle_no_rfi_flush); + +/* + * The RFI flush is not KPTI, but because users will see doco that says to use + * nopti we hijack that option here to also disable the RFI flush. + */ +static int __init handle_no_pti(char *p) +{ + pr_info("rfi-flush: disabling due to 'nopti' on command line.\n"); + handle_no_rfi_flush(NULL); + return 0; +} +early_param("nopti", handle_no_pti); + static void do_nothing(void *unused) { /* @@ -910,7 +931,8 @@ void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) enabled_flush_types = types; - rfi_flush_enable(enable); + if (!no_rfi_flush) + rfi_flush_enable(enable); } #endif /* CONFIG_PPC_BOOK3S_64 */ #endif From a46ca307a405edda96daf54a5d8baa6778753e82 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 10 Jan 2018 03:07:15 +1100 Subject: [PATCH 170/266] powerpc/pseries: Query hypervisor for RFI flush settings commit 8989d56878a7735dfdb234707a2fee6faf631085 upstream. A new hypervisor call is available which tells the guest settings related to the RFI flush. Use it to query the appropriate flush instruction(s), and whether the flush is required. Signed-off-by: Michael Neuling Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/setup.c | 37 +++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 36df46eaba24..dd2545fc9947 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -499,6 +499,39 @@ static void __init find_and_init_phbs(void) of_pci_check_probe_only(); } +static void pseries_setup_rfi_flush(void) +{ + struct h_cpu_char_result result; + enum l1d_flush_type types; + bool enable; + long rc; + + /* Enable by default */ + enable = true; + + rc = plpar_get_cpu_characteristics(&result); + if (rc == H_SUCCESS) { + types = L1D_FLUSH_NONE; + + if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2) + types |= L1D_FLUSH_MTTRIG; + if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30) + types |= L1D_FLUSH_ORI; + + /* Use fallback if nothing set in hcall */ + if (types == L1D_FLUSH_NONE) + types = L1D_FLUSH_FALLBACK; + + if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) + enable = false; + } else { + /* Default to fallback if case hcall is not available */ + types = L1D_FLUSH_FALLBACK; + } + + setup_rfi_flush(types, enable); +} + static void __init pSeries_setup_arch(void) { set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); @@ -515,7 +548,9 @@ static void __init pSeries_setup_arch(void) fwnmi_init(); - /* By default, only probe PCI (can be overriden by rtas_pci) */ + pseries_setup_rfi_flush(); + + /* By default, only probe PCI (can be overridden by rtas_pci) */ pci_add_flags(PCI_PROBE_ONLY); /* Find and initialize PCI host bridges */ From 95e4f102222aea0c9ff89a5a04c44612d9e400e8 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Wed, 10 Jan 2018 03:07:15 +1100 Subject: [PATCH 171/266] powerpc/powernv: Check device-tree for RFI flush settings commit 6e032b350cd1fdb830f18f8320ef0e13b4e24094 upstream. New device-tree properties are available which tell the hypervisor settings related to the RFI flush. Use them to determine the appropriate flush instruction to use, and whether the flush is required. Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/setup.c | 50 ++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index f48afc06ba14..30c6b3b7be90 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -35,13 +35,63 @@ #include #include #include +#include +#include #include "powernv.h" +static void pnv_setup_rfi_flush(void) +{ + struct device_node *np, *fw_features; + enum l1d_flush_type type; + int enable; + + /* Default to fallback in case fw-features are not available */ + type = L1D_FLUSH_FALLBACK; + enable = 1; + + np = of_find_node_by_name(NULL, "ibm,opal"); + fw_features = of_get_child_by_name(np, "fw-features"); + of_node_put(np); + + if (fw_features) { + np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2"); + if (np && of_property_read_bool(np, "enabled")) + type = L1D_FLUSH_MTTRIG; + + of_node_put(np); + + np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0"); + if (np && of_property_read_bool(np, "enabled")) + type = L1D_FLUSH_ORI; + + of_node_put(np); + + /* Enable unless firmware says NOT to */ + enable = 2; + np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0"); + if (np && of_property_read_bool(np, "disabled")) + enable--; + + of_node_put(np); + + np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1"); + if (np && of_property_read_bool(np, "disabled")) + enable--; + + of_node_put(np); + of_node_put(fw_features); + } + + setup_rfi_flush(type, enable > 0); +} + static void __init pnv_setup_arch(void) { set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); + pnv_setup_rfi_flush(); + /* Initialize SMP */ pnv_smp_init(); From 1e8014e74b141979f0cf65bfabe9a077879b11a1 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 16 Jan 2018 21:20:05 +1100 Subject: [PATCH 172/266] powerpc/64s: Wire up cpu_show_meltdown() commit fd6e440f20b1a4304553775fc55938848ff617c9 upstream. The recent commit 87590ce6e373 ("sysfs/cpu: Add vulnerability folder") added a generic folder and set of files for reporting information on CPU vulnerabilities. One of those was for meltdown: /sys/devices/system/cpu/vulnerabilities/meltdown This commit wires up that file for 64-bit Book3S powerpc. For now we default to "Vulnerable" unless the RFI flush is enabled. That may not actually be true on all hardware, further patches will refine the reporting based on the CPU/platform etc. But for now we default to being pessimists. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/setup_64.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 0c26025e18f9..58a1fa979655 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -136,6 +136,7 @@ config PPC select GENERIC_SMP_IDLE_THREAD select GENERIC_CMOS_UPDATE select GENERIC_TIME_VSYSCALL_OLD + select GENERIC_CPU_VULNERABILITIES if PPC_BOOK3S_64 select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS_BROADCAST if SMP select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 7db464c2b129..cd7bfec17654 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -934,5 +934,13 @@ void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) if (!no_rfi_flush) rfi_flush_enable(enable); } + +ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) +{ + if (rfi_flush) + return sprintf(buf, "Mitigation: RFI Flush\n"); + + return sprintf(buf, "Vulnerable\n"); +} #endif /* CONFIG_PPC_BOOK3S_64 */ #endif From b074e0bd527686da77d4c7efbe77ecc52c470234 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 16 Jan 2018 22:17:18 +1100 Subject: [PATCH 173/266] powerpc/64s: Allow control of RFI flush via debugfs commit 236003e6b5443c45c18e613d2b0d776a9f87540e upstream. Expose the state of the RFI flush (enabled/disabled) via debugfs, and allow it to be enabled/disabled at runtime. eg: $ cat /sys/kernel/debug/powerpc/rfi_flush 1 $ echo 0 > /sys/kernel/debug/powerpc/rfi_flush $ cat /sys/kernel/debug/powerpc/rfi_flush 0 Signed-off-by: Michael Ellerman Reviewed-by: Nicholas Piggin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/setup_64.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index cd7bfec17654..df4a87eb8da4 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -935,6 +936,35 @@ void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) rfi_flush_enable(enable); } +#ifdef CONFIG_DEBUG_FS +static int rfi_flush_set(void *data, u64 val) +{ + if (val == 1) + rfi_flush_enable(true); + else if (val == 0) + rfi_flush_enable(false); + else + return -EINVAL; + + return 0; +} + +static int rfi_flush_get(void *data, u64 *val) +{ + *val = rfi_flush ? 1 : 0; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_rfi_flush, rfi_flush_get, rfi_flush_set, "%llu\n"); + +static __init int rfi_flush_debugfs_init(void) +{ + debugfs_create_file("rfi_flush", 0600, powerpc_debugfs_root, NULL, &fops_rfi_flush); + return 0; +} +device_initcall(rfi_flush_debugfs_init); +#endif + ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) { if (rfi_flush) From f056ba2f25857c55433341ccf473944082819f12 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Sun, 19 Nov 2017 23:45:49 -0800 Subject: [PATCH 174/266] ASoC: pcm512x: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE commit 0cab20cec0b663b7be8e2be5998d5a4113647f86 upstream. This change resolves a new compile-time warning when built as a loadable module: WARNING: modpost: missing MODULE_LICENSE() in sound/soc/codecs/snd-soc-pcm512x-spi.o see include/linux/module.h for more information This adds the license as "GPL v2", which matches the header of the file. MODULE_DESCRIPTION and MODULE_AUTHOR are also added. Signed-off-by: Jesse Chan Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/pcm512x-spi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c index 712ed6598c48..ebdf9bd5a64c 100644 --- a/sound/soc/codecs/pcm512x-spi.c +++ b/sound/soc/codecs/pcm512x-spi.c @@ -70,3 +70,7 @@ static struct spi_driver pcm512x_spi_driver = { }; module_spi_driver(pcm512x_spi_driver); + +MODULE_DESCRIPTION("ASoC PCM512x codec driver - SPI"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL v2"); From c8e409017adfc8e4a171da311636478945d54f66 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 5 Feb 2018 10:45:55 -0700 Subject: [PATCH 175/266] usbip: vhci_hcd: clear just the USB_PORT_STAT_POWER bit Upstream commit 1c9de5bf4286 ("usbip: vhci-hcd: Add USB3 SuperSpeed support") vhci_hcd clears all the bits port_status bits instead of clearing just the USB_PORT_STAT_POWER bit when it handles ClearPortFeature: USB_PORT_FEAT_POWER. This causes vhci_hcd attach to fail in a bad state, leaving device unusable by the client. The device is still attached and however client can't use it. The problem was fixed as part of larger change to add USB3 Super Speed support. This patch isolates the one line fix to clear the USB_PORT_STAT_POWER from the original patch. Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vhci_hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 00d68945548e..2d96bfd34138 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -285,7 +285,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_POWER: usbip_dbg_vhci_rh( " ClearPortFeature: USB_PORT_FEAT_POWER\n"); - dum->port_status[rhport] = 0; + dum->port_status[rhport] &= ~USB_PORT_STAT_POWER; dum->resuming = 0; break; case USB_PORT_FEAT_C_RESET: From 1a2018a7ed150fffcba87b3ce67d56f4b9e991a7 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 5 Feb 2018 10:45:56 -0700 Subject: [PATCH 176/266] usbip: fix 3eee23c3ec14 tcp_socket address still in the status file Commit 3eee23c3ec14 ("usbip: prevent vhci_hcd driver from leaking a socket pointer address") backported the following commit from mailine. However, backport error caused the tcp_socket address to still leak. commit 2f2d0088eb93 ("usbip: prevent vhci_hcd driver from leaking a socket pointer address") When a client has a USB device attached over IP, the vhci_hcd driver is locally leaking a socket pointer address via the /sys/devices/platform/vhci_hcd/status file (world-readable) and in debug output when "usbip --debug port" is run. Fix it to not leak. The socket pointer address is not used at the moment and it was made visible as a convenient way to find IP address from socket pointer address by looking up /proc/net/{tcp,tcp6}. As this opens a security hole, the fix replaces socket pointer address with sockfd. Reported-by: Eric Biggers Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vhci_sysfs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 1c7f41a65565..b9432fdec775 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -53,7 +53,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr, * a security hole, the change is made to use sockfd instead. */ out += sprintf(out, - "prt sta spd bus dev sockfd local_busid\n"); + "prt sta spd dev sockfd local_busid\n"); for (i = 0; i < VHCI_NPORTS; i++) { struct vhci_device *vdev = port_to_vdev(i); @@ -64,12 +64,11 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr, if (vdev->ud.status == VDEV_ST_USED) { out += sprintf(out, "%03u %08x ", vdev->speed, vdev->devid); - out += sprintf(out, "%16p ", vdev->ud.tcp_socket); - out += sprintf(out, "%06u", vdev->ud.sockfd); + out += sprintf(out, "%06u ", vdev->ud.sockfd); out += sprintf(out, "%s", dev_name(&vdev->udev->dev)); } else - out += sprintf(out, "000 000 000 000000 0-0"); + out += sprintf(out, "000 00000000 000000 0-0"); out += sprintf(out, "\n"); spin_unlock(&vdev->ud.lock); From 197ceb5fc08493bbc7913743a5b6e5aa897d3ed7 Mon Sep 17 00:00:00 2001 From: Matthias Hintzmann Date: Tue, 6 Feb 2018 20:59:01 +0100 Subject: [PATCH 177/266] net: cdc_ncm: initialize drvflags before usage ctx->drvflags is checked in the if clause before beeing initialized. Move initialization before first usage. Note, that the if clause was backported with commit 75f82a703b30 ("cdc_ncm: Set NTB format again after altsetting switch for Huawei devices") from mainline (upstream commit 2b02c20ce0c2 ("cdc_ncm: Set NTB format again after altsetting switch for Huawei devices"). In mainline, the initialization is at the right place before the if clause. [mrkiko.rs@gmail.com: commit message tweaks] Fixes: 75f82a703b30 ("cdc_ncm: Set NTB format again after altsetting switch for Huawei devices") Signed-off-by: Matthias Hintzmann Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_ncm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 1228d0da4075..72cb30828a12 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -825,6 +825,9 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ goto error2; } + /* Device-specific flags */ + ctx->drvflags = drvflags; + /* * Some Huawei devices have been observed to come out of reset in NDP32 mode. * Let's check if this is the case, and set the device to NDP16 mode again if @@ -873,9 +876,6 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ /* finish setting up the device specific data */ cdc_ncm_setup(dev); - /* Device-specific flags */ - ctx->drvflags = drvflags; - /* Allocate the delayed NDP if needed. */ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL); From 69fcbf02d56f3bb08d661b21429f7fcf5374e439 Mon Sep 17 00:00:00 2001 From: Julian Scheel Date: Wed, 24 May 2017 12:28:23 +0200 Subject: [PATCH 178/266] ASoC: simple-card: Fix misleading error message commit 7ac45d1635a4cd2e99a4b11903d4a2815ca1b27b upstream. In case cpu could not be found the error message would always refer to /codec/ not being found in DT. Fix this by catching the cpu node not found case explicitly. Signed-off-by: Julian Scheel Signed-off-by: Mark Brown Signed-off-by: thongsyho Signed-off-by: Nhan Nguyen Signed-off-by: Greg Kroah-Hartman --- sound/soc/generic/simple-card.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index ff6fcd9f92f7..0b1b6fcb7500 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -343,13 +343,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, snprintf(prop, sizeof(prop), "%scpu", prefix); cpu = of_get_child_by_name(node, prop); + if (!cpu) { + ret = -EINVAL; + dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); + goto dai_link_of_err; + } + snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); snprintf(prop, sizeof(prop), "%scodec", prefix); codec = of_get_child_by_name(node, prop); - if (!cpu || !codec) { + if (!codec) { ret = -EINVAL; dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); goto dai_link_of_err; From e09eea9417d7c57546f12a5678440d3932960f71 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 May 2017 01:48:24 +0000 Subject: [PATCH 179/266] ASoC: rsnd: don't call free_irq() on Parent SSI commit 1f8754d4daea5f257370a52a30fcb22798c54516 upstream. If SSI uses shared pin, some SSI will be used as parent SSI. Then, normal SSI's remove and Parent SSI's remove (these are same SSI) will be called when unbind or remove timing. In this case, free_irq() will be called twice. This patch solve this issue. Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Reported-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown Signed-off-by: thongsyho Signed-off-by: Nhan Nguyen Signed-off-by: Greg Kroah-Hartman --- sound/soc/sh/rcar/rsnd.h | 2 ++ sound/soc/sh/rcar/ssi.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 085329878525..5976e3992dd1 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -235,6 +235,7 @@ enum rsnd_mod_type { RSND_MOD_MIX, RSND_MOD_CTU, RSND_MOD_SRC, + RSND_MOD_SSIP, /* SSI parent */ RSND_MOD_SSI, RSND_MOD_MAX, }; @@ -365,6 +366,7 @@ struct rsnd_dai_stream { }; #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) #define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index c62a2947ac14..94739b7aca77 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -550,11 +550,16 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); struct device *dev = rsnd_priv_to_dev(priv); int irq = ssi->info->irq; rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); + /* Do nothing for SSI parent mod */ + if (ssi_parent_mod == mod) + return 0; + /* PIO will request IRQ again */ devm_free_irq(dev, irq, mod); From 1e5ed917dc65aee4c8840686bf83c4a55ad4210d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 9 Aug 2017 02:16:20 +0000 Subject: [PATCH 180/266] ASoC: rsnd: avoid duplicate free_irq() commit e0936c3471a8411a5df327641fa3ffe12a2fb07b upstream. commit 1f8754d4daea5f ("ASoC: rsnd: don't call free_irq() on Parent SSI") fixed Parent SSI duplicate free_irq(). But on Renesas Sound, not only Parent SSI but also Multi SSI have same issue. This patch avoid duplicate free_irq() if it was not pure SSI. Fixes: 1f8754d4daea5f ("ASoC: rsnd: don't call free_irq() on Parent SSI") Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown Signed-off-by: thongsyho Signed-off-by: Nhan Nguyen Signed-off-by: Greg Kroah-Hartman --- sound/soc/sh/rcar/ssi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 94739b7aca77..38aae96267c9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -550,14 +550,14 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); + struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io); struct device *dev = rsnd_priv_to_dev(priv); int irq = ssi->info->irq; rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); - /* Do nothing for SSI parent mod */ - if (ssi_parent_mod == mod) + /* Do nothing if non SSI (= SSI parent, multi SSI) mod */ + if (pure_ssi_mod != mod) return 0; /* PIO will request IRQ again */ From a2f17cb2fe61f551e7dfd380de2f795a1c970346 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 10 Jul 2017 23:46:39 +0300 Subject: [PATCH 181/266] drm: rcar-du: Use the VBK interrupt for vblank events commit cbbb90b0c084d7dfb2ed8e3fecf8df200fbdd2a0 upstream. When implementing support for interlaced modes, the driver switched from reporting vblank events on the vertical blanking (VBK) interrupt to the frame end interrupt (FRM). This incorrectly divided the reported refresh rate by two. Fix it by moving back to the VBK interrupt. Fixes: 906eff7fcada ("drm: rcar-du: Implement support for interlaced modes") Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Signed-off-by: thongsyho Signed-off-by: Nhan Nguyen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 9befd624a5f0..25bdab6fc380 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -531,7 +531,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) status = rcar_du_crtc_read(rcrtc, DSSR); rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); - if (status & DSSR_FRM) { + if (status & DSSR_VBK) { drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index); rcar_du_crtc_finish_page_flip(rcrtc); ret = IRQ_HANDLED; From eb0a0e276988bf3cb84c630ddee5d47caa9ff176 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 29 Jul 2017 02:31:33 +0300 Subject: [PATCH 182/266] drm: rcar-du: Fix race condition when disabling planes at CRTC stop commit 641307df71fe77d7b38a477067495ede05d47295 upstream. When stopping the CRTC the driver must disable all planes and wait for the change to take effect at the next vblank. Merely calling drm_crtc_wait_one_vblank() is not enough, as the function doesn't include any mechanism to handle the race with vblank interrupts. Replace the drm_crtc_wait_one_vblank() call with a manual mechanism that handles the vblank interrupt race. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Signed-off-by: thongsyho Signed-off-by: Nhan Nguyen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 54 +++++++++++++++++++++++--- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 8 ++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 25bdab6fc380..6fab07935d16 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -371,6 +371,31 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) rcrtc->started = true; } +static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc) +{ + struct rcar_du_device *rcdu = rcrtc->group->dev; + struct drm_crtc *crtc = &rcrtc->crtc; + u32 status; + /* Make sure vblank interrupts are enabled. */ + drm_crtc_vblank_get(crtc); + /* + * Disable planes and calculate how many vertical blanking interrupts we + * have to wait for. If a vertical blanking interrupt has been triggered + * but not processed yet, we don't know whether it occurred before or + * after the planes got disabled. We thus have to wait for two vblank + * interrupts in that case. + */ + spin_lock_irq(&rcrtc->vblank_lock); + rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); + status = rcar_du_crtc_read(rcrtc, DSSR); + rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1; + spin_unlock_irq(&rcrtc->vblank_lock); + if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0, + msecs_to_jiffies(100))) + dev_warn(rcdu->dev, "vertical blanking timeout\n"); + drm_crtc_vblank_put(crtc); +} + static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) { struct drm_crtc *crtc = &rcrtc->crtc; @@ -379,17 +404,16 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) return; /* Disable all planes and wait for the change to take effect. This is - * required as the DSnPR registers are updated on vblank, and no vblank - * will occur once the CRTC is stopped. Disabling planes when starting - * the CRTC thus wouldn't be enough as it would start scanning out - * immediately from old frame buffers until the next vblank. + * required as the plane enable registers are updated on vblank, and no + * vblank will occur once the CRTC is stopped. Disabling planes when + * starting the CRTC thus wouldn't be enough as it would start scanning + * out immediately from old frame buffers until the next vblank. * * This increases the CRTC stop delay, especially when multiple CRTCs * are stopped in one operation as we now wait for one vblank per CRTC. * Whether this can be improved needs to be researched. */ - rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); - drm_crtc_wait_one_vblank(crtc); + rcar_du_crtc_disable_planes(rcrtc); /* Disable vertical blanking interrupt reporting. We first need to wait * for page flip completion before stopping the CRTC as userspace @@ -528,9 +552,25 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) irqreturn_t ret = IRQ_NONE; u32 status; + spin_lock(&rcrtc->vblank_lock); + status = rcar_du_crtc_read(rcrtc, DSSR); rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); + if (status & DSSR_VBK) { + /* + * Wake up the vblank wait if the counter reaches 0. This must + * be protected by the vblank_lock to avoid races in + * rcar_du_crtc_disable_planes(). + */ + if (rcrtc->vblank_count) { + if (--rcrtc->vblank_count == 0) + wake_up(&rcrtc->vblank_wait); + } + } + + spin_unlock(&rcrtc->vblank_lock); + if (status & DSSR_VBK) { drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index); rcar_du_crtc_finish_page_flip(rcrtc); @@ -585,6 +625,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) } init_waitqueue_head(&rcrtc->flip_wait); + init_waitqueue_head(&rcrtc->vblank_wait); + spin_lock_init(&rcrtc->vblank_lock); rcrtc->group = rgrp; rcrtc->mmio_offset = mmio_offsets[index]; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 2bbe3f5aab65..be22ce33b70a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -15,6 +15,7 @@ #define __RCAR_DU_CRTC_H__ #include +#include #include #include @@ -32,6 +33,9 @@ struct rcar_du_group; * @started: whether the CRTC has been started and is running * @event: event to post when the pending page flip completes * @flip_wait: wait queue used to signal page flip completion + * @vblank_lock: protects vblank_wait and vblank_count + * @vblank_wait: wait queue used to signal vertical blanking + * @vblank_count: number of vertical blanking interrupts to wait for * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC * @enabled: whether the CRTC is enabled, used to control system resume * @group: CRTC group this CRTC belongs to @@ -48,6 +52,10 @@ struct rcar_du_crtc { struct drm_pending_vblank_event *event; wait_queue_head_t flip_wait; + spinlock_t vblank_lock; + wait_queue_head_t vblank_wait; + unsigned int vblank_count; + unsigned int outputs; bool enabled; From 69f9dc4b71a70a2bbc23eaa57525df3ecdc881a3 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 28 Sep 2017 16:58:26 -0500 Subject: [PATCH 183/266] x86/asm: Fix inline asm call constraints for GCC 4.4 commit 520a13c530aeb5f63e011d668c42db1af19ed349 upstream. The kernel test bot (run by Xiaolong Ye) reported that the following commit: f5caf621ee35 ("x86/asm: Fix inline asm call constraints for Clang") is causing double faults in a kernel compiled with GCC 4.4. Linus subsequently diagnosed the crash pattern and the buggy commit and found that the issue is with this code: register unsigned int __asm_call_sp asm("esp"); #define ASM_CALL_CONSTRAINT "+r" (__asm_call_sp) Even on a 64-bit kernel, it's using ESP instead of RSP. That causes GCC to produce the following bogus code: ffffffff8147461d: 89 e0 mov %esp,%eax ffffffff8147461f: 4c 89 f7 mov %r14,%rdi ffffffff81474622: 4c 89 fe mov %r15,%rsi ffffffff81474625: ba 20 00 00 00 mov $0x20,%edx ffffffff8147462a: 89 c4 mov %eax,%esp ffffffff8147462c: e8 bf 52 05 00 callq ffffffff814c98f0 Despite the absurdity of it backing up and restoring the stack pointer for no reason, the bug is actually the fact that it's only backing up and restoring the lower 32 bits of the stack pointer. The upper 32 bits are getting cleared out, corrupting the stack pointer. So change the '__asm_call_sp' register variable to be associated with the actual full-size stack pointer. This also requires changing the __ASM_SEL() macro to be based on the actual compiled arch size, rather than the CONFIG value, because CONFIG_X86_64 compiles some files with '-m32' (e.g., realmode and vdso). Otherwise Clang fails to build the kernel because it complains about the use of a 64-bit register (RSP) in a 32-bit file. Reported-and-Bisected-and-Tested-by: kernel test robot Diagnosed-by: Linus Torvalds Signed-off-by: Josh Poimboeuf Cc: Alexander Potapenko Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Arnd Bergmann Cc: Dmitriy Vyukov Cc: LKP Cc: Linus Torvalds Cc: Matthias Kaehlcke Cc: Miguel Bernal Marin Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: f5caf621ee35 ("x86/asm: Fix inline asm call constraints for Clang") Link: http://lkml.kernel.org/r/20170928215826.6sdpmwtkiydiytim@treble Signed-off-by: Ingo Molnar Cc: Matthias Kaehlcke Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/asm.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index b9c6c7a6f5a6..1c79c8add0eb 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -11,10 +11,12 @@ # define __ASM_FORM_COMMA(x) " " #x "," #endif -#ifdef CONFIG_X86_32 +#ifndef __x86_64__ +/* 32 bit */ # define __ASM_SEL(a,b) __ASM_FORM(a) # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a) #else +/* 64 bit */ # define __ASM_SEL(a,b) __ASM_FORM(b) # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b) #endif From fff4f776df44afa3fd6ce043ca82c8b317294ad1 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 31 Jan 2018 16:29:30 +0200 Subject: [PATCH 184/266] ip6mr: fix stale iterator [ Upstream commit 4adfa79fc254efb7b0eb3cd58f62c2c3f805f1ba ] When we dump the ip6mr mfc entries via proc, we initialize an iterator with the table to dump but we don't clear the cache pointer which might be initialized from a prior read on the same descriptor that ended. This can result in lock imbalance (an unnecessary unlock) leading to other crashes and hangs. Clear the cache pointer like ipmr does to fix the issue. Thanks for the reliable reproducer. Here's syzbot's trace: WARNING: bad unlock balance detected! 4.15.0-rc3+ #128 Not tainted syzkaller971460/3195 is trying to release lock (mrt_lock) at: [<000000006898068d>] ipmr_mfc_seq_stop+0xe1/0x130 net/ipv6/ip6mr.c:553 but there are no more locks to release! other info that might help us debug this: 1 lock held by syzkaller971460/3195: #0: (&p->lock){+.+.}, at: [<00000000744a6565>] seq_read+0xd5/0x13d0 fs/seq_file.c:165 stack backtrace: CPU: 1 PID: 3195 Comm: syzkaller971460 Not tainted 4.15.0-rc3+ #128 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x257 lib/dump_stack.c:53 print_unlock_imbalance_bug+0x12f/0x140 kernel/locking/lockdep.c:3561 __lock_release kernel/locking/lockdep.c:3775 [inline] lock_release+0x5f9/0xda0 kernel/locking/lockdep.c:4023 __raw_read_unlock include/linux/rwlock_api_smp.h:225 [inline] _raw_read_unlock+0x1a/0x30 kernel/locking/spinlock.c:255 ipmr_mfc_seq_stop+0xe1/0x130 net/ipv6/ip6mr.c:553 traverse+0x3bc/0xa00 fs/seq_file.c:135 seq_read+0x96a/0x13d0 fs/seq_file.c:189 proc_reg_read+0xef/0x170 fs/proc/inode.c:217 do_loop_readv_writev fs/read_write.c:673 [inline] do_iter_read+0x3db/0x5b0 fs/read_write.c:897 compat_readv+0x1bf/0x270 fs/read_write.c:1140 do_compat_preadv64+0xdc/0x100 fs/read_write.c:1189 C_SYSC_preadv fs/read_write.c:1209 [inline] compat_SyS_preadv+0x3b/0x50 fs/read_write.c:1203 do_syscall_32_irqs_on arch/x86/entry/common.c:327 [inline] do_fast_syscall_32+0x3ee/0xf9d arch/x86/entry/common.c:389 entry_SYSENTER_compat+0x51/0x60 arch/x86/entry/entry_64_compat.S:125 RIP: 0023:0xf7f73c79 RSP: 002b:00000000e574a15c EFLAGS: 00000292 ORIG_RAX: 000000000000014d RAX: ffffffffffffffda RBX: 000000000000000f RCX: 0000000020a3afb0 RDX: 0000000000000001 RSI: 0000000000000067 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 BUG: sleeping function called from invalid context at lib/usercopy.c:25 in_atomic(): 1, irqs_disabled(): 0, pid: 3195, name: syzkaller971460 INFO: lockdep is turned off. CPU: 1 PID: 3195 Comm: syzkaller971460 Not tainted 4.15.0-rc3+ #128 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x257 lib/dump_stack.c:53 ___might_sleep+0x2b2/0x470 kernel/sched/core.c:6060 __might_sleep+0x95/0x190 kernel/sched/core.c:6013 __might_fault+0xab/0x1d0 mm/memory.c:4525 _copy_to_user+0x2c/0xc0 lib/usercopy.c:25 copy_to_user include/linux/uaccess.h:155 [inline] seq_read+0xcb4/0x13d0 fs/seq_file.c:279 proc_reg_read+0xef/0x170 fs/proc/inode.c:217 do_loop_readv_writev fs/read_write.c:673 [inline] do_iter_read+0x3db/0x5b0 fs/read_write.c:897 compat_readv+0x1bf/0x270 fs/read_write.c:1140 do_compat_preadv64+0xdc/0x100 fs/read_write.c:1189 C_SYSC_preadv fs/read_write.c:1209 [inline] compat_SyS_preadv+0x3b/0x50 fs/read_write.c:1203 do_syscall_32_irqs_on arch/x86/entry/common.c:327 [inline] do_fast_syscall_32+0x3ee/0xf9d arch/x86/entry/common.c:389 entry_SYSENTER_compat+0x51/0x60 arch/x86/entry/entry_64_compat.S:125 RIP: 0023:0xf7f73c79 RSP: 002b:00000000e574a15c EFLAGS: 00000292 ORIG_RAX: 000000000000014d RAX: ffffffffffffffda RBX: 000000000000000f RCX: 0000000020a3afb0 RDX: 0000000000000001 RSI: 0000000000000067 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 WARNING: CPU: 1 PID: 3195 at lib/usercopy.c:26 _copy_to_user+0xb5/0xc0 lib/usercopy.c:26 Reported-by: syzbot Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6mr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 8361d73ab653..e5846d1f9b55 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -495,6 +495,7 @@ static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) return ERR_PTR(-ENOENT); it->mrt = mrt; + it->cache = NULL; return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1) : SEQ_START_TOKEN; } From 47b32f0653d758b5920d98924f164a2d9a02c662 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 1 Feb 2018 10:26:57 -0800 Subject: [PATCH 185/266] net: igmp: add a missing rcu locking section [ Upstream commit e7aadb27a5415e8125834b84a74477bfbee4eff5 ] Newly added igmpv3_get_srcaddr() needs to be called under rcu lock. Timer callbacks do not ensure this locking. ============================= WARNING: suspicious RCU usage 4.15.0+ #200 Not tainted ----------------------------- ./include/linux/inetdevice.h:216 suspicious rcu_dereference_check() usage! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 3 locks held by syzkaller616973/4074: #0: (&mm->mmap_sem){++++}, at: [<00000000bfce669e>] __do_page_fault+0x32d/0xc90 arch/x86/mm/fault.c:1355 #1: ((&im->timer)){+.-.}, at: [<00000000619d2f71>] lockdep_copy_map include/linux/lockdep.h:178 [inline] #1: ((&im->timer)){+.-.}, at: [<00000000619d2f71>] call_timer_fn+0x1c6/0x820 kernel/time/timer.c:1316 #2: (&(&im->lock)->rlock){+.-.}, at: [<000000005f833c5c>] spin_lock_bh include/linux/spinlock.h:315 [inline] #2: (&(&im->lock)->rlock){+.-.}, at: [<000000005f833c5c>] igmpv3_send_report+0x98/0x5b0 net/ipv4/igmp.c:600 stack backtrace: CPU: 0 PID: 4074 Comm: syzkaller616973 Not tainted 4.15.0+ #200 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x257 lib/dump_stack.c:53 lockdep_rcu_suspicious+0x123/0x170 kernel/locking/lockdep.c:4592 __in_dev_get_rcu include/linux/inetdevice.h:216 [inline] igmpv3_get_srcaddr net/ipv4/igmp.c:329 [inline] igmpv3_newpack+0xeef/0x12e0 net/ipv4/igmp.c:389 add_grhead.isra.27+0x235/0x300 net/ipv4/igmp.c:432 add_grec+0xbd3/0x1170 net/ipv4/igmp.c:565 igmpv3_send_report+0xd5/0x5b0 net/ipv4/igmp.c:605 igmp_send_report+0xc43/0x1050 net/ipv4/igmp.c:722 igmp_timer_expire+0x322/0x5c0 net/ipv4/igmp.c:831 call_timer_fn+0x228/0x820 kernel/time/timer.c:1326 expire_timers kernel/time/timer.c:1363 [inline] __run_timers+0x7ee/0xb70 kernel/time/timer.c:1666 run_timer_softirq+0x4c/0x70 kernel/time/timer.c:1692 __do_softirq+0x2d7/0xb85 kernel/softirq.c:285 invoke_softirq kernel/softirq.c:365 [inline] irq_exit+0x1cc/0x200 kernel/softirq.c:405 exiting_irq arch/x86/include/asm/apic.h:541 [inline] smp_apic_timer_interrupt+0x16b/0x700 arch/x86/kernel/apic/apic.c:1052 apic_timer_interrupt+0xa9/0xb0 arch/x86/entry/entry_64.S:938 Fixes: a46182b00290 ("net: igmp: Use correct source address on IGMPv3 reports") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/igmp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 8212ed80da48..c67efa3e79dd 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -392,7 +392,11 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) pip->frag_off = htons(IP_DF); pip->ttl = 1; pip->daddr = fl4.daddr; + + rcu_read_lock(); pip->saddr = igmpv3_get_srcaddr(dev, &fl4); + rcu_read_unlock(); + pip->protocol = IPPROTO_IGMP; pip->tot_len = 0; /* filled in later */ ip_select_ident(net, skb, NULL); From 3cdf2975d9773249ca09c8de0f79637bcb9bee41 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Mon, 29 Jan 2018 17:53:42 +0800 Subject: [PATCH 186/266] qlcnic: fix deadlock bug [ Upstream commit 233ac3891607f501f08879134d623b303838f478 ] The following soft lockup was caught. This is a deadlock caused by recusive locking. Process kworker/u40:1:28016 was holding spin lock "mbx->queue_lock" in qlcnic_83xx_mailbox_worker(), while a softirq came in and ask the same spin lock in qlcnic_83xx_enqueue_mbx_cmd(). This lock should be hold by disable bh.. [161846.962125] NMI watchdog: BUG: soft lockup - CPU#1 stuck for 22s! [kworker/u40:1:28016] [161846.962367] Modules linked in: tun ocfs2 xen_netback xen_blkback xen_gntalloc xen_gntdev xen_evtchn xenfs xen_privcmd autofs4 ocfs2_dlmfs ocfs2_stack_o2cb ocfs2_dlm ocfs2_nodemanager ocfs2_stackglue configfs bnx2fc fcoe libfcoe libfc sunrpc 8021q mrp garp bridge stp llc bonding dm_round_robin dm_multipath iTCO_wdt iTCO_vendor_support pcspkr sb_edac edac_core i2c_i801 shpchp lpc_ich mfd_core ioatdma ipmi_devintf ipmi_si ipmi_msghandler sg ext4 jbd2 mbcache2 sr_mod cdrom sd_mod igb i2c_algo_bit i2c_core ahci libahci megaraid_sas ixgbe dca ptp pps_core vxlan udp_tunnel ip6_udp_tunnel qla2xxx scsi_transport_fc qlcnic crc32c_intel be2iscsi bnx2i cnic uio cxgb4i cxgb4 cxgb3i libcxgbi ipv6 cxgb3 mdio libiscsi_tcp qla4xxx iscsi_boot_sysfs libiscsi scsi_transport_iscsi dm_mirror dm_region_hash dm_log dm_mod [161846.962454] [161846.962460] CPU: 1 PID: 28016 Comm: kworker/u40:1 Not tainted 4.1.12-94.5.9.el6uek.x86_64 #2 [161846.962463] Hardware name: Oracle Corporation SUN SERVER X4-2L /ASSY,MB,X4-2L , BIOS 26050100 09/19/2017 [161846.962489] Workqueue: qlcnic_mailbox qlcnic_83xx_mailbox_worker [qlcnic] [161846.962493] task: ffff8801f2e34600 ti: ffff88004ca5c000 task.ti: ffff88004ca5c000 [161846.962496] RIP: e030:[] [] xen_hypercall_sched_op+0xa/0x20 [161846.962506] RSP: e02b:ffff880202e43388 EFLAGS: 00000206 [161846.962509] RAX: 0000000000000000 RBX: ffff8801f6996b70 RCX: ffffffff810013aa [161846.962511] RDX: ffff880202e433cc RSI: ffff880202e433b0 RDI: 0000000000000003 [161846.962513] RBP: ffff880202e433d0 R08: 0000000000000000 R09: ffff8801fe893200 [161846.962516] R10: ffff8801fe400538 R11: 0000000000000206 R12: ffff880202e4b000 [161846.962518] R13: 0000000000000050 R14: 0000000000000001 R15: 000000000000020d [161846.962528] FS: 0000000000000000(0000) GS:ffff880202e40000(0000) knlGS:ffff880202e40000 [161846.962531] CS: e033 DS: 0000 ES: 0000 CR0: 0000000080050033 [161846.962533] CR2: 0000000002612640 CR3: 00000001bb796000 CR4: 0000000000042660 [161846.962536] Stack: [161846.962538] ffff880202e43608 0000000000000000 ffffffff813f0442 ffff880202e433b0 [161846.962543] 0000000000000000 ffff880202e433cc ffffffff00000001 0000000000000000 [161846.962547] 00000009813f03d6 ffff880202e433e0 ffffffff813f0460 ffff880202e43440 [161846.962552] Call Trace: [161846.962555] [161846.962565] [] ? xen_poll_irq_timeout+0x42/0x50 [161846.962570] [] xen_poll_irq+0x10/0x20 [161846.962578] [] xen_lock_spinning+0xe2/0x110 [161846.962583] [] __raw_callee_save_xen_lock_spinning+0x11/0x20 [161846.962592] [] ? _raw_spin_lock+0x57/0x80 [161846.962609] [] qlcnic_83xx_enqueue_mbx_cmd+0x7c/0xe0 [qlcnic] [161846.962623] [] qlcnic_83xx_issue_cmd+0x58/0x210 [qlcnic] [161846.962636] [] qlcnic_83xx_sre_macaddr_change+0x162/0x1d0 [qlcnic] [161846.962649] [] qlcnic_83xx_change_l2_filter+0x2b/0x30 [qlcnic] [161846.962657] [] ? __skb_flow_dissect+0x18b/0x650 [161846.962670] [] qlcnic_send_filter+0x205/0x250 [qlcnic] [161846.962682] [] qlcnic_xmit_frame+0x547/0x7b0 [qlcnic] [161846.962691] [] xmit_one+0x82/0x1a0 [161846.962696] [] dev_hard_start_xmit+0x50/0xa0 [161846.962701] [] sch_direct_xmit+0x112/0x220 [161846.962706] [] __dev_queue_xmit+0x1df/0x5e0 [161846.962710] [] dev_queue_xmit_sk+0x13/0x20 [161846.962721] [] bond_dev_queue_xmit+0x35/0x80 [bonding] [161846.962729] [] __bond_start_xmit+0x1cb/0x210 [bonding] [161846.962736] [] bond_start_xmit+0x31/0x60 [bonding] [161846.962740] [] xmit_one+0x82/0x1a0 [161846.962745] [] dev_hard_start_xmit+0x50/0xa0 [161846.962749] [] __dev_queue_xmit+0x4ee/0x5e0 [161846.962754] [] dev_queue_xmit_sk+0x13/0x20 [161846.962760] [] vlan_dev_hard_start_xmit+0xb2/0x150 [8021q] [161846.962764] [] xmit_one+0x82/0x1a0 [161846.962769] [] dev_hard_start_xmit+0x50/0xa0 [161846.962773] [] __dev_queue_xmit+0x4ee/0x5e0 [161846.962777] [] dev_queue_xmit_sk+0x13/0x20 [161846.962789] [] br_dev_queue_push_xmit+0x54/0xa0 [bridge] [161846.962797] [] br_forward_finish+0x2f/0x90 [bridge] [161846.962807] [] ? ttwu_do_wakeup+0x1d/0x100 [161846.962811] [] ? __alloc_skb+0x8b/0x1f0 [161846.962818] [] __br_forward+0x8d/0x120 [bridge] [161846.962822] [] ? __kmalloc_reserve+0x3b/0xa0 [161846.962829] [] ? update_rq_runnable_avg+0xee/0x230 [161846.962836] [] br_forward+0x96/0xb0 [bridge] [161846.962845] [] br_handle_frame_finish+0x1ae/0x420 [bridge] [161846.962853] [] br_handle_frame+0x17f/0x260 [bridge] [161846.962862] [] ? br_handle_frame_finish+0x420/0x420 [bridge] [161846.962867] [] __netif_receive_skb_core+0x1f7/0x870 [161846.962872] [] __netif_receive_skb+0x22/0x70 [161846.962877] [] netif_receive_skb_internal+0x23/0x90 [161846.962884] [] ? xenvif_idx_release+0xea/0x100 [xen_netback] [161846.962889] [] ? _raw_spin_unlock_irqrestore+0x20/0x50 [161846.962893] [] netif_receive_skb_sk+0x24/0x90 [161846.962899] [] xenvif_tx_submit+0x2ca/0x3f0 [xen_netback] [161846.962906] [] xenvif_tx_action+0x9c/0xd0 [xen_netback] [161846.962915] [] xenvif_poll+0x35/0x70 [xen_netback] [161846.962920] [] napi_poll+0xcb/0x1e0 [161846.962925] [] net_rx_action+0x90/0x1c0 [161846.962931] [] __do_softirq+0x10a/0x350 [161846.962938] [] irq_exit+0x125/0x130 [161846.962943] [] xen_evtchn_do_upcall+0x39/0x50 [161846.962950] [] xen_do_hypervisor_callback+0x1e/0x40 [161846.962952] [161846.962959] [] ? _raw_spin_lock+0x4a/0x80 [161846.962964] [] ? _raw_spin_lock_irqsave+0x1e/0xa0 [161846.962978] [] ? qlcnic_83xx_mailbox_worker+0xb9/0x2a0 [qlcnic] [161846.962991] [] ? process_one_work+0x151/0x4b0 [161846.962995] [] ? check_events+0x12/0x20 [161846.963001] [] ? worker_thread+0x120/0x480 [161846.963005] [] ? __schedule+0x30b/0x890 [161846.963010] [] ? process_one_work+0x4b0/0x4b0 [161846.963015] [] ? process_one_work+0x4b0/0x4b0 [161846.963021] [] ? kthread+0xce/0xf0 [161846.963025] [] ? kthread_freezable_should_stop+0x70/0x70 [161846.963031] [] ? ret_from_fork+0x42/0x70 [161846.963035] [] ? kthread_freezable_should_stop+0x70/0x70 [161846.963037] Code: cc 51 41 53 b8 1c 00 00 00 0f 05 41 5b 59 c3 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc 51 41 53 b8 1d 00 00 00 0f 05 <41> 5b 59 c3 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc Signed-off-by: Junxiao Bi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- .../ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index f9640d5ce6ba..b4f3cb55605e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -3850,7 +3850,7 @@ static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter) struct list_head *head = &mbx->cmd_q; struct qlcnic_cmd_args *cmd = NULL; - spin_lock(&mbx->queue_lock); + spin_lock_bh(&mbx->queue_lock); while (!list_empty(head)) { cmd = list_entry(head->next, struct qlcnic_cmd_args, list); @@ -3861,7 +3861,7 @@ static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter) qlcnic_83xx_notify_cmd_completion(adapter, cmd); } - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); } static int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter) @@ -3897,12 +3897,12 @@ static void qlcnic_83xx_dequeue_mbx_cmd(struct qlcnic_adapter *adapter, { struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; - spin_lock(&mbx->queue_lock); + spin_lock_bh(&mbx->queue_lock); list_del(&cmd->list); mbx->num_cmds--; - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); qlcnic_83xx_notify_cmd_completion(adapter, cmd); } @@ -3967,7 +3967,7 @@ static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter, init_completion(&cmd->completion); cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN; - spin_lock(&mbx->queue_lock); + spin_lock_bh(&mbx->queue_lock); list_add_tail(&cmd->list, &mbx->cmd_q); mbx->num_cmds++; @@ -3975,7 +3975,7 @@ static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter, *timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT; queue_work(mbx->work_q, &mbx->work); - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); return 0; } @@ -4071,15 +4071,15 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work) mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT; spin_unlock_irqrestore(&mbx->aen_lock, flags); - spin_lock(&mbx->queue_lock); + spin_lock_bh(&mbx->queue_lock); if (list_empty(head)) { - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); return; } cmd = list_entry(head->next, struct qlcnic_cmd_args, list); - spin_unlock(&mbx->queue_lock); + spin_unlock_bh(&mbx->queue_lock); mbx_ops->encode_cmd(adapter, cmd); mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST); From 9a0ef3cc115962b73564615c8d70922f6f673d2a Mon Sep 17 00:00:00 2001 From: Chunhao Lin Date: Wed, 31 Jan 2018 01:32:36 +0800 Subject: [PATCH 187/266] r8169: fix RTL8168EP take too long to complete driver initialization. [ Upstream commit 086ca23d03c0d2f4088f472386778d293e15c5f6 ] Driver check the wrong register bit in rtl_ocp_tx_cond() that keep driver waiting until timeout. Fix this by waiting for the right register bit. Signed-off-by: Chunhao Lin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 24155380e43c..3783c40f568b 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -1387,7 +1387,7 @@ DECLARE_RTL_COND(rtl_ocp_tx_cond) { void __iomem *ioaddr = tp->mmio_addr; - return RTL_R8(IBISR0) & 0x02; + return RTL_R8(IBISR0) & 0x20; } static void rtl8168ep_stop_cmac(struct rtl8169_private *tp) @@ -1395,7 +1395,7 @@ static void rtl8168ep_stop_cmac(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; RTL_W8(IBCR2, RTL_R8(IBCR2) & ~0x01); - rtl_msleep_loop_wait_low(tp, &rtl_ocp_tx_cond, 50, 2000); + rtl_msleep_loop_wait_high(tp, &rtl_ocp_tx_cond, 50, 2000); RTL_W8(IBISR0, RTL_R8(IBISR0) | 0x20); RTL_W8(IBCR0, RTL_R8(IBCR0) & ~0x01); } From 117991ed14861122ea87133d0ea5881e6e3403ed Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Fri, 26 Jan 2018 16:40:41 +0800 Subject: [PATCH 188/266] tcp: release sk_frag.page in tcp_disconnect [ Upstream commit 9b42d55a66d388e4dd5550107df051a9637564fc ] socket can be disconnected and gets transformed back to a listening socket, if sk_frag.page is not released, which will be cloned into a new socket by sk_clone_lock, but the reference count of this page is increased, lead to a use after free or double free issue Signed-off-by: Li RongQing Cc: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 37e8966a457b..23d77ff1da59 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2276,6 +2276,12 @@ int tcp_disconnect(struct sock *sk, int flags) WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); + if (sk->sk_frag.page) { + put_page(sk->sk_frag.page); + sk->sk_frag.page = NULL; + sk->sk_frag.offset = 0; + } + sk->sk_error_report(sk); return err; } From 711df717314621c1a711fc485bdd70706e73bb64 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 25 Jan 2018 22:03:52 +0800 Subject: [PATCH 189/266] vhost_net: stop device during reset owner [ Upstream commit 4cd879515d686849eec5f718aeac62a70b067d82 ] We don't stop device before reset owner, this means we could try to serve any virtqueue kick before reset dev->worker. This will result a warn since the work was pending at llist during owner resetting. Fix this by stopping device during owner reset. Reported-by: syzbot+eb17c6162478cc50632c@syzkaller.appspotmail.com Fixes: 3a4d5c94e9593 ("vhost_net: a kernel-level virtio server") Signed-off-by: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9eda69e40678..44a5a8777053 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -981,6 +981,7 @@ static long vhost_net_reset_owner(struct vhost_net *n) } vhost_net_stop(n, &tx_sock, &rx_sock); vhost_net_flush(n); + vhost_dev_stop(&n->dev); vhost_dev_reset_owner(&n->dev, memory); vhost_net_vq_reset(n); done: From 4f8a4e9984479c05bbf78f09e1744711a3eb32b3 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Mon, 20 Nov 2017 15:56:28 -0500 Subject: [PATCH 190/266] media: soc_camera: soc_scale_crop: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE commit 5331aec1bf9c9da557668174e0a4bfcee39f1121 upstream. This change resolves a new compile-time warning when built as a loadable module: WARNING: modpost: missing MODULE_LICENSE() in drivers/media/platform/soc_camera/soc_scale_crop.o see include/linux/module.h for more information This adds the license as "GPL", which matches the header of the file. MODULE_DESCRIPTION and MODULE_AUTHOR are also added. Signed-off-by: Jesse Chan Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/soc_camera/soc_scale_crop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c index bda29bc1b933..2f74a5ac0147 100644 --- a/drivers/media/platform/soc_camera/soc_scale_crop.c +++ b/drivers/media/platform/soc_camera/soc_scale_crop.c @@ -405,3 +405,7 @@ void soc_camera_calc_client_output(struct soc_camera_device *icd, mf->height = soc_camera_shift_scale(rect->height, shift, scale_v); } EXPORT_SYMBOL(soc_camera_calc_client_output); + +MODULE_DESCRIPTION("soc-camera scaling-cropping functions"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL"); From 33813d43dd593e1c32c567c75483233212b825ae Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 8 Jun 2017 14:48:18 +0100 Subject: [PATCH 191/266] KEYS: encrypted: fix buffer overread in valid_master_desc() commit 794b4bc292f5d31739d89c0202c54e7dc9bc3add upstream. With the 'encrypted' key type it was possible for userspace to provide a data blob ending with a master key description shorter than expected, e.g. 'keyctl add encrypted desc "new x" @s'. When validating such a master key description, validate_master_desc() could read beyond the end of the buffer. Fix this by using strncmp() instead of memcmp(). [Also clean up the code to deduplicate some logic.] Cc: Mimi Zohar Signed-off-by: Eric Biggers Signed-off-by: David Howells Signed-off-by: James Morris Signed-off-by: Jin Qian Signed-off-by: Greg Kroah-Hartman --- security/keys/encrypted-keys/encrypted.c | 31 ++++++++++++------------ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index ce295c0c1da0..e44e844c8ec4 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -141,23 +141,22 @@ static int valid_ecryptfs_desc(const char *ecryptfs_desc) */ static int valid_master_desc(const char *new_desc, const char *orig_desc) { - if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) { - if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN) - goto out; - if (orig_desc) - if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN)) - goto out; - } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) { - if (strlen(new_desc) == KEY_USER_PREFIX_LEN) - goto out; - if (orig_desc) - if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN)) - goto out; - } else - goto out; + int prefix_len; + + if (!strncmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) + prefix_len = KEY_TRUSTED_PREFIX_LEN; + else if (!strncmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) + prefix_len = KEY_USER_PREFIX_LEN; + else + return -EINVAL; + + if (!new_desc[prefix_len]) + return -EINVAL; + + if (orig_desc && strncmp(new_desc, orig_desc, prefix_len)) + return -EINVAL; + return 0; -out: - return -EINVAL; } /* From 076e4ab3279eb3ddb206de44d04df7aeb2428e09 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 17 Nov 2015 01:07:57 -0500 Subject: [PATCH 192/266] don't put symlink bodies in pagecache into highmem commit 21fc61c73c3903c4c312d0802da01ec2b323d174 upstream. kmap() in page_follow_link_light() needed to go - allowing to hold an arbitrary number of kmaps for long is a great way to deadlocking the system. new helper (inode_nohighmem(inode)) needs to be used for pagecache symlinks inodes; done for all in-tree cases. page_follow_link_light() instrumented to yell about anything missed. Signed-off-by: Al Viro Signed-off-by: Jin Qian Signed-off-by: Jin Qian Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 1 + fs/ext4/namei.c | 1 + fs/ext4/symlink.c | 10 +++------- fs/f2fs/inode.c | 1 + fs/f2fs/namei.c | 5 ++--- fs/inode.c | 6 ++++++ include/linux/fs.h | 1 + 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 4df1cb19a243..f0cabc8c96cb 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4417,6 +4417,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) inode->i_op = &ext4_symlink_inode_operations; ext4_set_aops(inode); } + inode_nohighmem(inode); } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { inode->i_op = &ext4_special_inode_operations; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 4c36dca486cc..32960b3ecd4f 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3151,6 +3151,7 @@ static int ext4_symlink(struct inode *dir, if ((disk_link.len > EXT4_N_BLOCKS * 4)) { if (!encryption_required) inode->i_op = &ext4_symlink_inode_operations; + inode_nohighmem(inode); ext4_set_aops(inode); /* * We cannot call page_symlink() with transaction started diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index e8e7af62ac95..287c3980fa0b 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -45,7 +45,7 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return ERR_CAST(cpage); - caddr = kmap(cpage); + caddr = page_address(cpage); caddr[size] = 0; } @@ -75,16 +75,12 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook /* Null-terminate the name */ if (res <= plen) paddr[res] = '\0'; - if (cpage) { - kunmap(cpage); + if (cpage) page_cache_release(cpage); - } return *cookie = paddr; errout: - if (cpage) { - kunmap(cpage); + if (cpage) page_cache_release(cpage); - } kfree(paddr); return ERR_PTR(res); } diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 97e20decacb4..5528801a5baf 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -202,6 +202,7 @@ make_now: inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &f2fs_dblock_aops; } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 2c32110f9fc0..484df6850747 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -351,6 +351,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &f2fs_dblock_aops; f2fs_lock_op(sbi); @@ -942,7 +943,7 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return ERR_CAST(cpage); - caddr = kmap(cpage); + caddr = page_address(cpage); caddr[size] = 0; /* Symlink is encrypted */ @@ -982,13 +983,11 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook /* Null-terminate the name */ paddr[res] = '\0'; - kunmap(cpage); page_cache_release(cpage); return *cookie = paddr; errout: kfree(cstr.name); f2fs_fname_crypto_free_buffer(&pstr); - kunmap(cpage); page_cache_release(cpage); return ERR_PTR(res); } diff --git a/fs/inode.c b/fs/inode.c index b0edef500590..b95615f3fc50 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2028,3 +2028,9 @@ void inode_set_flags(struct inode *inode, unsigned int flags, new_flags) != old_flags)); } EXPORT_SYMBOL(inode_set_flags); + +void inode_nohighmem(struct inode *inode) +{ + mapping_set_gfp_mask(inode->i_mapping, GFP_USER); +} +EXPORT_SYMBOL(inode_nohighmem); diff --git a/include/linux/fs.h b/include/linux/fs.h index c8decb7075d6..f746a59fcc88 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3066,5 +3066,6 @@ static inline bool dir_relax(struct inode *inode) } extern bool path_noexec(const struct path *path); +extern void inode_nohighmem(struct inode *inode); #endif /* _LINUX_FS_H */ From 9ece237e5b9c4a532e06869aa45df7c4c65c07cd Mon Sep 17 00:00:00 2001 From: Robert Baronescu Date: Tue, 10 Oct 2017 13:21:59 +0300 Subject: [PATCH 193/266] crypto: tcrypt - fix S/G table for test_aead_speed() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5c6ac1d4f8fbdbed65dbeb8cf149d736409d16a1 upstream. In case buffer length is a multiple of PAGE_SIZE, the S/G table is incorrectly generated. Fix this by handling buflen = k * PAGE_SIZE separately. Signed-off-by: Robert Baronescu Signed-off-by: Herbert Xu Signed-off-by: Horia Geantă Signed-off-by: Greg Kroah-Hartman --- crypto/tcrypt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index f522828d45c9..1d92b5d2d6bd 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -291,11 +291,13 @@ static void sg_init_aead(struct scatterlist *sg, char *xbuf[XBUFSIZE], } sg_init_table(sg, np + 1); - np--; + if (rem) + np--; for (k = 0; k < np; k++) sg_set_buf(&sg[k + 1], xbuf[k], PAGE_SIZE); - sg_set_buf(&sg[k + 1], xbuf[k], rem); + if (rem) + sg_set_buf(&sg[k + 1], xbuf[k], rem); } static void test_aead_speed(const char *algo, int enc, unsigned int secs, From 3fe9cdee4205a4876154f469247c7a3176ccaac7 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 18 Dec 2016 17:44:13 +0100 Subject: [PATCH 194/266] x86/microcode/AMD: Do not load when running on a hypervisor commit a15a753539eca8ba243d576f02e7ca9c4b7d7042 upstream with minor adjustments. Doing so is completely void of sense for multiple reasons so prevent it. Set dis_ucode_ldr to true and thus disable the microcode loader by default to address xen pv guests which execute the AP path but not the BSP path. By having it turned off by default, the APs won't run into the loader either. Also, check CPUID(1).ECX[31] which hypervisors set. Well almost, not the xen pv one. That one gets the aforementioned "fix". Also, improve the detection method by caching the final decision whether to continue loading in dis_ucode_ldr and do it once on the BSP. The APs then simply test that value. Signed-off-by: Borislav Petkov Tested-by: Juergen Gross Tested-by: Boris Ostrovsky Acked-by: Juergen Gross Link: http://lkml.kernel.org/r/20161218164414.9649-4-bp@alien8.de Signed-off-by: Thomas Gleixner Signed-off-by: Rolf Neugebauer Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/core.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index b3e94ef461fd..1b3e0aa4c511 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -44,7 +44,7 @@ static struct microcode_ops *microcode_ops; -static bool dis_ucode_ldr; +static bool dis_ucode_ldr = true; static int __init disable_loader(char *str) { @@ -81,6 +81,7 @@ struct cpu_info_ctx { static bool __init check_loader_disabled_bsp(void) { + u32 a, b, c, d; #ifdef CONFIG_X86_32 const char *cmdline = (const char *)__pa_nodebug(boot_command_line); const char *opt = "dis_ucode_ldr"; @@ -93,8 +94,23 @@ static bool __init check_loader_disabled_bsp(void) bool *res = &dis_ucode_ldr; #endif - if (cmdline_find_option_bool(cmdline, option)) - *res = true; + if (!have_cpuid_p()) + return *res; + + a = 1; + c = 0; + native_cpuid(&a, &b, &c, &d); + + /* + * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not + * completely accurate as xen pv guests don't see that CPUID bit set but + * that's good enough as they don't land on the BSP path anyway. + */ + if (c & BIT(31)) + return *res; + + if (cmdline_find_option_bool(cmdline, option) <= 0) + *res = false; return *res; } @@ -126,9 +142,6 @@ void __init load_ucode_bsp(void) if (check_loader_disabled_bsp()) return; - if (!have_cpuid_p()) - return; - vendor = x86_vendor(); family = x86_family(); @@ -162,9 +175,6 @@ void load_ucode_ap(void) if (check_loader_disabled_ap()) return; - if (!have_cpuid_p()) - return; - vendor = x86_vendor(); family = x86_family(); From ba929f5f3c263f3b975a3b95328f66203a57b536 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 12 Oct 2017 13:23:16 +0200 Subject: [PATCH 195/266] x86/microcode: Do the family check first commit 1f161f67a272cc4f29f27934dd3f74cb657eb5c4 upstream with adjustments. On CPUs like AMD's Geode, for example, we shouldn't even try to load microcode because they do not support the modern microcode loading interface. However, we do the family check *after* the other checks whether the loader has been disabled on the command line or whether we're running in a guest. So move the family checks first in order to exit early if we're being loaded on an unsupported family. Reported-and-tested-by: Sven Glodowski Signed-off-by: Borislav Petkov Cc: # 4.11.. Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://bugzilla.suse.com/show_bug.cgi?id=1061396 Link: http://lkml.kernel.org/r/20171012112316.977-1-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Rolf Neugebauer Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/core.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 1b3e0aa4c511..ce5f8a2e7ae6 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -94,9 +94,6 @@ static bool __init check_loader_disabled_bsp(void) bool *res = &dis_ucode_ldr; #endif - if (!have_cpuid_p()) - return *res; - a = 1; c = 0; native_cpuid(&a, &b, &c, &d); @@ -138,8 +135,9 @@ void __init load_ucode_bsp(void) { int vendor; unsigned int family; + bool intel = true; - if (check_loader_disabled_bsp()) + if (!have_cpuid_p()) return; vendor = x86_vendor(); @@ -147,16 +145,27 @@ void __init load_ucode_bsp(void) switch (vendor) { case X86_VENDOR_INTEL: - if (family >= 6) - load_ucode_intel_bsp(); + if (family < 6) + return; break; + case X86_VENDOR_AMD: - if (family >= 0x10) - load_ucode_amd_bsp(family); + if (family < 0x10) + return; + intel = false; break; + default: - break; + return; } + + if (check_loader_disabled_bsp()) + return; + + if (intel) + load_ucode_intel_bsp(); + else + load_ucode_amd_bsp(family); } static bool check_loader_disabled_ap(void) From 5c2ea7f7bb2102a6b8caa057af628d1ee7783e24 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Mon, 15 Jan 2018 14:30:03 +0100 Subject: [PATCH 196/266] powerpc/pseries: include linux/types.h in asm/hvcall.h commit 1b689a95ce7427075f9ac9fb4aea1af530742b7f upstream. Commit 6e032b350cd1 ("powerpc/powernv: Check device-tree for RFI flush settings") uses u64 in asm/hvcall.h without including linux/types.h This breaks hvcall.h users that do not include the header themselves. Fixes: 6e032b350cd1 ("powerpc/powernv: Check device-tree for RFI flush settings") Signed-off-by: Michal Suchanek Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/hvcall.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 51adbde09845..449bbb87c257 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -298,6 +298,7 @@ #define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR (1ull << 61) // IBM bit 2 #ifndef __ASSEMBLY__ +#include /** * plpar_hcall_norets: - Make a pseries hypervisor call with no return arguments From e343f5fd73575876c30e2187608e6c246c2041cc Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 15 Dec 2017 12:48:32 -0800 Subject: [PATCH 197/266] cifs: Fix missing put_xid in cifs_file_strict_mmap commit f04a703c3d613845ae3141bfaf223489de8ab3eb upstream. If cifs_zap_mapping() returned an error, we would return without putting the xid that we got earlier. Restructure cifs_file_strict_mmap() and cifs_file_mmap() to be more similar to each other and have a single point of return that always puts the xid. Signed-off-by: Matthew Wilcox Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/file.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index ec2d07bb9beb..744be3c146f5 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -3241,20 +3241,18 @@ static const struct vm_operations_struct cifs_file_vm_ops = { int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) { - int rc, xid; + int xid, rc = 0; struct inode *inode = file_inode(file); xid = get_xid(); - if (!CIFS_CACHE_READ(CIFS_I(inode))) { + if (!CIFS_CACHE_READ(CIFS_I(inode))) rc = cifs_zap_mapping(inode); - if (rc) - return rc; - } - - rc = generic_file_mmap(file, vma); - if (rc == 0) + if (!rc) + rc = generic_file_mmap(file, vma); + if (!rc) vma->vm_ops = &cifs_file_vm_ops; + free_xid(xid); return rc; } @@ -3264,16 +3262,16 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) int rc, xid; xid = get_xid(); + rc = cifs_revalidate_file(file); - if (rc) { + if (rc) cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n", rc); - free_xid(xid); - return rc; - } - rc = generic_file_mmap(file, vma); - if (rc == 0) + if (!rc) + rc = generic_file_mmap(file, vma); + if (!rc) vma->vm_ops = &cifs_file_vm_ops; + free_xid(xid); return rc; } From aa8c1051abaa9d2c3465338c8100660e817f1299 Mon Sep 17 00:00:00 2001 From: Daniel N Pettersson Date: Thu, 11 Jan 2018 16:00:12 +0100 Subject: [PATCH 198/266] cifs: Fix autonegotiate security settings mismatch commit 9aca7e454415f7878b28524e76bebe1170911a88 upstream. Autonegotiation gives a security settings mismatch error if the SMB server selects an SMBv3 dialect that isn't SMB3.02. The exact error is "protocol revalidation - security settings mismatch". This can be tested using Samba v4.2 or by setting the global Samba setting max protocol = SMB3_00. The check that fails in smb3_validate_negotiate is the dialect verification of the negotiate info response. This is because it tries to verify against the protocol_id in the global smbdefault_values. The protocol_id in smbdefault_values is SMB3.02. In SMB2_negotiate the protocol_id in smbdefault_values isn't updated, it is global so it probably shouldn't be, but server->dialect is. This patch changes the check in smb3_validate_negotiate to use server->dialect instead of server->vals->protocol_id. The patch works with autonegotiate and when using a specific version in the vers mount option. Signed-off-by: Daniel N Pettersson Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2pdu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index f2ff60e58ec8..84614a5edb87 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -580,8 +580,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) } /* check validate negotiate info response matches what we got earlier */ - if (pneg_rsp->Dialect != - cpu_to_le16(tcon->ses->server->vals->protocol_id)) + if (pneg_rsp->Dialect != cpu_to_le16(tcon->ses->server->dialect)) goto vneg_out; if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode)) From f260cb7751a0dfda5c444b61189e071253279a22 Mon Sep 17 00:00:00 2001 From: Aurelien Aptel Date: Thu, 25 Jan 2018 15:59:39 +0100 Subject: [PATCH 199/266] CIFS: zero sensitive data when freeing commit 97f4b7276b829a8927ac903a119bef2f963ccc58 upstream. also replaces memset()+kfree() by kzfree(). Signed-off-by: Aurelien Aptel Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsencrypt.c | 3 +-- fs/cifs/connect.c | 6 +++--- fs/cifs/misc.c | 14 ++++---------- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 4acbc390a7d6..1d707a67f8ac 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -306,9 +306,8 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, { int i; int rc; - char password_with_pad[CIFS_ENCPWD_SIZE]; + char password_with_pad[CIFS_ENCPWD_SIZE] = {0}; - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); if (password) strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0a2bf9462637..077ad3a06c9a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1695,7 +1695,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, tmp_end++; if (!(tmp_end < end && tmp_end[1] == delim)) { /* No it is not. Set the password to NULL */ - kfree(vol->password); + kzfree(vol->password); vol->password = NULL; break; } @@ -1733,7 +1733,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, options = end; } - kfree(vol->password); + kzfree(vol->password); /* Now build new password string */ temp_len = strlen(value); vol->password = kzalloc(temp_len+1, GFP_KERNEL); @@ -4148,7 +4148,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) reset_cifs_unix_caps(0, tcon, NULL, vol_info); out: kfree(vol_info->username); - kfree(vol_info->password); + kzfree(vol_info->password); kfree(vol_info); return tcon; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 2396ab099849..0cc699d9b932 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -99,14 +99,11 @@ sesInfoFree(struct cifs_ses *buf_to_free) kfree(buf_to_free->serverOS); kfree(buf_to_free->serverDomain); kfree(buf_to_free->serverNOS); - if (buf_to_free->password) { - memset(buf_to_free->password, 0, strlen(buf_to_free->password)); - kfree(buf_to_free->password); - } + kzfree(buf_to_free->password); kfree(buf_to_free->user_name); kfree(buf_to_free->domainName); - kfree(buf_to_free->auth_key.response); - kfree(buf_to_free); + kzfree(buf_to_free->auth_key.response); + kzfree(buf_to_free); } struct cifs_tcon * @@ -137,10 +134,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free) } atomic_dec(&tconInfoAllocCount); kfree(buf_to_free->nativeFileSystem); - if (buf_to_free->password) { - memset(buf_to_free->password, 0, strlen(buf_to_free->password)); - kfree(buf_to_free->password); - } + kzfree(buf_to_free->password); kfree(buf_to_free); } From 002530fd6057df8595ffe391ea63d1e99e573151 Mon Sep 17 00:00:00 2001 From: Yang Shunyong Date: Mon, 29 Jan 2018 14:40:11 +0800 Subject: [PATCH 200/266] dmaengine: dmatest: fix container_of member in dmatest_callback commit 66b3bd2356e0a1531c71a3dcf96944621e25c17c upstream. The type of arg passed to dmatest_callback is struct dmatest_done. It refers to test_done in struct dmatest_thread, not done_wait. Fixes: 6f6a23a213be ("dmaengine: dmatest: move callback wait ...") Signed-off-by: Yang Shunyong Acked-by: Adam Wallis Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/dmatest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 7254c20007f8..6796eb1a8a4c 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -329,7 +329,7 @@ static void dmatest_callback(void *arg) { struct dmatest_done *done = arg; struct dmatest_thread *thread = - container_of(arg, struct dmatest_thread, done_wait); + container_of(done, struct dmatest_thread, test_done); if (!thread->done) { done->done = true; wake_up_all(done->wait); From 9b6cab80102ff73bf099c623c778af48a3684d2e Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 9 Feb 2018 15:21:31 -0800 Subject: [PATCH 201/266] x86/kaiser: fix build error with KASAN && !FUNCTION_GRAPH_TRACER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a build fix for the 4.4 PTI backport. 4.4 kernels do not have commit be7635e7287e ("arch, ftrace: for KASAN put hard/soft IRQ entries into separate sections") which went into 4.6. Consequently, the irqentry sections are only created when CONFIG_FUNCTION_GRAPH_TRACER is enabled, not also when CONFIG_KASAN is enabled. Therefore, fix the condition for trying to add a user mapping for this section. This fixes the following build error: arch/x86/mm/kaiser.c: In function ‘kaiser_init’: arch/x86/mm/kaiser.c:367:33: error: ‘__irqentry_text_start’ undeclared (first use in this function) kaiser_add_user_map_ptrs_early(__irqentry_text_start, [...] Signed-off-by: Eric Biggers Acked-by: Hugh Dickins Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/kaiser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/mm/kaiser.c b/arch/x86/mm/kaiser.c index 2298434f7bdb..7a72e32e4806 100644 --- a/arch/x86/mm/kaiser.c +++ b/arch/x86/mm/kaiser.c @@ -363,7 +363,7 @@ void __init kaiser_init(void) kaiser_add_user_map_ptrs_early(__entry_text_start, __entry_text_end, __PAGE_KERNEL_RX); -#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN) +#ifdef CONFIG_FUNCTION_GRAPH_TRACER kaiser_add_user_map_ptrs_early(__irqentry_text_start, __irqentry_text_end, __PAGE_KERNEL_RX); From 4f3e6ab44b928ef70b77aa374886cb59fd9e4171 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 13 Feb 2018 16:45:20 +0100 Subject: [PATCH 202/266] kaiser: fix compile error without vsyscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tobias noticed a compile error on 4.4.115, and it's the same on 4.9.80: arch/x86/mm/kaiser.c: In function ‘kaiser_init’: arch/x86/mm/kaiser.c:348:8: error: ‘vsyscall_pgprot’ undeclared (first use in this function) It seems like his combination of kernel options doesn't work for KAISER. X86_VSYSCALL_EMULATION is not set on his system, while LEGACY_VSYSCALL is set to NONE (LEGACY_VSYSCALL_NONE=y). He managed to get things compiling again, by moving the 'extern unsigned long vsyscall_pgprot' outside of the preprocessor statement. This works because the optimizer removes that code (vsyscall_enabled() is always false) - and that's how it was done in some older backports. Reported-by: Tobias Jakobi Signed-off-by: Hugh Dickins Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/vsyscall.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h index 9ee85066f407..62210da19a92 100644 --- a/arch/x86/include/asm/vsyscall.h +++ b/arch/x86/include/asm/vsyscall.h @@ -13,7 +13,6 @@ extern void map_vsyscall(void); */ extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address); extern bool vsyscall_enabled(void); -extern unsigned long vsyscall_pgprot; #else static inline void map_vsyscall(void) {} static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) @@ -22,5 +21,6 @@ static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) } static inline bool vsyscall_enabled(void) { return false; } #endif +extern unsigned long vsyscall_pgprot; #endif /* _ASM_X86_VSYSCALL_H */ From cb92c8fb3bda8fe5c073603c7a5b5f5936cc4882 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 13 May 2016 21:18:52 -0500 Subject: [PATCH 203/266] netfilter: nf_queue: Make the queue_handler pernet commit dc3ee32e96d74dd6c80eed63af5065cb75899299 upstream. Florian Weber reported: > Under full load (unshare() in loop -> OOM conditions) we can > get kernel panic: > > BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 > IP: [] nfqnl_nf_hook_drop+0x35/0x70 > [..] > task: ffff88012dfa3840 ti: ffff88012dffc000 task.ti: ffff88012dffc000 > RIP: 0010:[] [] nfqnl_nf_hook_drop+0x35/0x70 > RSP: 0000:ffff88012dfffd80 EFLAGS: 00010206 > RAX: 0000000000000008 RBX: ffffffff81add0c0 RCX: ffff88013fd80000 > [..] > Call Trace: > [] nf_queue_nf_hook_drop+0x18/0x20 > [] nf_unregister_net_hook+0xdb/0x150 > [] netfilter_net_exit+0x2f/0x60 > [] ops_exit_list.isra.4+0x38/0x60 > [] setup_net+0xc2/0x120 > [] copy_net_ns+0x79/0x120 > [] create_new_namespaces+0x11b/0x1e0 > [] unshare_nsproxy_namespaces+0x57/0xa0 > [] SyS_unshare+0x1b2/0x340 > [] entry_SYSCALL_64_fastpath+0x1e/0xa8 > Code: 65 00 48 89 e5 41 56 41 55 41 54 53 83 e8 01 48 8b 97 70 12 00 00 48 98 49 89 f4 4c 8b 74 c2 18 4d 8d 6e 08 49 81 c6 88 00 00 00 <49> 8b 5d 00 48 85 db 74 1a 48 89 df 4c 89 e2 48 c7 c6 90 68 47 > The simple fix for this requires a new pernet variable for struct nf_queue that indicates when it is safe to use the dynamically allocated nf_queue state. As we need a variable anyway make nf_register_queue_handler and nf_unregister_queue_handler pernet. This allows the existing logic of when it is safe to use the state from the nfnetlink_queue module to be reused with no changes except for making it per net. The syncrhonize_rcu from nf_unregister_queue_handler is moved to a new function nfnl_queue_net_exit_batch so that the worst case of having a syncrhonize_rcu in the pernet exit path is not experienced in batch mode. Reported-by: Florian Westphal Signed-off-by: "Eric W. Biederman" Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Cc: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- include/net/netfilter/nf_queue.h | 4 ++-- include/net/netns/netfilter.h | 2 ++ net/netfilter/nf_queue.c | 17 ++++++++--------- net/netfilter/nfnetlink_queue.c | 18 ++++++++++++------ 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index 9c5638ad872e..0dbce55437f2 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h @@ -28,8 +28,8 @@ struct nf_queue_handler { struct nf_hook_ops *ops); }; -void nf_register_queue_handler(const struct nf_queue_handler *qh); -void nf_unregister_queue_handler(void); +void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh); +void nf_unregister_queue_handler(struct net *net); void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); void nf_queue_entry_get_refs(struct nf_queue_entry *entry); diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h index 38aa4983e2a9..36d723579af2 100644 --- a/include/net/netns/netfilter.h +++ b/include/net/netns/netfilter.h @@ -5,11 +5,13 @@ struct proc_dir_entry; struct nf_logger; +struct nf_queue_handler; struct netns_nf { #if defined CONFIG_PROC_FS struct proc_dir_entry *proc_netfilter; #endif + const struct nf_queue_handler __rcu *queue_handler; const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO]; #ifdef CONFIG_SYSCTL struct ctl_table_header *nf_log_dir_header; diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 5baa8e24e6ac..b19ad20a705c 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -26,23 +26,21 @@ * Once the queue is registered it must reinject all packets it * receives, no matter what. */ -static const struct nf_queue_handler __rcu *queue_handler __read_mostly; /* return EBUSY when somebody else is registered, return EEXIST if the * same handler is registered, return 0 in case of success. */ -void nf_register_queue_handler(const struct nf_queue_handler *qh) +void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh) { /* should never happen, we only have one queueing backend in kernel */ - WARN_ON(rcu_access_pointer(queue_handler)); - rcu_assign_pointer(queue_handler, qh); + WARN_ON(rcu_access_pointer(net->nf.queue_handler)); + rcu_assign_pointer(net->nf.queue_handler, qh); } EXPORT_SYMBOL(nf_register_queue_handler); /* The caller must flush their queue before this */ -void nf_unregister_queue_handler(void) +void nf_unregister_queue_handler(struct net *net) { - RCU_INIT_POINTER(queue_handler, NULL); - synchronize_rcu(); + RCU_INIT_POINTER(net->nf.queue_handler, NULL); } EXPORT_SYMBOL(nf_unregister_queue_handler); @@ -103,7 +101,7 @@ void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops) const struct nf_queue_handler *qh; rcu_read_lock(); - qh = rcu_dereference(queue_handler); + qh = rcu_dereference(net->nf.queue_handler); if (qh) qh->nf_hook_drop(net, ops); rcu_read_unlock(); @@ -122,9 +120,10 @@ int nf_queue(struct sk_buff *skb, struct nf_queue_entry *entry = NULL; const struct nf_afinfo *afinfo; const struct nf_queue_handler *qh; + struct net *net = state->net; /* QUEUE == DROP if no one is waiting, to be safe. */ - qh = rcu_dereference(queue_handler); + qh = rcu_dereference(net->nf.queue_handler); if (!qh) { status = -ESRCH; goto err; diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index c14d2e8eaec3..f853b55bf877 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -1382,21 +1382,29 @@ static int __net_init nfnl_queue_net_init(struct net *net) net->nf.proc_netfilter, &nfqnl_file_ops)) return -ENOMEM; #endif + nf_register_queue_handler(net, &nfqh); return 0; } static void __net_exit nfnl_queue_net_exit(struct net *net) { + nf_unregister_queue_handler(net); #ifdef CONFIG_PROC_FS remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter); #endif } +static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list) +{ + synchronize_rcu(); +} + static struct pernet_operations nfnl_queue_net_ops = { - .init = nfnl_queue_net_init, - .exit = nfnl_queue_net_exit, - .id = &nfnl_queue_net_id, - .size = sizeof(struct nfnl_queue_net), + .init = nfnl_queue_net_init, + .exit = nfnl_queue_net_exit, + .exit_batch = nfnl_queue_net_exit_batch, + .id = &nfnl_queue_net_id, + .size = sizeof(struct nfnl_queue_net), }; static int __init nfnetlink_queue_init(void) @@ -1417,7 +1425,6 @@ static int __init nfnetlink_queue_init(void) } register_netdevice_notifier(&nfqnl_dev_notifier); - nf_register_queue_handler(&nfqh); return status; cleanup_netlink_notifier: @@ -1429,7 +1436,6 @@ out: static void __exit nfnetlink_queue_fini(void) { - nf_unregister_queue_handler(); unregister_netdevice_notifier(&nfqnl_dev_notifier); nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); From 77f56f5d39e95a152a755d53b0d870b92fbf466b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 15 Dec 2017 10:32:03 +0100 Subject: [PATCH 204/266] posix-timer: Properly check sigevent->sigev_notify commit cef31d9af908243421258f1df35a4a644604efbe upstream. timer_create() specifies via sigevent->sigev_notify the signal delivery for the new timer. The valid modes are SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD and (SIGEV_SIGNAL | SIGEV_THREAD_ID). The sanity check in good_sigevent() is only checking the valid combination for the SIGEV_THREAD_ID bit, i.e. SIGEV_SIGNAL, but if SIGEV_THREAD_ID is not set it accepts any random value. This has no real effects on the posix timer and signal delivery code, but it affects show_timer() which handles the output of /proc/$PID/timers. That function uses a string array to pretty print sigev_notify. The access to that array has no bound checks, so random sigev_notify cause access beyond the array bounds. Add proper checks for the valid notify modes and remove the SIGEV_THREAD_ID masking from various code pathes as SIGEV_NONE can never be set in combination with SIGEV_THREAD_ID. Reported-by: Eric Biggers Reported-by: Dmitry Vyukov Reported-by: Alexey Dobriyan Signed-off-by: Thomas Gleixner Cc: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/time/posix-timers.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index f2826c35e918..fc7c37ad90a0 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -507,17 +507,22 @@ static struct pid *good_sigevent(sigevent_t * event) { struct task_struct *rtn = current->group_leader; - if ((event->sigev_notify & SIGEV_THREAD_ID ) && - (!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) || - !same_thread_group(rtn, current) || - (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL)) + switch (event->sigev_notify) { + case SIGEV_SIGNAL | SIGEV_THREAD_ID: + rtn = find_task_by_vpid(event->sigev_notify_thread_id); + if (!rtn || !same_thread_group(rtn, current)) + return NULL; + /* FALLTHRU */ + case SIGEV_SIGNAL: + case SIGEV_THREAD: + if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX) + return NULL; + /* FALLTHRU */ + case SIGEV_NONE: + return task_pid(rtn); + default: return NULL; - - if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) && - ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX))) - return NULL; - - return task_pid(rtn); + } } void posix_timers_register_clock(const clockid_t clock_id, @@ -745,8 +750,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) /* interval timer ? */ if (iv.tv64) cur_setting->it_interval = ktime_to_timespec(iv); - else if (!hrtimer_active(timer) && - (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) + else if (!hrtimer_active(timer) && timr->it_sigev_notify != SIGEV_NONE) return; now = timer->base->get_time(); @@ -757,7 +761,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) * expiry is > now. */ if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING || - (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) + timr->it_sigev_notify == SIGEV_NONE)) timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv); remaining = __hrtimer_expires_remaining_adjusted(timer, now); @@ -767,7 +771,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) * A single shot SIGEV_NONE timer must return 0, when * it is expired ! */ - if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) + if (timr->it_sigev_notify != SIGEV_NONE) cur_setting->it_value.tv_nsec = 1; } else cur_setting->it_value = ktime_to_timespec(remaining); @@ -865,7 +869,7 @@ common_timer_set(struct k_itimer *timr, int flags, timr->it.real.interval = timespec_to_ktime(new_setting->it_interval); /* SIGEV_NONE timers are not queued ! See common_timer_get */ - if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { + if (timr->it_sigev_notify == SIGEV_NONE) { /* Setup correct expiry time for relative timers */ if (mode == HRTIMER_MODE_REL) { hrtimer_add_expires(timer, timer->base->get_time()); From 1bfe362d84b8133343402598642f32bc866a87d3 Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Tue, 7 Mar 2017 00:57:20 +0100 Subject: [PATCH 205/266] usb: gadget: uvc: Missing files for configfs interface commit c8cd751060b149997b9de53a494fb1490ded72c5 upstream. Commit 76e0da34c7ce ("usb-gadget/uvc: use per-attribute show and store methods") caused a stringification of an undefined macro argument "aname", so three UVC parameters (streaming_interval, streaming_maxpacket and streaming_maxburst) were named "aname". Add the definition of "aname" to the main macro and name the filenames as originaly intended. Signed-off-by: Petr Cvek Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc_configfs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index ad8c9b05572d..01656f1c6d65 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -2202,7 +2202,7 @@ static struct configfs_item_operations uvc_item_ops = { .release = uvc_attr_release, }; -#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \ +#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ static ssize_t f_uvc_opts_##cname##_show( \ struct config_item *item, char *page) \ { \ @@ -2245,16 +2245,16 @@ end: \ return ret; \ } \ \ -UVC_ATTR(f_uvc_opts_, cname, aname) +UVC_ATTR(f_uvc_opts_, cname, cname) #define identity_conv(x) (x) -UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv, - 16); -UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu, - 3072); -UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv, - 15); +UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv, + kstrtou8, u8, identity_conv, 16); +UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu, + kstrtou16, u16, le16_to_cpu, 3072); +UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv, + kstrtou8, u8, identity_conv, 15); #undef identity_conv From af9de1a10f93f8d2c9ee5dce67c3abcd53ef7de5 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 23 Jan 2018 20:45:37 -0500 Subject: [PATCH 206/266] sched/rt: Use container_of() to get root domain in rto_push_irq_work_func() commit ad0f1d9d65938aec72a698116cd73a980916895e upstream. When the rto_push_irq_work_func() is called, it looks at the RT overloaded bitmask in the root domain via the runqueue (rq->rd). The problem is that during CPU up and down, nothing here stops rq->rd from changing between taking the rq->rd->rto_lock and releasing it. That means the lock that is released is not the same lock that was taken. Instead of using this_rq()->rd to get the root domain, as the irq work is part of the root domain, we can simply get the root domain from the irq work that is passed to the routine: container_of(work, struct root_domain, rto_push_work) This keeps the root domain consistent. Reported-by: Pavan Kondeti Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 4bdced5c9a292 ("sched/rt: Simplify the IPI based RT balancing logic") Link: http://lkml.kernel.org/r/CAEU1=PkiHO35Dzna8EQqNSKW1fr1y1zRQ5y66X117MG06sQtNA@mail.gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/sched/rt.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 95fefb364dab..bc9724344434 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1833,9 +1833,8 @@ static void push_rt_tasks(struct rq *rq) * the rt_loop_next will cause the iterator to perform another scan. * */ -static int rto_next_cpu(struct rq *rq) +static int rto_next_cpu(struct root_domain *rd) { - struct root_domain *rd = rq->rd; int next; int cpu; @@ -1911,7 +1910,7 @@ static void tell_cpu_to_push(struct rq *rq) * Otherwise it is finishing up and an ipi needs to be sent. */ if (rq->rd->rto_cpu < 0) - cpu = rto_next_cpu(rq); + cpu = rto_next_cpu(rq->rd); raw_spin_unlock(&rq->rd->rto_lock); @@ -1924,6 +1923,8 @@ static void tell_cpu_to_push(struct rq *rq) /* Called from hardirq context */ void rto_push_irq_work_func(struct irq_work *work) { + struct root_domain *rd = + container_of(work, struct root_domain, rto_push_work); struct rq *rq; int cpu; @@ -1939,18 +1940,18 @@ void rto_push_irq_work_func(struct irq_work *work) raw_spin_unlock(&rq->lock); } - raw_spin_lock(&rq->rd->rto_lock); + raw_spin_lock(&rd->rto_lock); /* Pass the IPI to the next rt overloaded queue */ - cpu = rto_next_cpu(rq); + cpu = rto_next_cpu(rd); - raw_spin_unlock(&rq->rd->rto_lock); + raw_spin_unlock(&rd->rto_lock); if (cpu < 0) return; /* Try the next RT overloaded CPU */ - irq_work_queue_on(&rq->rd->rto_push_work, cpu); + irq_work_queue_on(&rd->rto_push_work, cpu); } #endif /* HAVE_RT_PUSH_IPI */ From 911357aed6e35b4c094a5ca419ca987dc48bfbfb Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 23 Jan 2018 20:45:38 -0500 Subject: [PATCH 207/266] sched/rt: Up the root domain ref count when passing it around via IPIs commit 364f56653708ba8bcdefd4f0da2a42904baa8eeb upstream. When issuing an IPI RT push, where an IPI is sent to each CPU that has more than one RT task scheduled on it, it references the root domain's rto_mask, that contains all the CPUs within the root domain that has more than one RT task in the runable state. The problem is, after the IPIs are initiated, the rq->lock is released. This means that the root domain that is associated to the run queue could be freed while the IPIs are going around. Add a sched_get_rd() and a sched_put_rd() that will increment and decrement the root domain's ref count respectively. This way when initiating the IPIs, the scheduler will up the root domain's ref count before releasing the rq->lock, ensuring that the root domain does not go away until the IPI round is complete. Reported-by: Pavan Kondeti Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 4bdced5c9a292 ("sched/rt: Simplify the IPI based RT balancing logic") Link: http://lkml.kernel.org/r/CAEU1=PkiHO35Dzna8EQqNSKW1fr1y1zRQ5y66X117MG06sQtNA@mail.gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/sched/core.c | 13 +++++++++++++ kernel/sched/rt.c | 9 +++++++-- kernel/sched/sched.h | 2 ++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index e6d1173a2046..c5b1c62623cf 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5896,6 +5896,19 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd) call_rcu_sched(&old_rd->rcu, free_rootdomain); } +void sched_get_rd(struct root_domain *rd) +{ + atomic_inc(&rd->refcount); +} + +void sched_put_rd(struct root_domain *rd) +{ + if (!atomic_dec_and_test(&rd->refcount)) + return; + + call_rcu_sched(&rd->rcu, free_rootdomain); +} + static int init_rootdomain(struct root_domain *rd) { memset(rd, 0, sizeof(*rd)); diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index bc9724344434..e0b5169aeac4 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1916,8 +1916,11 @@ static void tell_cpu_to_push(struct rq *rq) rto_start_unlock(&rq->rd->rto_loop_start); - if (cpu >= 0) + if (cpu >= 0) { + /* Make sure the rd does not get freed while pushing */ + sched_get_rd(rq->rd); irq_work_queue_on(&rq->rd->rto_push_work, cpu); + } } /* Called from hardirq context */ @@ -1947,8 +1950,10 @@ void rto_push_irq_work_func(struct irq_work *work) raw_spin_unlock(&rd->rto_lock); - if (cpu < 0) + if (cpu < 0) { + sched_put_rd(rd); return; + } /* Try the next RT overloaded CPU */ irq_work_queue_on(&rd->rto_push_work, cpu); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 448a8266ceea..0c9ebd82a684 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -553,6 +553,8 @@ struct root_domain { }; extern struct root_domain def_root_domain; +extern void sched_get_rd(struct root_domain *rd); +extern void sched_put_rd(struct root_domain *rd); #ifdef HAVE_RT_PUSH_IPI extern void rto_push_irq_work_func(struct irq_work *work); From 3196c1515ea683bb6f95673feb2998f605ab581d Mon Sep 17 00:00:00 2001 From: Mohamed Ghannam Date: Tue, 5 Dec 2017 20:58:35 +0000 Subject: [PATCH 208/266] dccp: CVE-2017-8824: use-after-free in DCCP code commit 69c64866ce072dea1d1e59a0d61e0f66c0dffb76 upstream. Whenever the sock object is in DCCP_CLOSED state, dccp_disconnect() must free dccps_hc_tx_ccid and dccps_hc_rx_ccid and set to NULL. Signed-off-by: Mohamed Ghannam Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/proto.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/dccp/proto.c b/net/dccp/proto.c index b68168fcc06a..9d43c1f40274 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -259,6 +259,7 @@ int dccp_disconnect(struct sock *sk, int flags) { struct inet_connection_sock *icsk = inet_csk(sk); struct inet_sock *inet = inet_sk(sk); + struct dccp_sock *dp = dccp_sk(sk); int err = 0; const int old_state = sk->sk_state; @@ -278,6 +279,10 @@ int dccp_disconnect(struct sock *sk, int flags) sk->sk_err = ECONNRESET; dccp_clear_xmit_timers(sk); + ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); + ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); + dp->dccps_hc_rx_ccid = NULL; + dp->dccps_hc_tx_ccid = NULL; __skb_queue_purge(&sk->sk_receive_queue); __skb_queue_purge(&sk->sk_write_queue); From ca48c81cff0e5b56e525414b75990bcb64b7cbb9 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Tue, 26 Sep 2017 17:10:20 -0400 Subject: [PATCH 209/266] media: dvb-usb-v2: lmedm04: Improve logic checking of warm start commit 3d932ee27e852e4904647f15b64dedca51187ad7 upstream. Warm start has no check as whether a genuine device has connected and proceeds to next execution path. Check device should read 0x47 at offset of 2 on USB descriptor read and it is the amount requested of 6 bytes. Fix for kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access as Reported-by: Andrey Konovalov Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/dvb-usb-v2/lmedm04.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 3721ee63b8fb..efb9f6aa9daa 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -503,18 +503,23 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, static int lme2510_return_status(struct dvb_usb_device *d) { - int ret = 0; + int ret; u8 *data; - data = kzalloc(10, GFP_KERNEL); + data = kzalloc(6, GFP_KERNEL); if (!data) return -ENOMEM; - ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200); - info("Firmware Status: %x (%x)", ret , data[2]); + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + 0x06, 0x80, 0x0302, 0x00, + data, 0x6, 200); + if (ret != 6) + ret = -EINVAL; + else + ret = data[2]; + + info("Firmware Status: %6ph", data); - ret = (ret < 0) ? -ENODEV : data[2]; kfree(data); return ret; } @@ -1199,6 +1204,7 @@ static int lme2510_get_adapter_count(struct dvb_usb_device *d) static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) { struct lme2510_state *st = d->priv; + int status; usb_reset_configuration(d->udev); @@ -1207,12 +1213,16 @@ static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware; - if (lme2510_return_status(d) == 0x44) { + status = lme2510_return_status(d); + if (status == 0x44) { *name = lme_firmware_switch(d, 0); return COLD; } - return 0; + if (status != 0x47) + return -EINVAL; + + return WARM; } static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, From f6ea3133ca0c6a7a8120e3c704b507138d4b5902 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Tue, 26 Sep 2017 17:10:21 -0400 Subject: [PATCH 210/266] media: dvb-usb-v2: lmedm04: move ts2020 attach to dm04_lme2510_tuner commit 7bf7a7116ed313c601307f7e585419369926ab05 upstream. When the tuner was split from m88rs2000 the attach function is in wrong place. Move to dm04_lme2510_tuner to trap errors on failure and removing a call to lme_coldreset. Prevents driver starting up without any tuner connected. Fixes to trap for ts2020 fail. LME2510(C): FE Found M88RS2000 ts2020: probe of 0-0060 failed with error -11 ... LME2510(C): TUN Found RS2000 tuner kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] PREEMPT SMP KASAN Reported-by: Andrey Konovalov Signed-off-by: Malcolm Priestley Tested-by: Andrey Konovalov Signed-off-by: Mauro Carvalho Chehab Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/dvb-usb-v2/lmedm04.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index efb9f6aa9daa..09c97847bf95 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -1083,8 +1083,6 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) if (adap->fe[0]) { info("FE Found M88RS2000"); - dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config, - &d->i2c_adap); st->i2c_tuner_gate_w = 5; st->i2c_tuner_gate_r = 5; st->i2c_tuner_addr = 0x60; @@ -1150,17 +1148,18 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) ret = st->tuner_config; break; case TUNER_RS2000: - ret = st->tuner_config; + if (dvb_attach(ts2020_attach, adap->fe[0], + &ts2020_config, &d->i2c_adap)) + ret = st->tuner_config; break; default: break; } - if (ret) + if (ret) { info("TUN Found %s tuner", tun_msg[ret]); - else { - info("TUN No tuner found --- resetting device"); - lme_coldreset(d); + } else { + info("TUN No tuner found"); return -ENODEV; } From b4b3ad0c8c90b4a9fe1dc9ecca9211a72e580976 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Oct 2017 15:54:10 +0200 Subject: [PATCH 211/266] mtd: cfi: convert inline functions to macros commit 9e343e87d2c4c707ef8fae2844864d4dde3a2d13 upstream. The map_word_() functions, dating back to linux-2.6.8, try to perform bitwise operations on a 'map_word' structure. This may have worked with compilers that were current then (gcc-3.4 or earlier), but end up being rather inefficient on any version I could try now (gcc-4.4 or higher). Specifically we hit a problem analyzed in gcc PR81715 where we fail to reuse the stack space for local variables. This can be seen immediately in the stack consumption for cfi_staa_erase_varsize() and other functions that (with CONFIG_KASAN) can be up to 2200 bytes. Changing the inline functions into macros brings this down to 1280 bytes. Without KASAN, the same problem exists, but the stack consumption is lower to start with, my patch shrinks it from 920 to 496 bytes on with arm-linux-gnueabi-gcc-5.4, and saves around 1KB in .text size for cfi_cmdset_0020.c, as it avoids copying map_word structures for each call to one of these helpers. With the latest gcc-8 snapshot, the problem is fixed in upstream gcc, but nobody uses that yet, so we should still work around it in mainline kernels and probably backport the workaround to stable kernels as well. We had a couple of other functions that suffered from the same gcc bug, and all of those had a simpler workaround involving dummy variables in the inline function. Unfortunately that did not work here, the macro hack was the best I could come up with. It would also be helpful to have someone to a little performance testing on the patch, to see how much it helps in terms of CPU utilitzation. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 Signed-off-by: Arnd Bergmann Acked-by: Richard Weinberger Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- include/linux/mtd/map.h | 120 +++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 64 deletions(-) diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 806d0ab845e0..676d3d2a1a0a 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -265,75 +265,67 @@ void map_destroy(struct mtd_info *mtd); #define INVALIDATE_CACHED_RANGE(map, from, size) \ do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0) +#define map_word_equal(map, val1, val2) \ +({ \ + int i, ret = 1; \ + for (i = 0; i < map_words(map); i++) \ + if ((val1).x[i] != (val2).x[i]) { \ + ret = 0; \ + break; \ + } \ + ret; \ +}) -static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2) -{ - int i; +#define map_word_and(map, val1, val2) \ +({ \ + map_word r; \ + int i; \ + for (i = 0; i < map_words(map); i++) \ + r.x[i] = (val1).x[i] & (val2).x[i]; \ + r; \ +}) - for (i = 0; i < map_words(map); i++) { - if (val1.x[i] != val2.x[i]) - return 0; - } +#define map_word_clr(map, val1, val2) \ +({ \ + map_word r; \ + int i; \ + for (i = 0; i < map_words(map); i++) \ + r.x[i] = (val1).x[i] & ~(val2).x[i]; \ + r; \ +}) - return 1; -} +#define map_word_or(map, val1, val2) \ +({ \ + map_word r; \ + int i; \ + for (i = 0; i < map_words(map); i++) \ + r.x[i] = (val1).x[i] | (val2).x[i]; \ + r; \ +}) -static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2) -{ - map_word r; - int i; +#define map_word_andequal(map, val1, val2, val3) \ +({ \ + int i, ret = 1; \ + for (i = 0; i < map_words(map); i++) { \ + if (((val1).x[i] & (val2).x[i]) != (val2).x[i]) { \ + ret = 0; \ + break; \ + } \ + } \ + ret; \ +}) - for (i = 0; i < map_words(map); i++) - r.x[i] = val1.x[i] & val2.x[i]; - - return r; -} - -static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2) -{ - map_word r; - int i; - - for (i = 0; i < map_words(map); i++) - r.x[i] = val1.x[i] & ~val2.x[i]; - - return r; -} - -static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2) -{ - map_word r; - int i; - - for (i = 0; i < map_words(map); i++) - r.x[i] = val1.x[i] | val2.x[i]; - - return r; -} - -static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3) -{ - int i; - - for (i = 0; i < map_words(map); i++) { - if ((val1.x[i] & val2.x[i]) != val3.x[i]) - return 0; - } - - return 1; -} - -static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2) -{ - int i; - - for (i = 0; i < map_words(map); i++) { - if (val1.x[i] & val2.x[i]) - return 1; - } - - return 0; -} +#define map_word_bitsset(map, val1, val2) \ +({ \ + int i, ret = 0; \ + for (i = 0; i < map_words(map); i++) { \ + if ((val1).x[i] & (val2).x[i]) { \ + ret = 1; \ + break; \ + } \ + } \ + ret; \ +}) static inline map_word map_word_load(struct map_info *map, const void *ptr) { From eda72c8338e04d2c7a9782dc561ff772c419fb26 Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Mon, 8 Jan 2018 15:36:48 -0500 Subject: [PATCH 212/266] mtd: nand: brcmnand: Disable prefetch by default commit f953f0f89663c39f08f4baaa8a4a881401b65654 upstream. Brcm nand controller prefetch feature needs to be disabled by default. Enabling affects performance on random reads as well as dma reads. Signed-off-by: Kamal Dasu Fixes: 27c5b17cd1b1 ("mtd: nand: add NAND driver "library" for Broadcom STB NAND controller") Acked-by: Florian Fainelli Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/brcmnand/brcmnand.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c index 4a07ba1195b5..d125d19a35e4 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/brcmnand/brcmnand.c @@ -1922,16 +1922,9 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) tmp &= ~ACC_CONTROL_PARTIAL_PAGE; tmp &= ~ACC_CONTROL_RD_ERASED; tmp &= ~ACC_CONTROL_FAST_PGM_RDIN; - if (ctrl->features & BRCMNAND_HAS_PREFETCH) { - /* - * FIXME: Flash DMA + prefetch may see spurious erased-page ECC - * errors - */ - if (has_flash_dma(ctrl)) - tmp &= ~ACC_CONTROL_PREFETCH; - else - tmp |= ACC_CONTROL_PREFETCH; - } + if (ctrl->features & BRCMNAND_HAS_PREFETCH) + tmp &= ~ACC_CONTROL_PREFETCH; + nand_writereg(ctrl, offs, tmp); return 0; From 105f7cd0cf69d37d685cd9fb1b07133be24ae59b Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 12 Jan 2018 10:13:36 +0100 Subject: [PATCH 213/266] mtd: nand: Fix nand_do_read_oob() return value commit 87e89ce8d0d14f573c068c61bec2117751fb5103 upstream. Starting from commit 041e4575f034 ("mtd: nand: handle ECC errors in OOB"), nand_do_read_oob() (from the NAND core) did return 0 or a negative error, and the MTD layer expected it. However, the trend for the NAND layer is now to return an error or a positive number of bitflips. Deciding which status to return to the user belongs to the MTD layer. Commit e47f68587b82 ("mtd: check for max_bitflips in mtd_read_oob()") brought this logic to the mtd_read_oob() function while the return value coming from nand_do_read_oob() (called by the ->_read_oob() hook) was left unchanged. Fixes: e47f68587b82 ("mtd: check for max_bitflips in mtd_read_oob()") Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/nand_base.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 7ba109e8cf88..27864c0863ef 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2023,6 +2023,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { + unsigned int max_bitflips = 0; int page, realpage, chipnr; struct nand_chip *chip = mtd->priv; struct mtd_ecc_stats stats; @@ -2083,6 +2084,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, nand_wait_ready(mtd); } + max_bitflips = max_t(unsigned int, max_bitflips, ret); + readlen -= len; if (!readlen) break; @@ -2108,7 +2111,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; - return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; + return max_bitflips; } /** From 8f6456565a140ea1d0fc85a56663d8437e303cdf Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 24 Jan 2018 23:49:31 +0100 Subject: [PATCH 214/266] mtd: nand: sunxi: Fix ECC strength choice commit f4c6cd1a7f2275d5bc0e494b21fff26f8dde80f0 upstream. When the requested ECC strength does not exactly match the strengths supported by the ECC engine, the driver is selecting the closest strength meeting the 'selected_strength > requested_strength' constraint. Fix the fact that, in this particular case, ecc->strength value was not updated to match the 'selected_strength'. For instance, one can encounter this issue when no ECC requirement is filled in the device tree while the NAND chip minimum requirement is not a strength/step_size combo natively supported by the ECC engine. Fixes: 1fef62c1423b ("mtd: nand: add sunxi NAND flash controller support") Suggested-by: Boris Brezillon Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/sunxi_nand.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 824711845c44..3bb9b34d9e77 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -1046,8 +1046,14 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, /* Add ECC info retrieval from DT */ for (i = 0; i < ARRAY_SIZE(strengths); i++) { - if (ecc->strength <= strengths[i]) + if (ecc->strength <= strengths[i]) { + /* + * Update ecc->strength value with the actual strength + * that will be used by the ECC engine. + */ + ecc->strength = strengths[i]; break; + } } if (i >= ARRAY_SIZE(strengths)) { From 022af4898b3f025c9757d6687b68459c8f985983 Mon Sep 17 00:00:00 2001 From: Bradley Bolen Date: Thu, 18 Jan 2018 08:55:20 -0500 Subject: [PATCH 215/266] ubi: block: Fix locking for idr_alloc/idr_remove commit 7f29ae9f977bcdc3654e68bc36d170223c52fd48 upstream. This fixes a race with idr_alloc where gd->first_minor can be set to the same value for two simultaneous calls to ubiblock_create. Each instance calls device_add_disk with the same first_minor. device_add_disk calls bdi_register_owner which generates several warnings. WARNING: CPU: 1 PID: 179 at kernel-source/fs/sysfs/dir.c:31 sysfs_warn_dup+0x68/0x88 sysfs: cannot create duplicate filename '/devices/virtual/bdi/252:2' WARNING: CPU: 1 PID: 179 at kernel-source/lib/kobject.c:240 kobject_add_internal+0x1ec/0x2f8 kobject_add_internal failed for 252:2 with -EEXIST, don't try to register things with the same name in the same directory WARNING: CPU: 1 PID: 179 at kernel-source/fs/sysfs/dir.c:31 sysfs_warn_dup+0x68/0x88 sysfs: cannot create duplicate filename '/dev/block/252:2' However, device_add_disk does not error out when bdi_register_owner returns an error. Control continues until reaching blk_register_queue. It then BUGs. kernel BUG at kernel-source/fs/sysfs/group.c:113! [] (internal_create_group) from [] (sysfs_create_group+0x20/0x24) [] (sysfs_create_group) from [] (blk_trace_init_sysfs+0x18/0x20) [] (blk_trace_init_sysfs) from [] (blk_register_queue+0xd8/0x154) [] (blk_register_queue) from [] (device_add_disk+0x194/0x44c) [] (device_add_disk) from [] (ubiblock_create+0x284/0x2e0) [] (ubiblock_create) from [] (vol_cdev_ioctl+0x450/0x554) [] (vol_cdev_ioctl) from [] (vfs_ioctl+0x30/0x44) [] (vfs_ioctl) from [] (do_vfs_ioctl+0xa0/0x790) [] (do_vfs_ioctl) from [] (SyS_ioctl+0x44/0x68) [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x34) Locking idr_alloc/idr_remove removes the race and keeps gd->first_minor unique. Fixes: 2bf50d42f3a4 ("UBI: block: Dynamically allocate minor numbers") Signed-off-by: Bradley Bolen Reviewed-by: Boris Brezillon Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/block.c | 42 +++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index ebf46ad2d513..b2fb0528c092 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -99,6 +99,8 @@ struct ubiblock { /* Linked list of all ubiblock instances */ static LIST_HEAD(ubiblock_devices); +static DEFINE_IDR(ubiblock_minor_idr); +/* Protects ubiblock_devices and ubiblock_minor_idr */ static DEFINE_MUTEX(devices_mutex); static int ubiblock_major; @@ -354,8 +356,6 @@ static struct blk_mq_ops ubiblock_mq_ops = { .map_queue = blk_mq_map_queue, }; -static DEFINE_IDR(ubiblock_minor_idr); - int ubiblock_create(struct ubi_volume_info *vi) { struct ubiblock *dev; @@ -368,14 +368,15 @@ int ubiblock_create(struct ubi_volume_info *vi) /* Check that the volume isn't already handled */ mutex_lock(&devices_mutex); if (find_dev_nolock(vi->ubi_num, vi->vol_id)) { - mutex_unlock(&devices_mutex); - return -EEXIST; + ret = -EEXIST; + goto out_unlock; } - mutex_unlock(&devices_mutex); dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL); - if (!dev) - return -ENOMEM; + if (!dev) { + ret = -ENOMEM; + goto out_unlock; + } mutex_init(&dev->dev_mutex); @@ -440,14 +441,13 @@ int ubiblock_create(struct ubi_volume_info *vi) goto out_free_queue; } - mutex_lock(&devices_mutex); list_add_tail(&dev->list, &ubiblock_devices); - mutex_unlock(&devices_mutex); /* Must be the last step: anyone can call file ops from now on */ add_disk(dev->gd); dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", dev->ubi_num, dev->vol_id, vi->name); + mutex_unlock(&devices_mutex); return 0; out_free_queue: @@ -460,6 +460,8 @@ out_put_disk: put_disk(dev->gd); out_free_dev: kfree(dev); +out_unlock: + mutex_unlock(&devices_mutex); return ret; } @@ -481,30 +483,36 @@ static void ubiblock_cleanup(struct ubiblock *dev) int ubiblock_remove(struct ubi_volume_info *vi) { struct ubiblock *dev; + int ret; mutex_lock(&devices_mutex); dev = find_dev_nolock(vi->ubi_num, vi->vol_id); if (!dev) { - mutex_unlock(&devices_mutex); - return -ENODEV; + ret = -ENODEV; + goto out_unlock; } /* Found a device, let's lock it so we can check if it's busy */ mutex_lock(&dev->dev_mutex); if (dev->refcnt > 0) { - mutex_unlock(&dev->dev_mutex); - mutex_unlock(&devices_mutex); - return -EBUSY; + ret = -EBUSY; + goto out_unlock_dev; } /* Remove from device list */ list_del(&dev->list); - mutex_unlock(&devices_mutex); - ubiblock_cleanup(dev); mutex_unlock(&dev->dev_mutex); + mutex_unlock(&devices_mutex); + kfree(dev); return 0; + +out_unlock_dev: + mutex_unlock(&dev->dev_mutex); +out_unlock: + mutex_unlock(&devices_mutex); + return ret; } static int ubiblock_resize(struct ubi_volume_info *vi) @@ -633,6 +641,7 @@ static void ubiblock_remove_all(void) struct ubiblock *next; struct ubiblock *dev; + mutex_lock(&devices_mutex); list_for_each_entry_safe(dev, next, &ubiblock_devices, list) { /* The module is being forcefully removed */ WARN_ON(dev->desc); @@ -641,6 +650,7 @@ static void ubiblock_remove_all(void) ubiblock_cleanup(dev); kfree(dev); } + mutex_unlock(&devices_mutex); } int __init ubiblock_init(void) From 7406be05b66818c4c20e3e63078dae88e94169c6 Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Fri, 15 Dec 2017 16:12:32 -0500 Subject: [PATCH 216/266] nfs/pnfs: fix nfs_direct_req ref leak when i/o falls back to the mds commit ba4a76f703ab7eb72941fdaac848502073d6e9ee upstream. Currently when falling back to doing I/O through the MDS (via pnfs_{read|write}_through_mds), the client frees the nfs_pgio_header without releasing the reference taken on the dreq via pnfs_generic_pg_{read|write}pages -> nfs_pgheader_init -> nfs_direct_pgio_init. It then takes another reference on the dreq via nfs_generic_pg_pgios -> nfs_pgheader_init -> nfs_direct_pgio_init and as a result the requester will become stuck in inode_dio_wait. Once that happens, other processes accessing the inode will become stuck as well. Ensure that pnfs_read_through_mds() and pnfs_write_through_mds() clean up correctly by calling hdr->completion_ops->completion() instead of calling hdr->release() directly. This can be reproduced (sometimes) by performing "storage failover takeover" commands on NetApp filer while doing direct I/O from a client. This can also be reproduced using SystemTap to simulate a failure while doing direct I/O from a client (from Dave Wysochanski ): stap -v -g -e 'probe module("nfs_layout_nfsv41_files").function("nfs4_fl_prepare_ds").return { $return=NULL; exit(); }' Suggested-by: Trond Myklebust Signed-off-by: Scott Mayhew Fixes: 1ca018d28d ("pNFS: Fix a memory leak when attempted pnfs fails") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/pnfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 7af7bedd7c02..c8e75e5e6a67 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1943,7 +1943,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, nfs_pageio_reset_write_mds(desc); mirror->pg_recoalesce = 1; } - hdr->release(hdr); + hdr->completion_ops->completion(hdr); } static enum pnfs_try_status @@ -2058,7 +2058,7 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, nfs_pageio_reset_read_mds(desc); mirror->pg_recoalesce = 1; } - hdr->release(hdr); + hdr->completion_ops->completion(hdr); } /* From 79e10b1a8dbc3da57fae6fef90f4112e65b3d214 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 18 Dec 2017 14:39:13 -0500 Subject: [PATCH 217/266] NFS: Add a cond_resched() to nfs_commit_release_pages() commit 7f1bda447c9bd48b415acedba6b830f61591601f upstream. The commit list can get very large, and so we need a cond_resched() in nfs_commit_release_pages() in order to ensure we don't hog the CPU for excessive periods of time. Reported-by: Mike Galbraith Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/write.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 7a9b6e347249..6e81a5b5858e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1746,6 +1746,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags); next: nfs_unlock_and_release_request(req); + /* Latency breaker */ + cond_resched(); } nfss = NFS_SERVER(data->inode); if (atomic_long_read(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) From ae0499e7b11fe83717b0f3aebb436cdeabf5ba66 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 16 Jan 2018 10:08:00 -0500 Subject: [PATCH 218/266] NFS: commit direct writes even if they fail partially commit 1b8d97b0a837beaf48a8449955b52c650a7114b4 upstream. If some of the WRITE calls making up an O_DIRECT write syscall fail, we neglect to commit, even if some of the WRITEs succeed. We also depend on the commit code to free the reference count on the nfs_page taken in the "if (request_commit)" case at the end of nfs_direct_write_completion(). The problem was originally noticed because ENOSPC's encountered partway through a write would result in a closed file being sillyrenamed when it should have been unlinked. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/direct.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 4b1d08f56aba..5fd3cf54b2b3 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -787,10 +787,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) spin_lock(&dreq->lock); - if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { - dreq->flags = 0; + if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) dreq->error = hdr->error; - } if (dreq->error == 0) { nfs_direct_good_bytes(dreq, hdr); if (nfs_write_need_commit(hdr)) { From fb8b16859a50f0d1fbf3e97e6ee1a82c23422b60 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 19 Jan 2018 15:15:34 -0800 Subject: [PATCH 219/266] NFS: reject request for id_legacy key without auxdata commit 49686cbbb3ebafe42e63868222f269d8053ead00 upstream. nfs_idmap_legacy_upcall() is supposed to be called with 'aux' pointing to a 'struct idmap', via the call to request_key_with_auxdata() in nfs_idmap_request_key(). However it can also be reached via the request_key() system call in which case 'aux' will be NULL, causing a NULL pointer dereference in nfs_idmap_prepare_pipe_upcall(), assuming that the key description is valid enough to get that far. Fix this by making nfs_idmap_legacy_upcall() negate the key if no auxdata is provided. As usual, this bug was found by syzkaller. A simple reproducer using the command-line keyctl program is: keyctl request2 id_legacy uid:0 '' @s Fixes: 57e62324e469 ("NFS: Store the legacy idmapper result in the keyring") Reported-by: syzbot+5dfdbcf7b3eb5912abbb@syzkaller.appspotmail.com Signed-off-by: Eric Biggers Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4idmap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c index 5ba22c6b0ffa..1ee62e62ea76 100644 --- a/fs/nfs/nfs4idmap.c +++ b/fs/nfs/nfs4idmap.c @@ -567,9 +567,13 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, struct idmap_msg *im; struct idmap *idmap = (struct idmap *)aux; struct key *key = cons->key; - int ret = -ENOMEM; + int ret = -ENOKEY; + + if (!aux) + goto out1; /* msg and im are freed in idmap_pipe_destroy_msg */ + ret = -ENOMEM; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) goto out1; From f1db1b8055e6ef6e5bf94699c32fc001ce7ba063 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Fri, 19 Jan 2018 09:18:54 +0100 Subject: [PATCH 220/266] kernfs: fix regression in kernfs_fop_write caused by wrong type commit ba87977a49913129962af8ac35b0e13e0fa4382d upstream. Commit b7ce40cff0b9 ("kernfs: cache atomic_write_len in kernfs_open_file") changes type of local variable 'len' from ssize_t to size_t. This change caused that the *ppos value is updated also when the previous write callback failed. Mentioned snippet: ... len = ops->write(...); <- return value can be negative ... if (len > 0) <- true here in this case *ppos += len; ... Fixes: b7ce40cff0b9 ("kernfs: cache atomic_write_len in kernfs_open_file") Acked-by: Tejun Heo Signed-off-by: Ivan Vecera Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 6e9a912d394c..6875bd5d35f6 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -272,7 +272,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf, { struct kernfs_open_file *of = kernfs_of(file); const struct kernfs_ops *ops; - size_t len; + ssize_t len; char *buf; if (of->atomic_write_len) { From 769e7b5fc95fe55b3469003aa3e672fbe9252015 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 6 Dec 2017 16:41:08 +0100 Subject: [PATCH 221/266] ahci: Annotate PCI ids for mobile Intel chipsets as such commit ca1b4974bd237f2373b0e980b11957aac3499b56 upstream. Intel uses different SATA PCI ids for the Desktop and Mobile SKUs of their chipsets. For older models the comment describing which chipset the PCI id is for, aksi indicates when we're dealing with a mobile SKU. Extend the comments for recent chipsets to also indicate mobile SKUs. The information this commit adds comes from Intel's chipset datasheets. This commit is a preparation patch for allowing a different default sata link powermanagement policy for mobile chipsets. Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ahci.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 60a15831c009..b0b62e07d68f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -260,9 +260,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */ { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */ - { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */ + { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH M AHCI */ { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ - { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */ + { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH M RAID */ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */ { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */ { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */ @@ -285,9 +285,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */ { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */ - { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */ + { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT M AHCI */ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */ - { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */ + { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT M RAID */ { PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */ { PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */ { PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */ @@ -296,20 +296,20 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */ { PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */ - { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */ + { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point M AHCI */ { PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */ - { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point M RAID */ { PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */ - { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */ + { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point M AHCI */ { PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */ - { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point M RAID */ { PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */ - { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point M RAID */ { PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */ - { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point M RAID */ { PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */ { PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */ { PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */ @@ -350,21 +350,21 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */ { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */ { PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */ - { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */ + { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series M AHCI */ { PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */ - { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series M RAID */ { PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */ - { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series M RAID */ { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */ - { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series M RAID */ { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */ { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */ { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */ { PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */ - { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */ + { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H M AHCI */ { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */ - { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */ + { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H M RAID */ { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/ From cbf32c1eb86444bfe4e87a9fd162762a9ba5d2a0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 6 Dec 2017 16:41:09 +0100 Subject: [PATCH 222/266] ahci: Add PCI ids for Intel Bay Trail, Cherry Trail and Apollo Lake AHCI commit 998008b779e424bd7513c434d0ab9c1268459009 upstream. Add PCI ids for Intel Bay Trail, Cherry Trail and Apollo Lake AHCI SATA controllers. This commit is a preparation patch for allowing a different default sata link powermanagement policy for mobile chipsets. Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ahci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b0b62e07d68f..9ac900c70711 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -382,6 +382,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0x0f22), board_ahci }, /* Bay Trail AHCI */ + { PCI_VDEVICE(INTEL, 0x0f23), board_ahci }, /* Bay Trail AHCI */ + { PCI_VDEVICE(INTEL, 0x22a3), board_ahci }, /* Cherry Trail AHCI */ + { PCI_VDEVICE(INTEL, 0x5ae3), board_ahci }, /* Apollo Lake AHCI */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, From 1f16aea4c55bb947266b68158d384c6c4c7e76b1 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 11 Jan 2018 15:55:50 +0300 Subject: [PATCH 223/266] ahci: Add Intel Cannon Lake PCH-H PCI ID commit f919dde0772a894c693a1eeabc77df69d6a9b937 upstream. Add Intel Cannon Lake PCH-H PCI ID to the list of supported controllers. Signed-off-by: Mika Westerberg Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ahci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 9ac900c70711..8ddf5d5c94fd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -382,6 +382,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */ { PCI_VDEVICE(INTEL, 0x0f22), board_ahci }, /* Bay Trail AHCI */ { PCI_VDEVICE(INTEL, 0x0f23), board_ahci }, /* Bay Trail AHCI */ { PCI_VDEVICE(INTEL, 0x22a3), board_ahci }, /* Cherry Trail AHCI */ From c311cf44ca749f114dc0f28a7e288f358ac595c8 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 3 Jan 2018 11:16:22 -0800 Subject: [PATCH 224/266] crypto: hash - introduce crypto_hash_alg_has_setkey() commit cd6ed77ad5d223dc6299fb58f62e0f5267f7e2ba upstream. Templates that use an shash spawn can use crypto_shash_alg_has_setkey() to determine whether the underlying algorithm requires a key or not. But there was no corresponding function for ahash spawns. Add it. Note that the new function actually has to support both shash and ahash algorithms, since the ahash API can be used with either. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/ahash.c | 11 +++++++++++ include/crypto/internal/hash.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/crypto/ahash.c b/crypto/ahash.c index f9caf0f74199..7006dbfd39bd 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -637,5 +637,16 @@ struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(ahash_attr_alg); +bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg) +{ + struct crypto_alg *alg = &halg->base; + + if (alg->cra_type != &crypto_ahash_type) + return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg)); + + return __crypto_ahash_alg(alg)->setkey != NULL; +} +EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 9779c35f8454..dab9569f22bf 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -91,6 +91,8 @@ static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg) return alg->setkey != shash_no_setkey; } +bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg); + int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, struct hash_alg_common *alg, struct crypto_instance *inst); From 693d395faecaab8321d506042653fe81aa7d6da0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 3 Jan 2018 11:16:23 -0800 Subject: [PATCH 225/266] crypto: cryptd - pass through absence of ->setkey() commit 841a3ff329713f796a63356fef6e2f72e4a3f6a3 upstream. When the cryptd template is used to wrap an unkeyed hash algorithm, don't install a ->setkey() method to the cryptd instance. This change is necessary for cryptd to keep working with unkeyed hash algorithms once we start enforcing that ->setkey() is called when present. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/cryptd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/cryptd.c b/crypto/cryptd.c index 26a504db3f53..10a5a3eb675a 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -654,7 +654,8 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, inst->alg.finup = cryptd_hash_finup_enqueue; inst->alg.export = cryptd_hash_export; inst->alg.import = cryptd_hash_import; - inst->alg.setkey = cryptd_hash_setkey; + if (crypto_shash_alg_has_setkey(salg)) + inst->alg.setkey = cryptd_hash_setkey; inst->alg.digest = cryptd_hash_digest_enqueue; err = ahash_register_instance(tmpl, inst); From de1ca9ef43de77e507752182c1b5050851a1aa58 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 3 Jan 2018 11:16:25 -0800 Subject: [PATCH 226/266] crypto: poly1305 - remove ->setkey() method commit a16e772e664b9a261424107784804cffc8894977 upstream. Since Poly1305 requires a nonce per invocation, the Linux kernel implementations of Poly1305 don't use the crypto API's keying mechanism and instead expect the key and nonce as the first 32 bytes of the data. But ->setkey() is still defined as a stub returning an error code. This prevents Poly1305 from being used through AF_ALG and will also break it completely once we start enforcing that all crypto API users (not just AF_ALG) call ->setkey() if present. Fix it by removing crypto_poly1305_setkey(), leaving ->setkey as NULL. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- arch/x86/crypto/poly1305_glue.c | 1 - crypto/poly1305_generic.c | 17 +++++------------ include/crypto/poly1305.h | 2 -- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/arch/x86/crypto/poly1305_glue.c b/arch/x86/crypto/poly1305_glue.c index 4264a3d59589..7c064887b783 100644 --- a/arch/x86/crypto/poly1305_glue.c +++ b/arch/x86/crypto/poly1305_glue.c @@ -164,7 +164,6 @@ static struct shash_alg alg = { .init = poly1305_simd_init, .update = poly1305_simd_update, .final = crypto_poly1305_final, - .setkey = crypto_poly1305_setkey, .descsize = sizeof(struct poly1305_simd_desc_ctx), .base = { .cra_name = "poly1305", diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c index 2df9835dfbc0..bca99238948f 100644 --- a/crypto/poly1305_generic.c +++ b/crypto/poly1305_generic.c @@ -51,17 +51,6 @@ int crypto_poly1305_init(struct shash_desc *desc) } EXPORT_SYMBOL_GPL(crypto_poly1305_init); -int crypto_poly1305_setkey(struct crypto_shash *tfm, - const u8 *key, unsigned int keylen) -{ - /* Poly1305 requires a unique key for each tag, which implies that - * we can't set it on the tfm that gets accessed by multiple users - * simultaneously. Instead we expect the key as the first 32 bytes in - * the update() call. */ - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(crypto_poly1305_setkey); - static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key) { /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ @@ -80,6 +69,11 @@ static void poly1305_setskey(struct poly1305_desc_ctx *dctx, const u8 *key) dctx->s[3] = le32_to_cpuvp(key + 12); } +/* + * Poly1305 requires a unique key for each tag, which implies that we can't set + * it on the tfm that gets accessed by multiple users simultaneously. Instead we + * expect the key as the first 32 bytes in the update() call. + */ unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, const u8 *src, unsigned int srclen) { @@ -285,7 +279,6 @@ static struct shash_alg poly1305_alg = { .init = crypto_poly1305_init, .update = crypto_poly1305_update, .final = crypto_poly1305_final, - .setkey = crypto_poly1305_setkey, .descsize = sizeof(struct poly1305_desc_ctx), .base = { .cra_name = "poly1305", diff --git a/include/crypto/poly1305.h b/include/crypto/poly1305.h index 894df59b74e4..d586f741cab5 100644 --- a/include/crypto/poly1305.h +++ b/include/crypto/poly1305.h @@ -30,8 +30,6 @@ struct poly1305_desc_ctx { }; int crypto_poly1305_init(struct shash_desc *desc); -int crypto_poly1305_setkey(struct crypto_shash *tfm, - const u8 *key, unsigned int keylen); unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, const u8 *src, unsigned int srclen); int crypto_poly1305_update(struct shash_desc *desc, From 49ffe04fcdf29c8925344bce314d9398b2d7743d Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 19 Apr 2017 15:11:00 -0700 Subject: [PATCH 227/266] nsfs: mark dentry with DCACHE_RCUACCESS commit 073c516ff73557a8f7315066856c04b50383ac34 upstream. Andrey reported a use-after-free in __ns_get_path(): spin_lock include/linux/spinlock.h:299 [inline] lockref_get_not_dead+0x19/0x80 lib/lockref.c:179 __ns_get_path+0x197/0x860 fs/nsfs.c:66 open_related_ns+0xda/0x200 fs/nsfs.c:143 sock_ioctl+0x39d/0x440 net/socket.c:1001 vfs_ioctl fs/ioctl.c:45 [inline] do_vfs_ioctl+0x1bf/0x1780 fs/ioctl.c:685 SYSC_ioctl fs/ioctl.c:700 [inline] SyS_ioctl+0x8f/0xc0 fs/ioctl.c:691 We are under rcu read lock protection at that point: rcu_read_lock(); d = atomic_long_read(&ns->stashed); if (!d) goto slow; dentry = (struct dentry *)d; if (!lockref_get_not_dead(&dentry->d_lockref)) goto slow; rcu_read_unlock(); but don't use a proper RCU API on the free path, therefore a parallel __d_free() could free it at the same time. We need to mark the stashed dentry with DCACHE_RCUACCESS so that __d_free() will be called after all readers leave RCU. Fixes: e149ed2b805f ("take the targets of /proc/*/ns/* symlinks to separate fs") Cc: Alexander Viro Cc: Andrew Morton Reported-by: Andrey Konovalov Signed-off-by: Cong Wang Signed-off-by: Linus Torvalds Cc: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- fs/nsfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nsfs.c b/fs/nsfs.c index 8f20d6016e20..914ca6b2794d 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -95,6 +95,7 @@ slow: return ERR_PTR(-ENOMEM); } d_instantiate(dentry, inode); + dentry->d_flags |= DCACHE_RCUACCESS; dentry->d_fsdata = (void *)ns_ops; d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); if (d) { From 15e3780a8add9d5cd6bdc9df9cdc4e0d9b8e55dd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:27 +0100 Subject: [PATCH 228/266] media: v4l2-ioctl.c: don't copy back the result for -ENOTTY commit 181a4a2d5a0a7b43cab08a70710d727e7764ccdd upstream. If the ioctl returned -ENOTTY, then don't bother copying back the result as there is no point. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-ioctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 7486af2c8ae4..5e2a7e59f578 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2783,8 +2783,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, /* Handles IOCTL */ err = func(file, cmd, parg); - if (err == -ENOIOCTLCMD) + if (err == -ENOTTY || err == -ENOIOCTLCMD) { err = -ENOTTY; + goto out; + } + if (err == 0) { if (cmd == VIDIOC_DQBUF) trace_v4l2_dqbuf(video_devdata(file)->minor, parg); From 587a6b832441e9a2fe2adbf16d4aa2667fdd63a8 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Wed, 14 Feb 2018 12:52:28 +0100 Subject: [PATCH 229/266] vb2: V4L2_BUF_FLAG_DONE is set after DQBUF commit 3171cc2b4eb9831ab4df1d80d0410a945b8bc84e upstream. According to the doc, V4L2_BUF_FLAG_DONE is cleared after DQBUF: V4L2_BUF_FLAG_DONE 0x00000004 ... After calling the VIDIOC_QBUF or VIDIOC_DQBUF it is always cleared ... Unfortunately, it seems that videobuf2 keeps it set after DQBUF. This can be tested with vivid and dev_debug: [257604.338082] video1: VIDIOC_DQBUF: 71:33:25.00260479 index=3, type=vid-cap, flags=0x00002004, field=none, sequence=163, memory=userptr, bytesused=460800, offset/userptr=0x344b000, length=460800 This patch forces FLAG_DONE to 0 after calling DQBUF. Reported-by: Dimitrios Katsaros Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/videobuf2-v4l2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c index 6c441be8f893..bf23234d957e 100644 --- a/drivers/media/v4l2-core/videobuf2-v4l2.c +++ b/drivers/media/v4l2-core/videobuf2-v4l2.c @@ -593,6 +593,12 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, b->flags & V4L2_BUF_FLAG_LAST) q->last_buffer_dequeued = true; + /* + * After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be + * cleared. + */ + b->flags &= ~V4L2_BUF_FLAG_DONE; + return ret; } From 4a85bbbcb5d5d3afb66b6c9a9ba54d02e30f8b4f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:29 +0100 Subject: [PATCH 230/266] media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF commit 3ee6d040719ae09110e5cdf24d5386abe5d1b776 upstream. The result of the VIDIOC_PREPARE_BUF ioctl was never copied back to userspace since it was missing in the switch. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 4379b949bb93..f47a30b89281 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -1022,6 +1022,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_create32(&karg.v2crt, up); break; + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: From 04d632236ad250f527ff9d7e3b2696783e82409c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:30 +0100 Subject: [PATCH 231/266] media: v4l2-compat-ioctl32.c: fix the indentation commit b7b957d429f601d6d1942122b339474f31191d75 upstream. The indentation of this source is all over the place. Fix this. This patch only changes whitespace. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 208 +++++++++--------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index f47a30b89281..c849b67b98df 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -48,11 +48,11 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(&kp->w, &up->w, sizeof(up->w)) || - get_user(kp->field, &up->field) || - get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount)) - return -EFAULT; + copy_from_user(&kp->w, &up->w, sizeof(up->w)) || + get_user(kp->field, &up->field) || + get_user(kp->chromakey, &up->chromakey) || + get_user(kp->clipcount, &up->clipcount)) + return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; if (kp->clipcount) { @@ -82,10 +82,10 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || - put_user(kp->field, &up->field) || - put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount)) - return -EFAULT; + put_user(kp->field, &up->field) || + put_user(kp->chromakey, &up->chromakey) || + put_user(kp->clipcount, &up->clipcount)) + return -EFAULT; return 0; } @@ -97,7 +97,7 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) + struct v4l2_pix_format_mplane __user *up) { if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -112,7 +112,7 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi } static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) + struct v4l2_pix_format_mplane __user *up) { if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) return -EFAULT; @@ -218,7 +218,7 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); default: pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -265,7 +265,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); default: pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); + kp->type); return -EINVAL; } } @@ -299,7 +299,7 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 { /* other fields are not set by the user, nor used by the driver */ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || - get_user(kp->index, &up->index)) + get_user(kp->index, &up->index)) return -EFAULT; return 0; } @@ -307,13 +307,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || - put_user(kp->index, &up->index) || - put_user(kp->id, &up->id) || - copy_to_user(up->name, kp->name, 24) || - copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) - return -EFAULT; + put_user(kp->index, &up->index) || + put_user(kp->id, &up->id) || + copy_to_user(up->name, kp->name, 24) || + copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || + put_user(kp->framelines, &up->framelines) || + copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) + return -EFAULT; return 0; } @@ -353,14 +353,14 @@ struct v4l2_buffer32 { }; static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, - enum v4l2_memory memory) + enum v4l2_memory memory) { void __user *up_pln; compat_long_t p; if (copy_in_user(up, up32, 2 * sizeof(__u32)) || - copy_in_user(&up->data_offset, &up32->data_offset, - sizeof(__u32))) + copy_in_user(&up->data_offset, &up32->data_offset, + sizeof(__u32))) return -EFAULT; if (memory == V4L2_MEMORY_USERPTR) { @@ -374,7 +374,7 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return -EFAULT; } else { if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(__u32))) + sizeof(__u32))) return -EFAULT; } @@ -382,23 +382,23 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ } static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, - enum v4l2_memory memory) + enum v4l2_memory memory) { if (copy_in_user(up32, up, 2 * sizeof(__u32)) || - copy_in_user(&up32->data_offset, &up->data_offset, - sizeof(__u32))) + copy_in_user(&up32->data_offset, &up->data_offset, + sizeof(__u32))) return -EFAULT; /* For MMAP, driver might've set up the offset, so copy it back. * USERPTR stays the same (was userspace-provided), so no copying. */ if (memory == V4L2_MEMORY_MMAP) if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, - sizeof(__u32))) + sizeof(__u32))) return -EFAULT; /* For DMABUF, driver might've set up the fd, so copy it back. */ if (memory == V4L2_MEMORY_DMABUF) if (copy_in_user(&up32->m.fd, &up->m.fd, - sizeof(int))) + sizeof(int))) return -EFAULT; return 0; @@ -413,19 +413,19 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int ret; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || - get_user(kp->index, &up->index) || - get_user(kp->type, &up->type) || - get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory) || - get_user(kp->length, &up->length)) - return -EFAULT; + get_user(kp->index, &up->index) || + get_user(kp->type, &up->type) || + get_user(kp->flags, &up->flags) || + get_user(kp->memory, &up->memory) || + get_user(kp->length, &up->length)) + return -EFAULT; if (V4L2_TYPE_IS_OUTPUT(kp->type)) if (get_user(kp->bytesused, &up->bytesused) || - get_user(kp->field, &up->field) || - get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, - &up->timestamp.tv_usec)) + get_user(kp->field, &up->field) || + get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + get_user(kp->timestamp.tv_usec, + &up->timestamp.tv_usec)) return -EFAULT; if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { @@ -442,13 +442,13 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user uplane32 = compat_ptr(p); if (!access_ok(VERIFY_READ, uplane32, - num_planes * sizeof(struct v4l2_plane32))) + num_planes * sizeof(struct v4l2_plane32))) return -EFAULT; /* We don't really care if userspace decides to kill itself * by passing a very big num_planes value */ uplane = compat_alloc_user_space(num_planes * - sizeof(struct v4l2_plane)); + sizeof(struct v4l2_plane)); kp->m.planes = (__force struct v4l2_plane *)uplane; while (--num_planes >= 0) { @@ -466,12 +466,12 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user break; case V4L2_MEMORY_USERPTR: { - compat_long_t tmp; + compat_long_t tmp; - if (get_user(tmp, &up->m.userptr)) - return -EFAULT; + if (get_user(tmp, &up->m.userptr)) + return -EFAULT; - kp->m.userptr = (unsigned long)compat_ptr(tmp); + kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; case V4L2_MEMORY_OVERLAY: @@ -497,22 +497,22 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int ret; if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || - put_user(kp->index, &up->index) || - put_user(kp->type, &up->type) || - put_user(kp->flags, &up->flags) || - put_user(kp->memory, &up->memory)) - return -EFAULT; + put_user(kp->index, &up->index) || + put_user(kp->type, &up->type) || + put_user(kp->flags, &up->flags) || + put_user(kp->memory, &up->memory)) + return -EFAULT; if (put_user(kp->bytesused, &up->bytesused) || - put_user(kp->field, &up->field) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->reserved2, &up->reserved2) || - put_user(kp->reserved, &up->reserved) || - put_user(kp->length, &up->length)) - return -EFAULT; + put_user(kp->field, &up->field) || + put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || + copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || + put_user(kp->sequence, &up->sequence) || + put_user(kp->reserved2, &up->reserved2) || + put_user(kp->reserved, &up->reserved) || + put_user(kp->length, &up->length)) + return -EFAULT; if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { num_planes = kp->length; @@ -576,11 +576,11 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame u32 tmp; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || - get_user(tmp, &up->base) || - get_user(kp->capability, &up->capability) || - get_user(kp->flags, &up->flags) || - copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) - return -EFAULT; + get_user(tmp, &up->base) || + get_user(kp->capability, &up->capability) || + get_user(kp->flags, &up->flags) || + copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) + return -EFAULT; kp->base = (__force void *)compat_ptr(tmp); return 0; } @@ -590,11 +590,11 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame u32 tmp = (u32)((unsigned long)kp->base); if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || - put_user(tmp, &up->base) || - put_user(kp->capability, &up->capability) || - put_user(kp->flags, &up->flags) || - copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) - return -EFAULT; + put_user(tmp, &up->base) || + put_user(kp->capability, &up->capability) || + put_user(kp->flags, &up->flags) || + copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) + return -EFAULT; return 0; } @@ -669,12 +669,12 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext compat_caddr_t p; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || - get_user(kp->ctrl_class, &up->ctrl_class) || - get_user(kp->count, &up->count) || - get_user(kp->error_idx, &up->error_idx) || - copy_from_user(kp->reserved, up->reserved, - sizeof(kp->reserved))) - return -EFAULT; + get_user(kp->ctrl_class, &up->ctrl_class) || + get_user(kp->count, &up->count) || + get_user(kp->error_idx, &up->error_idx) || + copy_from_user(kp->reserved, up->reserved, + sizeof(kp->reserved))) + return -EFAULT; n = kp->count; if (n == 0) { kp->controls = NULL; @@ -684,7 +684,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; ucontrols = compat_ptr(p); if (!access_ok(VERIFY_READ, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + n * sizeof(struct v4l2_ext_control32))) return -EFAULT; kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); kp->controls = (__force struct v4l2_ext_control *)kcontrols; @@ -719,11 +719,11 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext compat_caddr_t p; if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || - put_user(kp->ctrl_class, &up->ctrl_class) || - put_user(kp->count, &up->count) || - put_user(kp->error_idx, &up->error_idx) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) - return -EFAULT; + put_user(kp->ctrl_class, &up->ctrl_class) || + put_user(kp->count, &up->count) || + put_user(kp->error_idx, &up->error_idx) || + copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; if (!kp->count) return 0; @@ -731,7 +731,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; ucontrols = compat_ptr(p); if (!access_ok(VERIFY_WRITE, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + n * sizeof(struct v4l2_ext_control32))) return -EFAULT; while (--n >= 0) { @@ -769,15 +769,15 @@ struct v4l2_event32 { static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || - put_user(kp->type, &up->type) || - copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || - put_user(kp->pending, &up->pending) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || - put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) - return -EFAULT; + put_user(kp->type, &up->type) || + copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || + put_user(kp->pending, &up->pending) || + put_user(kp->sequence, &up->sequence) || + put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || + put_user(kp->id, &up->id) || + copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) + return -EFAULT; return 0; } @@ -794,12 +794,12 @@ static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) u32 tmp; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || - get_user(kp->pad, &up->pad) || - get_user(kp->start_block, &up->start_block) || - get_user(kp->blocks, &up->blocks) || - get_user(tmp, &up->edid) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) - return -EFAULT; + get_user(kp->pad, &up->pad) || + get_user(kp->start_block, &up->start_block) || + get_user(kp->blocks, &up->blocks) || + get_user(tmp, &up->edid) || + copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + return -EFAULT; kp->edid = (__force u8 *)compat_ptr(tmp); return 0; } @@ -809,12 +809,12 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) u32 tmp = (u32)((unsigned long)kp->edid); if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || - put_user(kp->pad, &up->pad) || - put_user(kp->start_block, &up->start_block) || - put_user(kp->blocks, &up->blocks) || - put_user(tmp, &up->edid) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) - return -EFAULT; + put_user(kp->pad, &up->pad) || + put_user(kp->start_block, &up->start_block) || + put_user(kp->blocks, &up->blocks) || + put_user(tmp, &up->edid) || + copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + return -EFAULT; return 0; } From 56a4fbdf5092d64f1f29a1e45508f18f3072f316 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:31 +0100 Subject: [PATCH 232/266] media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32 commit 486c521510c44a04cd756a9267e7d1e271c8a4ba upstream. These helper functions do not really help. Move the code to the __get/put_v4l2_format32 functions. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 104 ++++-------------- 1 file changed, 20 insertions(+), 84 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index c849b67b98df..5ebc11476f63 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -89,78 +89,6 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return 0; } -static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format))) - return -EFAULT; - return 0; -} - struct v4l2_format32 { __u32 type; /* enum v4l2_buf_type */ union { @@ -199,23 +127,27 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + return copy_from_user(&kp->fmt.pix, &up->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); + return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); + return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SDR_CAPTURE: case V4L2_BUF_TYPE_SDR_OUTPUT: - return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); + return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr, + sizeof(kp->fmt.sdr)) ? -EFAULT : 0; default: pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", kp->type); @@ -246,23 +178,27 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us switch (kp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + return copy_to_user(&up->fmt.pix, &kp->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); + return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); + return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SDR_CAPTURE: case V4L2_BUF_TYPE_SDR_OUTPUT: - return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); + return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr, + sizeof(kp->fmt.sdr)) ? -EFAULT : 0; default: pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", kp->type); From 57f0817a6dd82cf0b3188f36df191abd629555c8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:32 +0100 Subject: [PATCH 233/266] media: v4l2-compat-ioctl32.c: avoid sizeof(type) commit 333b1e9f96ce05f7498b581509bb30cde03018bf upstream. Instead of doing sizeof(struct foo) use sizeof(*up). There even were cases where 4 * sizeof(__u32) was used instead of sizeof(kp->reserved), which is very dangerous when the size of the reserved array changes. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 77 +++++++++---------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 5ebc11476f63..ace1d7b050a5 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -47,7 +47,7 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || get_user(kp->chromakey, &up->chromakey) || @@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); kp->clips = kclips; while (--n >= 0) { if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) @@ -157,14 +157,14 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32))) + if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; return __get_v4l2_format32(kp, up); } static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) { - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) return -EFAULT; return __get_v4l2_format32(&kp->format, &up->format); @@ -208,14 +208,14 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32))) + if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; return __put_v4l2_format32(kp, up); } static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; @@ -234,7 +234,7 @@ struct v4l2_standard32 { static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->index, &up->index)) return -EFAULT; return 0; @@ -242,13 +242,13 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->index, &up->index) || put_user(kp->id, &up->id) || - copy_to_user(up->name, kp->name, 24) || + copy_to_user(up->name, kp->name, sizeof(up->name)) || copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -296,7 +296,7 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(&up->data_offset, &up32->data_offset, - sizeof(__u32))) + sizeof(up->data_offset))) return -EFAULT; if (memory == V4L2_MEMORY_USERPTR) { @@ -306,11 +306,11 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ if (put_user((unsigned long)up_pln, &up->m.userptr)) return -EFAULT; } else if (memory == V4L2_MEMORY_DMABUF) { - if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int))) + if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd))) return -EFAULT; } else { if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(__u32))) + sizeof(up32->m.mem_offset))) return -EFAULT; } @@ -322,19 +322,19 @@ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ { if (copy_in_user(up32, up, 2 * sizeof(__u32)) || copy_in_user(&up32->data_offset, &up->data_offset, - sizeof(__u32))) + sizeof(up->data_offset))) return -EFAULT; /* For MMAP, driver might've set up the offset, so copy it back. * USERPTR stays the same (was userspace-provided), so no copying. */ if (memory == V4L2_MEMORY_MMAP) if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, - sizeof(__u32))) + sizeof(up->m.mem_offset))) return -EFAULT; /* For DMABUF, driver might've set up the fd, so copy it back. */ if (memory == V4L2_MEMORY_DMABUF) if (copy_in_user(&up32->m.fd, &up->m.fd, - sizeof(int))) + sizeof(up->m.fd))) return -EFAULT; return 0; @@ -348,7 +348,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int num_planes; int ret; - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->index, &up->index) || get_user(kp->type, &up->type) || get_user(kp->flags, &up->flags) || @@ -360,8 +360,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user if (get_user(kp->bytesused, &up->bytesused) || get_user(kp->field, &up->field) || get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, - &up->timestamp.tv_usec)) + get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) return -EFAULT; if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { @@ -378,13 +377,12 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user uplane32 = compat_ptr(p); if (!access_ok(VERIFY_READ, uplane32, - num_planes * sizeof(struct v4l2_plane32))) + num_planes * sizeof(*uplane32))) return -EFAULT; /* We don't really care if userspace decides to kill itself * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * - sizeof(struct v4l2_plane)); + uplane = compat_alloc_user_space(num_planes * sizeof(*uplane)); kp->m.planes = (__force struct v4l2_plane *)uplane; while (--num_planes >= 0) { @@ -432,7 +430,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user int num_planes; int ret; - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->index, &up->index) || put_user(kp->type, &up->type) || put_user(kp->flags, &up->flags) || @@ -443,7 +441,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user put_user(kp->field, &up->field) || put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || + copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || put_user(kp->sequence, &up->sequence) || put_user(kp->reserved2, &up->reserved2) || put_user(kp->reserved, &up->reserved) || @@ -511,7 +509,7 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame { u32 tmp; - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(tmp, &up->base) || get_user(kp->capability, &up->capability) || get_user(kp->flags, &up->flags) || @@ -525,7 +523,7 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame { u32 tmp = (u32)((unsigned long)kp->base); - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(tmp, &up->base) || put_user(kp->capability, &up->capability) || put_user(kp->flags, &up->flags) || @@ -549,14 +547,14 @@ struct v4l2_input32 { Otherwise it is identical to the 32-bit version. */ static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) { - if (copy_from_user(kp, up, sizeof(struct v4l2_input32))) + if (copy_from_user(kp, up, sizeof(*up))) return -EFAULT; return 0; } static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) { - if (copy_to_user(up, kp, sizeof(struct v4l2_input32))) + if (copy_to_user(up, kp, sizeof(*up))) return -EFAULT; return 0; } @@ -604,12 +602,11 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext int n; compat_caddr_t p; - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->ctrl_class, &up->ctrl_class) || get_user(kp->count, &up->count) || get_user(kp->error_idx, &up->error_idx) || - copy_from_user(kp->reserved, up->reserved, - sizeof(kp->reserved))) + copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; n = kp->count; if (n == 0) { @@ -619,10 +616,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_READ, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols))) return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); + kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols)); kp->controls = (__force struct v4l2_ext_control *)kcontrols; while (--n >= 0) { u32 id; @@ -654,7 +650,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext int n = kp->count; compat_caddr_t p; - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->ctrl_class, &up->ctrl_class) || put_user(kp->count, &up->count) || put_user(kp->error_idx, &up->error_idx) || @@ -666,8 +662,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_WRITE, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols))) return -EFAULT; while (--n >= 0) { @@ -704,7 +699,7 @@ struct v4l2_event32 { static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) { - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->type, &up->type) || copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || put_user(kp->pending, &up->pending) || @@ -712,7 +707,7 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) + copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return 0; } @@ -729,7 +724,7 @@ static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) { u32 tmp; - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(kp->pad, &up->pad) || get_user(kp->start_block, &up->start_block) || get_user(kp->blocks, &up->blocks) || @@ -744,7 +739,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) { u32 tmp = (u32)((unsigned long)kp->edid); - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || put_user(kp->pad, &up->pad) || put_user(kp->start_block, &up->start_block) || put_user(kp->blocks, &up->blocks) || From c6cbc2c3539fd68d37dff300870f56869d21bb82 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:33 +0100 Subject: [PATCH 234/266] media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32 commit 8ed5a59dcb47a6f76034ee760b36e089f3e82529 upstream. The struct v4l2_plane32 should set m.userptr as well. The same happens in v4l2_buffer32 and v4l2-compliance tests for this. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index ace1d7b050a5..af197980ab8e 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -299,19 +299,24 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ sizeof(up->data_offset))) return -EFAULT; - if (memory == V4L2_MEMORY_USERPTR) { + switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: + if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, + sizeof(up32->m.mem_offset))) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: if (get_user(p, &up32->m.userptr)) return -EFAULT; up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, &up->m.userptr)) return -EFAULT; - } else if (memory == V4L2_MEMORY_DMABUF) { + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd))) return -EFAULT; - } else { - if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(up32->m.mem_offset))) - return -EFAULT; + break; } return 0; @@ -320,22 +325,32 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { + unsigned long p; + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || copy_in_user(&up32->data_offset, &up->data_offset, sizeof(up->data_offset))) return -EFAULT; - /* For MMAP, driver might've set up the offset, so copy it back. - * USERPTR stays the same (was userspace-provided), so no copying. */ - if (memory == V4L2_MEMORY_MMAP) + switch (memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, sizeof(up->m.mem_offset))) return -EFAULT; - /* For DMABUF, driver might've set up the fd, so copy it back. */ - if (memory == V4L2_MEMORY_DMABUF) + break; + case V4L2_MEMORY_USERPTR: + if (get_user(p, &up->m.userptr) || + put_user((compat_ulong_t)ptr_to_compat((__force void *)p), + &up32->m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_DMABUF: if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd))) return -EFAULT; + break; + } return 0; } @@ -395,6 +410,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (get_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; @@ -408,10 +424,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (get_user(kp->m.fd, &up->m.fd)) return -EFAULT; @@ -468,6 +480,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: if (put_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; @@ -475,10 +488,6 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user if (put_user(kp->m.userptr, &up->m.userptr)) return -EFAULT; break; - case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; case V4L2_MEMORY_DMABUF: if (put_user(kp->m.fd, &up->m.fd)) return -EFAULT; From d64d203f201975604578f71982ba13fe71bd86d6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:34 +0100 Subject: [PATCH 235/266] media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer commit b8c601e8af2d08f733d74defa8465303391bb930 upstream. ctrl_is_pointer just hardcoded two known string controls, but that caused problems when using e.g. custom controls that use a pointer for the payload. Reimplement this function: it now finds the v4l2_ctrl (if the driver uses the control framework) or it calls vidioc_query_ext_ctrl (if the driver implements that directly). In both cases it can now check if the control is a pointer control or not. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index af197980ab8e..2104d3af94f5 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -587,24 +589,39 @@ struct v4l2_ext_control32 { }; } __attribute__ ((packed)); -/* The following function really belong in v4l2-common, but that causes - a circular dependency between modules. We need to think about this, but - for now this will do. */ - -/* Return non-zero if this control is a pointer type. Currently only - type STRING is a pointer type. */ -static inline int ctrl_is_pointer(u32 id) +/* Return true if this control is a pointer type. */ +static inline bool ctrl_is_pointer(struct file *file, u32 id) { - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; + struct video_device *vdev = video_devdata(file); + struct v4l2_fh *fh = NULL; + struct v4l2_ctrl_handler *hdl = NULL; + struct v4l2_query_ext_ctrl qec = { id }; + const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; + + if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) + fh = file->private_data; + + if (fh && fh->ctrl_handler) + hdl = fh->ctrl_handler; + else if (vdev->ctrl_handler) + hdl = vdev->ctrl_handler; + + if (hdl) { + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id); + + return ctrl && ctrl->is_ptr; } + + if (!ops->vidioc_query_ext_ctrl) + return false; + + return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && + (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); } -static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int get_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; @@ -636,7 +653,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return -EFAULT; if (get_user(id, &kcontrols->id)) return -EFAULT; - if (ctrl_is_pointer(id)) { + if (ctrl_is_pointer(file, id)) { void __user *s; if (get_user(p, &ucontrols->string)) @@ -651,7 +668,9 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext return 0; } -static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) +static int put_v4l2_ext_controls32(struct file *file, + struct v4l2_ext_controls *kp, + struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols = @@ -683,7 +702,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext /* Do not modify the pointer when copying a pointer control. The contents of the pointer was changed, not the pointer itself. */ - if (ctrl_is_pointer(id)) + if (ctrl_is_pointer(file, id)) size -= sizeof(ucontrols->value64); if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; @@ -897,7 +916,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(&karg.v2ecs, up); + err = get_v4l2_ext_controls32(file, &karg.v2ecs, up); compatible_arg = 0; break; case VIDIOC_DQEVENT: @@ -924,7 +943,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - if (put_v4l2_ext_controls32(&karg.v2ecs, up)) + if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) err = -EFAULT; break; } From 8fbc22b34365bfeb72b1e3a63ba9239d327137dc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:35 +0100 Subject: [PATCH 236/266] media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs commit 273caa260035c03d89ad63d72d8cd3d9e5c5e3f1 upstream. If the device is of type VFL_TYPE_SUBDEV then vdev->ioctl_ops is NULL so the 'if (!ops->vidioc_query_ext_ctrl)' check would crash. Add a test for !ops to the condition. All sub-devices that have controls will use the control framework, so they do not have an equivalent to ops->vidioc_query_ext_ctrl. Returning false if ops is NULL is the correct thing to do here. Fixes: b8c601e8af ("v4l2-compat-ioctl32.c: fix ctrl_is_pointer") Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Reported-by: Laurent Pinchart Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 2104d3af94f5..0c3949a00570 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -612,7 +612,7 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) return ctrl && ctrl->is_ptr; } - if (!ops->vidioc_query_ext_ctrl) + if (!ops || !ops->vidioc_query_ext_ctrl) return false; return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && From 8b775336cc1f7ce334a55e1287656bd0fd0ac8cf Mon Sep 17 00:00:00 2001 From: Daniel Mentz Date: Wed, 14 Feb 2018 12:52:36 +0100 Subject: [PATCH 237/266] media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha commit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream. Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output overlays.") added the field global_alpha to struct v4l2_window but did not update the compat layer accordingly. This change adds global_alpha to struct v4l2_window32 and copies the value for global_alpha back and forth. Signed-off-by: Daniel Mentz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 0c3949a00570..e55231a12f00 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -45,6 +45,7 @@ struct v4l2_window32 { compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8 global_alpha; }; static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) @@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount)) + get_user(kp->clipcount, &up->clipcount) || + get_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; @@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || put_user(kp->field, &up->field) || put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount)) + put_user(kp->clipcount, &up->clipcount) || + put_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; return 0; } From 4c8ba4d5ad2fc0d2c11ade4997571f654a573f87 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:37 +0100 Subject: [PATCH 238/266] media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32 commit a751be5b142ef6bcbbb96d9899516f4d9c8d0ef4 upstream. put_v4l2_window32() didn't copy back the clip list to userspace. Drivers can update the clip rectangles, so this should be done. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 61 +++++++++++++------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index e55231a12f00..84fb4c54b101 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -50,6 +50,11 @@ struct v4l2_window32 { static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { + struct v4l2_clip32 __user *uclips; + struct v4l2_clip __user *kclips; + compat_caddr_t p; + u32 n; + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || @@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; - if (kp->clipcount) { - struct v4l2_clip32 __user *uclips; - struct v4l2_clip __user *kclips; - int n = kp->clipcount; - compat_caddr_t p; - - if (get_user(p, &up->clips)) - return -EFAULT; - uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(*kclips)); - kp->clips = kclips; - while (--n >= 0) { - if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, &kclips->next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else + if (!kp->clipcount) { kp->clips = NULL; + return 0; + } + + n = kp->clipcount; + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); + kclips = compat_alloc_user_space(n * sizeof(*kclips)); + kp->clips = kclips; + while (n--) { + if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) + return -EFAULT; + if (put_user(n ? kclips + 1 : NULL, &kclips->next)) + return -EFAULT; + uclips++; + kclips++; + } return 0; } static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) { + struct v4l2_clip __user *kclips = kp->clips; + struct v4l2_clip32 __user *uclips; + u32 n = kp->clipcount; + compat_caddr_t p; + if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || put_user(kp->field, &up->field) || put_user(kp->chromakey, &up->chromakey) || put_user(kp->clipcount, &up->clipcount) || put_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; + + if (!kp->clipcount) + return 0; + + if (get_user(p, &up->clips)) + return -EFAULT; + uclips = compat_ptr(p); + while (n--) { + if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) + return -EFAULT; + uclips++; + kclips++; + } return 0; } From edbc67ef654b4abf14e7de391ce286a722bfda13 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:38 +0100 Subject: [PATCH 239/266] media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type commit 169f24ca68bf0f247d111aef07af00dd3a02ae88 upstream. There is nothing wrong with using an unknown buffer type. So stop spamming the kernel log whenever this happens. The kernel will just return -EINVAL to signal this. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 84fb4c54b101..c8635e4f91ef 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -175,8 +175,6 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr, sizeof(kp->fmt.sdr)) ? -EFAULT : 0; default: - pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } @@ -226,8 +224,6 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr, sizeof(kp->fmt.sdr)) ? -EFAULT : 0; default: - pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); return -EINVAL; } } From af41ce9e1304db4008356d36236d4f85199ecf87 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 14 Feb 2018 12:52:39 +0100 Subject: [PATCH 240/266] media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors commit d83a8243aaefe62ace433e4384a4f077bed86acb upstream. Some ioctls need to copy back the result even if the ioctl returned an error. However, don't do this for the error code -ENOTTY. It makes no sense in that cases. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index c8635e4f91ef..4b6ea1b20d2a 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -956,6 +956,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar set_fs(old_fs); } + if (err == -ENOTTY) + return err; + /* Special case: even after an error we need to put the results back for these ioctls since the error_idx will contain information on which control failed. */ From e87f9596660622f01ed8f90b7088615933dca320 Mon Sep 17 00:00:00 2001 From: Daniel Mentz Date: Wed, 14 Feb 2018 12:52:40 +0100 Subject: [PATCH 241/266] media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic commit a1dfb4c48cc1e64eeb7800a27c66a6f7e88d075a upstream. The 32-bit compat v4l2 ioctl handling is implemented based on its 64-bit equivalent. It converts 32-bit data structures into its 64-bit equivalents and needs to provide the data to the 64-bit ioctl in user space memory which is commonly allocated using compat_alloc_user_space(). However, due to how that function is implemented, it can only be called a single time for every syscall invocation. Supposedly to avoid this limitation, the existing code uses a mix of memory from the kernel stack and memory allocated through compat_alloc_user_space(). Under normal circumstances, this would not work, because the 64-bit ioctl expects all pointers to point to user space memory. As a workaround, set_fs(KERNEL_DS) is called to temporarily disable this extra safety check and allow kernel pointers. However, this might introduce a security vulnerability: The result of the 32-bit to 64-bit conversion is writeable by user space because the output buffer has been allocated via compat_alloc_user_space(). A malicious user space process could then manipulate pointers inside this output buffer, and due to the previous set_fs(KERNEL_DS) call, functions like get_user() or put_user() no longer prevent kernel memory access. The new approach is to pre-calculate the total amount of user space memory that is needed, allocate it using compat_alloc_user_space() and then divide up the allocated memory to accommodate all data structures that need to be converted. An alternative approach would have been to retain the union type karg that they allocated on the kernel stack in do_video_ioctl(), copy all data from user space into karg and then back to user space. However, we decided against this approach because it does not align with other compat syscall implementations. Instead, we tried to replicate the get_user/put_user pairs as found in other places in the kernel: if (get_user(clipcount, &up->clipcount) || put_user(clipcount, &kp->clipcount)) return -EFAULT; Notes from hans.verkuil@cisco.com: This patch was taken from: https://github.com/LineageOS/android_kernel_samsung_apq8084/commit/97b733953c06e4f0398ade18850f0817778255f7 Clearly nobody could be bothered to upstream this patch or at minimum tell us :-( We only heard about this a week ago. This patch was rebased and cleaned up. Compared to the original I also swapped the order of the convert_in_user arguments so that they matched copy_in_user. It was hard to review otherwise. I also replaced the ALLOC_USER_SPACE/ALLOC_AND_GET by a normal function. Fixes: 6b5a9492ca ("v4l: introduce string control support.") Signed-off-by: Daniel Mentz Co-developed-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 776 +++++++++++------- 1 file changed, 499 insertions(+), 277 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 4b6ea1b20d2a..943f90e392a7 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -22,6 +22,14 @@ #include #include +/* Use the same argument order as copy_in_user */ +#define assign_in_user(to, from) \ +({ \ + typeof(*from) __assign_tmp; \ + \ + get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \ +}) + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = -ENOIOCTLCMD; @@ -35,12 +43,12 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct v4l2_clip32 { struct v4l2_rect c; - compat_caddr_t next; + compat_caddr_t next; }; struct v4l2_window32 { struct v4l2_rect w; - __u32 field; /* enum v4l2_field */ + __u32 field; /* enum v4l2_field */ __u32 chromakey; compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; @@ -48,37 +56,41 @@ struct v4l2_window32 { __u8 global_alpha; }; -static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +static int get_v4l2_window32(struct v4l2_window __user *kp, + struct v4l2_window32 __user *up, + void __user *aux_buf, u32 aux_space) { struct v4l2_clip32 __user *uclips; struct v4l2_clip __user *kclips; compat_caddr_t p; - u32 n; + u32 clipcount; if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - copy_from_user(&kp->w, &up->w, sizeof(up->w)) || - get_user(kp->field, &up->field) || - get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount) || - get_user(kp->global_alpha, &up->global_alpha)) + copy_in_user(&kp->w, &up->w, sizeof(up->w)) || + assign_in_user(&kp->field, &up->field) || + assign_in_user(&kp->chromakey, &up->chromakey) || + assign_in_user(&kp->global_alpha, &up->global_alpha) || + get_user(clipcount, &up->clipcount) || + put_user(clipcount, &kp->clipcount)) return -EFAULT; - if (kp->clipcount > 2048) + if (clipcount > 2048) return -EINVAL; - if (!kp->clipcount) { - kp->clips = NULL; - return 0; - } + if (!clipcount) + return put_user(NULL, &kp->clips); - n = kp->clipcount; if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(*kclips)); - kp->clips = kclips; - while (n--) { + if (aux_space < clipcount * sizeof(*kclips)) + return -EFAULT; + kclips = aux_buf; + if (put_user(kclips, &kp->clips)) + return -EFAULT; + + while (clipcount--) { if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, &kclips->next)) + if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next)) return -EFAULT; uclips++; kclips++; @@ -86,27 +98,28 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user return 0; } -static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +static int put_v4l2_window32(struct v4l2_window __user *kp, + struct v4l2_window32 __user *up) { struct v4l2_clip __user *kclips = kp->clips; struct v4l2_clip32 __user *uclips; - u32 n = kp->clipcount; compat_caddr_t p; + u32 clipcount; - if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || - put_user(kp->field, &up->field) || - put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount) || - put_user(kp->global_alpha, &up->global_alpha)) + if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) || + assign_in_user(&up->field, &kp->field) || + assign_in_user(&up->chromakey, &kp->chromakey) || + assign_in_user(&up->global_alpha, &kp->global_alpha) || + get_user(clipcount, &kp->clipcount) || + put_user(clipcount, &up->clipcount)) return -EFAULT; - - if (!kp->clipcount) + if (!clipcount) return 0; if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); - while (n--) { + while (clipcount--) { if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) return -EFAULT; uclips++; @@ -145,101 +158,158 @@ struct v4l2_create_buffers32 { __u32 reserved[8]; }; -static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) { - if (get_user(kp->type, &up->type)) + u32 type; + + if (get_user(type, &up->type)) return -EFAULT; - switch (kp->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return copy_from_user(&kp->fmt.pix, &up->fmt.pix, - sizeof(kp->fmt.pix)) ? -EFAULT : 0; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, - sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + switch (type) { case V4L2_BUF_TYPE_VIDEO_OVERLAY: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); - case V4L2_BUF_TYPE_VBI_CAPTURE: - case V4L2_BUF_TYPE_VBI_OUTPUT: - return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi, - sizeof(kp->fmt.vbi)) ? -EFAULT : 0; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced, - sizeof(kp->fmt.sliced)) ? -EFAULT : 0; - case V4L2_BUF_TYPE_SDR_CAPTURE: - case V4L2_BUF_TYPE_SDR_OUTPUT: - return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr, - sizeof(kp->fmt.sdr)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { + u32 clipcount; + + if (get_user(clipcount, &up->fmt.win.clipcount)) + return -EFAULT; + if (clipcount > 2048) + return -EINVAL; + *size = clipcount * sizeof(struct v4l2_clip); + return 0; + } default: - return -EINVAL; + *size = 0; + return 0; } } -static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size) { if (!access_ok(VERIFY_READ, up, sizeof(*up))) return -EFAULT; - return __get_v4l2_format32(kp, up); + return __bufsize_v4l2_format(up, size); } -static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int __get_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up, + void __user *aux_buf, u32 aux_space) { - if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) - return -EFAULT; - return __get_v4l2_format32(&kp->format, &up->format); -} + u32 type; -static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) -{ - if (put_user(kp->type, &up->type)) + if (get_user(type, &up->type) || put_user(type, &kp->type)) return -EFAULT; - switch (kp->type) { + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return copy_to_user(&up->fmt.pix, &kp->fmt.pix, + return copy_in_user(&kp->fmt.pix, &up->fmt.pix, sizeof(kp->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, + return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp, sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); + return get_v4l2_window32(&kp->fmt.win, &up->fmt.win, + aux_buf, aux_space); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi, + return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi, sizeof(kp->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced, + return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced, sizeof(kp->fmt.sliced)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SDR_CAPTURE: case V4L2_BUF_TYPE_SDR_OUTPUT: - return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr, + return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr, sizeof(kp->fmt.sdr)) ? -EFAULT : 0; default: return -EINVAL; } } -static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +static int get_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; + return __get_v4l2_format32(kp, up, aux_buf, aux_space); +} + +static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up, + u32 *size) +{ + if (!access_ok(VERIFY_READ, up, sizeof(*up))) + return -EFAULT; + return __bufsize_v4l2_format(&up->format, size); +} + +static int get_v4l2_create32(struct v4l2_create_buffers __user *kp, + struct v4l2_create_buffers32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + copy_in_user(kp, up, + offsetof(struct v4l2_create_buffers32, format))) + return -EFAULT; + return __get_v4l2_format32(&kp->format, &up->format, + aux_buf, aux_space); +} + +static int __put_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up) +{ + u32 type; + + if (get_user(type, &kp->type)) + return -EFAULT; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return copy_in_user(&up->fmt.pix, &kp->fmt.pix, + sizeof(kp->fmt.pix)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp, + sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi, + sizeof(kp->fmt.vbi)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced, + sizeof(kp->fmt.sliced)) ? -EFAULT : 0; + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: + return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr, + sizeof(kp->fmt.sdr)) ? -EFAULT : 0; + default: + return -EINVAL; + } +} + +static int put_v4l2_format32(struct v4l2_format __user *kp, + struct v4l2_format32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) return -EFAULT; return __put_v4l2_format32(kp, up); } -static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) +static int put_v4l2_create32(struct v4l2_create_buffers __user *kp, + struct v4l2_create_buffers32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || - copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + copy_in_user(up, kp, + offsetof(struct v4l2_create_buffers32, format)) || + copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved))) return -EFAULT; return __put_v4l2_format32(&kp->format, &up->format); } @@ -253,24 +323,27 @@ struct v4l2_standard32 { __u32 reserved[4]; }; -static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int get_v4l2_standard32(struct v4l2_standard __user *kp, + struct v4l2_standard32 __user *up) { /* other fields are not set by the user, nor used by the driver */ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->index, &up->index)) + assign_in_user(&kp->index, &up->index)) return -EFAULT; return 0; } -static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +static int put_v4l2_standard32(struct v4l2_standard __user *kp, + struct v4l2_standard32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->index, &up->index) || - put_user(kp->id, &up->id) || - copy_to_user(up->name, kp->name, sizeof(up->name)) || - copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + assign_in_user(&up->index, &kp->index) || + assign_in_user(&up->id, &kp->id) || + copy_in_user(up->name, kp->name, sizeof(up->name)) || + copy_in_user(&up->frameperiod, &kp->frameperiod, + sizeof(up->frameperiod)) || + assign_in_user(&up->framelines, &kp->framelines) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -310,11 +383,11 @@ struct v4l2_buffer32 { __u32 reserved; }; -static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +static int get_v4l2_plane32(struct v4l2_plane __user *up, + struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { - void __user *up_pln; - compat_long_t p; + compat_ulong_t p; if (copy_in_user(up, up32, 2 * sizeof(__u32)) || copy_in_user(&up->data_offset, &up32->data_offset, @@ -329,10 +402,8 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return -EFAULT; break; case V4L2_MEMORY_USERPTR: - if (get_user(p, &up32->m.userptr)) - return -EFAULT; - up_pln = compat_ptr(p); - if (put_user((unsigned long)up_pln, &up->m.userptr)) + if (get_user(p, &up32->m.userptr) || + put_user((unsigned long)compat_ptr(p), &up->m.userptr)) return -EFAULT; break; case V4L2_MEMORY_DMABUF: @@ -344,7 +415,8 @@ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return 0; } -static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, +static int put_v4l2_plane32(struct v4l2_plane __user *up, + struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { unsigned long p; @@ -368,8 +440,7 @@ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return -EFAULT; break; case V4L2_MEMORY_DMABUF: - if (copy_in_user(&up32->m.fd, &up->m.fd, - sizeof(up->m.fd))) + if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd))) return -EFAULT; break; } @@ -377,37 +448,75 @@ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __ return 0; } -static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size) { + u32 type; + u32 length; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(type, &up->type) || + get_user(length, &up->length)) + return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + if (length > VIDEO_MAX_PLANES) + return -EINVAL; + + /* + * We don't really care if userspace decides to kill itself + * by passing a very big length value + */ + *size = length * sizeof(struct v4l2_plane); + } else { + *size = 0; + } + return 0; +} + +static int get_v4l2_buffer32(struct v4l2_buffer __user *kp, + struct v4l2_buffer32 __user *up, + void __user *aux_buf, u32 aux_space) +{ + u32 type; + u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; - int num_planes; int ret; if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->index, &up->index) || - get_user(kp->type, &up->type) || - get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory) || - get_user(kp->length, &up->length)) + assign_in_user(&kp->index, &up->index) || + get_user(type, &up->type) || + put_user(type, &kp->type) || + assign_in_user(&kp->flags, &up->flags) || + get_user(memory, &up->memory) || + put_user(memory, &kp->memory) || + get_user(length, &up->length) || + put_user(length, &kp->length)) return -EFAULT; - if (V4L2_TYPE_IS_OUTPUT(kp->type)) - if (get_user(kp->bytesused, &up->bytesused) || - get_user(kp->field, &up->field) || - get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) + if (V4L2_TYPE_IS_OUTPUT(type)) + if (assign_in_user(&kp->bytesused, &up->bytesused) || + assign_in_user(&kp->field, &up->field) || + assign_in_user(&kp->timestamp.tv_sec, + &up->timestamp.tv_sec) || + assign_in_user(&kp->timestamp.tv_usec, + &up->timestamp.tv_usec)) return -EFAULT; - if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + u32 num_planes = length; + if (num_planes == 0) { - kp->m.planes = NULL; - /* num_planes == 0 is legal, e.g. when userspace doesn't - * need planes array on DQBUF*/ - return 0; + /* + * num_planes == 0 is legal, e.g. when userspace doesn't + * need planes array on DQBUF + */ + return put_user(NULL, &kp->m.planes); } + if (num_planes > VIDEO_MAX_PLANES) + return -EINVAL; if (get_user(p, &up->m.planes)) return -EFAULT; @@ -417,37 +526,43 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user num_planes * sizeof(*uplane32))) return -EFAULT; - /* We don't really care if userspace decides to kill itself - * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * sizeof(*uplane)); - kp->m.planes = (__force struct v4l2_plane *)uplane; + /* + * We don't really care if userspace decides to kill itself + * by passing a very big num_planes value + */ + if (aux_space < num_planes * sizeof(*uplane)) + return -EFAULT; - while (--num_planes >= 0) { - ret = get_v4l2_plane32(uplane, uplane32, kp->memory); + uplane = aux_buf; + if (put_user((__force struct v4l2_plane *)uplane, + &kp->m.planes)) + return -EFAULT; + + while (num_planes--) { + ret = get_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; - ++uplane; - ++uplane32; + uplane++; + uplane32++; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) + if (assign_in_user(&kp->m.offset, &up->m.offset)) return -EFAULT; break; - case V4L2_MEMORY_USERPTR: - { - compat_long_t tmp; + case V4L2_MEMORY_USERPTR: { + compat_ulong_t userptr; - if (get_user(tmp, &up->m.userptr)) - return -EFAULT; - - kp->m.userptr = (unsigned long)compat_ptr(tmp); - } + if (get_user(userptr, &up->m.userptr) || + put_user((unsigned long)compat_ptr(userptr), + &kp->m.userptr)) + return -EFAULT; break; + } case V4L2_MEMORY_DMABUF: - if (get_user(kp->m.fd, &up->m.fd)) + if (assign_in_user(&kp->m.fd, &up->m.fd)) return -EFAULT; break; } @@ -456,62 +571,70 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user return 0; } -static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +static int put_v4l2_buffer32(struct v4l2_buffer __user *kp, + struct v4l2_buffer32 __user *up) { + u32 type; + u32 length; + enum v4l2_memory memory; struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; - int num_planes; int ret; if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->index, &up->index) || - put_user(kp->type, &up->type) || - put_user(kp->flags, &up->flags) || - put_user(kp->memory, &up->memory)) + assign_in_user(&up->index, &kp->index) || + get_user(type, &kp->type) || + put_user(type, &up->type) || + assign_in_user(&up->flags, &kp->flags) || + get_user(memory, &kp->memory) || + put_user(memory, &up->memory)) return -EFAULT; - if (put_user(kp->bytesused, &up->bytesused) || - put_user(kp->field, &up->field) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->reserved2, &up->reserved2) || - put_user(kp->reserved, &up->reserved) || - put_user(kp->length, &up->length)) + if (assign_in_user(&up->bytesused, &kp->bytesused) || + assign_in_user(&up->field, &kp->field) || + assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || + assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) || + copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) || + assign_in_user(&up->sequence, &kp->sequence) || + assign_in_user(&up->reserved2, &kp->reserved2) || + assign_in_user(&up->reserved, &kp->reserved) || + get_user(length, &kp->length) || + put_user(length, &up->length)) return -EFAULT; - if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + u32 num_planes = length; + if (num_planes == 0) return 0; - uplane = (__force struct v4l2_plane __user *)kp->m.planes; + if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes))) + return -EFAULT; if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p); - while (--num_planes >= 0) { - ret = put_v4l2_plane32(uplane, uplane32, kp->memory); + while (num_planes--) { + ret = put_v4l2_plane32(uplane, uplane32, memory); if (ret) return ret; ++uplane; ++uplane32; } } else { - switch (kp->memory) { + switch (memory) { case V4L2_MEMORY_MMAP: case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) + if (assign_in_user(&up->m.offset, &kp->m.offset)) return -EFAULT; break; case V4L2_MEMORY_USERPTR: - if (put_user(kp->m.userptr, &up->m.userptr)) + if (assign_in_user(&up->m.userptr, &kp->m.userptr)) return -EFAULT; break; case V4L2_MEMORY_DMABUF: - if (put_user(kp->m.fd, &up->m.fd)) + if (assign_in_user(&up->m.fd, &kp->m.fd)) return -EFAULT; break; } @@ -523,7 +646,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user struct v4l2_framebuffer32 { __u32 capability; __u32 flags; - compat_caddr_t base; + compat_caddr_t base; struct { __u32 width; __u32 height; @@ -536,29 +659,32 @@ struct v4l2_framebuffer32 { } fmt; }; -static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, + struct v4l2_framebuffer32 __user *up) { - u32 tmp; + compat_caddr_t tmp; if (!access_ok(VERIFY_READ, up, sizeof(*up)) || get_user(tmp, &up->base) || - get_user(kp->capability, &up->capability) || - get_user(kp->flags, &up->flags) || - copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) + put_user((__force void *)compat_ptr(tmp), &kp->base) || + assign_in_user(&kp->capability, &up->capability) || + assign_in_user(&kp->flags, &up->flags) || + copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt))) return -EFAULT; - kp->base = (__force void *)compat_ptr(tmp); return 0; } -static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, + struct v4l2_framebuffer32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->base); + void *base; if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(tmp, &up->base) || - put_user(kp->capability, &up->capability) || - put_user(kp->flags, &up->flags) || - copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) + get_user(base, &kp->base) || + put_user(ptr_to_compat(base), &up->base) || + assign_in_user(&up->capability, &kp->capability) || + assign_in_user(&up->flags, &kp->flags) || + copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt))) return -EFAULT; return 0; } @@ -571,21 +697,26 @@ struct v4l2_input32 { __u32 tuner; /* Associated tuner */ compat_u64 std; __u32 status; - __u32 reserved[4]; + __u32 capabilities; + __u32 reserved[3]; }; -/* The 64-bit v4l2_input struct has extra padding at the end of the struct. - Otherwise it is identical to the 32-bit version. */ -static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) +/* + * The 64-bit v4l2_input struct has extra padding at the end of the struct. + * Otherwise it is identical to the 32-bit version. + */ +static inline int get_v4l2_input32(struct v4l2_input __user *kp, + struct v4l2_input32 __user *up) { - if (copy_from_user(kp, up, sizeof(*up))) + if (copy_in_user(kp, up, sizeof(*up))) return -EFAULT; return 0; } -static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) +static inline int put_v4l2_input32(struct v4l2_input __user *kp, + struct v4l2_input32 __user *up) { - if (copy_to_user(up, kp, sizeof(*up))) + if (copy_in_user(up, kp, sizeof(*up))) return -EFAULT; return 0; } @@ -639,40 +770,64 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); } +static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up, + u32 *size) +{ + u32 count; + + if (!access_ok(VERIFY_READ, up, sizeof(*up)) || + get_user(count, &up->count)) + return -EFAULT; + if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; + *size = count * sizeof(struct v4l2_ext_control); + return 0; +} + static int get_v4l2_ext_controls32(struct file *file, - struct v4l2_ext_controls *kp, - struct v4l2_ext_controls32 __user *up) + struct v4l2_ext_controls __user *kp, + struct v4l2_ext_controls32 __user *up, + void __user *aux_buf, u32 aux_space) { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; - int n; + u32 count; + u32 n; compat_caddr_t p; if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->ctrl_class, &up->ctrl_class) || - get_user(kp->count, &up->count) || - get_user(kp->error_idx, &up->error_idx) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + assign_in_user(&kp->ctrl_class, &up->ctrl_class) || + get_user(count, &up->count) || + put_user(count, &kp->count) || + assign_in_user(&kp->error_idx, &up->error_idx) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - n = kp->count; - if (n == 0) { - kp->controls = NULL; - return 0; - } + + if (count == 0) + return put_user(NULL, &kp->controls); + if (count > V4L2_CID_MAX_CTRLS) + return -EINVAL; if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols))) + if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols))) return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols)); - kp->controls = (__force struct v4l2_ext_control *)kcontrols; - while (--n >= 0) { + if (aux_space < count * sizeof(*kcontrols)) + return -EFAULT; + kcontrols = aux_buf; + if (put_user((__force struct v4l2_ext_control *)kcontrols, + &kp->controls)) + return -EFAULT; + + for (n = 0; n < count; n++) { u32 id; if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; + if (get_user(id, &kcontrols->id)) return -EFAULT; + if (ctrl_is_pointer(file, id)) { void __user *s; @@ -689,43 +844,54 @@ static int get_v4l2_ext_controls32(struct file *file, } static int put_v4l2_ext_controls32(struct file *file, - struct v4l2_ext_controls *kp, + struct v4l2_ext_controls __user *kp, struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols = - (__force struct v4l2_ext_control __user *)kp->controls; - int n = kp->count; + struct v4l2_ext_control __user *kcontrols; + u32 count; + u32 n; compat_caddr_t p; if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->ctrl_class, &up->ctrl_class) || - put_user(kp->count, &up->count) || - put_user(kp->error_idx, &up->error_idx) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + assign_in_user(&up->ctrl_class, &kp->ctrl_class) || + get_user(count, &kp->count) || + put_user(count, &up->count) || + assign_in_user(&up->error_idx, &kp->error_idx) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) || + get_user(kcontrols, &kp->controls)) return -EFAULT; - if (!kp->count) - return 0; + if (!count) + return 0; if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols))) + if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols))) return -EFAULT; - while (--n >= 0) { - unsigned size = sizeof(*ucontrols); + for (n = 0; n < count; n++) { + unsigned int size = sizeof(*ucontrols); u32 id; - if (get_user(id, &kcontrols->id)) + if (get_user(id, &kcontrols->id) || + put_user(id, &ucontrols->id) || + assign_in_user(&ucontrols->size, &kcontrols->size) || + copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2, + sizeof(ucontrols->reserved2))) return -EFAULT; - /* Do not modify the pointer when copying a pointer control. - The contents of the pointer was changed, not the pointer - itself. */ + + /* + * Do not modify the pointer when copying a pointer control. + * The contents of the pointer was changed, not the pointer + * itself. + */ if (ctrl_is_pointer(file, id)) size -= sizeof(ucontrols->value64); + if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; + ucontrols++; kcontrols++; } @@ -745,17 +911,18 @@ struct v4l2_event32 { __u32 reserved[8]; }; -static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) +static int put_v4l2_event32(struct v4l2_event __user *kp, + struct v4l2_event32 __user *up) { if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->type, &up->type) || - copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || - put_user(kp->pending, &up->pending) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || - put_user(kp->id, &up->id) || - copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) + assign_in_user(&up->type, &kp->type) || + copy_in_user(&up->u, &kp->u, sizeof(kp->u)) || + assign_in_user(&up->pending, &kp->pending) || + assign_in_user(&up->sequence, &kp->sequence) || + assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) || + assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) || + assign_in_user(&up->id, &kp->id) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -768,31 +935,34 @@ struct v4l2_edid32 { compat_caddr_t edid; }; -static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int get_v4l2_edid32(struct v4l2_edid __user *kp, + struct v4l2_edid32 __user *up) { - u32 tmp; + compat_uptr_t tmp; if (!access_ok(VERIFY_READ, up, sizeof(*up)) || - get_user(kp->pad, &up->pad) || - get_user(kp->start_block, &up->start_block) || - get_user(kp->blocks, &up->blocks) || + assign_in_user(&kp->pad, &up->pad) || + assign_in_user(&kp->start_block, &up->start_block) || + assign_in_user(&kp->blocks, &up->blocks) || get_user(tmp, &up->edid) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + put_user(compat_ptr(tmp), &kp->edid) || + copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - kp->edid = (__force u8 *)compat_ptr(tmp); return 0; } -static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) +static int put_v4l2_edid32(struct v4l2_edid __user *kp, + struct v4l2_edid32 __user *up) { - u32 tmp = (u32)((unsigned long)kp->edid); + void *edid; if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - put_user(kp->pad, &up->pad) || - put_user(kp->start_block, &up->start_block) || - put_user(kp->blocks, &up->blocks) || - put_user(tmp, &up->edid) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) + assign_in_user(&up->pad, &kp->pad) || + assign_in_user(&up->start_block, &kp->start_block) || + assign_in_user(&up->blocks, &kp->blocks) || + get_user(edid, &kp->edid) || + put_user(ptr_to_compat(edid), &up->edid) || + copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } @@ -809,7 +979,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) #define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32) -#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) +#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) @@ -825,22 +995,23 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32) +static int alloc_userspace(unsigned int size, u32 aux_space, + void __user **up_native) +{ + *up_native = compat_alloc_user_space(size + aux_space); + if (!*up_native) + return -ENOMEM; + if (clear_user(*up_native, size)) + return -EFAULT; + return 0; +} + static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - union { - struct v4l2_format v2f; - struct v4l2_buffer v2b; - struct v4l2_framebuffer v2fb; - struct v4l2_input v2i; - struct v4l2_standard v2s; - struct v4l2_ext_controls v2ecs; - struct v4l2_event v2ev; - struct v4l2_create_buffers v2crt; - struct v4l2_edid v2edid; - unsigned long vx; - int vi; - } karg; void __user *up = compat_ptr(arg); + void __user *up_native = NULL; + void __user *aux_buf; + u32 aux_space; int compatible_arg = 1; long err = 0; @@ -879,30 +1050,52 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_STREAMOFF: case VIDIOC_S_INPUT: case VIDIOC_S_OUTPUT: - err = get_user(karg.vi, (s32 __user *)up); + err = alloc_userspace(sizeof(unsigned int), 0, &up_native); + if (!err && assign_in_user((unsigned int __user *)up_native, + (compat_uint_t __user *)up)) + err = -EFAULT; compatible_arg = 0; break; case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: + err = alloc_userspace(sizeof(unsigned int), 0, &up_native); compatible_arg = 0; break; case VIDIOC_G_EDID: case VIDIOC_S_EDID: - err = get_v4l2_edid32(&karg.v2edid, up); + err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native); + if (!err) + err = get_v4l2_edid32(up_native, up); compatible_arg = 0; break; case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = get_v4l2_format32(&karg.v2f, up); + err = bufsize_v4l2_format(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_format), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_format); + err = get_v4l2_format32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; case VIDIOC_CREATE_BUFS: - err = get_v4l2_create32(&karg.v2crt, up); + err = bufsize_v4l2_create(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_create_buffers), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_create_buffers); + err = get_v4l2_create32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; @@ -910,36 +1103,63 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = get_v4l2_buffer32(&karg.v2b, up); + err = bufsize_v4l2_buffer(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_buffer), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_buffer); + err = get_v4l2_buffer32(up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; case VIDIOC_S_FBUF: - err = get_v4l2_framebuffer32(&karg.v2fb, up); + err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, + &up_native); + if (!err) + err = get_v4l2_framebuffer32(up_native, up); compatible_arg = 0; break; case VIDIOC_G_FBUF: + err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, + &up_native); compatible_arg = 0; break; case VIDIOC_ENUMSTD: - err = get_v4l2_standard32(&karg.v2s, up); + err = alloc_userspace(sizeof(struct v4l2_standard), 0, + &up_native); + if (!err) + err = get_v4l2_standard32(up_native, up); compatible_arg = 0; break; case VIDIOC_ENUMINPUT: - err = get_v4l2_input32(&karg.v2i, up); + err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native); + if (!err) + err = get_v4l2_input32(up_native, up); compatible_arg = 0; break; case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(file, &karg.v2ecs, up); + err = bufsize_v4l2_ext_controls(up, &aux_space); + if (!err) + err = alloc_userspace(sizeof(struct v4l2_ext_controls), + aux_space, &up_native); + if (!err) { + aux_buf = up_native + sizeof(struct v4l2_ext_controls); + err = get_v4l2_ext_controls32(file, up_native, up, + aux_buf, aux_space); + } compatible_arg = 0; break; case VIDIOC_DQEVENT: + err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native); compatible_arg = 0; break; } @@ -948,25 +1168,26 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar if (compatible_arg) err = native_ioctl(file, cmd, (unsigned long)up); - else { - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - err = native_ioctl(file, cmd, (unsigned long)&karg); - set_fs(old_fs); - } + else + err = native_ioctl(file, cmd, (unsigned long)up_native); if (err == -ENOTTY) return err; - /* Special case: even after an error we need to put the - results back for these ioctls since the error_idx will - contain information on which control failed. */ + /* + * Special case: even after an error we need to put the + * results back for these ioctls since the error_idx will + * contain information on which control failed. + */ switch (cmd) { case VIDIOC_G_EXT_CTRLS: case VIDIOC_S_EXT_CTRLS: case VIDIOC_TRY_EXT_CTRLS: - if (put_v4l2_ext_controls32(file, &karg.v2ecs, up)) + if (put_v4l2_ext_controls32(file, up_native, up)) + err = -EFAULT; + break; + case VIDIOC_S_EDID: + if (put_v4l2_edid32(up_native, up)) err = -EFAULT; break; } @@ -978,45 +1199,46 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_S_OUTPUT: case VIDIOC_G_INPUT: case VIDIOC_G_OUTPUT: - err = put_user(((s32)karg.vi), (s32 __user *)up); + if (assign_in_user((compat_uint_t __user *)up, + ((unsigned int __user *)up_native))) + err = -EFAULT; break; case VIDIOC_G_FBUF: - err = put_v4l2_framebuffer32(&karg.v2fb, up); + err = put_v4l2_framebuffer32(up_native, up); break; case VIDIOC_DQEVENT: - err = put_v4l2_event32(&karg.v2ev, up); + err = put_v4l2_event32(up_native, up); break; case VIDIOC_G_EDID: - case VIDIOC_S_EDID: - err = put_v4l2_edid32(&karg.v2edid, up); + err = put_v4l2_edid32(up_native, up); break; case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: - err = put_v4l2_format32(&karg.v2f, up); + err = put_v4l2_format32(up_native, up); break; case VIDIOC_CREATE_BUFS: - err = put_v4l2_create32(&karg.v2crt, up); + err = put_v4l2_create32(up_native, up); break; case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: - err = put_v4l2_buffer32(&karg.v2b, up); + err = put_v4l2_buffer32(up_native, up); break; case VIDIOC_ENUMSTD: - err = put_v4l2_standard32(&karg.v2s, up); + err = put_v4l2_standard32(up_native, up); break; case VIDIOC_ENUMINPUT: - err = put_v4l2_input32(&karg.v2i, up); + err = put_v4l2_input32(up_native, up); break; } return err; From 7b66838321edc86d094cf49d0c2b314b6c3179c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Mon, 5 Feb 2018 11:15:52 +0200 Subject: [PATCH 242/266] crypto: caam - fix endless loop when DECO acquire fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 225ece3e7dad4cfc44cca38ce7a3a80f255ea8f1 upstream. In case DECO0 cannot be acquired - i.e. run_descriptor_deco0() fails with -ENODEV, caam_probe() enters an endless loop: run_descriptor_deco0 ret -ENODEV -> instantiate_rng -ENODEV, overwritten by -EAGAIN ret -EAGAIN -> caam_probe -EAGAIN results in endless loop It turns out the error path in instantiate_rng() is incorrect, the checks are done in the wrong order. Fixes: 1005bccd7a4a6 ("crypto: caam - enable instantiation of all RNG4 state handles") Reported-by: Bryan O'Donoghue Suggested-by: Auer Lukas Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/caam/ctrl.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 53e61459c69f..ee87eb77095c 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -224,12 +224,16 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask, * without any error (HW optimizations for later * CAAM eras), then try again. */ - rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK; - if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) || - !(rdsta_val & (1 << sh_idx))) - ret = -EAGAIN; if (ret) break; + + rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK; + if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) || + !(rdsta_val & (1 << sh_idx))) { + ret = -EAGAIN; + break; + } + dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); /* Clear the contents before recreating the descriptor */ memset(desc, 0x00, CAAM_CMD_SZ * 7); From b1da6f0262b000b9834728f4f767111882451efc Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 6 Feb 2018 17:56:06 +0000 Subject: [PATCH 243/266] arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls commit 20e8175d246e9f9deb377f2784b3e7dfb2ad3e86 upstream. KVM doesn't follow the SMCCC when it comes to unimplemented calls, and inject an UNDEF instead of returning an error. Since firmware calls are now used for security mitigation, they are becoming more common, and the undef is counter productive. Instead, let's follow the SMCCC which states that -1 must be returned to the caller when getting an unknown function number. Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/handle_exit.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c index f36b5b1acd1f..05b2f8294968 100644 --- a/arch/arm/kvm/handle_exit.c +++ b/arch/arm/kvm/handle_exit.c @@ -45,7 +45,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) ret = kvm_psci_call(vcpu); if (ret < 0) { - kvm_inject_undefined(vcpu); + vcpu_set_reg(vcpu, 0, ~0UL); return 1; } @@ -54,7 +54,16 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) { - kvm_inject_undefined(vcpu); + /* + * "If an SMC instruction executed at Non-secure EL1 is + * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a + * Trap exception, not a Secure Monitor Call exception [...]" + * + * We need to advance the PC after the trap, as it would + * otherwise return to the same address... + */ + vcpu_set_reg(vcpu, 0, ~0UL); + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); return 1; } From 0e524b26cdcc81a2609d076123e3fd139853eee5 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Thu, 9 Nov 2017 20:27:20 +0200 Subject: [PATCH 244/266] KVM: nVMX: Fix races when sending nested PI while dest enters/leaves L2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6b6977117f50d60455ace86b2d256f6fb4f3de05 upstream. Consider the following scenario: 1. CPU A calls vmx_deliver_nested_posted_interrupt() to send an IPI to CPU B via virtual posted-interrupt mechanism. 2. CPU B is currently executing L2 guest. 3. vmx_deliver_nested_posted_interrupt() calls kvm_vcpu_trigger_posted_interrupt() which will note that vcpu->mode == IN_GUEST_MODE. 4. Assume that before CPU A sends the physical POSTED_INTR_NESTED_VECTOR IPI, CPU B exits from L2 to L0 during event-delivery (valid IDT-vectoring-info). 5. CPU A now sends the physical IPI. The IPI is received in host and it's handler (smp_kvm_posted_intr_nested_ipi()) does nothing. 6. Assume that before CPU A sets pi_pending=true and KVM_REQ_EVENT, CPU B continues to run in L0 and reach vcpu_enter_guest(). As KVM_REQ_EVENT is not set yet, vcpu_enter_guest() will continue and resume L2 guest. 7. At this point, CPU A sets pi_pending=true and KVM_REQ_EVENT but it's too late! CPU B already entered L2 and KVM_REQ_EVENT will only be consumed at next L2 entry! Another scenario to consider: 1. CPU A calls vmx_deliver_nested_posted_interrupt() to send an IPI to CPU B via virtual posted-interrupt mechanism. 2. Assume that before CPU A calls kvm_vcpu_trigger_posted_interrupt(), CPU B is at L0 and is about to resume into L2. Further assume that it is in vcpu_enter_guest() after check for KVM_REQ_EVENT. 3. At this point, CPU A calls kvm_vcpu_trigger_posted_interrupt() which will note that vcpu->mode != IN_GUEST_MODE. Therefore, do nothing and return false. Then, will set pi_pending=true and KVM_REQ_EVENT. 4. Now CPU B continue and resumes into L2 guest without processing the posted-interrupt until next L2 entry! To fix both issues, we just need to change vmx_deliver_nested_posted_interrupt() to set pi_pending=true and KVM_REQ_EVENT before calling kvm_vcpu_trigger_posted_interrupt(). It will fix the first scenario by chaging step (6) to note that KVM_REQ_EVENT and pi_pending=true and therefore process nested posted-interrupt. It will fix the second scenario by two possible ways: 1. If kvm_vcpu_trigger_posted_interrupt() is called while CPU B has changed vcpu->mode to IN_GUEST_MODE, physical IPI will be sent and will be received when CPU resumes into L2. 2. If kvm_vcpu_trigger_posted_interrupt() is called while CPU B hasn't yet changed vcpu->mode to IN_GUEST_MODE, then after CPU B will change vcpu->mode it will call kvm_request_pending() which will return true and therefore force another round of vcpu_enter_guest() which will note that KVM_REQ_EVENT and pi_pending=true and therefore process nested posted-interrupt. Fixes: 705699a13994 ("KVM: nVMX: Enable nested posted interrupt processing") Signed-off-by: Liran Alon Reviewed-by: Nikita Leshenko Reviewed-by: Krish Sadhukhan [Add kvm_vcpu_kick to also handle the case where L1 doesn't intercept L2 HLT and L2 executes HLT instruction. - Paolo] Signed-off-by: Paolo Bonzini Signed-off-by: Radim Krčmář Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/vmx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index f8d785aa2e96..2a1a8737015b 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -4595,14 +4595,15 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu, if (is_guest_mode(vcpu) && vector == vmx->nested.posted_intr_nv) { - /* the PIR and ON have been set by L1. */ - kvm_vcpu_trigger_posted_interrupt(vcpu); /* * If a posted intr is not recognized by hardware, * we will accomplish it in the next vmentry. */ vmx->nested.pi_pending = true; kvm_make_request(KVM_REQ_EVENT, vcpu); + /* the PIR and ON have been set by L1. */ + if (!kvm_vcpu_trigger_posted_interrupt(vcpu)) + kvm_vcpu_kick(vcpu); return 0; } return -1; From febb867324cb97d82645a32f94d1ac11ce1a00f5 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 1 Jan 2018 18:26:47 +0100 Subject: [PATCH 245/266] watchdog: imx2_wdt: restore previous timeout after suspend+resume commit 0be267255cef64e1c58475baa7b25568355a3816 upstream. When the watchdog device is suspended, its timeout is set to the maximum value. During resume, the previously set timeout should be restored. This does not work at the moment. The suspend function calls imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME); and resume reverts this by calling imx2_wdt_set_timeout(wdog, wdog->timeout); However, imx2_wdt_set_timeout() updates wdog->timeout. Therefore, wdog->timeout is set to IMX2_WDT_MAX_TIME when we enter the resume function. Fix this by adding a new function __imx2_wdt_set_timeout() which only updates the hardware settings. imx2_wdt_set_timeout() now calls __imx2_wdt_set_timeout() and then saves the new timeout to wdog->timeout. During suspend, we call __imx2_wdt_set_timeout() directly so that wdog->timeout won't be updated and we can restore the previous value during resume. This approach makes wdog->timeout different from the actual setting in the hardware which is usually not a good thing. However, the two differ only while we're suspended and no kernel code is running, so it should be ok in this case. Signed-off-by: Martin Kaiser Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/imx2_wdt.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 29ef719a6a3c..d69ab1e28d7d 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -161,15 +161,21 @@ static void imx2_wdt_timer_ping(unsigned long arg) mod_timer(&wdev->timer, jiffies + wdog->timeout * HZ / 2); } -static int imx2_wdt_set_timeout(struct watchdog_device *wdog, - unsigned int new_timeout) +static void __imx2_wdt_set_timeout(struct watchdog_device *wdog, + unsigned int new_timeout) { struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); - wdog->timeout = new_timeout; - regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT, WDOG_SEC_TO_COUNT(new_timeout)); +} + +static int imx2_wdt_set_timeout(struct watchdog_device *wdog, + unsigned int new_timeout) +{ + __imx2_wdt_set_timeout(wdog, new_timeout); + + wdog->timeout = new_timeout; return 0; } @@ -353,7 +359,11 @@ static int imx2_wdt_suspend(struct device *dev) /* The watchdog IP block is running */ if (imx2_wdt_is_running(wdev)) { - imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME); + /* + * Don't update wdog->timeout, we'll restore the current value + * during resume. + */ + __imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME); imx2_wdt_ping(wdog); /* The watchdog is not active */ From 6b3bfe719b65a19349c65ef112ad61e64b7068c0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Jan 2018 07:20:39 -0500 Subject: [PATCH 246/266] media: ts2020: avoid integer overflows on 32 bit machines commit 81742be14b6a90c9fd0ff6eb4218bdf696ad8e46 upstream. Before this patch, when compiled for arm32, the signal strength were reported as: Lock (0x1f) Signal= 4294908.66dBm C/N= 12.79dB Because of a 32 bit integer overflow. After it, it is properly reported as: Lock (0x1f) Signal= -58.64dBm C/N= 12.79dB Fixes: 0f91c9d6bab9 ("[media] TS2020: Calculate tuner gain correctly") Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb-frontends/ts2020.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index 7979e5d6498b..7ca359391535 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -369,7 +369,7 @@ static int ts2020_read_tuner_gain(struct dvb_frontend *fe, unsigned v_agc, gain2 = clamp_t(long, gain2, 0, 13); v_agc = clamp_t(long, v_agc, 400, 1100); - *_gain = -(gain1 * 2330 + + *_gain = -((__s64)gain1 * 2330 + gain2 * 3500 + v_agc * 24 / 10 * 10 + 10000); @@ -387,7 +387,7 @@ static int ts2020_read_tuner_gain(struct dvb_frontend *fe, unsigned v_agc, gain3 = clamp_t(long, gain3, 0, 6); v_agc = clamp_t(long, v_agc, 600, 1600); - *_gain = -(gain1 * 2650 + + *_gain = -((__s64)gain1 * 2650 + gain2 * 3380 + gain3 * 2850 + v_agc * 176 / 100 * 10 - From 6f8e7a83de1eb755533dff9f5c02cd35f9714c16 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Jan 2018 06:01:57 -0500 Subject: [PATCH 247/266] media: cxusb, dib0700: ignore XC2028_I2C_FLUSH commit 9893b905e743ded332575ca04486bd586c0772f7 upstream. The XC2028_I2C_FLUSH only needs to be implemented on a few devices. Others can safely ignore it. That prevents filling the dmesg with lots of messages like: dib0700: stk7700ph_xc3028_callback: unknown command 2, arg 0 Fixes: 4d37ece757a8 ("[media] tuner/xc2028: Add I2C flush callback") Reported-by: Enrico Mioso Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/dvb-usb/cxusb.c | 2 ++ drivers/media/usb/dvb-usb/dib0700_devices.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index ab7151181728..d00b27ed73a6 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -818,6 +818,8 @@ static int dvico_bluebird_xc2028_callback(void *ptr, int component, case XC2028_RESET_CLK: deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg); break; + case XC2028_I2C_FLUSH: + break; default: deb_info("%s: unknown command %d, arg %d\n", __func__, command, arg); diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 7df0707a0455..38c03283a441 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -431,6 +431,7 @@ static int stk7700ph_xc3028_callback(void *ptr, int component, state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); break; case XC2028_RESET_CLK: + case XC2028_I2C_FLUSH: break; default: err("%s: unknown command %d, arg %d\n", __func__, From c832448d07df6bc5d20f81e6871c64fb9df2143a Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 6 Feb 2018 15:37:55 -0800 Subject: [PATCH 248/266] kernel/async.c: revert "async: simplify lowest_in_progress()" commit 4f7e988e63e336827f4150de48163bed05d653bd upstream. This reverts commit 92266d6ef60c ("async: simplify lowest_in_progress()") which was simply wrong: In the case where domain is NULL, we now use the wrong offsetof() in the list_first_entry macro, so we don't actually fetch the ->cookie value, but rather the eight bytes located sizeof(struct list_head) further into the struct async_entry. On 64 bit, that's the data member, while on 32 bit, that's a u64 built from func and data in some order. I think the bug happens to be harmless in practice: It obviously only affects callers which pass a NULL domain, and AFAICT the only such caller is async_synchronize_full() -> async_synchronize_full_domain(NULL) -> async_synchronize_cookie_domain(ASYNC_COOKIE_MAX, NULL) and the ASYNC_COOKIE_MAX means that in practice we end up waiting for the async_global_pending list to be empty - but it would break if somebody happened to pass (void*)-1 as the data element to async_schedule, and of course also if somebody ever does a async_synchronize_cookie_domain(, NULL) with a "finite" cookie value. Maybe the "harmless in practice" means this isn't -stable material. But I'm not completely confident my quick git grep'ing is enough, and there might be affected code in one of the earlier kernels that has since been removed, so I'll leave the decision to the stable guys. Link: http://lkml.kernel.org/r/20171128104938.3921-1-linux@rasmusvillemoes.dk Fixes: 92266d6ef60c "async: simplify lowest_in_progress()" Signed-off-by: Rasmus Villemoes Acked-by: Tejun Heo Cc: Arjan van de Ven Cc: Adam Wallis Cc: Lai Jiangshan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/async.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/kernel/async.c b/kernel/async.c index 4c3773c0bf63..f1fd155abff6 100644 --- a/kernel/async.c +++ b/kernel/async.c @@ -84,20 +84,24 @@ static atomic_t entry_count; static async_cookie_t lowest_in_progress(struct async_domain *domain) { - struct list_head *pending; + struct async_entry *first = NULL; async_cookie_t ret = ASYNC_COOKIE_MAX; unsigned long flags; spin_lock_irqsave(&async_lock, flags); - if (domain) - pending = &domain->pending; - else - pending = &async_global_pending; + if (domain) { + if (!list_empty(&domain->pending)) + first = list_first_entry(&domain->pending, + struct async_entry, domain_list); + } else { + if (!list_empty(&async_global_pending)) + first = list_first_entry(&async_global_pending, + struct async_entry, global_list); + } - if (!list_empty(pending)) - ret = list_first_entry(pending, struct async_entry, - domain_list)->cookie; + if (first) + ret = first->cookie; spin_unlock_irqrestore(&async_lock, flags); return ret; From 24346d134b2d00408a1ba1400e0d32dab64d7e5c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 17 Jan 2018 21:05:55 +0100 Subject: [PATCH 249/266] HID: quirks: Fix keyboard + touchpad on Toshiba Click Mini not working commit edfc3722cfef4217c7fe92b272cbe0288ba1ff57 upstream. The Toshiba Click Mini uses an i2c attached keyboard/touchpad combo (single i2c_hid device for both) which has a vid:pid of 04F3:0401, which is also used by a bunch of Elan touchpads which are handled by the drivers/input/mouse/elan_i2c driver, but that driver deals with pure touchpads and does not work for a combo device such as the one on the Toshiba Click Mini. The combo on the Mini has an ACPI id of ELAN0800, which is not claimed by the elan_i2c driver, so check for that and if it is found do not ignore the device. This fixes the keyboard/touchpad combo on the Mini not working (although with the touchpad in mouse emulation mode). Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 3ba486d0ec6f..6861b74e2b61 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2308,7 +2308,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) }, - { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) }, { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, @@ -2578,6 +2577,17 @@ bool hid_ignore(struct hid_device *hdev) strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0) return true; break; + case USB_VENDOR_ID_ELAN: + /* + * Many Elan devices have a product id of 0x0401 and are handled + * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev + * is not (and cannot be) handled by that driver -> + * Ignore all 0x0401 devs except for the ELAN0800 dev. + */ + if (hdev->product == 0x0401 && + strncmp(hdev->name, "ELAN0800", 8) != 0) + return true; + break; } if (hdev->type == HID_TYPE_USBMOUSE && From 727b1a6e72e4daa18daad0f3e862c60470df3dd0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 29 Nov 2017 20:29:07 +0100 Subject: [PATCH 250/266] Bluetooth: btsdio: Do not bind to non-removable BCM43341 commit b4cdaba274247c9c841c6a682c08fa91fb3aa549 upstream. BCM43341 devices soldered onto the PCB (non-removable) always (AFAICT) use an UART connection for bluetooth. But they also advertise btsdio support on their 3th sdio function, this causes 2 problems: 1) A non functioning BT HCI getting registered 2) Since the btsdio driver does not have suspend/resume callbacks, mmc_sdio_pre_suspend will return -ENOSYS, causing mmc_pm_notify() to react as if the SDIO-card is removed and since the slot is marked as non-removable it will never get detected as inserted again. Which results in wifi no longer working after a suspend/resume. This commit fixes both by making btsdio ignore BCM43341 devices when connected to a slot which is marked non-removable. Signed-off-by: Hans de Goede Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btsdio.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index 7b624423a7e8..89ccb604045c 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -291,6 +292,14 @@ static int btsdio_probe(struct sdio_func *func, tuple = tuple->next; } + /* BCM43341 devices soldered onto the PCB (non-removable) use an + * uart connection for bluetooth, ignore the BT SDIO interface. + */ + if (func->vendor == SDIO_VENDOR_ID_BROADCOM && + func->device == SDIO_DEVICE_ID_BROADCOM_43341 && + !mmc_card_is_removable(func->card->host)) + return -ENODEV; + data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; From 356c94212d3c4e4bd194b46a45385d7f12c36668 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Wed, 20 Dec 2017 19:00:07 +0800 Subject: [PATCH 251/266] Revert "Bluetooth: btusb: fix QCA Rome suspend/resume" commit 7d06d5895c159f64c46560dc258e553ad8670fe0 upstream. This reverts commit fd865802c66bc451dc515ed89360f84376ce1a56. This commit causes a regression on some QCA ROME chips. The USB device reset happens in btusb_open(), hence firmware loading gets interrupted. Furthermore, this commit stops working after commit ("a0085f2510e8976614ad8f766b209448b385492f Bluetooth: btusb: driver to enable the usb-wakeup feature"). Reset-resume quirk only gets enabled in btusb_suspend() when it's not a wakeup source. If we really want to reset the USB device, we need to do it before btusb_open(). Let's handle it in drivers/usb/core/quirks.c. Cc: Leif Liddy Cc: Matthias Kaehlcke Cc: Brian Norris Cc: Daniel Drake Signed-off-by: Kai-Heng Feng Reviewed-by: Brian Norris Tested-by: Brian Norris Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 1ccad79ce77c..7bb8055bd10c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2969,12 +2969,6 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_QCA_ROME) { data->setup_on_usb = btusb_setup_qca; hdev->set_bdaddr = btusb_set_bdaddr_ath3012; - - /* QCA Rome devices lose their updated firmware over suspend, - * but the USB hub doesn't notice any status change. - * Explicitly request a device reset on resume. - */ - set_bit(BTUSB_RESET_RESUME, &data->flags); } #ifdef CONFIG_BT_HCIBTUSB_RTL From 32a3eda07cc980af4758ff40b7ae9cf262168e50 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 8 Jan 2018 10:44:16 +0100 Subject: [PATCH 252/266] Bluetooth: btusb: Restore QCA Rome suspend/resume fix with a "rewritten" version commit 61f5acea8737d9b717fcc22bb6679924f3c82b98 upstream. Commit 7d06d5895c15 ("Revert "Bluetooth: btusb: fix QCA...suspend/resume"") removed the setting of the BTUSB_RESET_RESUME quirk for QCA Rome devices, instead favoring adding USB_QUIRK_RESET_RESUME quirks in usb/core/quirks.c. This was done because the DIY BTUSB_RESET_RESUME reset-resume handling has several issues (see the original commit message). An added advantage of moving over to the USB-core reset-resume handling is that it also disables autosuspend for these devices, which is similarly broken on these. But there are 2 issues with this approach: 1) It leaves the broken DIY BTUSB_RESET_RESUME code in place for Realtek devices. 2) Sofar only 2 of the 10 QCA devices known to the btusb code have been added to usb/core/quirks.c and if we fix the Realtek case the same way we need to add an additional 14 entries. So in essence we need to duplicate a large part of the usb_device_id table in btusb.c in usb/core/quirks.c and manually keep them in sync. This commit instead restores setting a reset-resume quirk for QCA devices in the btusb.c code, avoiding the duplicate usb_device_id table problem. This commit avoids the problems with the original DIY BTUSB_RESET_RESUME code by simply setting the USB_QUIRK_RESET_RESUME quirk directly on the usb_device. This commit also moves the BTUSB_REALTEK case over to directly setting the USB_QUIRK_RESET_RESUME on the usb_device and removes the now unused BTUSB_RESET_RESUME code. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1514836 Fixes: 7d06d5895c15 ("Revert "Bluetooth: btusb: fix QCA...suspend/resume"") Cc: Leif Liddy Cc: Matthias Kaehlcke Cc: Brian Norris Cc: Daniel Drake Cc: Kai-Heng Feng Signed-off-by: Hans de Goede Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7bb8055bd10c..54cef3dc0beb 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -360,8 +361,8 @@ static const struct usb_device_id blacklist_table[] = { #define BTUSB_FIRMWARE_LOADED 7 #define BTUSB_FIRMWARE_FAILED 8 #define BTUSB_BOOTING 9 -#define BTUSB_RESET_RESUME 10 -#define BTUSB_DIAG_RUNNING 11 +#define BTUSB_DIAG_RUNNING 10 +#define BTUSB_OOB_WAKE_ENABLED 11 struct btusb_data { struct hci_dev *hdev; @@ -2969,6 +2970,12 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_QCA_ROME) { data->setup_on_usb = btusb_setup_qca; hdev->set_bdaddr = btusb_set_bdaddr_ath3012; + + /* QCA Rome devices lose their updated firmware over suspend, + * but the USB hub doesn't notice any status change. + * explicitly request a device reset on resume. + */ + interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; } #ifdef CONFIG_BT_HCIBTUSB_RTL @@ -2979,7 +2986,7 @@ static int btusb_probe(struct usb_interface *intf, * but the USB hub doesn't notice any status change. * Explicitly request a device reset on resume. */ - set_bit(BTUSB_RESET_RESUME, &data->flags); + interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; } #endif @@ -3136,14 +3143,6 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message) btusb_stop_traffic(data); usb_kill_anchored_urbs(&data->tx_anchor); - /* Optionally request a device reset on resume, but only when - * wakeups are disabled. If wakeups are enabled we assume the - * device will stay powered up throughout suspend. - */ - if (test_bit(BTUSB_RESET_RESUME, &data->flags) && - !device_may_wakeup(&data->udev->dev)) - data->udev->reset_resume = 1; - return 0; } From 6471c3d1900f4860e871c4f1d4133a338f588313 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 1 Aug 2017 04:16:47 -0500 Subject: [PATCH 253/266] signal/openrisc: Fix do_unaligned_access to send the proper signal commit 500d58300571b6602341b041f97c082a461ef994 upstream. While reviewing the signal sending on openrisc the do_unaligned_access function stood out because it is obviously wrong. A comment about an si_code set above when actually si_code is never set. Leading to a random si_code being sent to userspace in the event of an unaligned access. Looking further SIGBUS BUS_ADRALN is the proper pair of signal and si_code to send for an unaligned access. That is what other architectures do and what is required by posix. Given that do_unaligned_access is broken in a way that no one can be relying on it on openrisc fix the code to just do the right thing. Fixes: 769a8a96229e ("OpenRISC: Traps") Cc: Jonas Bonn Cc: Stefan Kristiansson Cc: Stafford Horne Cc: Arnd Bergmann Cc: openrisc@lists.librecores.org Acked-by: Stafford Horne Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman --- arch/openrisc/kernel/traps.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index 3d3f6062f49c..605a284922fb 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -302,12 +302,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) siginfo_t info; if (user_mode(regs)) { - /* Send a SIGSEGV */ - info.si_signo = SIGSEGV; + /* Send a SIGBUS */ + info.si_signo = SIGBUS; info.si_errno = 0; - /* info.si_code has been set above */ - info.si_addr = (void *)address; - force_sig_info(SIGSEGV, &info, current); + info.si_code = BUS_ADRALN; + info.si_addr = (void __user *)address; + force_sig_info(SIGBUS, &info, current); } else { printk("KERNEL: Unaligned Access 0x%.8lx\n", address); show_registers(regs); From fbc1425f4544371b5fe20b9a93f73b85c08dfe29 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 24 Jul 2017 17:30:30 -0500 Subject: [PATCH 254/266] signal/sh: Ensure si_signo is initialized in do_divide_error commit 0e88bb002a9b2ee8cc3cc9478ce2dc126f849696 upstream. Set si_signo. Cc: Yoshinori Sato Cc: Rich Felker Cc: Paul Mundt Cc: linux-sh@vger.kernel.org Fixes: 0983b31849bb ("sh: Wire up division and address error exceptions on SH-2A.") Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman --- arch/sh/kernel/traps_32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index ff639342a8be..c5b997757988 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -607,7 +607,8 @@ asmlinkage void do_divide_error(unsigned long r4) break; } - force_sig_info(SIGFPE, &info, current); + info.si_signo = SIGFPE; + force_sig_info(info.si_signo, &info, current); } #endif From f6d7ea7a180177fcf5c0aabb45dc8e2503a5fd9e Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Tue, 2 Jan 2018 14:01:34 -0500 Subject: [PATCH 255/266] alpha: fix crash if pthread_create races with signal delivery commit 21ffceda1c8b3807615c40d440d7815e0c85d366 upstream. On alpha, a process will crash if it attempts to start a thread and a signal is delivered at the same time. The crash can be reproduced with this program: https://cygwin.com/ml/cygwin/2014-11/msg00473.html The reason for the crash is this: * we call the clone syscall * we go to the function copy_process * copy process calls copy_thread_tls, it is a wrapper around copy_thread * copy_thread sets the tls pointer: childti->pcb.unique = regs->r20 * copy_thread sets regs->r20 to zero * we go back to copy_process * copy process checks "if (signal_pending(current))" and returns -ERESTARTNOINTR * the clone syscall is restarted, but this time, regs->r20 is zero, so the new thread is created with zero tls pointer * the new thread crashes in start_thread when attempting to access tls The comment in the code says that setting the register r20 is some compatibility with OSF/1. But OSF/1 doesn't use the CLONE_SETTLS flag, so we don't have to zero r20 if CLONE_SETTLS is set. This patch fixes the bug by zeroing regs->r20 only if CLONE_SETTLS is not set. Signed-off-by: Mikulas Patocka Signed-off-by: Matt Turner Signed-off-by: Greg Kroah-Hartman --- arch/alpha/kernel/process.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 84d13263ce46..8095fb2c5c94 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -273,12 +273,13 @@ copy_thread(unsigned long clone_flags, unsigned long usp, application calling fork. */ if (clone_flags & CLONE_SETTLS) childti->pcb.unique = regs->r20; + else + regs->r20 = 0; /* OSF/1 has some strange fork() semantics. */ childti->pcb.usp = usp ?: rdusp(); *childregs = *regs; childregs->r0 = 0; childregs->r19 = 0; childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ - regs->r20 = 0; stack = ((struct switch_stack *) regs) - 1; *childstack = *stack; childstack->r26 = (unsigned long) ret_from_fork; From 4bd9d85ab3db74527d7db46874a93459e6c0cee2 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Tue, 2 Jan 2018 13:59:54 -0500 Subject: [PATCH 256/266] alpha: fix reboot on Avanti platform commit 55fc633c41a08ce9244ff5f528f420b16b1e04d6 upstream. We need to define NEED_SRM_SAVE_RESTORE on the Avanti, otherwise we get machine check exception when attempting to reboot the machine. Signed-off-by: Mikulas Patocka Signed-off-by: Matt Turner Signed-off-by: Greg Kroah-Hartman --- arch/alpha/kernel/pci_impl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h index 2b0ac429f5eb..412bb3c24f36 100644 --- a/arch/alpha/kernel/pci_impl.h +++ b/arch/alpha/kernel/pci_impl.h @@ -143,7 +143,8 @@ struct pci_iommu_arena }; #if defined(CONFIG_ALPHA_SRM) && \ - (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA)) + (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \ + defined(CONFIG_ALPHA_AVANTI)) # define NEED_SRM_SAVE_RESTORE #else # undef NEED_SRM_SAVE_RESTORE From 1c11f153eb35260b3baab5996d7aa9e974dbb5dd Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 5 Jan 2018 14:27:58 -0800 Subject: [PATCH 257/266] xtensa: fix futex_atomic_cmpxchg_inatomic commit ca47480921587ae30417dd234a9f79af188e3666 upstream. Return 0 if the operation was successful, not the userspace memory value. Check that userspace value equals passed oldval, not itself. Don't update *uval if the value wasn't read from userspace memory. This fixes process hang due to infinite loop in futex_lock_pi. It also fixes a bunch of glibc tests nptl/tst-mutexpi*. Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/include/asm/futex.h | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h index b39531babec0..72bfc1cbc2b5 100644 --- a/arch/xtensa/include/asm/futex.h +++ b/arch/xtensa/include/asm/futex.h @@ -109,7 +109,6 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { int ret = 0; - u32 prev; if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) return -EFAULT; @@ -120,26 +119,24 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, __asm__ __volatile__ ( " # futex_atomic_cmpxchg_inatomic\n" - "1: l32i %1, %3, 0\n" - " mov %0, %5\n" - " wsr %1, scompare1\n" - "2: s32c1i %0, %3, 0\n" - "3:\n" + " wsr %5, scompare1\n" + "1: s32c1i %1, %4, 0\n" + " s32i %1, %6, 0\n" + "2:\n" " .section .fixup,\"ax\"\n" " .align 4\n" - "4: .long 3b\n" - "5: l32r %1, 4b\n" - " movi %0, %6\n" + "3: .long 2b\n" + "4: l32r %1, 3b\n" + " movi %0, %7\n" " jx %1\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .long 1b,5b,2b,5b\n" + " .long 1b,4b\n" " .previous\n" - : "+r" (ret), "=&r" (prev), "+m" (*uaddr) - : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT) + : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval) + : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT) : "memory"); - *uval = prev; return ret; } From 89dea03c095d01d70136bcc190b895bbe4590217 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 13 Nov 2017 16:12:06 +0000 Subject: [PATCH 258/266] EDAC, octeon: Fix an uninitialized variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 544e92581a2ac44607d7cc602c6b54d18656f56d upstream. Fix an uninitialized variable warning in the Octeon EDAC driver, as seen in MIPS cavium_octeon_defconfig builds since v4.14 with Codescape GNU Tools 2016.05-03: drivers/edac/octeon_edac-lmc.c In function ‘octeon_lmc_edac_poll_o2’: drivers/edac/octeon_edac-lmc.c:87:24: warning: ‘((long unsigned int*)&int_reg)[1]’ may \ be used uninitialized in this function [-Wmaybe-uninitialized] if (int_reg.s.sec_err || int_reg.s.ded_err) { ^ Iinitialise the whole int_reg variable to zero before the conditional assignments in the error injection case. Signed-off-by: James Hogan Acked-by: David Daney Cc: linux-edac Cc: linux-mips@linux-mips.org Fixes: 1bc021e81565 ("EDAC: Octeon: Add error injection support") Link: http://lkml.kernel.org/r/20171113161206.20990-1-james.hogan@mips.com Signed-off-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman --- drivers/edac/octeon_edac-lmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c index cda6dab5067a..6b65a102b49d 100644 --- a/drivers/edac/octeon_edac-lmc.c +++ b/drivers/edac/octeon_edac-lmc.c @@ -79,6 +79,7 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci) if (!pvt->inject) int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx)); else { + int_reg.u64 = 0; if (pvt->error_type == 1) int_reg.s.sec_err = 1; if (pvt->error_type == 2) From 36675d5da0205e9aebe5f25f1be46c19a73812ac Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 2 Jan 2018 11:39:47 -0800 Subject: [PATCH 259/266] pktcdvd: Fix pkt_setup_dev() error path commit 5a0ec388ef0f6e33841aeb810d7fa23f049ec4cd upstream. Commit 523e1d399ce0 ("block: make gendisk hold a reference to its queue") modified add_disk() and disk_release() but did not update any of the error paths that trigger a put_disk() call after disk->queue has been assigned. That introduced the following behavior in the pktcdvd driver if pkt_new_dev() fails: Kernel BUG at 00000000e98fd882 [verbose debug info unavailable] Since disk_release() calls blk_put_queue() anyway if disk->queue != NULL, fix this by removing the blk_cleanup_queue() call from the pkt_setup_dev() error path. Fixes: commit 523e1d399ce0 ("block: make gendisk hold a reference to its queue") Signed-off-by: Bart Van Assche Cc: Tejun Heo Cc: Maciej S. Szmigiero Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/pktcdvd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index d06c62eccdf0..156968a6655d 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2779,7 +2779,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) pd->pkt_dev = MKDEV(pktdev_major, idx); ret = pkt_new_dev(pd, dev); if (ret) - goto out_new_dev; + goto out_mem2; /* inherit events of the host device */ disk->events = pd->bdev->bd_disk->events; @@ -2797,8 +2797,6 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) mutex_unlock(&ctl_mutex); return 0; -out_new_dev: - blk_cleanup_queue(disk->queue); out_mem2: put_disk(disk); out_mem: From 2b107726836177838d5be167323cb18513c8d083 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Tue, 5 Dec 2017 09:29:19 +0200 Subject: [PATCH 260/266] btrfs: Handle btrfs_set_extent_delalloc failure in fixup worker commit f3038ee3a3f1017a1cbe9907e31fa12d366c5dcb upstream. This function was introduced by 247e743cbe6e ("Btrfs: Use async helpers to deal with pages that have been improperly dirtied") and it didn't do any error handling then. This function might very well fail in ENOMEM situation, yet it's not handled, this could lead to inconsistent state. So let's handle the failure by setting the mapping error bit. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index af1da85da509..86d209fc4992 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2015,7 +2015,15 @@ again: goto out; } - btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state); + ret = btrfs_set_extent_delalloc(inode, page_start, page_end, + &cached_state); + if (ret) { + mapping_set_error(page->mapping, ret); + end_extent_writepage(page, ret, page_start, page_end); + ClearPageChecked(page); + goto out; + } + ClearPageChecked(page); set_page_dirty(page); out: From 5571210221d07217776390c762aa1325a236b93f Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 13 Feb 2018 09:19:37 -0700 Subject: [PATCH 261/266] nvme: Fix managing degraded controllers commit 5bae7f73d378a986 upstream Upstream is a near rewrite of the async nvme probe that ultimately didn't even cleanly merge in 4.5. This patch is a much smaller change targeted to the regression introduced in 4.4. If a controller is in a degraded mode that needs admin assistence to recover, we need to leave the controller running. We just want to disable namespace access without shuting the controller down. Fixes: 3cf519b5a8d4("nvme: merge nvme_dev_start, nvme_dev_resume and nvme_async_probe") Signed-off-by: Keith Busch Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/pci.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index d6ceb8b91cd6..1c8aedf21370 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2976,10 +2976,16 @@ static void nvme_dev_shutdown(struct nvme_dev *dev) mutex_unlock(&dev->shutdown_lock); } -static void nvme_dev_remove(struct nvme_dev *dev) +static void nvme_remove_namespaces(struct nvme_dev *dev) { struct nvme_ns *ns, *next; + list_for_each_entry_safe(ns, next, &dev->namespaces, list) + nvme_ns_remove(ns); +} + +static void nvme_dev_remove(struct nvme_dev *dev) +{ if (nvme_io_incapable(dev)) { /* * If the device is not capable of IO (surprise hot-removal, @@ -2989,8 +2995,7 @@ static void nvme_dev_remove(struct nvme_dev *dev) */ nvme_dev_shutdown(dev); } - list_for_each_entry_safe(ns, next, &dev->namespaces, list) - nvme_ns_remove(ns); + nvme_remove_namespaces(dev); } static int nvme_setup_prp_pools(struct nvme_dev *dev) @@ -3174,7 +3179,7 @@ static void nvme_probe_work(struct work_struct *work) */ if (dev->online_queues < 2) { dev_warn(dev->dev, "IO queues not created\n"); - nvme_dev_remove(dev); + nvme_remove_namespaces(dev); } else { nvme_unfreeze_queues(dev); nvme_dev_add(dev); From 591060a7a0a09cbaa5b6c04bd309966586aa9d2e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 19 Jan 2018 10:06:03 +0100 Subject: [PATCH 262/266] ACPI: sbshc: remove raw pointer from printk() message commit 43cdd1b716b26f6af16da4e145b6578f98798bf6 upstream. There's no need to be printing a raw kernel pointer to the kernel log at every boot. So just remove it, and change the whole message to use the correct dev_info() call at the same time. Reported-by: Wang Qize Signed-off-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/sbshc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 2fa8304171e0..7a3431018e0a 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -275,8 +275,8 @@ static int acpi_smbus_hc_add(struct acpi_device *device) device->driver_data = hc; acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc); - printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n", - hc->ec, hc->offset, hc->query_bit); + dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n", + hc->offset, hc->query_bit); return 0; } From 3b0104f9e21a49cd03b91c7794b3e3e6cc0bc277 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Wed, 8 Nov 2017 09:39:46 +0200 Subject: [PATCH 263/266] ovl: fix failure to fsync lower dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d796e77f1dd541fe34481af2eee6454688d13982 upstream. As a writable mount, it is not expected for overlayfs to return EINVAL/EROFS for fsync, even if dir/file is not changed. This commit fixes the case of fsync of directory, which is easier to address, because overlayfs already implements fsync file operation for directories. The problem reported by Raphael is that new PostgreSQL 10.0 with a database in overlayfs where lower layer in squashfs fails to start. The failure is due to fsync error, when PostgreSQL does fsync on all existing db directories on startup and a specific directory exists lower layer with no changes. Reported-by: Raphael Hertzog Signed-off-by: Amir Goldstein Tested-by: Raphaël Hertzog Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/overlayfs/readdir.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index adcb1398c481..299a6e1d6b77 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -441,10 +441,14 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, struct dentry *dentry = file->f_path.dentry; struct file *realfile = od->realfile; + /* Nothing to sync for lower */ + if (!OVL_TYPE_UPPER(ovl_path_type(dentry))) + return 0; + /* * Need to check if we started out being a lower dir, but got copied up */ - if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) { + if (!od->is_upper) { struct inode *inode = file_inode(file); realfile = lockless_dereference(od->upperfile); From 2dab22193943230c4ff63fd9496b2ed5c044e519 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 1 Aug 2017 05:02:38 -0500 Subject: [PATCH 264/266] mn10300/misalignment: Use SIGSEGV SEGV_MAPERR to report a failed user copy commit 6ac1dc736b323011a55ecd1fc5897c24c4f77cbd upstream. Setting si_code to 0 is the same a setting si_code to SI_USER which is definitely not correct. With si_code set to SI_USER si_pid and si_uid will be copied to userspace instead of si_addr. Which is very wrong. So fix this by using a sensible si_code (SEGV_MAPERR) for this failure. Fixes: b920de1b77b7 ("mn10300: add the MN10300/AM33 architecture to the kernel") Cc: David Howells Cc: Masakazu Urade Cc: Koichi Yasutake Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman --- arch/mn10300/mm/misalignment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c index b9920b1edd5a..70cef54dc40f 100644 --- a/arch/mn10300/mm/misalignment.c +++ b/arch/mn10300/mm/misalignment.c @@ -437,7 +437,7 @@ transfer_failed: info.si_signo = SIGSEGV; info.si_errno = 0; - info.si_code = 0; + info.si_code = SEGV_MAPERR; info.si_addr = (void *) regs->pc; force_sig_info(SIGSEGV, &info, current); return; From a94d7722b39206e96e639cd5cf2cf037c69d5ce8 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Mon, 5 Feb 2018 22:05:31 -0500 Subject: [PATCH 265/266] ftrace: Remove incorrect setting of glob search field commit 7b6586562708d2b3a04fe49f217ddbadbbbb0546 upstream. __unregister_ftrace_function_probe() will incorrectly parse the glob filter because it resets the search variable that was setup by filter_parse_regex(). Al Viro reported this: After that call of filter_parse_regex() we could have func_g.search not equal to glob only if glob started with '!' or '*'. In the former case we would've buggered off with -EINVAL (not = 1). In the latter we would've set func_g.search equal to glob + 1, calculated the length of that thing in func_g.len and proceeded to reset func_g.search back to glob. Suppose the glob is e.g. *foo*. We end up with func_g.type = MATCH_MIDDLE_ONLY; func_g.len = 3; func_g.search = "*foo"; Feeding that to ftrace_match_record() will not do anything sane - we will be looking for names containing "*foo" (->len is ignored for that one). Link: http://lkml.kernel.org/r/20180127031706.GE13338@ZenIV.linux.org.uk Fixes: 3ba009297149f ("ftrace: Introduce ftrace_glob structure") Reviewed-by: Dmitry Safonov <0x7f454c46@gmail.com> Reviewed-by: Masami Hiramatsu Reported-by: Al Viro Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/ftrace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index fc0051fd672d..ac758a53fcea 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -3845,7 +3845,6 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, func_g.type = filter_parse_regex(glob, strlen(glob), &func_g.search, ¬); func_g.len = strlen(func_g.search); - func_g.search = glob; /* we do not support '!' for function probes */ if (WARN_ON(not)) From 0f48bd7cf032bb4cb9f433de0fef694e15fb93ef Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 16 Feb 2018 20:09:48 +0100 Subject: [PATCH 266/266] Linux 4.4.116 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9c60120dd9fd..71acaecd7899 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 115 +SUBLEVEL = 116 EXTRAVERSION = NAME = Blurry Fish Butt