github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/guest/guest_pci_configuration.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   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9  
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  #include "file_codes.h"
    18  #define VMM_DEADLOOP()          VMM_DEADLOOP_LOG(GUEST_PCI_CONFIGURATION_C)
    19  #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(GUEST_PCI_CONFIGURATION_C, __condition)
    20  #include "guest_pci_configuration.h"
    21  #include "guest.h"
    22  #include "hash64_api.h"
    23  #include "memory_allocator.h"
    24  #include "list.h"
    25  #include "vmexit_io.h"
    26  #include "guest_cpu.h"
    27  #include "hw_utils.h"
    28  #include "heap.h"
    29  #ifdef JLMDEBUG
    30  #include "jlmdebug.h"
    31  #endif
    32  #ifdef PCI_SCAN
    33  #pragma warning (disable:4100)
    34  
    35  extern
    36  void io_transparent_read_handler(
    37      GUEST_CPU_HANDLE    gcpu,
    38      IO_PORT_ID          port_id,
    39      unsigned            port_size, // 1, 2, 4
    40      void               *p_value
    41      );
    42  
    43  extern
    44  void io_transparent_write_handler(
    45      GUEST_CPU_HANDLE    gcpu,
    46      IO_PORT_ID          port_id,
    47      unsigned            port_size, // 1, 2, 4
    48      void               *p_value
    49      );
    50  
    51  static void apply_default_device_assignment(GUEST_ID guest_id);
    52  static GUEST_PCI_DEVICES* find_guest_devices(GUEST_ID guest_id);
    53  #ifdef INCLUDE_UNUSED_CODE
    54  static GUEST_PCI_DEVICE* find_device(GUEST_ID guest_id, UINT8 bus, UINT8 device, UINT8 function);
    55  #endif
    56  static void pci_read_hide (GUEST_CPU_HANDLE  gcpu, GUEST_PCI_DEVICE *pci_device,
    57                      UINT32 port_id, UINT32 port_size, void   *value);
    58  static void pci_write_hide (GUEST_CPU_HANDLE  gcpu, GUEST_PCI_DEVICE *pci_device,
    59                      UINT32 port_id, UINT32 port_size, void   *value);
    60  
    61  static void pci_read_passthrough(GUEST_CPU_HANDLE  gcpu,
    62                      GUEST_PCI_DEVICE * pci_device,
    63                      UINT32 port_id, UINT32 port_size, void   *value);
    64  
    65  static
    66  void pci_write_passthrough(GUEST_CPU_HANDLE  gcpu,
    67                      GUEST_PCI_DEVICE * pci_device, UINT32 port_id,
    68                      UINT32 port_size, void   *value);
    69  #ifdef INCLUDE_UNUSED_CODE
    70  static void io_pci_data_handler(GUEST_CPU_HANDLE  gcpu,
    71                      UINT16 port_id, unsigned  port_size, // 1, 2, 4
    72                      RW_ACCESS access, void *p_value);
    73  
    74  static void io_pci_address_handler(GUEST_CPU_HANDLE  gcpu,
    75                      UINT16  port_id, unsigned  port_size, // 1, 2, 4
    76                      RW_ACCESS access, void *p_value);
    77  #endif
    78  
    79  static LIST_ELEMENT guest_pci_devices[1];
    80  static HASH64_HANDLE device_to_guest = HASH64_INVALID_HANDLE;
    81  
    82  static GPCI_GUEST_PROFILE device_owner_guest_profile = {pci_read_passthrough, pci_write_passthrough}; // passthrough
    83  static GPCI_GUEST_PROFILE no_devices_guest_profile = {pci_read_hide, pci_write_hide};
    84  
    85  BOOLEAN gpci_initialize(void)
    86  {
    87      GUEST_HANDLE   guest;
    88      GUEST_ECONTEXT guest_ctx;
    89  
    90      vmm_zeromem(guest_pci_devices, sizeof(guest_pci_devices));
    91      list_init(guest_pci_devices);
    92      device_to_guest = hash64_create_default_hash(256);
    93      for( guest = guest_first( &guest_ctx ); guest; guest = guest_next( &guest_ctx )) {
    94          gpci_guest_initialize(guest_get_id(guest));
    95      }
    96      return TRUE;
    97  }
    98  
    99  BOOLEAN gpci_guest_initialize(GUEST_ID guest_id)
   100  {
   101      GUEST_PCI_DEVICES *gpci = NULL;
   102  
   103      gpci = (GUEST_PCI_DEVICES *)vmm_memory_alloc(sizeof(GUEST_PCI_DEVICES));
   104      VMM_ASSERT(gpci);
   105      if(gpci == NULL) {
   106          return FALSE;
   107      }
   108      gpci->guest_id = guest_id;
   109      list_add(guest_pci_devices, gpci->guests);
   110      gpci->gcpu_pci_access_address = (PCI_CONFIG_ADDRESS *) vmm_malloc(guest_gcpu_count(guest_handle(guest_id)) * sizeof(PCI_CONFIG_ADDRESS));
   111      VMM_ASSERT(gpci->gcpu_pci_access_address);
   112      apply_default_device_assignment(guest_id);
   113      return TRUE;
   114  }
   115  
   116  static void apply_default_device_assignment(GUEST_ID guest_id)
   117  {
   118      UINT16 bus, dev, func; // 16-bit bus to avoid wrap around on bus==256
   119      HOST_PCI_DEVICE *host_pci_device = NULL;
   120      GPCI_GUEST_PROFILE *guest_profile = NULL;
   121      GUEST_DEVICE_VIRTUALIZATION_TYPE type;
   122  
   123      if(guest_id == guest_get_default_device_owner_guest_id()) {
   124          guest_profile = &device_owner_guest_profile;
   125          type = GUEST_DEVICE_VIRTUALIZATION_DIRECT_ASSIGNMENT;
   126      }
   127      else {
   128          guest_profile = &no_devices_guest_profile;
   129          type = GUEST_DEVICE_VIRTUALIZATION_HIDDEN;
   130      }
   131      for(bus = 0; bus < PCI_MAX_NUM_BUSES; bus++) {
   132          for(dev = 0; dev < PCI_MAX_NUM_DEVICES_ON_BUS; dev++) {
   133              for(func = 0; func < PCI_MAX_NUM_FUNCTIONS_ON_DEVICE; func++) {
   134                  host_pci_device = get_host_pci_device((UINT8) bus, (UINT8) dev, (UINT8) func);
   135                  if(NULL == host_pci_device) { // device not found
   136                      continue;
   137                  }
   138                  gpci_register_device(guest_id, type, host_pci_device,
   139                                       NULL, guest_profile->pci_read, guest_profile->pci_write);
   140              }
   141          }
   142      }
   143  
   144  }
   145  
   146  BOOLEAN gpci_register_device(GUEST_ID guest_id, GUEST_DEVICE_VIRTUALIZATION_TYPE type,
   147                               HOST_PCI_DEVICE *host_pci_device, UINT8* config_space,
   148                               GUEST_PCI_READ_HANDLER pci_read, GUEST_PCI_WRITE_HANDLER pci_write)
   149  {
   150      GUEST_PCI_DEVICE *guest_pci_device = NULL;
   151      GUEST_PCI_DEVICES *gpci = find_guest_devices(guest_id);
   152      PCI_DEV_INDEX dev_index = 0;
   153  
   154      VMM_ASSERT(NULL != gpci);
   155      VMM_ASSERT(NULL != host_pci_device);
   156      dev_index = gpci->device_lookup_table[host_pci_device->address];
   157      if(dev_index != 0) { // already registered
   158          VMM_LOG(mask_anonymous, level_trace,"Warning: guest pci duplicate registration: guest #%d device(%d, %d, %d)\r\n",
   159              guest_id, GET_PCI_BUS(host_pci_device->address), GET_PCI_DEVICE(host_pci_device->address), GET_PCI_FUNCTION(host_pci_device->address));
   160          return FALSE;
   161      }
   162      dev_index = (PCI_DEV_INDEX) gpci->num_devices++;
   163      VMM_ASSERT(dev_index < PCI_MAX_NUM_SUPPORTED_DEVICES + 1);
   164      gpci->device_lookup_table[host_pci_device->address] = dev_index;
   165      guest_pci_device = &gpci->devices[dev_index];
   166      vmm_zeromem(guest_pci_device, sizeof(GUEST_PCI_DEVICE));
   167      guest_pci_device->guest_id = guest_id;
   168      guest_pci_device->host_device = host_pci_device;
   169      guest_pci_device->config_space = config_space;
   170      guest_pci_device->pci_read = pci_read;
   171      guest_pci_device->pci_write = pci_write;
   172      guest_pci_device->type = type;
   173      switch(type) {
   174        case GUEST_DEVICE_VIRTUALIZATION_DIRECT_ASSIGNMENT:
   175          hash64_insert(device_to_guest, (UINT64) host_pci_device->address, guest_id);
   176  
   177        case GUEST_DEVICE_VIRTUALIZATION_HIDDEN:
   178          break;
   179        default:
   180          break;
   181      }
   182      return TRUE;
   183  }
   184  
   185  static GUEST_PCI_DEVICES* find_guest_devices(GUEST_ID guest_id)
   186  {
   187      GUEST_PCI_DEVICES *guest_devices = NULL;
   188      LIST_ELEMENT *guest_iter = NULL;
   189      BOOLEAN guest_found = FALSE;
   190  
   191      LIST_FOR_EACH(guest_pci_devices, guest_iter) {
   192          guest_devices = LIST_ENTRY(guest_iter, GUEST_PCI_DEVICES, guests);
   193          if(guest_devices->guest_id == guest_id) {
   194              guest_found = TRUE;
   195              break;
   196          }
   197      }
   198      if(guest_found) {
   199          return guest_devices;
   200      }
   201      return NULL;
   202  }
   203  
   204  #ifdef INCLUDE_UNUSED_CODE
   205  static GUEST_PCI_DEVICE* find_device(GUEST_ID guest_id, UINT8 bus, UINT8 device, UINT8 function)
   206  {
   207      GUEST_PCI_DEVICES *gpci;
   208      PCI_DEV_INDEX dev_index;
   209  
   210      gpci = find_guest_devices(guest_id);
   211      VMM_ASSERT(gpci);
   212      dev_index = gpci->device_lookup_table[PCI_GET_ADDRESS(bus, device, function)];
   213      if(dev_index == 0) {
   214          return NULL;
   215      }
   216      return &gpci->devices[dev_index];
   217  }
   218  
   219  void gpci_unregister_device(GUEST_ID guest_id, UINT16 bus, UINT16 device, UINT16 function)
   220  {
   221      GUEST_PCI_DEVICE *guest_pci_device = NULL;
   222      GUEST_PCI_DEVICES *gpci;
   223      PCI_DEV_INDEX dev_index;
   224  
   225      gpci = find_guest_devices(guest_id);
   226      VMM_ASSERT(gpci);
   227  
   228      dev_index = gpci->device_lookup_table[PCI_GET_ADDRESS(bus, device, function)];
   229      if(dev_index == 0) { // not found
   230          return;
   231      }
   232  
   233      guest_pci_device = &gpci->devices[dev_index];
   234      if(guest_pci_device->type == GUEST_DEVICE_VIRTUALIZATION_DIRECT_ASSIGNMENT) {
   235          hash64_remove(device_to_guest, (UINT64) guest_pci_device->host_device->address);
   236      }
   237      gpci->device_lookup_table[PCI_GET_ADDRESS(bus, device, function)] = 0;
   238  }
   239  #endif
   240  
   241  GUEST_ID gpci_get_device_guest_id(UINT16 bus, UINT16 device, UINT16 function)
   242  {
   243      BOOLEAN status = FALSE;
   244      UINT64 owner_guest_id = 0;
   245  
   246      if(FALSE == PCI_IS_ADDRESS_VALID(bus, device, function)) {
   247          return INVALID_GUEST_ID;
   248      }
   249      status = hash64_lookup(device_to_guest, (UINT64) PCI_GET_ADDRESS(bus, device, function), &owner_guest_id);
   250      return (GUEST_ID) owner_guest_id;
   251  }
   252  
   253  static void pci_read_hide (GUEST_CPU_HANDLE  gcpu UNUSED, GUEST_PCI_DEVICE *pci_device UNUSED,
   254                      UINT32 port_id UNUSED, UINT32 port_size, void *value)
   255  {
   256      vmm_memset(value, 0xff, port_size);
   257  }
   258  
   259  static void pci_write_hide (GUEST_CPU_HANDLE  gcpu UNUSED, GUEST_PCI_DEVICE *pci_device UNUSED,
   260                       UINT32 port_id UNUSED, UINT32 port_size UNUSED, void *value UNUSED)
   261  {
   262  }
   263  
   264  static void pci_read_passthrough (GUEST_CPU_HANDLE  gcpu, GUEST_PCI_DEVICE *pci_device UNUSED,
   265                             UINT32 port_id, UINT32 port_size, void   *value)
   266  {
   267      io_transparent_read_handler(gcpu, (IO_PORT_ID) port_id, port_size, value);
   268  }
   269  
   270  static void pci_write_passthrough (GUEST_CPU_HANDLE  gcpu, GUEST_PCI_DEVICE *pci_device UNUSED,
   271                              UINT32 port_id, UINT32 port_size, void   *value)
   272  {
   273      io_transparent_write_handler(gcpu, (IO_PORT_ID) port_id, port_size, &value);
   274  }
   275  
   276  #ifdef INCLUDE_UNUSED_CODE
   277  static void io_read_pci_address(GUEST_CPU_HANDLE  gcpu,
   278                                  UINT16            port_id UNUSED,
   279                                  unsigned          port_size, // 1, 2, 4
   280                                  void              *p_value)
   281  {
   282      GUEST_PCI_DEVICES *gpci = NULL;
   283      const VIRTUAL_CPU_ID *vcpu = NULL;
   284  
   285      vcpu = guest_vcpu(gcpu);
   286      VMM_ASSERT(vcpu);
   287  
   288      gpci = find_guest_devices(vcpu->guest_id);
   289      VMM_ASSERT(gpci);
   290  
   291      vmm_memcpy(p_value, (void *) &(gpci->gcpu_pci_access_address[vcpu->guest_cpu_id]), port_size);
   292  
   293  }
   294  
   295  static void io_write_pci_address(GUEST_CPU_HANDLE  gcpu,
   296                                   UINT16            port_id UNUSED,
   297                                   unsigned          port_size, // 1, 2, 4
   298                                   void              *p_value)
   299  {
   300      GUEST_PCI_DEVICES *gpci = NULL;
   301      const VIRTUAL_CPU_ID *vcpu = NULL;
   302  
   303      vcpu = guest_vcpu(gcpu);
   304      VMM_ASSERT(vcpu);
   305  
   306      gpci = find_guest_devices(vcpu->guest_id);
   307      VMM_ASSERT(gpci);
   308  
   309      vmm_memcpy((void *) &(gpci->gcpu_pci_access_address[vcpu->guest_cpu_id]), p_value, port_size);
   310  }
   311  
   312  static void io_pci_address_handler(GUEST_CPU_HANDLE  gcpu,
   313                        UINT16 port_id, unsigned  port_size, // 1, 2, 4
   314                        RW_ACCESS access, void *p_value)
   315  {
   316      VMM_LOG(mask_anonymous, level_trace,"io_pci_address_handler cpu#%d: port %p size %p rw %p\n", hw_cpu_id(), port_id, port_size, access);
   317      switch (access) {
   318      case WRITE_ACCESS:
   319          io_write_pci_address(gcpu, port_id, port_size, p_value);
   320          break;
   321      case READ_ACCESS:
   322          io_read_pci_address(gcpu, port_id, port_size, p_value);
   323          break;
   324      default:
   325          VMM_LOG(mask_anonymous, level_trace,"Invalid IO access(%d)\n", access);
   326          VMM_DEADLOOP();
   327          break;
   328      }
   329  }
   330  
   331  static void io_read_pci_data(GUEST_CPU_HANDLE  gcpu,
   332                        UINT16 port_id, unsigned port_size, // 1, 2, 4
   333                        void   *p_value)
   334  {
   335      GUEST_PCI_DEVICES *gpci = NULL;
   336      const VIRTUAL_CPU_ID *vcpu = NULL;
   337      PCI_CONFIG_ADDRESS *pci_addr = NULL;
   338      GUEST_PCI_DEVICE *guest_pci_device = NULL;
   339  
   340      vcpu = guest_vcpu(gcpu);
   341      VMM_ASSERT(vcpu);
   342  
   343      gpci = find_guest_devices(vcpu->guest_id);
   344      VMM_ASSERT(gpci);
   345  
   346      pci_addr = &gpci->gcpu_pci_access_address[vcpu->guest_cpu_id];
   347      guest_pci_device = find_device(vcpu->guest_id, (UINT8) pci_addr->Bits.Bus, (UINT8) pci_addr->Bits.Device, (UINT8) pci_addr->Bits.Function);
   348  
   349      if(0 == pci_addr->Bits.Enable || guest_pci_device == NULL) {
   350          vmm_memset(p_value, 0xff, port_size);
   351      }
   352      else {
   353          guest_pci_device->pci_read(gcpu, guest_pci_device, port_id, port_size, p_value);
   354      }
   355  }
   356  
   357  
   358  static void io_write_pci_data(GUEST_CPU_HANDLE  gcpu,
   359                        UINT16  port_id, unsigned  port_size, // 1, 2, 4
   360                        void *p_value)
   361  {
   362      GUEST_PCI_DEVICES *gpci = NULL;
   363      const VIRTUAL_CPU_ID *vcpu = NULL;
   364      PCI_CONFIG_ADDRESS *pci_addr = NULL;
   365      GUEST_PCI_DEVICE *device = NULL;
   366  
   367      vcpu = guest_vcpu(gcpu);
   368      VMM_ASSERT(vcpu);
   369  
   370      gpci = find_guest_devices(vcpu->guest_id);
   371      VMM_ASSERT(gpci);
   372  
   373      pci_addr = &gpci->gcpu_pci_access_address[vcpu->guest_cpu_id];
   374      device = find_device(vcpu->guest_id, (UINT8) pci_addr->Bits.Bus, (UINT8) pci_addr->Bits.Device, (UINT8) pci_addr->Bits.Function);
   375  
   376      if(1 == pci_addr->Bits.Enable && device != NULL) {
   377          device->pci_write(gcpu, device, port_id, port_size, p_value);
   378      }
   379  }
   380  
   381  static void io_pci_data_handler(GUEST_CPU_HANDLE  gcpu,
   382                        UINT16 port_id, unsigned  port_size, // 1, 2, 4
   383                        RW_ACCESS access, void  *p_value)
   384  {
   385      VMM_LOG(mask_anonymous, level_trace,
   386              "io_pci_data_handler cpu#%d: port %p size %p rw %p\n", 
   387               hw_cpu_id(), port_id, port_size, access);
   388      switch (access) {
   389        case WRITE_ACCESS:
   390          io_write_pci_data(gcpu, port_id, port_size, p_value);
   391          break;
   392        case READ_ACCESS:
   393          io_read_pci_data(gcpu, port_id, port_size, p_value);
   394          break;
   395        default:
   396          VMM_LOG(mask_anonymous, level_trace,"Invalid IO access(%d)\n", access);
   397          VMM_DEADLOOP();
   398          break;
   399      }
   400  }
   401  #endif
   402  
   403  #endif //PCI_SCAN
   404