arch/arm64/kvm/pauth.c

Source file repositories/reference/linux-study-clean/arch/arm64/kvm/pauth.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/pauth.c
Extension
.c
Size
4778 bytes
Lines
207
Domain
Architecture Layer
Bucket
arch/arm64
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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2024 - Google LLC
 * Author: Marc Zyngier <maz@kernel.org>
 *
 * Primitive PAuth emulation for ERETAA/ERETAB.
 *
 * This code assumes that is is run from EL2, and that it is part of
 * the emulation of ERETAx for a guest hypervisor. That's a lot of
 * baked-in assumptions and shortcuts.
 *
 * Do no reuse for anything else!
 */

#include <linux/kvm_host.h>

#include <asm/gpr-num.h>
#include <asm/kvm_emulate.h>
#include <asm/pointer_auth.h>

/* PACGA Xd, Xn, Xm */
#define PACGA(d,n,m)					\
	asm volatile(__DEFINE_ASM_GPR_NUMS		\
		     ".inst 0x9AC03000          |"	\
		     "(.L__gpr_num_%[Rd] << 0)  |"	\
		     "(.L__gpr_num_%[Rn] << 5)  |"	\
		     "(.L__gpr_num_%[Rm] << 16)\n"	\
		     : [Rd] "=r" ((d))			\
		     : [Rn] "r" ((n)), [Rm] "r" ((m)))

static u64 compute_pac(struct kvm_vcpu *vcpu, u64 ptr,
		       struct ptrauth_key ikey)
{
	struct ptrauth_key gkey;
	u64 mod, pac = 0;

	preempt_disable();

	if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU))
		mod = __vcpu_sys_reg(vcpu, SP_EL2);
	else
		mod = read_sysreg(sp_el1);

	gkey.lo = read_sysreg_s(SYS_APGAKEYLO_EL1);
	gkey.hi = read_sysreg_s(SYS_APGAKEYHI_EL1);

	__ptrauth_key_install_nosync(APGA, ikey);
	isb();

	PACGA(pac, ptr, mod);
	isb();

	__ptrauth_key_install_nosync(APGA, gkey);

	preempt_enable();

	/* PAC in the top 32bits */
	return pac;
}

static bool effective_tbi(struct kvm_vcpu *vcpu, bool bit55)
{
	u64 tcr = vcpu_read_sys_reg(vcpu, TCR_EL2);
	bool tbi, tbid;

	/*
	 * Since we are authenticating an instruction address, we have
	 * to take TBID into account. If E2H==0, ignore VA[55], as
	 * TCR_EL2 only has a single TBI/TBID. If VA[55] was set in
	 * this case, this is likely a guest bug...
	 */
	if (!vcpu_el2_e2h_is_set(vcpu)) {
		tbi = tcr & BIT(20);
		tbid = tcr & BIT(29);
	} else if (bit55) {
		tbi = tcr & TCR_TBI1;
		tbid = tcr & TCR_TBID1;
	} else {
		tbi = tcr & TCR_TBI0;
		tbid = tcr & TCR_TBID0;
	}

	return tbi && !tbid;
}

static int compute_bottom_pac(struct kvm_vcpu *vcpu, bool bit55)
{
	static const int maxtxsz = 39; // Revisit these two values once
	static const int mintxsz = 16; // (if) we support TTST/LVA/LVA2
	u64 tcr = vcpu_read_sys_reg(vcpu, TCR_EL2);

Annotation

Implementation Notes