Context |
Check |
Description |
snowpatch_ozlabs/apply_patch |
warning
|
Failed to apply on branch powerpc/merge (54dc28ff5e0b3585224d49a31b53e030342ca5c3)
|
snowpatch_ozlabs/apply_patch |
warning
|
Failed to apply on branch powerpc/next (45591da765885f7320a111d290b3a28a23eed359)
|
snowpatch_ozlabs/apply_patch |
warning
|
Failed to apply on branch linus/master (51184ae37e0518fd90cb437a2fbc953ae558cd0d)
|
snowpatch_ozlabs/apply_patch |
warning
|
Failed to apply on branch powerpc/fixes (5990cdee689c6885b27c6d969a3d58b09002b0bc)
|
snowpatch_ozlabs/apply_patch |
warning
|
Failed to apply on branch linux-next (8bdabd09ec86a993419c8c98a4f34c12bc902c6c)
|
snowpatch_ozlabs/apply_patch |
fail
|
Failed to apply to any branch
|
@@ -583,6 +583,8 @@ static inline int check_io_access(struct pt_regs *regs)
#define REASON_ILLEGAL (ESR_PIL | ESR_PUO)
#define REASON_PRIVILEGED ESR_PPR
#define REASON_TRAP ESR_PTR
+#define REASON_PREFIXED 0
+#define REASON_BOUNDARY 0
/* single-step stuff */
#define single_stepping(regs) (current->thread.debug.dbcr0 & DBCR0_IC)
@@ -597,12 +599,16 @@ static inline int check_io_access(struct pt_regs *regs)
#define REASON_ILLEGAL SRR1_PROGILL
#define REASON_PRIVILEGED SRR1_PROGPRIV
#define REASON_TRAP SRR1_PROGTRAP
+#define REASON_PREFIXED SRR1_PREFIXED
+#define REASON_BOUNDARY SRR1_BOUNDARY
#define single_stepping(regs) ((regs)->msr & MSR_SE)
#define clear_single_step(regs) ((regs)->msr &= ~MSR_SE)
#define clear_br_trace(regs) ((regs)->msr &= ~MSR_BE)
#endif
+#define inst_length(reason) (((reason) & REASON_PREFIXED) ? 8 : 4)
+
#if defined(CONFIG_E500)
int machine_check_e500mc(struct pt_regs *regs)
{
@@ -1593,11 +1599,20 @@ void alignment_exception(struct pt_regs *regs)
{
enum ctx_state prev_state = exception_enter();
int sig, code, fixed = 0;
+ unsigned long reason;
/* We restore the interrupt state now */
if (!arch_irq_disabled_regs(regs))
local_irq_enable();
+ reason = get_reason(regs);
+
+ if (reason & REASON_BOUNDARY) {
+ sig = SIGBUS;
+ code = BUS_ADRALN;
+ goto bad;
+ }
+
if (tm_abort_check(regs, TM_CAUSE_ALIGNMENT | TM_CAUSE_PERSISTENT))
goto bail;
@@ -1606,7 +1621,8 @@ void alignment_exception(struct pt_regs *regs)
fixed = fix_alignment(regs);
if (fixed == 1) {
- regs->nip += 4; /* skip over emulated instruction */
+ /* skip over emulated instruction */
+ regs->nip += inst_length(reason);
emulate_single_step(regs);
goto bail;
}
@@ -1619,6 +1635,7 @@ void alignment_exception(struct pt_regs *regs)
sig = SIGBUS;
code = BUS_ADRALN;
}
+bad:
if (user_mode(regs))
_exception(sig, regs, code, regs->dar);
else
If a prefixed instruction results in an alignment exception, the SRR1_PREFIXED bit is set. The handler attempts to emulate the responsible instruction and then increment the NIP past it. Use SRR1_PREFIXED to determine by how much the NIP should be incremented. Prefixed instructions are not permitted to cross 64-byte boundaries. If they do the alignment interrupt is invoked with SRR1 BOUNDARY bit set. If this occurs send a SIGBUS to the offending process if in user mode. If in kernel mode call bad_page_fault(). Signed-off-by: Jordan Niethe <jniethe5@gmail.com> --- v2: - Move __get_user_instr() and __get_user_instr_inatomic() to this commit (previously in "powerpc sstep: Prepare to support prefixed instructions"). - Rename sufx to suffix - Use a macro for calculating instruction length v3: Move __get_user_{instr(), instr_inatomic()} up with the other get_user definitions and remove nested if. v4: Rolled into "Add prefixed instructions to instruction data type" v5: Only one definition of inst_length() --- arch/powerpc/kernel/traps.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)