On Mon, 20 Aug 2018 19:41:56 +1000 Nicholas Piggin <npig...@gmail.com> wrote:
> +long do_slb_fault(struct pt_regs *regs, unsigned long ea) > +{ > + unsigned long id = REGION_ID(ea); > + > + /* IRQs are not reconciled here, so can't check irqs_disabled */ > + VM_WARN_ON(mfmsr() & MSR_EE); > + > + /* > + * SLB kernel faults must be very careful not to touch anything > + * that is not bolted. E.g., PACA and global variables are okay, > + * mm->context stuff is not. > + * > + * SLB user faults can access all of kernel memory, but must be > + * careful not to touch things like IRQ state because it is not > + * "reconciled" here. The difficulty is that we must use > + * fast_exception_return to return from kernel SLB faults without > + * looking at possible non-bolted memory. We could test user vs > + * kernel faults in the interrupt handler asm and do a full fault, > + * reconcile, ret_from_except for user faults which would make them > + * first class kernel code. But for performance it's probably nicer > + * if they go via fast_exception_return too. > + */ > + if (id >= KERNEL_REGION_ID) { > + return slb_allocate_kernel(ea, id); > + } else { > + struct mm_struct *mm = current->mm; > + > + if (unlikely(!mm)) > + return -EFAULT; > > - handle_multi_context_slb_miss(context, ea); > - exception_exit(prev_state); > - return; > + return slb_allocate_user(mm, ea); > + } > +} > > -slb_bad_addr: > +void do_bad_slb_fault(struct pt_regs *regs, unsigned long ea, long err) > +{ > if (user_mode(regs)) > _exception(SIGSEGV, regs, SEGV_BNDERR, ea); > else > bad_page_fault(regs, ea, SIGSEGV); > - exception_exit(prev_state); > } I knew I forgot something -- forgot to test MSR[RI] here. That can be done just by returning a different error from do_slb_fault if RI is clear, and do_bad_slb_fault will call unrecoverable_exception() if it sees that code. Thanks, Nick