github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/host/isr.c (about) 1 /* 2 * Copyright (c) 2013 Intel Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 * See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 15 #include "vmm_defs.h" 16 #include "libc.h" 17 #include "hw_utils.h" 18 #include "hw_setjmp.h" 19 #include "trial_exec.h" 20 #include "guest_cpu.h" 21 #include "idt.h" 22 #include "isr.h" 23 #include "vmm_dbg.h" 24 #include "vmcs_api.h" 25 #include "scheduler.h" 26 #include "file_codes.h" 27 28 #define VMM_DEADLOOP() VMM_DEADLOOP_LOG(ISR_C) 29 #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(ISR_C, __condition) 30 #ifdef JLMDEBUG 31 #include "jlmdebug.h" 32 #endif 33 34 35 extern ISR_PARAMETERS_ON_STACK *g_exception_stack; 36 37 38 #define INTERRUPT_COUNT_VECTORS 256 39 #define EXCEPTION_COUNT_VECTORS 32 40 41 #define ERROR_CODE_EXT_BIT 0x1 42 #define ERROR_CODE_IN_IDT 0x2 43 #define ERROR_CODE_TI 0x4 44 45 #define RFLAGS_IF 9 // Interrupt flag in RFLAGS register 46 47 typedef enum { 48 INTERRUPT_CLASS, 49 ABORT_CLASS, 50 FAULT_CLASS, 51 TRAP_CLASS, 52 RESERVED_CLASS 53 } EXCEPTION_CLASS_ENUM; 54 55 56 static VMM_ISR_HANDLER isr_table[INTERRUPT_COUNT_VECTORS]; 57 58 static const char *exception_message[] = { 59 "Divide Error", 60 "Debug Breakpoint", 61 "NMI", 62 "Breakpoint", 63 "Overflow", 64 "Bound Range Exceeded", 65 "Undefined Opcode", 66 "No Math Coprocessor", 67 "Double Fault", 68 "Reserved 0x09", 69 "Invalid Task Segment selector", 70 "Segment Not present", 71 "Stack Segment Fault", 72 "General Protection Fault", 73 "Page Fault", 74 "Reserved 0x0f", 75 "Math Fault", 76 "Alignment Check", 77 "Machine Check", 78 "SIMD Floating Point Numeric Error", 79 "Reserved SIMD Floating Point Numeric Error" 80 }; 81 82 const UINT8 exception_class[] = { 83 FAULT_CLASS, //Divide Error 84 TRAP_CLASS, //Debug Breakpoint 85 INTERRUPT_CLASS,//NMI 86 TRAP_CLASS, //Breakpoint 87 TRAP_CLASS, //Overflow 88 FAULT_CLASS, //Bound Range Exceeded 89 FAULT_CLASS, //Undefined Opcode 90 FAULT_CLASS, //No Math Coprocessor 91 ABORT_CLASS, //Double Fault 92 RESERVED_CLASS, //Reserved 0x09 93 FAULT_CLASS, //Invalid Task Segment selector 94 FAULT_CLASS, //Segment Not present 95 FAULT_CLASS, //Stack Segment Fault 96 FAULT_CLASS, //General Protection Fault 97 FAULT_CLASS, //Page Fault 98 RESERVED_CLASS, //Reserved 0x0f 99 FAULT_CLASS, //Math Fault 100 FAULT_CLASS, //Alignment Check 101 ABORT_CLASS, //Machine Check 102 FAULT_CLASS, //SIMD Floating Point Numeric Error 103 RESERVED_CLASS, //Reserved SIMD Floating Point Numeric Error 104 }; 105 106 107 /* 108 * FUNCTION : isr_c_handler() 109 * PURPOSE : Generic ISR handler which calls registered 110 * : vector specific handlers. 111 * : Clear FLAGS.IF 112 * ARGUMENTS : IN ISR_PARAMETERS_ON_STACK *p_stack - points 113 * : to the stack, where FLAGS register stored 114 * : as a part of return from interrupt cycle 115 */ 116 void isr_c_handler(IN ISR_PARAMETERS_ON_STACK *p_stack) 117 { 118 VECTOR_ID vector_id = (VECTOR_ID) p_stack->a.vector_id; 119 BOOLEAN interrut_during_emulation; 120 121 if (FALSE == (interrut_during_emulation = gcpu_process_interrupt(vector_id))) { 122 BOOLEAN handled = FALSE; 123 // if it is a fault exception, 124 // skip faulty instruction in case there is instruction length supplied 125 if (vector_id < NELEMENTS(exception_class) && FAULT_CLASS == exception_class[vector_id]) { 126 TRIAL_DATA *p_trial_data = trial_execution_get_last(); 127 128 if (NULL != p_trial_data) { 129 p_stack->u.errcode_exception.ip = (ADDRESS)hw_exception_post_handler; 130 p_stack->u.errcode_exception.sp = (ADDRESS)p_trial_data->saved_env; 131 p_trial_data->fault_vector = vector_id; 132 p_trial_data->error_code= (UINT32) p_stack->u.errcode_exception.errcode; 133 handled = TRUE; 134 } 135 } 136 if (FALSE == handled) { 137 if (NULL == isr_table[vector_id]) { 138 VMM_LOG(mask_anonymous, level_trace,"Interrupt vector(%d) handler is not registered\n", vector_id); 139 } 140 else { 141 (isr_table[vector_id])(p_stack); 142 } 143 } 144 } 145 if (vector_id >= EXCEPTION_COUNT_VECTORS || interrut_during_emulation) { 146 // apparently interrupts were enabled 147 // but we don't process more than one interrupt per VMEXIT, 148 // and we don't process more than one interrupt per emulated instruction 149 // p_stack->flags is actually eflags / rflags on the stack 150 // clear flags.IF to prevent interrupt re-enabling 151 BIT_CLR(p_stack->u.exception.flags, RFLAGS_IF); 152 } 153 // Before returning to the assmbler code, need to set pointer to the 154 // EXCEPTION_STACK ip member. 155 if (FALSE == interrut_during_emulation && isr_error_code_required(vector_id)) { 156 // case exception code DO was pushed on the stack 157 p_stack->a.except_ip_ptr = (ADDRESS) &p_stack->u.errcode_exception.ip; 158 } 159 else { 160 // case no exception code was pushed on the stack 161 // (external interrupts or exception without error code) 162 p_stack->a.except_ip_ptr = (ADDRESS) &p_stack->u.exception.ip; 163 } 164 } 165 166 167 /* 168 * FUNCTION : isr_register_handler() 169 * PURPOSE : Registers ISR handler 170 * ARGUMENTS : VMM_ISR_HANDLER handler - is called 171 * : when vector interrupt/exception occurs 172 * : VECTOR_ID vector_id 173 */ 174 void isr_register_handler(IN VMM_ISR_HANDLER handler, IN VECTOR_ID vector_id) 175 { 176 isr_table[vector_id] = handler; 177 } 178 179 #pragma warning( push ) 180 #pragma warning( disable : 4100 ) 181 #ifdef DEBUG 182 183 static void print_exception_header( 184 ADDRESS cs USED_IN_DEBUG_ONLY, 185 ADDRESS ip USED_IN_DEBUG_ONLY, 186 VECTOR_ID vector_id USED_IN_DEBUG_ONLY, 187 size_t errcode USED_IN_DEBUG_ONLY) 188 { 189 CPU_ID cpu_id = hw_cpu_id(); 190 191 VMM_LOG_NOLOCK("*******************************************************************************\n"); 192 VMM_LOG_NOLOCK("* *\n"); 193 VMM_LOG_NOLOCK("* Intel Virtual Machine Monitor *\n"); 194 VMM_LOG_NOLOCK("* *\n"); 195 VMM_LOG_NOLOCK("*******************************************************************************\n"); 196 VMM_LOG_NOLOCK("\nException(%d) has occured on CPU(%d) at cs=%P ip=%P errcode=%Id", vector_id, cpu_id, cs, ip, errcode); 197 } 198 #pragma warning( pop ) 199 200 static void print_errcode_generic(ADDRESS errcode) 201 { 202 VMM_LOG_NOLOCK("Error code: 0X%X", errcode); 203 if ((errcode & ERROR_CODE_EXT_BIT) != 0) { 204 VMM_LOG_NOLOCK("External event\n"); 205 } 206 else { 207 VMM_LOG_NOLOCK("Internal event\n"); 208 } 209 if ((errcode & ERROR_CODE_IN_IDT) != 0) { 210 VMM_LOG_NOLOCK("Index is in IDT\n"); 211 } 212 else if ((errcode & ERROR_CODE_TI) != 0) { 213 VMM_LOG_NOLOCK("Index is in LDT\n"); 214 } 215 else { 216 VMM_LOG_NOLOCK("Index is in GDT\n"); 217 } 218 } 219 #endif //DEBUG 220 221 static void exception_handler_default_no_errcode(ISR_PARAMETERS_ON_STACK *p_stack) 222 { 223 VMM_DEBUG_CODE(print_exception_header(p_stack->u.exception.cs, 224 p_stack->u.exception.ip, (VECTOR_ID) p_stack->a.vector_id, 0)); 225 226 if (p_stack->a.vector_id < NELEMENTS(exception_message)) { 227 VMM_LOG_NOLOCK(" Error type: %s\n", exception_message[p_stack->a.vector_id]); 228 } 229 } 230 231 static void exception_handler_default_with_errcode(ISR_PARAMETERS_ON_STACK *p_stack) 232 { 233 VMM_DEBUG_CODE(print_exception_header(p_stack->u.errcode_exception.cs, 234 p_stack->u.errcode_exception.ip, (VECTOR_ID) p_stack->a.vector_id, 235 p_stack->u.errcode_exception.errcode)); 236 237 if (p_stack->a.vector_id < NELEMENTS(exception_message)) { 238 VMM_LOG_NOLOCK(" Exception type: %s\n", exception_message[p_stack->a.vector_id]); 239 } 240 } 241 242 static void exception_handler_default(ISR_PARAMETERS_ON_STACK *p_stack) 243 { 244 if (isr_error_code_required((VECTOR_ID) p_stack->a.vector_id)) { 245 exception_handler_default_with_errcode( p_stack ); 246 } 247 else { 248 exception_handler_default_no_errcode( p_stack ); 249 } 250 g_exception_stack = p_stack; 251 VMM_DEADLOOP(); 252 } 253 254 255 static void exception_handler_page_fault(ISR_PARAMETERS_ON_STACK *p_stack) 256 { 257 GUEST_CPU_HANDLE gcpu; 258 VMCS_OBJECT __attribute__ ((unused)) *vmcs; 259 260 VMM_DEBUG_CODE(print_exception_header(p_stack->u.errcode_exception.cs, 261 p_stack->u.errcode_exception.ip, (VECTOR_ID) p_stack->a.vector_id, 262 p_stack->u.errcode_exception.errcode)); 263 if (p_stack->a.vector_id < NELEMENTS(exception_message)) { 264 VMM_LOG_NOLOCK(" Error type: %s\n", exception_message[p_stack->a.vector_id]); 265 } 266 VMM_LOG_NOLOCK("Faulting address of page fault is %P RSP=%P\n", 267 hw_read_cr2(), 268 p_stack->u.errcode_exception.sp); 269 gcpu = scheduler_current_gcpu(); 270 vmcs = gcpu_get_vmcs(gcpu); 271 VMM_LOG_NOLOCK("Last VMEXIT reason = %d\n", (UINT32) vmcs_read(vmcs, VMCS_EXIT_INFO_REASON)); 272 g_exception_stack = p_stack; 273 VMM_DEADLOOP(); 274 } 275 276 static void exception_handler_undefined_opcode(ISR_PARAMETERS_ON_STACK *p_stack) 277 { 278 #ifdef DEBUG 279 UINT64 ip = p_stack->u.exception.ip; 280 UINT8* ip_ptr = (UINT8*)ip; 281 #endif 282 283 VMM_DEBUG_CODE(print_exception_header(p_stack->u.exception.cs, 284 p_stack->u.exception.ip, (VECTOR_ID) p_stack->a.vector_id, 0)); 285 if (p_stack->a.vector_id < NELEMENTS(exception_message)) { 286 VMM_LOG_NOLOCK(" Exception type: %s\n", exception_message[p_stack->a.vector_id]); 287 } 288 VMM_LOG_NOLOCK("IP = %P\n", ip_ptr); 289 VMM_LOG_NOLOCK("Encoding: %2x %2x %2x %2x\n", *ip_ptr, *(ip_ptr + 1), 290 *(ip_ptr + 2), *(ip_ptr + 3)); 291 g_exception_stack = p_stack; 292 VMM_DEADLOOP(); 293 } 294 295 static void isr_install_default_handlers(void) 296 { 297 unsigned vector_id; 298 for (vector_id = 0; vector_id < INTERRUPT_COUNT_VECTORS; ++vector_id) { 299 isr_register_handler(exception_handler_default, (UINT8) vector_id); 300 } 301 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_DIVIDE_ERROR); 302 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_DEBUG_BREAKPOINT); 303 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_NMI); 304 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_BREAKPOINT); 305 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_OVERFLOW); 306 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_BOUND_RANGE_EXCEEDED); 307 isr_register_handler(exception_handler_undefined_opcode, IA32_EXCEPTION_VECTOR_UNDEFINED_OPCODE); 308 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_NO_MATH_COPROCESSOR); 309 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_DOUBLE_FAULT); 310 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_INVALID_TASK_SEGMENT_SELECTOR); 311 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_SEGMENT_NOT_PRESENT); 312 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_STACK_SEGMENT_FAULT); 313 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_GENERAL_PROTECTION_FAULT); 314 isr_register_handler(exception_handler_page_fault, IA32_EXCEPTION_VECTOR_PAGE_FAULT); 315 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_MATH_FAULT); 316 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_ALIGNMENT_CHECK); 317 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_MACHINE_CHECK); 318 isr_register_handler(exception_handler_default, IA32_EXCEPTION_VECTOR_SIMD_FLOATING_POINT_NUMERIC_ERROR); 319 } 320 321 322 /* 323 * FUNCTION : isr_setup() 324 * PURPOSE : Builds ISR wrappers, IDT tables and 325 * : default high level ISR handlers for all CPUs. 326 */ 327 void isr_setup(void) 328 { 329 hw_idt_setup(); 330 isr_install_default_handlers(); 331 } 332 333 void isr_handling_start(void) 334 { 335 hw_idt_load(); 336 } 337 338 BOOLEAN isr_error_code_required(VECTOR_ID vector_id) 339 { 340 switch (vector_id) { 341 case IA32_EXCEPTION_VECTOR_DOUBLE_FAULT: 342 case IA32_EXCEPTION_VECTOR_PAGE_FAULT: 343 case IA32_EXCEPTION_VECTOR_INVALID_TASK_SEGMENT_SELECTOR: 344 case IA32_EXCEPTION_VECTOR_SEGMENT_NOT_PRESENT: 345 case IA32_EXCEPTION_VECTOR_STACK_SEGMENT_FAULT: 346 case IA32_EXCEPTION_VECTOR_GENERAL_PROTECTION_FAULT: 347 case IA32_EXCEPTION_VECTOR_ALIGNMENT_CHECK: 348 return TRUE; 349 default: 350 return FALSE; 351 } 352 } 353