diff options
Diffstat (limited to 'arch/mips/kernel')
26 files changed, 622 insertions, 173 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index d982be1..68e2b7d 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o obj-$(CONFIG_MIPS_CMP) += smp-cmp.o obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o +obj-$(CONFIG_MIPS_CPS_NS16550) += cps-vec-ns16550.o obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o obj-$(CONFIG_MIPS_SPRAM) += spram.o diff --git a/arch/mips/kernel/cps-vec-ns16550.S b/arch/mips/kernel/cps-vec-ns16550.S new file mode 100644 index 0000000..6d246ad --- /dev/null +++ b/arch/mips/kernel/cps-vec-ns16550.S @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Paul Burton <paul.burton@imgtec.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/asm-offsets.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <linux/serial_reg.h> + +#define UART_TX_OFS (UART_TX << CONFIG_MIPS_CPS_NS16550_SHIFT) +#define UART_LSR_OFS (UART_LSR << CONFIG_MIPS_CPS_NS16550_SHIFT) + +/** + * _mips_cps_putc() - write a character to the UART + * @a0: ASCII character to write + * @t9: UART base address + */ +LEAF(_mips_cps_putc) +1: lw t0, UART_LSR_OFS(t9) + andi t0, t0, UART_LSR_TEMT + beqz t0, 1b + sb a0, UART_TX_OFS(t9) + jr ra + END(_mips_cps_putc) + +/** + * _mips_cps_puts() - write a string to the UART + * @a0: pointer to NULL-terminated ASCII string + * @t9: UART base address + * + * Write a null-terminated ASCII string to the UART. + */ +NESTED(_mips_cps_puts, 0, ra) + move s7, ra + move s6, a0 + +1: lb a0, 0(s6) + beqz a0, 2f + jal _mips_cps_putc + PTR_ADDIU s6, s6, 1 + b 1b + +2: jr s7 + END(_mips_cps_puts) + +/** + * _mips_cps_putx4 - write a 4b hex value to the UART + * @a0: the 4b value to write to the UART + * @t9: UART base address + * + * Write a single hexadecimal character to the UART. + */ +NESTED(_mips_cps_putx4, 0, ra) + andi a0, a0, 0xf + li t0, '0' + blt a0, 10, 1f + li t0, 'a' + addiu a0, a0, -10 +1: addu a0, a0, t0 + b _mips_cps_putc + END(_mips_cps_putx4) + +/** + * _mips_cps_putx8 - write an 8b hex value to the UART + * @a0: the 8b value to write to the UART + * @t9: UART base address + * + * Write an 8 bit value (ie. 2 hexadecimal characters) to the UART. + */ +NESTED(_mips_cps_putx8, 0, ra) + move s3, ra + move s2, a0 + srl a0, a0, 4 + jal _mips_cps_putx4 + move a0, s2 + move ra, s3 + b _mips_cps_putx4 + END(_mips_cps_putx8) + +/** + * _mips_cps_putx16 - write a 16b hex value to the UART + * @a0: the 16b value to write to the UART + * @t9: UART base address + * + * Write a 16 bit value (ie. 4 hexadecimal characters) to the UART. + */ +NESTED(_mips_cps_putx16, 0, ra) + move s5, ra + move s4, a0 + srl a0, a0, 8 + jal _mips_cps_putx8 + move a0, s4 + move ra, s5 + b _mips_cps_putx8 + END(_mips_cps_putx16) + +/** + * _mips_cps_putx32 - write a 32b hex value to the UART + * @a0: the 32b value to write to the UART + * @t9: UART base address + * + * Write a 32 bit value (ie. 8 hexadecimal characters) to the UART. + */ +NESTED(_mips_cps_putx32, 0, ra) + move s7, ra + move s6, a0 + srl a0, a0, 16 + jal _mips_cps_putx16 + move a0, s6 + move ra, s7 + b _mips_cps_putx16 + END(_mips_cps_putx32) + +#ifdef CONFIG_64BIT + +/** + * _mips_cps_putx64 - write a 64b hex value to the UART + * @a0: the 64b value to write to the UART + * @t9: UART base address + * + * Write a 64 bit value (ie. 16 hexadecimal characters) to the UART. + */ +NESTED(_mips_cps_putx64, 0, ra) + move sp, ra + move s8, a0 + dsrl32 a0, a0, 0 + jal _mips_cps_putx32 + move a0, s8 + move ra, sp + b _mips_cps_putx32 + END(_mips_cps_putx64) + +#define _mips_cps_putxlong _mips_cps_putx64 + +#else /* !CONFIG_64BIT */ + +#define _mips_cps_putxlong _mips_cps_putx32 + +#endif /* !CONFIG_64BIT */ + +/** + * mips_cps_bev_dump() - dump relevant exception state to UART + * @a0: pointer to NULL-terminated ASCII string naming the exception + * + * Write information that may be useful in debugging an exception to the + * UART configured by CONFIG_MIPS_CPS_NS16550_*. As this BEV exception + * will only be run if something goes horribly wrong very early during + * the bringup of a core and it is very likely to be unsafe to perform + * memory accesses at that point (cache state indeterminate, EVA may not + * be configured, coherence may be disabled) let alone have a stack, + * this is all written in assembly using only registers & unmapped + * uncached access to the UART registers. + */ +LEAF(mips_cps_bev_dump) + move s0, ra + move s1, a0 + + li t9, CKSEG1ADDR(CONFIG_MIPS_CPS_NS16550_BASE) + + PTR_LA a0, str_newline + jal _mips_cps_puts + PTR_LA a0, str_bev + jal _mips_cps_puts + move a0, s1 + jal _mips_cps_puts + PTR_LA a0, str_newline + jal _mips_cps_puts + PTR_LA a0, str_newline + jal _mips_cps_puts + +#define DUMP_COP0_REG(reg, name, sz, _mfc0) \ + PTR_LA a0, 8f; \ + jal _mips_cps_puts; \ + _mfc0 a0, reg; \ + jal _mips_cps_putx##sz; \ + PTR_LA a0, str_newline; \ + jal _mips_cps_puts; \ + TEXT(name) + + DUMP_COP0_REG(CP0_CAUSE, "Cause: 0x", 32, mfc0) + DUMP_COP0_REG(CP0_STATUS, "Status: 0x", 32, mfc0) + DUMP_COP0_REG(CP0_EBASE, "EBase: 0x", long, MFC0) + DUMP_COP0_REG(CP0_BADVADDR, "BadVAddr: 0x", long, MFC0) + DUMP_COP0_REG(CP0_BADINSTR, "BadInstr: 0x", 32, mfc0) + + PTR_LA a0, str_newline + jal _mips_cps_puts + jr s0 + END(mips_cps_bev_dump) + +.pushsection .data +str_bev: .asciiz "BEV Exception: " +str_newline: .asciiz "\r\n" +.popsection diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 209ded1..8fd5a27 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -25,14 +25,32 @@ .set noreorder +#ifdef CONFIG_64BIT +# define STATUS_BITDEPS ST0_KX +#else +# define STATUS_BITDEPS 0 +#endif + +#ifdef CONFIG_MIPS_CPS_NS16550 + +#define DUMP_EXCEP(name) \ + PTR_LA a0, 8f; \ + jal mips_cps_bev_dump; \ + nop; \ + TEXT(name) + +#else /* !CONFIG_MIPS_CPS_NS16550 */ + +#define DUMP_EXCEP(name) + +#endif /* !CONFIG_MIPS_CPS_NS16550 */ + /* * Set dest to non-zero if the core supports the MT ASE, else zero. If * MT is not supported then branch to nomt. */ .macro has_mt dest, nomt - mfc0 \dest, CP0_CONFIG - bgez \dest, \nomt - mfc0 \dest, CP0_CONFIG, 1 + mfc0 \dest, CP0_CONFIG, 1 bgez \dest, \nomt mfc0 \dest, CP0_CONFIG, 2 bgez \dest, \nomt @@ -47,11 +65,9 @@ LEAF(mips_cps_core_entry) /* - * These first 12 bytes will be patched by cps_smp_setup to load the - * base address of the CM GCRs into register v1 and the CCA to use into - * register s0. + * These first 4 bytes will be patched by cps_smp_setup to load the + * CCA to use into register s0. */ - .quad 0 .word 0 /* Check whether we're here due to an NMI */ @@ -71,7 +87,7 @@ not_nmi: mtc0 t0, CP0_CAUSE /* Setup Status */ - li t0, ST0_CU1 | ST0_CU0 + li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS mtc0 t0, CP0_STATUS /* @@ -151,6 +167,12 @@ dcache_done: 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 */ li t0, 0xff sw t0, GCR_CL_COHERENCE_OFS(v1) @@ -188,36 +210,42 @@ dcache_done: .org 0x200 LEAF(excep_tlbfill) + DUMP_EXCEP("TLB Fill") b . nop END(excep_tlbfill) .org 0x280 LEAF(excep_xtlbfill) + DUMP_EXCEP("XTLB Fill") b . nop END(excep_xtlbfill) .org 0x300 LEAF(excep_cache) + DUMP_EXCEP("Cache") b . nop END(excep_cache) .org 0x380 LEAF(excep_genex) + DUMP_EXCEP("General") b . nop END(excep_genex) .org 0x400 LEAF(excep_intex) + DUMP_EXCEP("Interrupt") b . nop END(excep_intex) .org 0x480 LEAF(excep_ejtag) + DUMP_EXCEP("EJTAG") PTR_LA k0, ejtag_debug_handler jr k0 nop diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 09a51d0..6b90644 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -536,8 +536,7 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->options |= MIPS_CPU_SEGMENTS; if (config3 & MIPS_CONF3_MSA) c->ases |= MIPS_ASE_MSA; - /* Only tested on 32-bit cores */ - if ((config3 & MIPS_CONF3_PW) && config_enabled(CONFIG_32BIT)) { + if (config3 & MIPS_CONF3_PW) { c->htw_seq = 0; c->options |= MIPS_CPU_HTW; } diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c index e5ed7ad..1f91056 100644 --- a/arch/mips/kernel/csrc-r4k.c +++ b/arch/mips/kernel/csrc-r4k.c @@ -28,6 +28,43 @@ static u64 notrace r4k_read_sched_clock(void) return read_c0_count(); } +static inline unsigned int rdhwr_count(void) +{ + unsigned int count; + + __asm__ __volatile__( + " .set push\n" + " .set mips32r2\n" + " rdhwr %0, $2\n" + " .set pop\n" + : "=r" (count)); + + return count; +} + +static bool rdhwr_count_usable(void) +{ + unsigned int prev, curr, i; + + /* + * Older QEMUs have a broken implementation of RDHWR for the CP0 count + * which always returns a constant value. Try to identify this and don't + * use it in the VDSO if it is broken. This workaround can be removed + * once the fix has been in QEMU stable for a reasonable amount of time. + */ + for (i = 0, prev = rdhwr_count(); i < 100; i++) { + curr = rdhwr_count(); + + if (curr != prev) + return true; + + prev = curr; + } + + pr_warn("Not using R4K clocksource in VDSO due to broken RDHWR\n"); + return false; +} + int __init init_r4k_clocksource(void) { if (!cpu_has_counter || !mips_hpt_frequency) @@ -36,6 +73,13 @@ int __init init_r4k_clocksource(void) /* Calculate a somewhat reasonable rating value */ clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; + /* + * R2 onwards makes the count accessible to user mode so it can be used + * by the VDSO (HWREna is configured by configure_hwrena()). + */ + if (cpu_has_mips_r2_r6 && rdhwr_count_usable()) + clocksource_mips.archdata.vdso_clock_mode = VDSO_CLOCK_R4K; + clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency); diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index ab1478d..46794d6 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -134,6 +134,16 @@ void __init check_wait(void) return; } + /* + * MIPSr6 specifies that masked interrupts should unblock an executing + * wait instruction, and thus that it is safe for us to use + * r4k_wait_irqoff. Yippee! + */ + if (cpu_has_mips_r6) { + cpu_wait = r4k_wait_irqoff; + return; + } + switch (current_cpu_type()) { case CPU_R3081: case CPU_R3081E: @@ -155,12 +165,12 @@ void __init check_wait(void) case CPU_4KEC: case CPU_4KSC: case CPU_5KC: + case CPU_5KE: case CPU_25KF: case CPU_PR4450: case CPU_BMIPS3300: case CPU_BMIPS4350: case CPU_BMIPS4380: - case CPU_BMIPS5000: case CPU_CAVIUM_OCTEON: case CPU_CAVIUM_OCTEON_PLUS: case CPU_CAVIUM_OCTEON2: @@ -171,7 +181,9 @@ void __init check_wait(void) case CPU_XLP: cpu_wait = r4k_wait; break; - + case CPU_BMIPS5000: + cpu_wait = r4k_wait_irqoff; + break; case CPU_RM7000: cpu_wait = rm7k_wait_irqoff; break; @@ -196,7 +208,6 @@ void __init check_wait(void) case CPU_INTERAPTIV: case CPU_M5150: case CPU_QEMU_GENERIC: - case CPU_I6400: cpu_wait = r4k_wait; if (read_c0_config7() & MIPS_CONF7_WII) cpu_wait = r4k_wait_irqoff; diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index b8ceee5..1448c1f 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -9,6 +9,8 @@ */ #include <linux/errno.h> +#include <linux/percpu.h> +#include <linux/spinlock.h> #include <asm/mips-cm.h> #include <asm/mipsregs.h> @@ -136,6 +138,9 @@ static char *cm3_causes[32] = { "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f" }; +static DEFINE_PER_CPU_ALIGNED(spinlock_t, cm_core_lock); +static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags); + phys_addr_t __mips_cm_phys_base(void) { u32 config3 = read_c0_config3(); @@ -200,6 +205,7 @@ int mips_cm_probe(void) { phys_addr_t addr; u32 base_reg; + unsigned cpu; /* * No need to probe again if we have already been @@ -247,38 +253,70 @@ int mips_cm_probe(void) /* determine register width for this CM */ mips_cm_is64 = config_enabled(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3); + for_each_possible_cpu(cpu) + spin_lock_init(&per_cpu(cm_core_lock, cpu)); + return 0; } -void mips_cm_error_report(void) +void mips_cm_lock_other(unsigned int core, unsigned int vp) { - unsigned long revision = mips_cm_revision(); + unsigned curr_core; + 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; + } else { + BUG_ON(vp != 0); + val = core << CM_GCR_Cx_OTHER_CORENUM_SHF; + } + + write_gcr_cl_other(val); + /* - * CM3 has a 64-bit Error cause register with 0:57 containing the error - * info and 63:58 the error type. For old CMs, everything is contained - * in a single 32-bit register (0:26 and 31:27 respectively). Even - * though the cm_error is u64, we will simply ignore the upper word - * for CM2. + * Ensure the core-other region reflects the appropriate core & + * VP before any accesses to it occur. */ - u64 cm_error = read_gcr_error_cause(); - int cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF + - ((revision >= CM_REV_CM3) ? 31 : 0); - unsigned long cm_addr = read_gcr_error_addr(); - unsigned long cm_other = read_gcr_error_mult(); + mb(); +} + +void mips_cm_unlock_other(void) +{ + unsigned curr_core = current_cpu_data.core; + + spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core), + per_cpu(cm_core_lock_flags, curr_core)); + preempt_enable(); +} + +void mips_cm_error_report(void) +{ + u64 cm_error, cm_addr, cm_other; + unsigned long revision; int ocause, cause; char buf[256]; if (!mips_cm_present()) return; - cause = cm_error >> cm_error_cause_sft; + revision = mips_cm_revision(); - if (!cause) - /* All good */ - return; - - ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; if (revision < CM_REV_CM3) { /* CM2 */ + cm_error = read_gcr_error_cause(); + cm_addr = read_gcr_error_addr(); + cm_other = read_gcr_error_mult(); + cause = cm_error >> CM_GCR_ERROR_CAUSE_ERRTYPE_SHF; + ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; + + if (!cause) + return; + if (cause < 16) { unsigned long cca_bits = (cm_error >> 15) & 7; unsigned long tr_bits = (cm_error >> 12) & 7; @@ -310,18 +348,30 @@ void mips_cm_error_report(void) } pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, cm2_causes[cause], buf); - pr_err("CM_ADDR =%08lx\n", cm_addr); - pr_err("CM_OTHER=%08lx %s\n", cm_other, cm2_causes[ocause]); + pr_err("CM_ADDR =%08llx\n", cm_addr); + pr_err("CM_OTHER=%08llx %s\n", cm_other, cm2_causes[ocause]); } else { /* CM3 */ - /* Used by cause == {1,2,3} */ - unsigned long core_id_bits = (cm_error >> 22) & 0xf; - unsigned long vp_id_bits = (cm_error >> 18) & 0xf; - unsigned long cmd_bits = (cm_error >> 14) & 0xf; - unsigned long cmd_group_bits = (cm_error >> 11) & 0xf; - unsigned long cm3_cca_bits = (cm_error >> 8) & 7; - unsigned long mcp_bits = (cm_error >> 5) & 0xf; - unsigned long cm3_tr_bits = (cm_error >> 1) & 0xf; - unsigned long sched_bit = cm_error & 0x1; + ulong core_id_bits, vp_id_bits, cmd_bits, cmd_group_bits; + ulong cm3_cca_bits, mcp_bits, cm3_tr_bits, sched_bit; + + cm_error = read64_gcr_error_cause(); + cm_addr = read64_gcr_error_addr(); + cm_other = read64_gcr_error_mult(); + cause = cm_error >> CM3_GCR_ERROR_CAUSE_ERRTYPE_SHF; + ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; + + if (!cause) + return; + + /* Used by cause == {1,2,3} */ + core_id_bits = (cm_error >> 22) & 0xf; + vp_id_bits = (cm_error >> 18) & 0xf; + cmd_bits = (cm_error >> 14) & 0xf; + cmd_group_bits = (cm_error >> 11) & 0xf; + cm3_cca_bits = (cm_error >> 8) & 7; + mcp_bits = (cm_error >> 5) & 0xf; + cm3_tr_bits = (cm_error >> 1) & 0xf; + sched_bit = cm_error & 0x1; if (cause == 1 || cause == 3) { /* Tag ECC */ unsigned long tag_ecc = (cm_error >> 57) & 0x1; @@ -363,12 +413,14 @@ void mips_cm_error_report(void) cm3_cmd_group[cmd_group_bits], cm3_cca_bits, 1 << mcp_bits, cm3_tr[cm3_tr_bits], sched_bit); + } else { + buf[0] = 0; } pr_err("CM_ERROR=%llx %s <%s>\n", cm_error, cm3_causes[cause], buf); - pr_err("CM_ADDR =%lx\n", cm_addr); - pr_err("CM_OTHER=%lx %s\n", cm_other, cm3_causes[ocause]); + pr_err("CM_ADDR =%llx\n", cm_addr); + pr_err("CM_OTHER=%llx %s\n", cm_other, cm3_causes[ocause]); } /* reprime cause register */ diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index 8af4d62..566b8d2 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -76,6 +76,12 @@ void mips_cpc_lock_other(unsigned int core) spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core), per_cpu(cpc_core_lock_flags, curr_core)); write_cpc_cl_other(core << CPC_Cx_OTHER_CORENUM_SHF); + + /* + * Ensure the core-other region reflects the appropriate core & + * VP before any accesses to it occur. + */ + mb(); } void mips_cpc_unlock_other(void) diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index f2977f0..1f5aac7 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -22,6 +22,7 @@ #include <asm/asm.h> #include <asm/branch.h> #include <asm/break.h> +#include <asm/debug.h> #include <asm/fpu.h> #include <asm/fpu_emulator.h> #include <asm/inst.h> @@ -2363,7 +2364,6 @@ static const struct file_operations mipsr2_clear_fops = { static int __init mipsr2_init_debugfs(void) { - extern struct dentry *mips_debugfs_dir; struct dentry *mipsr2_emul; if (!mips_debugfs_dir) diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 65a74e4..2d23c83 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -594,3 +594,4 @@ EXPORT(sys_call_table) PTR sys_execveat PTR sys_userfaultfd PTR sys_membarrier + PTR sys_mlock2 diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index e732981..deac633 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -432,4 +432,5 @@ EXPORT(sys_call_table) PTR sys_execveat PTR sys_userfaultfd PTR sys_membarrier + PTR sys_mlock2 .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index c794843..5a69eb4 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -422,4 +422,5 @@ EXPORT(sysn32_call_table) PTR compat_sys_execveat /* 6320 */ PTR sys_userfaultfd PTR sys_membarrier + PTR sys_mlock2 .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 6369cfd..e4b6d7c 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -577,4 +577,5 @@ EXPORT(sys32_call_table) PTR compat_sys_execveat PTR sys_userfaultfd PTR sys_membarrier + PTR sys_mlock2 .size sys32_call_table,.-sys32_call_table diff --git a/arch/mips/kernel/segment.c b/arch/mips/kernel/segment.c index 076ead2..87bc74a 100644 --- a/arch/mips/kernel/segment.c +++ b/arch/mips/kernel/segment.c @@ -10,6 +10,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <asm/cpu.h> +#include <asm/debug.h> #include <asm/mipsregs.h> static void build_segment_config(char *str, unsigned int cfg) @@ -91,7 +92,6 @@ static const struct file_operations segments_fops = { static int __init segments_info(void) { - extern struct dentry *mips_debugfs_dir; struct dentry *segments; if (cpu_has_segments) { diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 4795151..66aac55 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -33,11 +33,16 @@ #include <asm/cache.h> #include <asm/cdmm.h> #include <asm/cpu.h> +#include <asm/debug.h> #include <asm/sections.h> #include <asm/setup.h> #include <asm/smp-ops.h> #include <asm/prom.h> +#ifdef CONFIG_MIPS_ELF_APPENDED_DTB +const char __section(.appended_dtb) __appended_dtb[0x100000]; +#endif /* CONFIG_MIPS_ELF_APPENDED_DTB */ + struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_data); @@ -616,6 +621,10 @@ static void __init request_crashkernel(struct resource *res) } #endif /* !defined(CONFIG_KEXEC) */ +#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER) +#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB) +#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_EXTEND) + static void __init arch_mem_init(char **cmdline_p) { struct memblock_region *reg; @@ -640,18 +649,24 @@ static void __init arch_mem_init(char **cmdline_p) pr_info("Determined physical RAM map:\n"); print_memory_map(); -#ifdef CONFIG_CMDLINE_BOOL -#ifdef CONFIG_CMDLINE_OVERRIDE +#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE) strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); #else + if ((USE_PROM_CMDLINE && arcs_cmdline[0]) || + (USE_DTB_CMDLINE && !boot_command_line[0])) + strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); + + if (EXTEND_WITH_PROM && arcs_cmdline[0]) { + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); + } + +#if defined(CONFIG_CMDLINE_BOOL) if (builtin_cmdline[0]) { - strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE); - strlcat(arcs_cmdline, builtin_cmdline, COMMAND_LINE_SIZE); + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); } - strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); #endif -#else - strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); #endif strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 2fec67b..bf792e2 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -36,7 +36,6 @@ #include <asm/ucontext.h> #include <asm/cpu-features.h> #include <asm/war.h> -#include <asm/vdso.h> #include <asm/dsp.h> #include <asm/inst.h> #include <asm/msa.h> @@ -752,16 +751,15 @@ static int setup_rt_frame(void *sig_return, struct ksignal *ksig, struct mips_abi mips_abi = { #ifdef CONFIG_TRAD_SIGNALS .setup_frame = setup_frame, - .signal_return_offset = offsetof(struct mips_vdso, signal_trampoline), #endif .setup_rt_frame = setup_rt_frame, - .rt_signal_return_offset = - offsetof(struct mips_vdso, rt_signal_trampoline), .restart = __NR_restart_syscall, .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), + + .vdso = &vdso_image, }; static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) @@ -801,11 +799,11 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) } if (sig_uses_siginfo(&ksig->ka)) - ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset, + ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn, ksig, regs, oldset); else - ret = abi->setup_frame(vdso + abi->signal_return_offset, ksig, - regs, oldset); + ret = abi->setup_frame(vdso + abi->vdso->off_sigreturn, + ksig, regs, oldset); signal_setup_done(ret, ksig, 0); } diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index f7e89524..4909639 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -31,7 +31,6 @@ #include <asm/ucontext.h> #include <asm/fpu.h> #include <asm/war.h> -#include <asm/vdso.h> #include <asm/dsp.h> #include "signal-common.h" @@ -406,14 +405,12 @@ static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig, */ struct mips_abi mips_abi_32 = { .setup_frame = setup_frame_32, - .signal_return_offset = - offsetof(struct mips_vdso, o32_signal_trampoline), .setup_rt_frame = setup_rt_frame_32, - .rt_signal_return_offset = - offsetof(struct mips_vdso, o32_rt_signal_trampoline), .restart = __NR_O32_restart_syscall, .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs), .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), + + .vdso = &vdso_image_o32, }; diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 0d017fd..a7bc384 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -38,7 +38,6 @@ #include <asm/fpu.h> #include <asm/cpu-features.h> #include <asm/war.h> -#include <asm/vdso.h> #include "signal-common.h" @@ -151,11 +150,11 @@ static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig, struct mips_abi mips_abi_n32 = { .setup_rt_frame = setup_rt_frame_n32, - .rt_signal_return_offset = - offsetof(struct mips_vdso, n32_rt_signal_trampoline), .restart = __NR_N32_restart_syscall, .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), + + .vdso = &vdso_image_n32, }; diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index c889377..e04c805 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -8,6 +8,7 @@ * option) any later version. */ +#include <linux/delay.h> #include <linux/io.h> #include <linux/irqchip/mips-gic.h> #include <linux/sched.h> @@ -37,8 +38,9 @@ static unsigned core_vpe_count(unsigned core) if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) return 1; - write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF); + mips_cm_lock_other(core, 0); cfg = read_gcr_co_config() & CM_GCR_Cx_CONFIG_PVPE_MSK; + mips_cm_unlock_other(); return (cfg >> CM_GCR_Cx_CONFIG_PVPE_SHF) + 1; } @@ -133,11 +135,9 @@ static void __init cps_prepare_cpus(unsigned int max_cpus) /* * Patch the start of mips_cps_core_entry to provide: * - * v1 = CM base address * s0 = kseg0 CCA */ entry_code = (u32 *)&mips_cps_core_entry; - UASM_i_LA(&entry_code, 3, (long)mips_cm_base); uasm_i_addiu(&entry_code, 16, 0, cca); blast_dcache_range((unsigned long)&mips_cps_core_entry, (unsigned long)entry_code); @@ -190,10 +190,11 @@ err_out: static void boot_core(unsigned core) { - u32 access; + u32 access, stat, seq_state; + unsigned timeout; /* Select the appropriate core */ - write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF); + mips_cm_lock_other(core, 0); /* Set its reset vector */ write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry)); @@ -210,12 +211,36 @@ static void boot_core(unsigned core) /* Reset the core */ mips_cpc_lock_other(core); write_cpc_co_cmd(CPC_Cx_CMD_RESET); + + timeout = 100; + while (true) { + stat = read_cpc_co_stat_conf(); + seq_state = stat & CPC_Cx_STAT_CONF_SEQSTATE_MSK; + + /* U6 == coherent execution, ie. the core is up */ + if (seq_state == CPC_Cx_STAT_CONF_SEQSTATE_U6) + break; + + /* Delay a little while before we start warning */ + if (timeout) { + timeout--; + mdelay(10); + continue; + } + + pr_warn("Waiting for core %u to start... STAT_CONF=0x%x\n", + core, stat); + mdelay(1000); + } + mips_cpc_unlock_other(); } else { /* Take the core out of reset */ write_gcr_co_reset_release(0); } + mips_cm_unlock_other(); + /* The core is now powered up */ bitmap_set(core_power, core, 1); } diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c index 5f0ab5b..9b63829 100644 --- a/arch/mips/kernel/smp-gic.c +++ b/arch/mips/kernel/smp-gic.c @@ -46,9 +46,11 @@ void gic_send_ipi_single(int cpu, unsigned int action) if (mips_cpc_present() && (core != current_cpu_data.core)) { while (!cpumask_test_cpu(cpu, &cpu_coherent_mask)) { + mips_cm_lock_other(core, 0); mips_cpc_lock_other(core); write_cpc_co_cmd(CPC_Cx_CMD_PWRUP); mips_cpc_unlock_other(); + mips_cm_unlock_other(); } } diff --git a/arch/mips/kernel/spinlock_test.c b/arch/mips/kernel/spinlock_test.c index 39f7ab7..f7d8695 100644 --- a/arch/mips/kernel/spinlock_test.c +++ b/arch/mips/kernel/spinlock_test.c @@ -5,7 +5,7 @@ #include <linux/debugfs.h> #include <linux/export.h> #include <linux/spinlock.h> - +#include <asm/debug.h> static int ss_get(void *data, u64 *val) { @@ -115,8 +115,6 @@ static int multi_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(fops_multi, multi_get, NULL, "%llu\n"); - -extern struct dentry *mips_debugfs_dir; static int __init spinlock_test(void) { struct dentry *d; diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index 1ba775d..506021f 100644 --- a/arch/mips/kernel/stacktrace.c +++ b/arch/mips/kernel/stacktrace.c @@ -12,14 +12,15 @@ * Save stack-backtrace addresses into a stack_trace buffer: */ static void save_raw_context_stack(struct stack_trace *trace, - unsigned long reg29) + unsigned long reg29, int savesched) { unsigned long *sp = (unsigned long *)reg29; unsigned long addr; while (!kstack_end(sp)) { addr = *sp++; - if (__kernel_text_address(addr)) { + if (__kernel_text_address(addr) && + (savesched || !in_sched_functions(addr))) { if (trace->skip > 0) trace->skip--; else @@ -31,7 +32,7 @@ static void save_raw_context_stack(struct stack_trace *trace, } static void save_context_stack(struct stack_trace *trace, - struct task_struct *tsk, struct pt_regs *regs) + struct task_struct *tsk, struct pt_regs *regs, int savesched) { unsigned long sp = regs->regs[29]; #ifdef CONFIG_KALLSYMS @@ -43,20 +44,22 @@ static void save_context_stack(struct stack_trace *trace, (unsigned long)task_stack_page(tsk); if (stack_page && sp >= stack_page && sp <= stack_page + THREAD_SIZE - 32) - save_raw_context_stack(trace, sp); + save_raw_context_stack(trace, sp, savesched); return; } do { - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = pc; - if (trace->nr_entries >= trace->max_entries) - break; + if (savesched || !in_sched_functions(pc)) { + if (trace->skip > 0) + trace->skip--; + else + trace->entries[trace->nr_entries++] = pc; + if (trace->nr_entries >= trace->max_entries) + break; + } pc = unwind_stack(tsk, &sp, pc, &ra); } while (pc); #else - save_raw_context_stack(trace, sp); + save_raw_context_stack(trace, sp, savesched); #endif } @@ -82,6 +85,6 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) regs->cp0_epc = tsk->thread.reg31; } else prepare_frametrace(regs); - save_context_stack(trace, tsk, regs); + save_context_stack(trace, tsk, regs, tsk == current); } EXPORT_SYMBOL_GPL(save_stack_trace_tsk); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index fdb392b..886cb19 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -37,6 +37,7 @@ #include <linux/irq.h> #include <linux/perf_event.h> +#include <asm/addrspace.h> #include <asm/bootinfo.h> #include <asm/branch.h> #include <asm/break.h> @@ -1856,12 +1857,14 @@ void __noreturn nmi_exception_handler(struct pt_regs *regs) { char str[100]; + nmi_enter(); raw_notifier_call_chain(&nmi_chain, 0, regs); bust_spinlocks(1); snprintf(str, 100, "CPU%d NMI taken, CP0_EPC=%lx\n", smp_processor_id(), regs->cp0_epc); regs->cp0_epc = read_c0_errorepc(); die(str, regs); + nmi_exit(); } #define VECTORSPACING 0x100 /* for EI/VI mode */ @@ -2204,12 +2207,8 @@ void __init trap_init(void) ebase = (unsigned long) __alloc_bootmem(size, 1 << fls(size), 0); } else { -#ifdef CONFIG_KVM_GUEST -#define KVM_GUEST_KSEG0 0x40000000 - ebase = KVM_GUEST_KSEG0; -#else - ebase = CKSEG0; -#endif + ebase = CAC_BASE; + if (cpu_has_mips_r2_r6) ebase += (read_c0_ebase() & 0x3ffff000); } diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 990354d..490cea5 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -85,6 +85,7 @@ #include <asm/branch.h> #include <asm/byteorder.h> #include <asm/cop2.h> +#include <asm/debug.h> #include <asm/fpu.h> #include <asm/fpu_emulator.h> #include <asm/inst.h> @@ -2295,7 +2296,6 @@ sigbus: } #ifdef CONFIG_DEBUG_FS -extern struct dentry *mips_debugfs_dir; static int __init debugfs_unaligned(void) { struct dentry *d; diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index ed2a278..975e997 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -1,122 +1,175 @@ /* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith <alex.smith@imgtec.com> * - * Copyright (C) 2009, 2010 Cavium Networks, 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 the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. */ - -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/init.h> #include <linux/binfmts.h> #include <linux/elf.h> -#include <linux/vmalloc.h> -#include <linux/unistd.h> -#include <linux/random.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/irqchip/mips-gic.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/timekeeper_internal.h> +#include <asm/abi.h> #include <asm/vdso.h> -#include <asm/uasm.h> -#include <asm/processor.h> + +/* Kernel-provided data used by the VDSO. */ +static union mips_vdso_data vdso_data __page_aligned_data; /* - * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... + * Mapping for the VDSO data/GIC pages. The real pages are mapped manually, as + * what we map and where within the area they are mapped is determined at + * runtime. */ -#define __NR_O32_sigreturn 4119 -#define __NR_O32_rt_sigreturn 4193 -#define __NR_N32_rt_sigreturn 6211 +static struct page *no_pages[] = { NULL }; +static struct vm_special_mapping vdso_vvar_mapping = { + .name = "[vvar]", + .pages = no_pages, +}; -static struct page *vdso_page; - -static void __init install_trampoline(u32 *tramp, unsigned int sigreturn) +static void __init init_vdso_image(struct mips_vdso_image *image) { - uasm_i_addiu(&tramp, 2, 0, sigreturn); /* li v0, sigreturn */ - uasm_i_syscall(&tramp, 0); + unsigned long num_pages, i; + + BUG_ON(!PAGE_ALIGNED(image->data)); + BUG_ON(!PAGE_ALIGNED(image->size)); + + num_pages = image->size / PAGE_SIZE; + + for (i = 0; i < num_pages; i++) { + image->mapping.pages[i] = + virt_to_page(image->data + (i * PAGE_SIZE)); + } } static int __init init_vdso(void) { - struct mips_vdso *vdso; - - vdso_page = alloc_page(GFP_KERNEL); - if (!vdso_page) - panic("Cannot allocate vdso"); - - vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL); - if (!vdso) - panic("Cannot map vdso"); - clear_page(vdso); - - install_trampoline(vdso->rt_signal_trampoline, __NR_rt_sigreturn); -#ifdef CONFIG_32BIT - install_trampoline(vdso->signal_trampoline, __NR_sigreturn); -#else - install_trampoline(vdso->n32_rt_signal_trampoline, - __NR_N32_rt_sigreturn); - install_trampoline(vdso->o32_signal_trampoline, __NR_O32_sigreturn); - install_trampoline(vdso->o32_rt_signal_trampoline, - __NR_O32_rt_sigreturn); + init_vdso_image(&vdso_image); + +#ifdef CONFIG_MIPS32_O32 + init_vdso_image(&vdso_image_o32); #endif - vunmap(vdso); +#ifdef CONFIG_MIPS32_N32 + init_vdso_image(&vdso_image_n32); +#endif return 0; } subsys_initcall(init_vdso); -static unsigned long vdso_addr(unsigned long start) +void update_vsyscall(struct timekeeper *tk) { - unsigned long offset = 0UL; - - if (current->flags & PF_RANDOMIZE) { - offset = get_random_int(); - offset <<= PAGE_SHIFT; - if (TASK_IS_32BIT_ADDR) - offset &= 0xfffffful; - else - offset &= 0xffffffful; + vdso_data_write_begin(&vdso_data); + + vdso_data.xtime_sec = tk->xtime_sec; + vdso_data.xtime_nsec = tk->tkr_mono.xtime_nsec; + vdso_data.wall_to_mono_sec = tk->wall_to_monotonic.tv_sec; + vdso_data.wall_to_mono_nsec = tk->wall_to_monotonic.tv_nsec; + vdso_data.cs_shift = tk->tkr_mono.shift; + + vdso_data.clock_mode = tk->tkr_mono.clock->archdata.vdso_clock_mode; + if (vdso_data.clock_mode != VDSO_CLOCK_NONE) { + vdso_data.cs_mult = tk->tkr_mono.mult; + vdso_data.cs_cycle_last = tk->tkr_mono.cycle_last; + vdso_data.cs_mask = tk->tkr_mono.mask; } - return STACK_TOP + offset; + vdso_data_write_end(&vdso_data); +} + +void update_vsyscall_tz(void) +{ + if (vdso_data.clock_mode != VDSO_CLOCK_NONE) { + vdso_data.tz_minuteswest = sys_tz.tz_minuteswest; + vdso_data.tz_dsttime = sys_tz.tz_dsttime; + } } int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { - int ret; - unsigned long addr; + struct mips_vdso_image *image = current->thread.abi->vdso; struct mm_struct *mm = current->mm; + unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr; + struct vm_area_struct *vma; + struct resource gic_res; + int ret; down_write(&mm->mmap_sem); - addr = vdso_addr(mm->start_stack); + /* + * Determine total area size. This includes the VDSO data itself, the + * data page, and the GIC user page if present. Always create a mapping + * for the GIC user area if the GIC is present regardless of whether it + * is the current clocksource, in case it comes into use later on. We + * only map a page even though the total area is 64K, as we only need + * the counter registers at the start. + */ + gic_size = gic_present ? PAGE_SIZE : 0; + vvar_size = gic_size + PAGE_SIZE; + size = vvar_size + image->size; + + base = get_unmapped_area(NULL, 0, size, 0, 0); + if (IS_ERR_VALUE(base)) { + ret = base; + goto out; + } + + data_addr = base + gic_size; + vdso_addr = data_addr + PAGE_SIZE; - addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0); - if (IS_ERR_VALUE(addr)) { - ret = addr; - goto up_fail; + vma = _install_special_mapping(mm, base, vvar_size, + VM_READ | VM_MAYREAD, + &vdso_vvar_mapping); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto out; } - ret = install_special_mapping(mm, addr, PAGE_SIZE, - VM_READ|VM_EXEC| - VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, - &vdso_page); + /* Map GIC user page. */ + if (gic_size) { + ret = gic_get_usm_range(&gic_res); + if (ret) + goto out; + + ret = io_remap_pfn_range(vma, base, + gic_res.start >> PAGE_SHIFT, + gic_size, + pgprot_noncached(PAGE_READONLY)); + if (ret) + goto out; + } + /* Map data page. */ + ret = remap_pfn_range(vma, data_addr, + virt_to_phys(&vdso_data) >> PAGE_SHIFT, + PAGE_SIZE, PAGE_READONLY); if (ret) - goto up_fail; + goto out; + + /* Map VDSO image. */ + vma = _install_special_mapping(mm, vdso_addr, image->size, + VM_READ | VM_EXEC | + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, + &image->mapping); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto out; + } - mm->context.vdso = (void *)addr; + mm->context.vdso = (void *)vdso_addr; + ret = 0; -up_fail: +out: up_write(&mm->mmap_sem); return ret; } - -const char *arch_vma_name(struct vm_area_struct *vma) -{ - if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) - return "[vdso]"; - return NULL; -} diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 07d32a4..0a93e83 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -17,7 +17,9 @@ OUTPUT_ARCH(mips) ENTRY(kernel_entry) PHDRS { text PT_LOAD FLAGS(7); /* RWX */ +#ifndef CONFIG_CAVIUM_OCTEON_SOC note PT_NOTE FLAGS(4); /* R__ */ +#endif /* CAVIUM_OCTEON_SOC */ } #ifdef CONFIG_32BIT @@ -71,7 +73,12 @@ SECTIONS __stop___dbe_table = .; } - NOTES :text :note +#ifdef CONFIG_CAVIUM_OCTEON_SOC +#define NOTES_HEADER +#else /* CONFIG_CAVIUM_OCTEON_SOC */ +#define NOTES_HEADER :note +#endif /* CONFIG_CAVIUM_OCTEON_SOC */ + NOTES :text NOTES_HEADER .dummy : { *(.dummy) } :text _sdata = .; /* Start of data section */ @@ -132,6 +139,11 @@ SECTIONS __appended_dtb = .; /* leave space for appended DTB */ . += 0x100000; +#elif defined(CONFIG_MIPS_ELF_APPENDED_DTB) + .appended_dtb : AT(ADDR(.appended_dtb) - LOAD_OFFSET) { + *(.appended_dtb) + KEEP(*(.appended_dtb)) + } #endif /* * Align to 64K in attempt to eliminate holes before the @@ -181,6 +193,7 @@ SECTIONS DISCARDS /DISCARD/ : { /* ABI crap starts here */ + *(.MIPS.abiflags) *(.MIPS.options) *(.options) *(.pdr) |