arch/powerpc/kernel/interrupt.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kernel/interrupt.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kernel/interrupt.c
Extension
.c
Size
8785 bytes
Lines
348
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (must_hard_disable) {
			local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
			__hard_RI_enable();
		}
		trace_hardirqs_off();

		return false;
	}
#endif
	return true;
}

/*
 * This should be called after a syscall returns, with r3 the return value
 * from the syscall. If this function returns non-zero, the system call
 * exit assembly should additionally load all GPR registers and CTR and XER
 * from the interrupt frame.
 *
 * The function graph tracer can not trace the return side of this function,
 * because RI=0 and soft mask state is "unreconciled", so it is marked notrace.
 */
notrace unsigned long syscall_exit_prepare(unsigned long r3,
					   struct pt_regs *regs,
					   long scv)
{
	unsigned long ti_flags;
	bool is_not_scv = !IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !scv;

	kuap_assert_locked();

	regs->result = r3;
	regs->exit_flags = 0;

	ti_flags = read_thread_flags();

	if (unlikely(r3 >= (unsigned long)-MAX_ERRNO) && is_not_scv) {
		if (likely(!(ti_flags & (_TIF_NOERROR | _TIF_RESTOREALL)))) {
			r3 = -r3;
			regs->ccr |= 0x10000000; /* Set SO bit in CR */
		}
	}

	if (unlikely(ti_flags & _TIF_PERSYSCALL_MASK)) {
		if (ti_flags & _TIF_RESTOREALL)
			regs->exit_flags = _TIF_RESTOREALL;
		else
			regs->gpr[3] = r3;
		clear_bits(_TIF_PERSYSCALL_MASK, &current_thread_info()->flags);
	} else {
		regs->gpr[3] = r3;
	}

	if (unlikely(ti_flags & _TIF_SYSCALL_DOTRACE)) {
		regs->exit_flags |= _TIF_RESTOREALL;
	}

	syscall_exit_to_user_mode(regs);

again:
	user_enter_irqoff();
	if (!prep_irq_for_enabled_exit(true)) {
		user_exit_irqoff();
		local_irq_enable();
		local_irq_disable();
		goto again;
	}

	/* Restore user access locks last */
	kuap_user_restore(regs);

#ifdef CONFIG_PPC64
	regs->exit_result = regs->exit_flags;
#endif

	return regs->exit_flags;
}

#ifdef CONFIG_PPC64
notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *regs)
{
	/*
	 * This is called when detecting a soft-pending interrupt as well as
	 * an alternate-return interrupt. So we can't just have the alternate
	 * return path clear SRR1[MSR] and set PACA_IRQ_HARD_DIS (unless
	 * the soft-pending case were to fix things up as well). RI might be
	 * disabled, in which case it gets re-enabled by __hard_irq_disable().
	 */
	__hard_irq_disable();
	local_paca->irq_happened |= PACA_IRQ_HARD_DIS;

Annotation

Implementation Notes