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