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