hc
2023-10-25 6c2073b7aa40e29d0eca7d571dd7bc590c7ecaa7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
 * Copyright (C) 2015 - ARM Ltd
 * Author: Marc Zyngier <marc.zyngier@arm.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
#include <linux/linkage.h>
 
#include <asm/alternative.h>
#include <asm/asm-offsets.h>
#include <asm/assembler.h>
#include <asm/fpsimdmacros.h>
#include <asm/kvm.h>
#include <asm/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
 
#define CPU_GP_REG_OFFSET(x)    (CPU_GP_REGS + x)
#define CPU_XREG_OFFSET(x)    CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
 
   .text
   .pushsection    .hyp.text, "ax"
 
/*
 * We treat x18 as callee-saved as the host may use it as a platform
 * register (e.g. for shadow call stack).
 */
.macro save_callee_saved_regs ctxt
   str    x18,      [\ctxt, #CPU_XREG_OFFSET(18)]
   stp    x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
   stp    x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
   stp    x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
   stp    x25, x26, [\ctxt, #CPU_XREG_OFFSET(25)]
   stp    x27, x28, [\ctxt, #CPU_XREG_OFFSET(27)]
   stp    x29, lr,  [\ctxt, #CPU_XREG_OFFSET(29)]
.endm
 
.macro restore_callee_saved_regs ctxt
   // We require \ctxt is not x18-x28
   ldr    x18,      [\ctxt, #CPU_XREG_OFFSET(18)]
   ldp    x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
   ldp    x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
   ldp    x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
   ldp    x25, x26, [\ctxt, #CPU_XREG_OFFSET(25)]
   ldp    x27, x28, [\ctxt, #CPU_XREG_OFFSET(27)]
   ldp    x29, lr,  [\ctxt, #CPU_XREG_OFFSET(29)]
.endm
 
/*
 * u64 __guest_enter(struct kvm_vcpu *vcpu,
 *             struct kvm_cpu_context *host_ctxt);
 */
ENTRY(__guest_enter)
   // x0: vcpu
   // x1: host context
   // x2-x17: clobbered by macros
   // x29: guest context
 
   // Store the host regs
   save_callee_saved_regs x1
 
   // Now the host state is stored if we have a pending RAS SError it must
   // affect the host. If any asynchronous exception is pending we defer
   // the guest entry. The DSB isn't necessary before v8.2 as any SError
   // would be fatal.
alternative_if ARM64_HAS_RAS_EXTN
   dsb    nshst
   isb
alternative_else_nop_endif
   mrs    x1, isr_el1
   cbz    x1,  1f
   mov    x0, #ARM_EXCEPTION_IRQ
   ret
 
1:
   add    x29, x0, #VCPU_CONTEXT
 
   // Restore guest regs x0-x17
   ldp    x0, x1,   [x29, #CPU_XREG_OFFSET(0)]
   ldp    x2, x3,   [x29, #CPU_XREG_OFFSET(2)]
   ldp    x4, x5,   [x29, #CPU_XREG_OFFSET(4)]
   ldp    x6, x7,   [x29, #CPU_XREG_OFFSET(6)]
   ldp    x8, x9,   [x29, #CPU_XREG_OFFSET(8)]
   ldp    x10, x11, [x29, #CPU_XREG_OFFSET(10)]
   ldp    x12, x13, [x29, #CPU_XREG_OFFSET(12)]
   ldp    x14, x15, [x29, #CPU_XREG_OFFSET(14)]
   ldp    x16, x17, [x29, #CPU_XREG_OFFSET(16)]
 
   // Restore guest regs x18-x29, lr
   restore_callee_saved_regs x29
 
   // Do not touch any register after this!
   eret
   sb
ENDPROC(__guest_enter)
 
ENTRY(__guest_exit)
   // x0: return code
   // x1: vcpu
   // x2-x29,lr: vcpu regs
   // vcpu x0-x1 on the stack
 
   add    x1, x1, #VCPU_CONTEXT
 
   ALTERNATIVE(nop, SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
 
   // Store the guest regs x2 and x3
   stp    x2, x3,   [x1, #CPU_XREG_OFFSET(2)]
 
   // Retrieve the guest regs x0-x1 from the stack
   ldp    x2, x3, [sp], #16    // x0, x1
 
   // Store the guest regs x0-x1 and x4-x17
   stp    x2, x3,   [x1, #CPU_XREG_OFFSET(0)]
   stp    x4, x5,   [x1, #CPU_XREG_OFFSET(4)]
   stp    x6, x7,   [x1, #CPU_XREG_OFFSET(6)]
   stp    x8, x9,   [x1, #CPU_XREG_OFFSET(8)]
   stp    x10, x11, [x1, #CPU_XREG_OFFSET(10)]
   stp    x12, x13, [x1, #CPU_XREG_OFFSET(12)]
   stp    x14, x15, [x1, #CPU_XREG_OFFSET(14)]
   stp    x16, x17, [x1, #CPU_XREG_OFFSET(16)]
 
   // Store the guest regs x18-x29, lr
   save_callee_saved_regs x1
 
   get_host_ctxt    x2, x3
 
   // Now restore the host regs
   restore_callee_saved_regs x2
 
alternative_if ARM64_HAS_RAS_EXTN
   // If we have the RAS extensions we can consume a pending error
   // without an unmask-SError and isb.
   esb
   mrs_s    x2, SYS_DISR_EL1
   str    x2, [x1, #(VCPU_FAULT_DISR - VCPU_CONTEXT)]
   cbz    x2, 1f
   msr_s    SYS_DISR_EL1, xzr
   orr    x0, x0, #(1<<ARM_EXIT_WITH_SERROR_BIT)
1:    ret
alternative_else
   // If we have a pending asynchronous abort, now is the
   // time to find out. From your VAXorcist book, page 666:
   // "Threaten me not, oh Evil one!  For I speak with
   // the power of DEC, and I command thee to show thyself!"
   mrs    x2, elr_el2
   mrs    x3, esr_el2
   mrs    x4, spsr_el2
   mov    x5, x0
 
   dsb    sy        // Synchronize against in-flight ld/st
   nop
   msr    daifclr, #4    // Unmask aborts
alternative_endif
 
   // This is our single instruction exception window. A pending
   // SError is guaranteed to occur at the earliest when we unmask
   // it, and at the latest just after the ISB.
abort_guest_exit_start:
 
   isb
 
abort_guest_exit_end:
   msr    daifset, #4    // Mask aborts
   ret
 
   _kvm_extable    abort_guest_exit_start, 9997f
   _kvm_extable    abort_guest_exit_end, 9997f
9997:
   msr    daifset, #4    // Mask aborts
   mov    x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
 
   // restore the EL1 exception context so that we can report some
   // information. Merge the exception code with the SError pending bit.
   msr    elr_el2, x2
   msr    esr_el2, x3
   msr    spsr_el2, x4
   orr    x0, x0, x5
1:    ret
ENDPROC(__guest_exit)