/* SPDX-License-Identifier: GPL-2.0
 *
 * Assembly level code for mshv_vtl VTL transition
 *
 * Copyright (c) 2025, Microsoft Corporation.
 *
 * Author:
 *   Naman Jain <namjain@microsoft.com>
 */

#include <linux/linkage.h>
#include <linux/static_call_types.h>
#include <asm/asm.h>
#include <asm/asm-offsets.h>
#include <asm/frame.h>
#include "mshv-asm-offsets.h"

	.text
	.section .noinstr.text, "ax"
/*
 * void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0)
 *
 * This function is used to context switch between different Virtual Trust Levels.
 * It is marked as 'noinstr' to prevent against instrumentation and debugging facilities.
 * NMIs aren't a problem because the NMI handler saves/restores CR2 specifically to guard
 * against #PFs in NMI context clobbering the guest state.
 */
SYM_FUNC_START(__mshv_vtl_return_call)
	/* Push callee save registers */
	pushq %rbp
	mov %rsp, %rbp
	pushq %r12
	pushq %r13
	pushq %r14
	pushq %r15
	pushq %rbx

	/* register switch to VTL0 clobbers all registers except rax/rcx */
	mov %_ASM_ARG1, %rax

	/* grab rbx/rbp/rsi/rdi/r8-r15 */
	mov MSHV_VTL_CPU_CONTEXT_rbx(%rax), %rbx
	mov MSHV_VTL_CPU_CONTEXT_rbp(%rax), %rbp
	mov MSHV_VTL_CPU_CONTEXT_rsi(%rax), %rsi
	mov MSHV_VTL_CPU_CONTEXT_rdi(%rax), %rdi
	mov MSHV_VTL_CPU_CONTEXT_r8(%rax), %r8
	mov MSHV_VTL_CPU_CONTEXT_r9(%rax), %r9
	mov MSHV_VTL_CPU_CONTEXT_r10(%rax), %r10
	mov MSHV_VTL_CPU_CONTEXT_r11(%rax), %r11
	mov MSHV_VTL_CPU_CONTEXT_r12(%rax), %r12
	mov MSHV_VTL_CPU_CONTEXT_r13(%rax), %r13
	mov MSHV_VTL_CPU_CONTEXT_r14(%rax), %r14
	mov MSHV_VTL_CPU_CONTEXT_r15(%rax), %r15

	mov MSHV_VTL_CPU_CONTEXT_cr2(%rax), %rdx
	mov %rdx, %cr2
	mov MSHV_VTL_CPU_CONTEXT_rdx(%rax), %rdx

	/* stash host registers on stack */
	pushq %rax
	pushq %rcx

	xor %ecx, %ecx

	/* make a hypercall to switch VTL */
	call STATIC_CALL_TRAMP_STR(__mshv_vtl_return_hypercall)

	/* stash guest registers on stack, restore saved host copies */
	pushq %rax
	pushq %rcx
	mov 16(%rsp), %rcx
	mov 24(%rsp), %rax

	mov %rdx, MSHV_VTL_CPU_CONTEXT_rdx(%rax)
	mov %cr2, %rdx
	mov %rdx, MSHV_VTL_CPU_CONTEXT_cr2(%rax)
	pop MSHV_VTL_CPU_CONTEXT_rcx(%rax)
	pop MSHV_VTL_CPU_CONTEXT_rax(%rax)
	add $16, %rsp

	/* save rbx/rbp/rsi/rdi/r8-r15 */
	mov %rbx, MSHV_VTL_CPU_CONTEXT_rbx(%rax)
	mov %rbp, MSHV_VTL_CPU_CONTEXT_rbp(%rax)
	mov %rsi, MSHV_VTL_CPU_CONTEXT_rsi(%rax)
	mov %rdi, MSHV_VTL_CPU_CONTEXT_rdi(%rax)
	mov %r8,  MSHV_VTL_CPU_CONTEXT_r8(%rax)
	mov %r9,  MSHV_VTL_CPU_CONTEXT_r9(%rax)
	mov %r10, MSHV_VTL_CPU_CONTEXT_r10(%rax)
	mov %r11, MSHV_VTL_CPU_CONTEXT_r11(%rax)
	mov %r12, MSHV_VTL_CPU_CONTEXT_r12(%rax)
	mov %r13, MSHV_VTL_CPU_CONTEXT_r13(%rax)
	mov %r14, MSHV_VTL_CPU_CONTEXT_r14(%rax)
	mov %r15, MSHV_VTL_CPU_CONTEXT_r15(%rax)

	/* pop callee-save registers r12-r15, rbx */
	pop %rbx
	pop %r15
	pop %r14
	pop %r13
	pop %r12

	pop %rbp
	RET
SYM_FUNC_END(__mshv_vtl_return_call)
/*
 * Make sure that static_call_key symbol: __SCK____mshv_vtl_return_hypercall is accessible here.
 * Below code is inspired from __ADDRESSABLE(sym) macro. Symbol name is kept simple, to avoid
 * naming it something like "__UNIQUE_ID_addressable___SCK____mshv_vtl_return_hypercall_662.0"
 * which would otherwise have been generated by the macro.
 */
	.section	.discard.addressable,"aw"
	.align 8
	.type	mshv_vtl_return_sym, @object
	.size	mshv_vtl_return_sym, 8
mshv_vtl_return_sym:
	.quad	__SCK____mshv_vtl_return_hypercall
