6
6
7
7
use super :: idt:: common:: X86ExceptionContext ;
8
8
use crate :: cpu:: cpuid:: { cpuid_table_raw, CpuidLeaf } ;
9
- use crate :: cpu:: extable:: handle_exception_table;
10
9
use crate :: cpu:: insn:: { insn_fetch, Instruction } ;
10
+ use crate :: cpu:: percpu:: this_cpu_mut;
11
11
use crate :: cpu:: registers:: X86GeneralRegs ;
12
12
use crate :: debug:: gdbstub:: svsm_gdbstub:: handle_db_exception;
13
13
use crate :: error:: SvsmError ;
14
+ use crate :: sev:: ghcb:: { GHCBIOSize , GHCB } ;
14
15
use core:: fmt;
15
16
16
17
pub const SVM_EXIT_EXCP_BASE : usize = 0x40 ;
17
18
pub const SVM_EXIT_LAST_EXCP : usize = 0x5f ;
18
19
pub const SVM_EXIT_CPUID : usize = 0x72 ;
20
+ pub const SVM_EXIT_IOIO : usize = 0x7b ;
19
21
pub const X86_TRAP_DB : usize = 0x01 ;
20
22
pub const X86_TRAP : usize = SVM_EXIT_EXCP_BASE + X86_TRAP_DB ;
21
23
@@ -52,7 +54,7 @@ pub fn stage2_handle_vc_exception(ctx: &mut X86ExceptionContext) {
52
54
let err = ctx. error_code ;
53
55
let rip = ctx. frame . rip ;
54
56
55
- vc_decode_insn ( ctx) . unwrap_or_else ( |e| {
57
+ let insn = vc_decode_insn ( ctx) . unwrap_or_else ( |e| {
56
58
panic ! (
57
59
"Unhandled #VC exception RIP {:#018x} error code: {:#018x} error {:?}" ,
58
60
rip, err, e
@@ -77,7 +79,48 @@ pub fn stage2_handle_vc_exception(ctx: &mut X86ExceptionContext) {
77
79
)
78
80
} ) ;
79
81
80
- vc_finish_insn ( ctx) ;
82
+ vc_finish_insn ( ctx, & insn) ;
83
+ }
84
+
85
+ pub fn handle_vc_exception ( ctx : & mut X86ExceptionContext ) {
86
+ let error_code = ctx. error_code ;
87
+ let rip = ctx. frame . rip ;
88
+
89
+ /*
90
+ * To handle NAE events, we're supposed to reset the VALID_BITMAP field of the GHCB.
91
+ * This is currently only relevant for IOIO handling. This field is currently reset in
92
+ * the ioio_{in,ou} methods but it would be better to move the reset out of the different
93
+ * handlers.
94
+ */
95
+ let ghcb = this_cpu_mut ( ) . ghcb ( ) ;
96
+
97
+ let insn = vc_decode_insn ( ctx) . unwrap_or_else ( |e| {
98
+ panic ! (
99
+ "Unhandled #VC exception RIP {:#018x} error code: {:#018x} error {:?}" ,
100
+ rip, error_code, e
101
+ )
102
+ } ) ;
103
+
104
+ match error_code {
105
+ // If the debugger is enabled then handle the DB exception
106
+ // by directly invoking the exception handler
107
+ X86_TRAP_DB => {
108
+ handle_db_exception ( ctx) ;
109
+ Ok ( ( ) )
110
+ }
111
+
112
+ SVM_EXIT_CPUID => handle_cpuid ( ctx) ,
113
+ SVM_EXIT_IOIO => handle_ioio ( ctx, ghcb, & insn) ,
114
+ _ => Err ( SvsmError :: Vc ( VcError :: Unsupported ) ) ,
115
+ }
116
+ . unwrap_or_else ( |err| {
117
+ panic ! (
118
+ "Unhandled #VC exception RIP {:#018x} error code: {:#018x}: #VC error: {:?}" ,
119
+ rip, error_code, err
120
+ )
121
+ } ) ;
122
+
123
+ vc_finish_insn ( ctx, & insn) ;
81
124
}
82
125
83
126
fn handle_cpuid ( ctx : & mut X86ExceptionContext ) -> Result < ( ) , SvsmError > {
@@ -117,13 +160,55 @@ fn snp_cpuid(regs: &mut X86GeneralRegs) -> Result<(), SvsmError> {
117
160
Ok ( ( ) )
118
161
}
119
162
120
- fn vc_finish_insn ( ctx : & mut X86ExceptionContext ) {
121
- ctx. frame . rip += ctx. insn . length ;
163
+ fn vc_finish_insn ( ctx : & mut X86ExceptionContext , insn : & Instruction ) {
164
+ ctx. frame . rip += insn. length ;
165
+ }
166
+
167
+ fn handle_ioio (
168
+ ctx : & mut X86ExceptionContext ,
169
+ ghcb : & mut GHCB ,
170
+ insn : & Instruction ,
171
+ ) -> Result < ( ) , SvsmError > {
172
+ let port: u16 = ( ctx. regs . rdx & 0xffff ) as u16 ;
173
+ let out_value: u64 = ctx. regs . rax as u64 ;
174
+
175
+ match insn. opcode . bytes [ 0 ] {
176
+ 0x6C ..=0x6F | 0xE4 ..=0xE7 => Err ( SvsmError :: Vc ( VcError :: Unsupported ) ) ,
177
+ 0xEC => {
178
+ let ret = ghcb. ioio_in ( port, GHCBIOSize :: Size8 ) ?;
179
+ ctx. regs . rax = ( ret & 0xff ) as usize ;
180
+ Ok ( ( ) )
181
+ }
182
+ 0xED => {
183
+ let mut size: GHCBIOSize = GHCBIOSize :: Size32 ;
184
+ let mut mask = 0xffffffff ;
185
+ if insn. prefixes . nb_bytes > 0 {
186
+ // inw instruction has a 0x66 operand-size prefix for word-sized operands.
187
+ size = GHCBIOSize :: Size16 ;
188
+ mask = 0xffff ;
189
+ }
190
+
191
+ let ret = ghcb. ioio_in ( port, size) ?;
192
+ ctx. regs . rax = ( ret & mask) as usize ;
193
+ Ok ( ( ) )
194
+ }
195
+ 0xEE => ghcb. ioio_out ( port, GHCBIOSize :: Size8 , out_value) ,
196
+ 0xEF => {
197
+ let mut size: GHCBIOSize = GHCBIOSize :: Size32 ;
198
+ if insn. prefixes . nb_bytes > 0 {
199
+ // outw instruction has a 0x66 operand-size prefix for word-sized operands.
200
+ size = GHCBIOSize :: Size16 ;
201
+ }
202
+
203
+ ghcb. ioio_out ( port, size, out_value)
204
+ }
205
+ _ => Err ( SvsmError :: Vc ( VcError :: DecodeFailed ) ) ,
206
+ }
122
207
}
123
208
124
- fn vc_decode_insn ( ctx : & mut X86ExceptionContext ) -> Result < ( ) , SvsmError > {
209
+ fn vc_decode_insn ( ctx : & mut X86ExceptionContext ) -> Result < Instruction , SvsmError > {
125
210
if !vc_decoding_needed ( ctx. error_code ) {
126
- return Ok ( ( ) ) ;
211
+ return Ok ( Instruction :: default ( ) ) ;
127
212
}
128
213
129
214
/*
@@ -135,30 +220,9 @@ fn vc_decode_insn(ctx: &mut X86ExceptionContext) -> Result<(), SvsmError> {
135
220
let mut insn = Instruction :: new ( insn_raw) ;
136
221
insn. decode ( ) ?;
137
222
138
- ctx. insn = insn;
139
-
140
- Ok ( ( ) )
223
+ Ok ( insn)
141
224
}
142
225
143
226
fn vc_decoding_needed ( error_code : usize ) -> bool {
144
227
!( SVM_EXIT_EXCP_BASE ..=SVM_EXIT_LAST_EXCP ) . contains ( & error_code)
145
228
}
146
-
147
- pub fn handle_vc_exception ( ctx : & mut X86ExceptionContext ) {
148
- let err = ctx. error_code ;
149
- let rip = ctx. frame . rip ;
150
-
151
- // If the debugger is enabled then handle the DB exception
152
- // by directly invoking the exception hander
153
- if err == ( SVM_EXIT_EXCP_BASE + X86_TRAP_DB ) {
154
- handle_db_exception ( ctx) ;
155
- return ;
156
- }
157
-
158
- if !handle_exception_table ( ctx) {
159
- panic ! (
160
- "Unhandled #VC exception RIP {:#018x} error code: {:#018x}" ,
161
- rip, err
162
- ) ;
163
- }
164
- }
0 commit comments