arch/arm64/kvm/hyp/nvhe/debug-sr.c

Source file repositories/reference/linux-study-clean/arch/arm64/kvm/hyp/nvhe/debug-sr.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/hyp/nvhe/debug-sr.c
Extension
.c
Size
5270 bytes
Lines
222
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

if (cpus_have_final_cap(ARM64_WORKAROUND_2064142)) {
			/*
			 * Some CPUs are so good, we have to drain 'em
			 * twice.
			 */
			tsb_csync();
			dsb(nsh);
		}

		/*
		 * Ensure that the Trace Buffer Unit is disabled before
		 * we start mucking with the stage-2 and trap
		 * configuration.
		 */
		isb();
	}
}

static bool __trace_needs_switch(void)
{
	return host_data_test_flag(TRBE_ENABLED) ||
	       host_data_test_flag(EL1_TRACING_CONFIGURED);
}

static void __trace_switch_to_guest(void)
{
	/* Unsupported with TRBE so disable */
	if (host_data_test_flag(TRBE_ENABLED))
		*host_data_ptr(trfcr_while_in_guest) = 0;

	__trace_do_switch(host_data_ptr(host_debug_state.trfcr_el1),
			  *host_data_ptr(trfcr_while_in_guest));
	__trace_drain_and_disable();
}

static void __trace_switch_to_host(void)
{
	u64 trblimitr_el1 = *host_data_ptr(host_debug_state.trblimitr_el1);

	if (trblimitr_el1 & TRBLIMITR_EL1_E) {
		/* Re-enable the Trace Buffer Unit for the host. */
		write_sysreg_s(trblimitr_el1, SYS_TRBLIMITR_EL1);
		isb();
		if (cpus_have_final_cap(ARM64_WORKAROUND_2038923)) {
			/*
			 * Make sure the unit is re-enabled before we
			 * poke TRFCR.
			 */
			isb();
		}
	}

	__trace_do_switch(host_data_ptr(trfcr_while_in_guest),
			  *host_data_ptr(host_debug_state.trfcr_el1));
}

static void __debug_save_brbe(void)
{
	u64 *brbcr_el1 = host_data_ptr(host_debug_state.brbcr_el1);

	*brbcr_el1 = 0;

	/* Check if the BRBE is enabled */
	if (!(read_sysreg_el1(SYS_BRBCR) & (BRBCR_ELx_E0BRE | BRBCR_ELx_ExBRE)))
		return;

	/*
	 * Prohibit branch record generation while we are in guest.
	 * Since access to BRBCR_EL1 is trapped, the guest can't
	 * modify the filtering set by the host.
	 */
	*brbcr_el1 = read_sysreg_el1(SYS_BRBCR);
	write_sysreg_el1(0, SYS_BRBCR);
}

static void __debug_restore_brbe(void)
{
	u64 brbcr_el1 = *host_data_ptr(host_debug_state.brbcr_el1);

	if (!brbcr_el1)
		return;

	/* Restore BRBE controls */
	write_sysreg_el1(brbcr_el1, SYS_BRBCR);
}

void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
{
	/* Disable and flush SPE data generation */
	if (host_data_test_flag(HAS_SPE))

Annotation

Implementation Notes