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