github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/guest/guest_control.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 "file_codes.h"
    16  #define VMM_DEADLOOP()          VMM_DEADLOOP_LOG(GUEST_CONTROL_C)
    17  #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(GUEST_CONTROL_C, __condition)
    18  #include "guest_internal.h"
    19  #include "guest_cpu.h"
    20  #include "vmm_dbg.h"
    21  #include "vmm_globals.h"
    22  #include "ipc.h"
    23  #include "scheduler.h"
    24  #ifdef JLMDEBUG
    25  #include "jlmdebug.h"
    26  #endif
    27  
    28  
    29  //
    30  // Main implementatuion idea:
    31  //    at boot stage just iterate through all gcpus and immediately apply
    32  //    at run stage use IPC to apply
    33  //
    34  
    35  typedef struct _IPC_COMM_GUEST_STRUCT {
    36      GUEST_HANDLE    guest;
    37      volatile UINT32 executed;
    38      UINT8           pad1[4];
    39  } IPC_COMM_GUEST_STRUCT;
    40  
    41  
    42  #pragma warning (push)
    43  #pragma warning (disable : 4100)
    44  
    45  // apply vmexit config to the gcpu that are allocated for the current host cpu
    46  static void apply_vmexit_config(CPU_ID from UNUSED, void* arg)
    47  {
    48      GUEST_GCPU_ECONTEXT ctx;
    49      GUEST_CPU_HANDLE    gcpu;
    50      CPU_ID              this_hcpu_id = hw_cpu_id();
    51  
    52      IPC_COMM_GUEST_STRUCT* ipc = (IPC_COMM_GUEST_STRUCT*)arg;
    53      GUEST_HANDLE        guest = ipc->guest;
    54      volatile UINT32*    p_executed_count = &(ipc->executed);
    55  
    56      VMM_ASSERT( guest );
    57  
    58      for( gcpu = guest_gcpu_first( guest, &ctx ); gcpu; gcpu = guest_gcpu_next( &ctx )) {
    59          if (this_hcpu_id == scheduler_get_host_cpu_id( gcpu )) {
    60              gcpu_control_apply_only( gcpu );
    61          }
    62      }
    63  
    64      // mark as done
    65      hw_interlocked_increment( (INT32*)p_executed_count );
    66  }
    67  
    68  #pragma warning (pop)
    69  
    70  void guest_control_setup( GUEST_HANDLE guest, const VMEXIT_CONTROL* request )
    71  {
    72      GUEST_GCPU_ECONTEXT ctx;
    73      GUEST_CPU_HANDLE    gcpu;
    74      VMM_STATE           vmm_state;
    75      CPU_ID              this_hcpu_id = hw_cpu_id();
    76  
    77      VMM_ASSERT( guest );
    78      // setup vmexit requests without applying
    79      for( gcpu = guest_gcpu_first( guest, &ctx ); 
    80              gcpu; gcpu = guest_gcpu_next( &ctx )) {
    81          gcpu_control_setup_only( gcpu, request );
    82      }
    83      // now apply
    84      vmm_state = vmm_get_state();
    85      if (VMM_STATE_BOOT == vmm_state) {
    86          // may be run on BSP only
    87          VMM_ASSERT( 0 == this_hcpu_id );
    88  
    89          // single thread mode with all APs yet not init
    90          for( gcpu = guest_gcpu_first( guest, &ctx ); gcpu; 
    91                  gcpu = guest_gcpu_next( &ctx )) {
    92              gcpu_control_apply_only( gcpu );
    93          }
    94      }
    95      else if (VMM_STATE_RUN == vmm_state) {
    96          IPC_COMM_GUEST_STRUCT ipc;
    97          UINT32                wait_for_ipc_count = 0;
    98          IPC_DESTINATION       ipc_dst;
    99  
   100          vmm_memset( &ipc, 0, sizeof(ipc) );
   101          vmm_memset( &ipc_dst, 0, sizeof(ipc_dst) );
   102  
   103          // multi-thread mode with all APs ready and running or in Wait-For-SIPI state
   104          // on behalf of guest
   105          ipc.guest = guest;
   106  
   107          // first apply for gcpus allocated for this hw cpu
   108          apply_vmexit_config( this_hcpu_id, &ipc );
   109          // reset executed counter and flush memory
   110          hw_assign_as_barrier( &(ipc.executed), 0);
   111          // send for execution
   112          ipc_dst.addr_shorthand = IPI_DST_ALL_EXCLUDING_SELF;
   113          wait_for_ipc_count = ipc_execute_handler( ipc_dst, apply_vmexit_config, &ipc );
   114          // wait for execution finish
   115          while (wait_for_ipc_count != ipc.executed) {
   116              // avoid deadlock - process one IPC if exist
   117              ipc_process_one_ipc();
   118              hw_pause();
   119          }
   120      }
   121      else {
   122          // not supported mode
   123          VMM_LOG(mask_anonymous, level_trace,
   124                  "Unsupported global vmm_state=%d in guest_request_vmexit_on()\n", vmm_state);
   125          VMM_DEADLOOP();
   126      }
   127  }
   128