github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/dbg/vmm_dbg.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 "guest_cpu.h" 16 #include "scheduler.h" 17 #include "common_libc.h" 18 #include "vmm_dbg.h" 19 #include "guest_cpu_vmenter_event.h" 20 #include "vmcs_api.h" 21 #include "isr.h" 22 #include "vmm_arch_defs.h" 23 #include "memory_dump.h" 24 #include "em64t_defs.h" 25 #include "vmm_stack_api.h" 26 #include "../memory/ept/fvs.h" 27 #include "vmm_callback.h" 28 29 UINT64 g_debug_gpa = 0; 30 UINT64 g_initial_vmcs[VMM_MAX_CPU_SUPPORTED] = {0}; 31 ISR_PARAMETERS_ON_STACK *g_exception_stack = NULL; 32 VMM_GP_REGISTERS g_exception_gpr = {{0}}; 33 34 extern BOOLEAN vmm_copy_to_guest_phy_addr(GUEST_CPU_HANDLE gcpu, void* gpa, UINT32 size, void* hva); 35 36 int CLI_active(void) 37 { 38 #ifdef CLI_INCLUDE 39 return (VMM_MASK_CHECK(mask_cli)) ? 1 : 0; 40 #else 41 return 0; 42 #endif 43 } 44 45 46 // Dump debug info to guest buffer 47 // To ensure only 1 signature string instance in memory dump 48 // 1. build signature one char at a time 49 // 2. no signature to serial output 50 // 3. clear signature in the string buffer after used 51 #define BUFFER_SIZE 256 52 void vmm_deadloop_internal(UINT32 file_code, UINT32 line_num, GUEST_CPU_HANDLE gcpu) 53 { 54 static UINT32 dump_started = 0; 55 char buffer[BUFFER_SIZE], err_msg[BUFFER_SIZE]; 56 UINT64 rsp, stack_base; 57 UINT32 size; 58 CPU_ID cpu_id; 59 EXCEPT_INFO header; 60 61 // skip dumping debug info if deadloop/assert happened before launch 62 if (g_debug_gpa == 0) 63 return; 64 65 cpu_id = hw_cpu_id(); 66 if (cpu_id >= MAX_CPUS) 67 return; 68 69 vmm_sprintf_s(err_msg, 128, "CPU%d: %s: Error: Could not copy deadloop message back to guest\n", 70 cpu_id, __FUNCTION__); 71 72 // send cpu id, file code, line number to serial port 73 vmm_printf("%02d%04d%04d\n", cpu_id, file_code, line_num); 74 75 // must match format defined in FILE_LINE_INFO 76 size = vmm_sprintf_s(buffer, BUFFER_SIZE, "%04d%04d", file_code, line_num); 77 78 // copy file code/line number to guest buffer at offset defined in DEADLOOP_DUMP 79 // strlen(signature) + sizeof(cpu_id) + file_line[cpu] 80 if (!vmm_copy_to_guest_phy_addr(gcpu, 81 (void*)(g_debug_gpa+8+8+(cpu_id*size)), 82 size, 83 (void*)buffer)) { 84 VMM_LOG(mask_uvmm, level_error, err_msg); 85 } 86 87 // only copy signature, VERSION, cpu_id, exception info, vmcs to guest 88 // buffer once 89 if (hw_interlocked_compare_exchange((INT32*)&dump_started,0,1) == 0) { 90 size = vmm_sprintf_s(buffer, BUFFER_SIZE, "%c%c%c%c%c%c%c%c%s%04d", 91 DEADLOOP_SIGNATURE[0], DEADLOOP_SIGNATURE[1], 92 DEADLOOP_SIGNATURE[2], DEADLOOP_SIGNATURE[3], 93 DEADLOOP_SIGNATURE[4], DEADLOOP_SIGNATURE[5], 94 DEADLOOP_SIGNATURE[6], DEADLOOP_SIGNATURE[7], VERSION, cpu_id); 95 96 // copy signature and cpu_id to guest buffer 97 if (!vmm_copy_to_guest_phy_addr(gcpu, 98 (void*)(g_debug_gpa), 99 size, 100 (void*)buffer)) { 101 VMM_LOG(mask_uvmm, level_error, err_msg); 102 } 103 104 // clear buffer erasing the signature or setting no exception flag 105 vmm_zeromem(buffer, sizeof(UINT64)); 106 107 // copy exception info to guest buffer 108 if (g_exception_stack != NULL) { 109 vmm_memcpy((void *)&header.exception_stack, g_exception_stack, sizeof(ISR_PARAMETERS_ON_STACK)); 110 header.base_address = vmm_startup_data.vmm_memory_layout[uvmm_image].base_address; 111 112 if (g_exception_stack->a.vector_id == IA32_EXCEPTION_VECTOR_PAGE_FAULT) 113 header.cr2 = hw_read_cr2(); 114 115 // copy exception info to guest buffer 116 if (!vmm_copy_to_guest_phy_addr(gcpu, 117 (void*)(g_debug_gpa+OFFSET_EXCEPTION), 118 sizeof(EXCEPT_INFO), 119 (void*)&header)) { 120 VMM_LOG(mask_uvmm, level_error, err_msg); 121 } 122 123 // copy GPRs to guest buffer 124 if (!vmm_copy_to_guest_phy_addr(gcpu, 125 (void*)(g_debug_gpa+OFFSET_GPR), 126 sizeof(VMM_GP_REGISTERS), 127 (void*)&g_exception_gpr)) { 128 VMM_LOG(mask_uvmm, level_error, err_msg); 129 } 130 131 // copy stack to guest buffer 132 rsp = isr_error_code_required((VECTOR_ID)g_exception_stack->a.vector_id) ? 133 g_exception_stack->u.errcode_exception.sp : 134 g_exception_stack->u.exception.sp; 135 136 vmm_stack_get_stack_pointer_for_cpu(cpu_id, &stack_base); 137 138 size = sizeof(UINT64)*STACK_TRACE_SIZE; 139 if ((rsp+size) > stack_base) 140 size = (UINT32)(stack_base-rsp); 141 142 if (!vmm_copy_to_guest_phy_addr(gcpu, 143 (void*)(g_debug_gpa+OFFSET_STACK), 144 size, 145 (void*)rsp)) { 146 VMM_LOG(mask_uvmm, level_error, err_msg); 147 } 148 } else { 149 // Clear base image address indicating exception did not happen 150 if (!vmm_copy_to_guest_phy_addr(gcpu, 151 (void*)(g_debug_gpa+OFFSET_EXCEPTION), 152 sizeof(UINT64), 153 (void*)buffer)) { 154 VMM_LOG(mask_uvmm, level_error, err_msg); 155 } 156 } 157 158 // copy vmcs to guest buffer 159 vmcs_dump_all(gcpu); 160 } 161 } 162 163 164 void vmm_deadloop_dump(UINT32 file_code, UINT32 line_num) 165 { 166 #define DEFAULT_VIEW_HANDLE 0 167 168 GUEST_CPU_HANDLE gcpu; 169 EM64T_RFLAGS rflags; 170 IA32_VMX_VMCS_GUEST_INTERRUPTIBILITY interruptibility; 171 172 gcpu = scheduler_current_gcpu(); 173 if(!gcpu) 174 VMM_UP_BREAKPOINT(); 175 176 report_uvmm_event(UVMM_EVENT_VMM_ASSERT, (VMM_IDENTIFICATION_DATA)gcpu, (const GUEST_VCPU*)guest_vcpu(gcpu), NULL); 177 178 // send debug info to serial port and guest buffer 179 vmm_deadloop_internal(file_code, line_num, gcpu); 180 181 // clear interrupt flag 182 rflags.Uint64 = gcpu_get_gp_reg(gcpu, IA32_REG_RFLAGS); 183 rflags.Bits.IFL = 0; 184 gcpu_set_gp_reg(gcpu, IA32_REG_RFLAGS, rflags.Uint64); 185 186 interruptibility.Uint32 = gcpu_get_interruptibility_state(gcpu); 187 interruptibility.Bits.BlockNextInstruction = 0; 188 gcpu_set_interruptibility_state(gcpu, interruptibility.Uint32); 189 190 // generate BSOD 191 gcpu_inject_gp0(gcpu); 192 gcpu_resume(gcpu); 193 } 194 195 196 // Generic debug helper function 197 198 #pragma warning( push ) 199 #pragma warning (disable : 4100) // Supress warnings about unreferenced formal parameter 200 201 BOOLEAN DeadloopHelper( const char* assert_condition, 202 const char* func_name, 203 const char* file_name, 204 UINT32 line_num, 205 UINT32 access_level) 206 { 207 (void)access_level; 208 if (!assert_condition) 209 { 210 vmm_printf("Deadloop in %s() - %s:%d\n", 211 func_name, 212 file_name, 213 line_num); 214 } 215 else 216 { 217 vmm_printf("VMM assert (%s) failed\n\t in %s() at %s:%d\n", 218 assert_condition, 219 func_name, 220 file_name, 221 line_num); 222 } 223 224 return TRUE; 225 } 226 #pragma warning( pop ) 227 228