| /* 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 |