github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/startup/create_guests.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(CREATE_GUESTS_C)
    17  #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(CREATE_GUESTS_C, __condition)
    18  #include "vmm_defs.h"
    19  #include "vmm_bootstrap_utils.h"
    20  #include "gpm_api.h"
    21  #include "guest.h"
    22  #include "guest_cpu.h"
    23  #include "host_cpu.h"
    24  #include "hw_utils.h"
    25  #include "scheduler.h"
    26  #include "layout_host_memory.h"
    27  #include "vmm_dbg.h"
    28  #include "vmexit_msr.h"
    29  #include "device_drivers_manager.h"
    30  #include "vmcall_api.h"
    31  #include "vmcall.h"
    32  #include "host_memory_manager_api.h"
    33  #include "vmm_startup.h"
    34  #include "vmm_events_data.h"
    35  #include "guest_pci_configuration.h"
    36  #include "ipc.h"
    37  #include "pat_manager.h"
    38  #ifdef JLMDEBUG
    39  #include "jlmdebug.h"
    40  #endif
    41  
    42  //
    43  // Read input data structure and create all guests
    44  //
    45  
    46  #ifdef FAST_VIEW_SWITCH
    47  extern void fvs_initialize(GUEST_HANDLE guest, UINT32 number_of_host_processors);
    48  #endif
    49  
    50  #if 0 // not defined
    51  static void raise_guest_create_event(GUEST_ID guest_id);  // moved to guest.c
    52  #endif
    53  
    54  #define PRIMARY_MAGIC 0
    55  
    56  
    57  // Add CPU to guest
    58  void add_cpu_to_guest(const VMM_GUEST_STARTUP* gstartup, GUEST_HANDLE guest, 
    59                              CPU_ID host_cpu_to_allocate, BOOLEAN ready_to_run )
    60  {
    61      GUEST_CPU_HANDLE gcpu;
    62      const VIRTUAL_CPU_ID* vcpu = NULL;
    63      const VMM_GUEST_CPU_STARTUP_STATE* cpus_arr = NULL;
    64  
    65  #ifdef JLMDEBUG1
    66      bprint("add_cpu_to_guest guest SU: %p,  guest: %d, host: %d\n",
    67              gstartup, guest, host_cpu_to_allocate);
    68  #endif
    69      gcpu = guest_add_cpu(guest);
    70      VMM_ASSERT(gcpu);
    71      // find init data
    72      vcpu= guest_vcpu(gcpu);
    73      VMM_ASSERT(vcpu);
    74      // register with scheduler
    75      scheduler_register_gcpu(gcpu, host_cpu_to_allocate, ready_to_run);
    76  #ifdef JLMDEBUG1
    77      bprint("done with scheduler_register_gcpu 0x%016lx\n", vcpu);
    78      bprint("guest_cpu_id: %d\n", vcpu->guest_cpu_id);
    79      bprint("states count: %d\n", gstartup->cpu_states_count);
    80  #endif
    81      if(vcpu->guest_cpu_id<gstartup->cpu_states_count) {
    82          cpus_arr = (const VMM_GUEST_CPU_STARTUP_STATE*)gstartup->cpu_states_array;
    83  #ifdef JLMDEBUG
    84          if(cpus_arr==NULL) {
    85              bprint("cpus_arr is NULL\n");
    86              LOOP_FOREVER
    87          }
    88  #endif
    89          VMM_ASSERT(cpus_arr);
    90          VMM_LOG(mask_anonymous, level_trace,
    91                  "Setting up initial state for the newly created Guest CPU\n");
    92  #ifdef JLMDEBUG1
    93          bprint("about to call gcpu_initialize(0x%016lx, 0x%016lx)\n", vcpu, gcpu);
    94  #endif
    95          gcpu_initialize(gcpu, &(cpus_arr[vcpu->guest_cpu_id]));
    96      }
    97      else {
    98          VMM_LOG(mask_anonymous, level_trace,
    99                  "Newly created Guest CPU was initialized with the Wait-For-SIPI state\n");
   100      }
   101      // host part will be initialized later
   102  #ifdef JLMDEBUG1
   103      bprint("done with add_cpu_to_guest\n");
   104  #endif
   105  }
   106  
   107  // Init guest except for guest memory
   108  // Return NULL on error
   109  static GUEST_HANDLE init_single_guest(UINT32 number_of_host_processors,
   110                                  const VMM_GUEST_STARTUP* gstartup, 
   111                                  const VMM_POLICY  *guest_policy)
   112  {
   113      GUEST_HANDLE  guest;
   114      UINT32        cpu_affinity = 0;
   115      UINT32        bit_number;
   116      BOOLEAN       ready_to_run = FALSE;
   117  
   118      if ((gstartup->size_of_this_struct!=sizeof(VMM_GUEST_STARTUP)) ||
   119          (gstartup->version_of_this_struct!=VMM_GUEST_STARTUP_VERSION )) {
   120          VMM_LOG(mask_anonymous, level_trace,
   121                  "ASSERT: unknown guest struct: size: %#x version %d\n",
   122                  gstartup->size_of_this_struct, gstartup->version_of_this_struct );
   123          return NULL;
   124      }
   125  #ifdef JLMDEBUG
   126      bprint("about to init_single_guest, guest magic: %d\n", 
   127             gstartup->guest_magic_number);
   128  #endif
   129  
   130      // create guest
   131      guest= guest_register(gstartup->guest_magic_number, 
   132                            gstartup->physical_memory_size,
   133                            gstartup->cpu_affinity, guest_policy);
   134      if (!guest) {
   135  #ifdef JLMDEBUG
   136          bprint("guest register failed\n");
   137          LOOP_FOREVER
   138  #endif
   139          return NULL;
   140      }
   141  #ifdef FAST_VIEW_SWITCH
   142      fvs_initialize(guest, number_of_host_processors);
   143  #endif
   144      vmexit_guest_initialize(guest_get_id(guest));
   145      if (gstartup->devices_count!=0) {
   146  #ifdef JLMDEBUG
   147          bprint("vmexit_guest_initialize failed\n");
   148          LOOP_FOREVER
   149  #endif
   150          return NULL;
   151      }
   152      if (gstartup->image_size) {
   153          guest_set_executable_image( guest, (const UINT8*)gstartup->image_address,
   154              gstartup->image_size, gstartup->image_offset_in_guest_physical_memory,
   155              BITMAP_GET(gstartup->flags, VMM_GUEST_FLAG_IMAGE_COMPRESSED)!=0);
   156      }
   157      if(BITMAP_GET(gstartup->flags, VMM_GUEST_FLAG_REAL_BIOS_ACCESS_ENABLE)!=0) {
   158  #ifdef JLMDEBUG
   159          bprint("calling guest_set_real_BIOS_access_enabled\n");
   160  #endif
   161          guest_set_real_BIOS_access_enabled(guest);
   162      }
   163      msr_vmexit_guest_setup(guest);  // setup MSR-related control structure
   164  #ifdef JLMDEBUG1
   165      bprint("finished msr_vmexit_guest_setup 0x%016lx\n", guest);
   166  #endif
   167  
   168      // init cpus.
   169      // first init CPUs that has initial state
   170      cpu_affinity = gstartup->cpu_affinity;
   171      if (cpu_affinity==0) {
   172          return NULL;
   173      }
   174      ready_to_run= (BITMAP_GET(gstartup->flags, VMM_GUEST_FLAG_LAUNCH_IMMEDIATELY)!=0);
   175      if (cpu_affinity == (UINT32)-1) {
   176          // special case - run on all existing CPUs
   177          for(bit_number= 0; bit_number<number_of_host_processors; bit_number++) {
   178  #ifdef JLMDEBUG1
   179              bprint("bit_number: %d\n", bit_number);
   180              bprint("gstartup: %p\n", gstartup);
   181  #endif
   182              add_cpu_to_guest(gstartup, guest, (CPU_ID)bit_number, ready_to_run);
   183              VMM_LOG(mask_anonymous, level_trace,
   184                      "CPU #%d added successfully to the current guest\n", bit_number);
   185          }
   186      }
   187  #ifdef DEBUG
   188      //register_vmcall_services(guest);
   189      guest_register_vmcall_services(guest);
   190  #endif
   191  #ifdef JLMDEBUG
   192      bprint("init_single_guest finished, ready_to_run: %d\n", ready_to_run );
   193  #endif
   194      return guest;
   195  }
   196  
   197  
   198  // Perform initialization of guests and guest CPUs
   199  // Should be called on BSP only while all APs are stopped
   200  // Return TRUE for success
   201  BOOLEAN initialize_all_guests( UINT32 number_of_host_processors,
   202  #if 0  // for later: additional excluded areas
   203          int num_excluded,
   204  #endif
   205          const VMM_MEMORY_LAYOUT* vmm_memory_layout,
   206          const VMM_GUEST_STARTUP* primary_guest_startup_state,
   207          UINT32 number_of_secondary_guests,
   208          const VMM_GUEST_STARTUP* secondary_guests_startup_state_array,
   209          const VMM_APPLICATION_PARAMS_STRUCT* application_params)
   210  {
   211      GUEST_HANDLE primary_guest;
   212      GPM_HANDLE   primary_guest_startup_gpm;
   213      BOOLEAN      ok = FALSE;
   214      GUEST_CPU_HANDLE gcpu;
   215      GUEST_GCPU_ECONTEXT gcpu_context;
   216  
   217      VMM_ASSERT(hw_cpu_id() == 0);
   218      VMM_ASSERT(number_of_host_processors > 0);
   219      VMM_ASSERT(vmm_memory_layout);
   220      VMM_ASSERT(primary_guest_startup_state);
   221  
   222      if (number_of_secondary_guests>0) {
   223          VMM_LOG(mask_anonymous, level_trace,"initialize_all_guests ASSERT: Secondary guests are yet not implemented\n");
   224          VMM_ASSERT( secondary_guests_startup_state_array );
   225          // init guests and allocate memory for them
   226          // shutdown temporary layout object
   227          VMM_DEADLOOP();
   228          return FALSE;
   229      }
   230  
   231      // first init primary guest
   232      VMM_LOG(mask_anonymous, level_trace,"Init primary guest\n");
   233  
   234      // BUGBUG: This is a workaround until loader will not do this!!!
   235      BITMAP_SET(((VMM_GUEST_STARTUP*)primary_guest_startup_state)->flags, 
   236            VMM_GUEST_FLAG_REAL_BIOS_ACCESS_ENABLE|VMM_GUEST_FLAG_LAUNCH_IMMEDIATELY);
   237  #ifdef JLMDEBUG
   238      bprint("initialize_all_guests, %d CPUs\n", number_of_host_processors);
   239  #endif
   240      // TODO: Uses global policy but should be part of VMM_GUEST_STARTUP structure.
   241      ((VMM_GUEST_STARTUP*)primary_guest_startup_state)->guest_magic_number= PRIMARY_MAGIC;
   242      primary_guest = init_single_guest(number_of_host_processors, 
   243                                        primary_guest_startup_state, NULL);  
   244      if (!primary_guest) {
   245          VMM_LOG(mask_anonymous, level_trace,
   246                   "initialize_all_guests: Cannot init primary guest\n");
   247          VMM_DEADLOOP();
   248          return FALSE;
   249      }
   250      guest_set_primary(primary_guest);
   251      primary_guest_startup_gpm = guest_get_startup_gpm(primary_guest);
   252  
   253      // init memory layout in the startup gpm
   254      // JLM(FIX) change this call
   255  #if 1
   256      ok = init_memory_layout(vmm_memory_layout, primary_guest_startup_gpm,
   257                              number_of_secondary_guests > 0, application_params);
   258  #else
   259      ok = init_memory_layout_from_mbr( num_excluded, vmm_memory_layout, primary_guest_startup_gpm,
   260                              number_of_secondary_guests > 0, application_params);
   261  #endif
   262  
   263      // Set active_gpm to startup gpm
   264      for(gcpu = guest_gcpu_first(primary_guest, &gcpu_context); gcpu; gcpu = guest_gcpu_next(&gcpu_context)) {
   265          gcpu_set_current_gpm(gcpu, primary_guest_startup_gpm);
   266      }
   267      VMM_LOG(mask_anonymous, level_trace,"Primary guest initialized successfully\n");
   268      return ok;
   269  }
   270  
   271  // Perform initialization of host cpu portion of all guest CPUs that run 
   272  // on specified host CPU.  Should be called on the target host CPU
   273  void initialize_host_vmcs_regions( CPU_ID current_cpu_id )
   274  {
   275      GUEST_CPU_HANDLE        gcpu;
   276      SCHEDULER_GCPU_ITERATOR it;
   277  
   278      VMM_ASSERT(current_cpu_id == hw_cpu_id());
   279      for (gcpu = scheduler_same_host_cpu_gcpu_first( &it, current_cpu_id );
   280           gcpu != NULL; gcpu = scheduler_same_host_cpu_gcpu_next( &it )) {
   281          // now init the host CPU part for vm-exits
   282          host_cpu_vmcs_init(gcpu);
   283      }
   284  }
   285