arm64 fixes:
- Plug the ongoing spin_unlock_wait/spin_is_locked mess - KGDB protocol fix to sync w/ GDB - Fix MIDR-based PMU probing for old 32-bit SMP systems (OMAP4/Realview) - Minor tweaks to the fault handling path -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABCgAGBQJXY97DAAoJELescNyEwWM08fYH/3QSj8P11PPIoyu1qEs+9kj1 r7lQGLMZoI/VS7OGPmgwpbQRHk227h0Rz4UnQ4/fTharVs5Pv9iPxnFKjCRCVVGK VuI815tWC+0mKlJ4ztn8cJk7+GgWiZttAn5qWafuXQUTfqm+ywZOxfiU0+aC9Ytn k5m3G46cyAvrBcNwLFcrwavzdyVjy/O3nEQVWmzT7uXmPknr52BmWjk3VuCMPdYd tEjoRK3Nt2xMV3E4A6oIINBz1KmmqGVW3Nzx2prD0d0oGwyT+3FDlHbm+b/fn7aK ti18FPUDiNSE67enYQ1+3wEyn1Ge/0Z/lLnKJxWXv4+qk3zwsCkp4h/SkOqv3fM= =0YtF -----END PGP SIGNATURE----- Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux Pull arm64 fixes from Will Deacon: "The main things are getting kgdb up and running with upstream GDB after a protocol change was reverted and fixing our spin_unlock_wait and spin_is_locked implementations after doing some similar work with PeterZ on the qspinlock code last week. Whilst we haven't seen any failures in practice, it's still worth getting this fixed. Summary: - Plug the ongoing spin_unlock_wait/spin_is_locked mess - KGDB protocol fix to sync w/ GDB - Fix MIDR-based PMU probing for old 32-bit SMP systems (OMAP4/Realview) - Minor tweaks to the fault handling path" * tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm64: kgdb: Match pstate size with gdbserver protocol arm64: spinlock: Ensure forward-progress in spin_unlock_wait arm64: spinlock: fix spin_unlock_wait for LSE atomics arm64: spinlock: order spin_{is_locked,unlock_wait} against local locks arm: pmu: Fix non-devicetree probing arm64: mm: mark fault_info table const arm64: fix dump_instr when PAN and UAO are in use
This commit is contained in:
Коммит
9cbbef4efb
|
@ -38,25 +38,54 @@ extern int kgdb_fault_expected;
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gdb is expecting the following registers layout.
|
* gdb remote procotol (well most versions of it) expects the following
|
||||||
|
* register layout.
|
||||||
*
|
*
|
||||||
* General purpose regs:
|
* General purpose regs:
|
||||||
* r0-r30: 64 bit
|
* r0-r30: 64 bit
|
||||||
* sp,pc : 64 bit
|
* sp,pc : 64 bit
|
||||||
* pstate : 64 bit
|
* pstate : 32 bit
|
||||||
* Total: 34
|
* Total: 33 + 1
|
||||||
* FPU regs:
|
* FPU regs:
|
||||||
* f0-f31: 128 bit
|
* f0-f31: 128 bit
|
||||||
* Total: 32
|
|
||||||
* Extra regs
|
|
||||||
* fpsr & fpcr: 32 bit
|
* fpsr & fpcr: 32 bit
|
||||||
* Total: 2
|
* Total: 32 + 2
|
||||||
*
|
*
|
||||||
|
* To expand a little on the "most versions of it"... when the gdb remote
|
||||||
|
* protocol for AArch64 was developed it depended on a statement in the
|
||||||
|
* Architecture Reference Manual that claimed "SPSR_ELx is a 32-bit register".
|
||||||
|
* and, as a result, allocated only 32-bits for the PSTATE in the remote
|
||||||
|
* protocol. In fact this statement is still present in ARM DDI 0487A.i.
|
||||||
|
*
|
||||||
|
* Unfortunately "is a 32-bit register" has a very special meaning for
|
||||||
|
* system registers. It means that "the upper bits, bits[63:32], are
|
||||||
|
* RES0.". RES0 is heavily used in the ARM architecture documents as a
|
||||||
|
* way to leave space for future architecture changes. So to translate a
|
||||||
|
* little for people who don't spend their spare time reading ARM architecture
|
||||||
|
* manuals, what "is a 32-bit register" actually means in this context is
|
||||||
|
* "is a 64-bit register but one with no meaning allocated to any of the
|
||||||
|
* upper 32-bits... *yet*".
|
||||||
|
*
|
||||||
|
* Perhaps then we should not be surprised that this has led to some
|
||||||
|
* confusion. Specifically a patch, influenced by the above translation,
|
||||||
|
* that extended PSTATE to 64-bit was accepted into gdb-7.7 but the patch
|
||||||
|
* was reverted in gdb-7.8.1 and all later releases, when this was
|
||||||
|
* discovered to be an undocumented protocol change.
|
||||||
|
*
|
||||||
|
* So... it is *not* wrong for us to only allocate 32-bits to PSTATE
|
||||||
|
* here even though the kernel itself allocates 64-bits for the same
|
||||||
|
* state. That is because this bit of code tells the kernel how the gdb
|
||||||
|
* remote protocol (well most versions of it) describes the register state.
|
||||||
|
*
|
||||||
|
* Note that if you are using one of the versions of gdb that supports
|
||||||
|
* the gdb-7.7 version of the protocol you cannot use kgdb directly
|
||||||
|
* without providing a custom register description (gdb can load new
|
||||||
|
* protocol descriptions at runtime).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GP_REGS 34
|
#define _GP_REGS 33
|
||||||
#define _FP_REGS 32
|
#define _FP_REGS 32
|
||||||
#define _EXTRA_REGS 2
|
#define _EXTRA_REGS 3
|
||||||
/*
|
/*
|
||||||
* general purpose registers size in bytes.
|
* general purpose registers size in bytes.
|
||||||
* pstate is only 4 bytes. subtract 4 bytes
|
* pstate is only 4 bytes. subtract 4 bytes
|
||||||
|
|
|
@ -30,22 +30,53 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||||
{
|
{
|
||||||
unsigned int tmp;
|
unsigned int tmp;
|
||||||
arch_spinlock_t lockval;
|
arch_spinlock_t lockval;
|
||||||
|
u32 owner;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure prior spin_lock operations to other locks have completed
|
||||||
|
* on this CPU before we test whether "lock" is locked.
|
||||||
|
*/
|
||||||
|
smp_mb();
|
||||||
|
owner = READ_ONCE(lock->owner) << 16;
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
" sevl\n"
|
" sevl\n"
|
||||||
"1: wfe\n"
|
"1: wfe\n"
|
||||||
"2: ldaxr %w0, %2\n"
|
"2: ldaxr %w0, %2\n"
|
||||||
|
/* Is the lock free? */
|
||||||
" eor %w1, %w0, %w0, ror #16\n"
|
" eor %w1, %w0, %w0, ror #16\n"
|
||||||
" cbnz %w1, 1b\n"
|
" cbz %w1, 3f\n"
|
||||||
|
/* Lock taken -- has there been a subsequent unlock->lock transition? */
|
||||||
|
" eor %w1, %w3, %w0, lsl #16\n"
|
||||||
|
" cbz %w1, 1b\n"
|
||||||
|
/*
|
||||||
|
* The owner has been updated, so there was an unlock->lock
|
||||||
|
* transition that we missed. That means we can rely on the
|
||||||
|
* store-release of the unlock operation paired with the
|
||||||
|
* load-acquire of the lock operation to publish any of our
|
||||||
|
* previous stores to the new lock owner and therefore don't
|
||||||
|
* need to bother with the writeback below.
|
||||||
|
*/
|
||||||
|
" b 4f\n"
|
||||||
|
"3:\n"
|
||||||
|
/*
|
||||||
|
* Serialise against any concurrent lockers by writing back the
|
||||||
|
* unlocked lock value
|
||||||
|
*/
|
||||||
ARM64_LSE_ATOMIC_INSN(
|
ARM64_LSE_ATOMIC_INSN(
|
||||||
/* LL/SC */
|
/* LL/SC */
|
||||||
" stxr %w1, %w0, %2\n"
|
" stxr %w1, %w0, %2\n"
|
||||||
" cbnz %w1, 2b\n", /* Serialise against any concurrent lockers */
|
|
||||||
/* LSE atomics */
|
|
||||||
" nop\n"
|
" nop\n"
|
||||||
" nop\n")
|
" nop\n",
|
||||||
|
/* LSE atomics */
|
||||||
|
" mov %w1, %w0\n"
|
||||||
|
" cas %w0, %w0, %2\n"
|
||||||
|
" eor %w1, %w1, %w0\n")
|
||||||
|
/* Somebody else wrote to the lock, GOTO 10 and reload the value */
|
||||||
|
" cbnz %w1, 2b\n"
|
||||||
|
"4:"
|
||||||
: "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
|
: "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
|
||||||
:
|
: "r" (owner)
|
||||||
: "memory");
|
: "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +179,7 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
|
||||||
|
|
||||||
static inline int arch_spin_is_locked(arch_spinlock_t *lock)
|
static inline int arch_spin_is_locked(arch_spinlock_t *lock)
|
||||||
{
|
{
|
||||||
|
smp_mb(); /* See arch_spin_unlock_wait */
|
||||||
return !arch_spin_value_unlocked(READ_ONCE(*lock));
|
return !arch_spin_value_unlocked(READ_ONCE(*lock));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,17 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
|
||||||
{ "x30", 8, offsetof(struct pt_regs, regs[30])},
|
{ "x30", 8, offsetof(struct pt_regs, regs[30])},
|
||||||
{ "sp", 8, offsetof(struct pt_regs, sp)},
|
{ "sp", 8, offsetof(struct pt_regs, sp)},
|
||||||
{ "pc", 8, offsetof(struct pt_regs, pc)},
|
{ "pc", 8, offsetof(struct pt_regs, pc)},
|
||||||
{ "pstate", 8, offsetof(struct pt_regs, pstate)},
|
/*
|
||||||
|
* struct pt_regs thinks PSTATE is 64-bits wide but gdb remote
|
||||||
|
* protocol disagrees. Therefore we must extract only the lower
|
||||||
|
* 32-bits. Look for the big comment in asm/kgdb.h for more
|
||||||
|
* detail.
|
||||||
|
*/
|
||||||
|
{ "pstate", 4, offsetof(struct pt_regs, pstate)
|
||||||
|
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||||
|
+ 4
|
||||||
|
#endif
|
||||||
|
},
|
||||||
{ "v0", 16, -1 },
|
{ "v0", 16, -1 },
|
||||||
{ "v1", 16, -1 },
|
{ "v1", 16, -1 },
|
||||||
{ "v2", 16, -1 },
|
{ "v2", 16, -1 },
|
||||||
|
@ -128,6 +138,8 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
|
||||||
memset((char *)gdb_regs, 0, NUMREGBYTES);
|
memset((char *)gdb_regs, 0, NUMREGBYTES);
|
||||||
thread_regs = task_pt_regs(task);
|
thread_regs = task_pt_regs(task);
|
||||||
memcpy((void *)gdb_regs, (void *)thread_regs->regs, GP_REG_BYTES);
|
memcpy((void *)gdb_regs, (void *)thread_regs->regs, GP_REG_BYTES);
|
||||||
|
/* Special case for PSTATE (check comments in asm/kgdb.h for details) */
|
||||||
|
dbg_get_reg(33, gdb_regs + GP_REG_BYTES, thread_regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
|
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
|
||||||
|
|
|
@ -64,8 +64,7 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to switch to kernel mode so that we can use __get_user
|
* We need to switch to kernel mode so that we can use __get_user
|
||||||
* to safely read from kernel space. Note that we now dump the
|
* to safely read from kernel space.
|
||||||
* code first, just in case the backtrace kills us.
|
|
||||||
*/
|
*/
|
||||||
fs = get_fs();
|
fs = get_fs();
|
||||||
set_fs(KERNEL_DS);
|
set_fs(KERNEL_DS);
|
||||||
|
@ -111,21 +110,12 @@ static void dump_backtrace_entry(unsigned long where)
|
||||||
print_ip_sym(where);
|
print_ip_sym(where);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_instr(const char *lvl, struct pt_regs *regs)
|
static void __dump_instr(const char *lvl, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long addr = instruction_pointer(regs);
|
unsigned long addr = instruction_pointer(regs);
|
||||||
mm_segment_t fs;
|
|
||||||
char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
|
char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
|
||||||
* We need to switch to kernel mode so that we can use __get_user
|
|
||||||
* to safely read from kernel space. Note that we now dump the
|
|
||||||
* code first, just in case the backtrace kills us.
|
|
||||||
*/
|
|
||||||
fs = get_fs();
|
|
||||||
set_fs(KERNEL_DS);
|
|
||||||
|
|
||||||
for (i = -4; i < 1; i++) {
|
for (i = -4; i < 1; i++) {
|
||||||
unsigned int val, bad;
|
unsigned int val, bad;
|
||||||
|
|
||||||
|
@ -139,8 +129,18 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printk("%sCode: %s\n", lvl, str);
|
printk("%sCode: %s\n", lvl, str);
|
||||||
|
}
|
||||||
|
|
||||||
set_fs(fs);
|
static void dump_instr(const char *lvl, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
if (!user_mode(regs)) {
|
||||||
|
mm_segment_t fs = get_fs();
|
||||||
|
set_fs(KERNEL_DS);
|
||||||
|
__dump_instr(lvl, regs);
|
||||||
|
set_fs(fs);
|
||||||
|
} else {
|
||||||
|
__dump_instr(lvl, regs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
|
static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
|
||||||
|
|
|
@ -441,7 +441,7 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fault_info {
|
static const struct fault_info {
|
||||||
int (*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs);
|
int (*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs);
|
||||||
int sig;
|
int sig;
|
||||||
int code;
|
int code;
|
||||||
|
|
|
@ -1010,8 +1010,8 @@ int arm_pmu_device_probe(struct platform_device *pdev,
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = init_fn(pmu);
|
ret = init_fn(pmu);
|
||||||
} else {
|
} else {
|
||||||
ret = probe_current_pmu(pmu, probe_table);
|
|
||||||
cpumask_setall(&pmu->supported_cpus);
|
cpumask_setall(&pmu->supported_cpus);
|
||||||
|
ret = probe_current_pmu(pmu, probe_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче