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