arch/arm64/kvm/stacktrace.c

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

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/stacktrace.c
Extension
.c
Size
6779 bytes
Lines
247
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

#include <linux/kvm.h>
#include <linux/kvm_host.h>

#include <asm/kvm_mmu.h>
#include <asm/stacktrace/nvhe.h>

static struct stack_info stackinfo_get_overflow(void)
{
	struct kvm_nvhe_stacktrace_info *stacktrace_info
				= this_cpu_ptr_nvhe_sym(kvm_stacktrace_info);
	unsigned long low = (unsigned long)stacktrace_info->overflow_stack_base;
	unsigned long high = low + OVERFLOW_STACK_SIZE;

	return (struct stack_info) {
		.low = low,
		.high = high,
	};
}

static struct stack_info stackinfo_get_overflow_kern_va(void)
{
	unsigned long low = (unsigned long)this_cpu_ptr_nvhe_sym(overflow_stack);
	unsigned long high = low + OVERFLOW_STACK_SIZE;

	return (struct stack_info) {
		.low = low,
		.high = high,
	};
}

static struct stack_info stackinfo_get_hyp(void)
{
	struct kvm_nvhe_stacktrace_info *stacktrace_info
				= this_cpu_ptr_nvhe_sym(kvm_stacktrace_info);
	unsigned long low = (unsigned long)stacktrace_info->stack_base;
	unsigned long high = low + NVHE_STACK_SIZE;

	return (struct stack_info) {
		.low = low,
		.high = high,
	};
}

static struct stack_info stackinfo_get_hyp_kern_va(void)
{
	unsigned long low = (unsigned long)*this_cpu_ptr(&kvm_arm_hyp_stack_base);
	unsigned long high = low + NVHE_STACK_SIZE;

	return (struct stack_info) {
		.low = low,
		.high = high,
	};
}

/*
 * kvm_nvhe_stack_kern_va - Convert KVM nVHE HYP stack addresses to a kernel VAs
 *
 * The nVHE hypervisor stack is mapped in the flexible 'private' VA range, to
 * allow for guard pages below the stack. Consequently, the fixed offset address
 * translation macros won't work here.
 *
 * The kernel VA is calculated as an offset from the kernel VA of the hypervisor
 * stack base.
 *
 * Returns true on success and updates @addr to its corresponding kernel VA;
 * otherwise returns false.
 */
static bool kvm_nvhe_stack_kern_va(unsigned long *addr, unsigned long size)
{
	struct stack_info stack_hyp, stack_kern;

	stack_hyp = stackinfo_get_hyp();
	stack_kern = stackinfo_get_hyp_kern_va();
	if (stackinfo_on_stack(&stack_hyp, *addr, size))
		goto found;

	stack_hyp = stackinfo_get_overflow();
	stack_kern = stackinfo_get_overflow_kern_va();
	if (stackinfo_on_stack(&stack_hyp, *addr, size))
		goto found;

	return false;

found:
	*addr = *addr - stack_hyp.low + stack_kern.low;
	return true;
}

/*
 * Convert a KVN nVHE HYP frame record address to a kernel VA

Annotation

Implementation Notes