github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/memory/memory_manager/gpm.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 <vmm_defs.h> 16 #include <gpm_api.h> 17 #include <memory_address_mapper_api.h> 18 #include <host_memory_manager_api.h> 19 #include <e820_abstraction.h> 20 #include <heap.h> 21 #include <vmm_dbg.h> 22 #include "file_codes.h" 23 24 #define VMM_DEADLOOP() VMM_DEADLOOP_LOG(GPM_C) 25 #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(GPM_C, __condition) 26 #ifdef JLMDEBUG 27 #include "jlmdebug.h" 28 #endif 29 30 #define GPM_INVALID_MAPPING (MAM_MAPPING_SUCCESSFUL + 1) 31 #define GPM_MMIO (MAM_MAPPING_SUCCESSFUL + 2) 32 33 34 typedef struct GPM_S { 35 MAM_HANDLE gpa_to_hpa; 36 MAM_HANDLE hpa_to_gpa; 37 } GPM; 38 39 static BOOLEAN gpm_get_range_details_and_advance_mam_iterator(IN MAM_HANDLE mam_handle, 40 IN OUT MAM_MEMORY_RANGES_ITERATOR* mem_ranges_iter, 41 OUT UINT64* range_start, OUT UINT64* range_size) { 42 MAM_MEMORY_RANGES_ITERATOR iter = *mem_ranges_iter; 43 MAM_MAPPING_RESULT res; 44 45 VMM_ASSERT(*mem_ranges_iter != MAM_INVALID_MEMORY_RANGES_ITERATOR); 46 do { 47 UINT64 tgt_addr; 48 MAM_ATTRIBUTES attrs; 49 50 iter = mam_get_range_details_from_iterator(mam_handle, iter, range_start, range_size); 51 res = mam_get_mapping(mam_handle, *range_start, &tgt_addr, &attrs); 52 } while ((res != MAM_MAPPING_SUCCESSFUL) && 53 (res != GPM_MMIO) && 54 (iter != MAM_INVALID_MEMORY_RANGES_ITERATOR)); 55 56 *mem_ranges_iter = iter; 57 if (iter != MAM_INVALID_MEMORY_RANGES_ITERATOR) { 58 return TRUE; 59 } 60 if ((res == MAM_MAPPING_SUCCESSFUL) || (res == GPM_MMIO)) { 61 return TRUE; 62 } 63 return FALSE; 64 } 65 66 67 BOOLEAN gpm_remove_all_relevant_hpa_to_gpa_mapping(GPM* gpm, GPA gpa, UINT64 size) { 68 MAM_HANDLE gpa_to_hpa; 69 MAM_HANDLE hpa_to_gpa; 70 UINT64 gpa_tmp; 71 gpa_to_hpa = gpm->gpa_to_hpa; 72 hpa_to_gpa = gpm->hpa_to_gpa; 73 74 // Remove all hpa mappings 75 for (gpa_tmp = gpa; gpa_tmp < gpa + size; gpa_tmp += PAGE_4KB_SIZE) { 76 UINT64 hpa; 77 MAM_ATTRIBUTES attrs; 78 79 if (mam_get_mapping(gpa_to_hpa, gpa_tmp, &hpa, &attrs) == MAM_MAPPING_SUCCESSFUL) { 80 if (!mam_insert_not_existing_range(hpa_to_gpa, hpa, PAGE_4KB_SIZE, GPM_INVALID_MAPPING)) { 81 return FALSE; 82 } 83 } 84 } 85 return TRUE; 86 } 87 88 89 GPM_HANDLE gpm_create_mapping(void) { 90 GPM* gpm; 91 MAM_HANDLE gpa_to_hpa; 92 MAM_HANDLE hpa_to_gpa; 93 94 gpm = (GPM*)vmm_memory_alloc(sizeof(GPM)); 95 if (gpm == NULL) { 96 goto failed_to_allocated_gpm; 97 } 98 gpa_to_hpa = mam_create_mapping(MAM_NO_ATTRIBUTES); 99 if (gpa_to_hpa == MAM_INVALID_HANDLE) { 100 goto failed_to_allocate_gpa_to_hpa_mapping; 101 } 102 hpa_to_gpa = mam_create_mapping(MAM_NO_ATTRIBUTES); 103 if (hpa_to_gpa == MAM_INVALID_HANDLE) { 104 goto failed_to_allocate_hpa_to_gpa_mapping; 105 } 106 gpm->gpa_to_hpa = gpa_to_hpa; 107 gpm->hpa_to_gpa = hpa_to_gpa; 108 return (GPM_HANDLE)gpm; 109 110 failed_to_allocate_hpa_to_gpa_mapping: 111 mam_destroy_mapping(gpa_to_hpa); 112 failed_to_allocate_gpa_to_hpa_mapping: 113 vmm_memory_free(gpm); 114 failed_to_allocated_gpm: 115 return GPM_INVALID_HANDLE; 116 } 117 118 BOOLEAN gpm_add_mapping(IN GPM_HANDLE gpm_handle, IN GPA gpa, IN HPA hpa, IN UINT64 size, MAM_ATTRIBUTES attrs) { 119 GPM* gpm = (GPM*)gpm_handle; 120 MAM_HANDLE gpa_to_hpa; 121 122 if (gpm_handle == GPM_INVALID_HANDLE) { 123 return FALSE; 124 } 125 gpa_to_hpa = gpm->gpa_to_hpa; 126 if (!mam_insert_range(gpa_to_hpa, (UINT64)gpa, (UINT64)hpa, size, attrs)) { 127 return FALSE; 128 } 129 #ifdef USE_HPA_TO_GPA 130 MAM_HANDLE hpa_to_gpa; 131 hpa_to_gpa = gpm->hpa_to_gpa; 132 if (!mam_insert_range(hpa_to_gpa, (UINT64)hpa, (UINT64)gpa, size, attrs)) { 133 return FALSE; 134 } 135 #endif 136 return TRUE; 137 } 138 139 BOOLEAN gpm_remove_mapping(IN GPM_HANDLE gpm_handle, IN GPA gpa, IN UINT64 size) { 140 GPM* gpm = (GPM*)gpm_handle; 141 MAM_HANDLE gpa_to_hpa; 142 143 if (gpm_handle == GPM_INVALID_HANDLE) { 144 return FALSE; 145 } 146 #ifdef USE_HPA_TO_GPA 147 // Remove all hpa mappings 148 if (!gpm_remove_all_relevant_hpa_to_gpa_mapping(gpm, gpa, size)) { 149 return FALSE; 150 } 151 #endif 152 gpa_to_hpa = gpm->gpa_to_hpa; 153 return (BOOLEAN)mam_insert_not_existing_range(gpa_to_hpa, (UINT64)gpa, size, GPM_INVALID_MAPPING); 154 } 155 156 157 BOOLEAN gpm_add_mmio_range(IN GPM_HANDLE gpm_handle, IN GPA gpa, IN UINT64 size) { 158 GPM* gpm = (GPM*)gpm_handle; 159 MAM_HANDLE gpa_to_hpa; 160 161 if (gpm_handle == GPM_INVALID_HANDLE) { 162 return FALSE; 163 } 164 165 #ifdef USE_HPA_TO_GPA 166 // Remove all hpa mappings 167 if (!gpm_remove_all_relevant_hpa_to_gpa_mapping(gpm, gpa, size)) { 168 return FALSE; 169 } 170 #endif 171 gpa_to_hpa = gpm->gpa_to_hpa; 172 return (BOOLEAN)mam_insert_not_existing_range(gpa_to_hpa, 173 (UINT64)gpa, size, GPM_MMIO); 174 } 175 176 BOOLEAN gpm_is_mmio_address(IN GPM_HANDLE gpm_handle, IN GPA gpa) { 177 GPM* gpm = (GPM*)gpm_handle; 178 MAM_HANDLE gpa_to_hpa; 179 UINT64 hpa_tmp; 180 MAM_MAPPING_RESULT res; 181 MAM_ATTRIBUTES attrs; 182 183 if (gpm_handle == GPM_INVALID_HANDLE) { 184 return FALSE; 185 } 186 gpa_to_hpa = gpm->gpa_to_hpa; 187 res = (BOOLEAN)mam_get_mapping(gpa_to_hpa, (UINT64)gpa, &hpa_tmp, &attrs); 188 if (res != GPM_MMIO) { 189 return FALSE; 190 } 191 return TRUE; 192 } 193 194 195 BOOLEAN gpm_gpa_to_hpa(IN GPM_HANDLE gpm_handle, IN GPA gpa, OUT HPA* hpa, 196 OUT MAM_ATTRIBUTES *hpa_attrs) { 197 GPM* gpm = (GPM*)gpm_handle; 198 MAM_HANDLE gpa_to_hpa; 199 UINT64 hpa_tmp; 200 MAM_MAPPING_RESULT res; 201 MAM_ATTRIBUTES attrs; 202 203 if (gpm_handle == GPM_INVALID_HANDLE) { 204 return FALSE; 205 } 206 gpa_to_hpa = gpm->gpa_to_hpa; 207 res = mam_get_mapping(gpa_to_hpa, (UINT64)gpa, &hpa_tmp, &attrs); 208 if (res != MAM_MAPPING_SUCCESSFUL) { 209 return FALSE; 210 } 211 *hpa = *((HPA*)(&hpa_tmp)); 212 *hpa_attrs = *((MAM_ATTRIBUTES*)(&attrs)); 213 return TRUE; 214 } 215 216 BOOLEAN gpm_gpa_to_hva(IN GPM_HANDLE gpm_handle, IN GPA gpa, OUT HVA* hva) { 217 GPM* gpm = (GPM*)gpm_handle; 218 MAM_HANDLE gpa_to_hpa; 219 UINT64 hpa_tmp; 220 UINT64 hva_tmp; 221 HPA hpa; 222 MAM_MAPPING_RESULT res; 223 MAM_ATTRIBUTES attrs; 224 225 if (gpm_handle == GPM_INVALID_HANDLE) { 226 return FALSE; 227 } 228 gpa_to_hpa = gpm->gpa_to_hpa; 229 res = (BOOLEAN)mam_get_mapping(gpa_to_hpa, (UINT64)gpa, &hpa_tmp, &attrs); 230 if (res != MAM_MAPPING_SUCCESSFUL) { 231 return FALSE; 232 } 233 hpa = *((HPA*)(&hpa_tmp)); 234 res = hmm_hpa_to_hva(hpa, &hva_tmp); 235 if (res) { 236 *hva = *((HVA*)(&hva_tmp)); 237 } 238 else { 239 VMM_LOG(mask_anonymous, level_trace,"Warning!!! Failed Translation Host Physical to Host Virtual\n"); 240 } 241 return res; 242 } 243 244 BOOLEAN gpm_hpa_to_gpa(IN GPM_HANDLE gpm_handle, IN HPA hpa, OUT GPA* gpa) { 245 GPM* gpm = (GPM*)gpm_handle; 246 MAM_HANDLE hpa_to_gpa; 247 UINT64 gpa_tmp; 248 MAM_MAPPING_RESULT res; 249 MAM_ATTRIBUTES attrs; 250 251 if (gpm_handle == GPM_INVALID_HANDLE) { 252 return FALSE; 253 } 254 255 hpa_to_gpa = gpm->hpa_to_gpa; 256 res = mam_get_mapping(hpa_to_gpa, (UINT64)hpa, &gpa_tmp, &attrs); 257 if (res != MAM_MAPPING_SUCCESSFUL) { 258 return FALSE; 259 } 260 *gpa = *((GPA*)(&gpa_tmp)); 261 return TRUE; 262 } 263 264 BOOLEAN gpm_create_e820_map(IN GPM_HANDLE gpm_handle, 265 OUT E820_HANDLE* e820_handle) { 266 GPM* gpm = (GPM*)gpm_handle; 267 MAM_HANDLE gpa_to_hpa; 268 E820_HANDLE e820_map; 269 E820_ABSTRACTION_RANGE_ITERATOR e820_iter; 270 MAM_MEMORY_RANGES_ITERATOR mem_ranges_iter; 271 GPA range_start; 272 UINT64 range_size; 273 GPA addr; 274 UINT64 size; 275 276 if (gpm_handle == GPM_INVALID_HANDLE) { 277 return FALSE; 278 } 279 gpa_to_hpa = gpm->gpa_to_hpa; 280 if (!e820_abstraction_create_new_map(&e820_map)) { 281 return FALSE; 282 } 283 e820_iter = e820_abstraction_iterator_get_first(E820_ORIGINAL_MAP); 284 mem_ranges_iter = mam_get_memory_ranges_iterator(gpa_to_hpa); 285 if ((mem_ranges_iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) || 286 (e820_iter == E820_ABSTRACTION_NULL_ITERATOR)) { 287 return FALSE; 288 } 289 if(!gpm_get_range_details_and_advance_mam_iterator(gpa_to_hpa, &mem_ranges_iter, &range_start, &range_size)) { 290 // No appropriate ranges exist 291 return FALSE; 292 } 293 while (e820_iter != E820_ABSTRACTION_NULL_ITERATOR) { 294 const INT15_E820_MEMORY_MAP_ENTRY_EXT* orig_map_entry = e820_abstraction_iterator_get_range_details(e820_iter); 295 296 if (((UINT64)range_start >= orig_map_entry->basic_entry.base_address) && 297 ((UINT64)range_start + range_size <= orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length)) { 298 BOOLEAN encountered_non_contigues_regions = FALSE; 299 while ((mem_ranges_iter != MAM_INVALID_MEMORY_RANGES_ITERATOR) && 300 ((UINT64)range_start + range_size <= orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length)) { 301 302 if(!gpm_get_range_details_and_advance_mam_iterator(gpa_to_hpa, &mem_ranges_iter, &addr, &size)) { 303 // There are no more ranges 304 break; 305 } 306 if (addr > (range_start + range_size)) { 307 if (!e820_abstraction_add_new_range(e820_map, range_start, range_size, orig_map_entry->basic_entry.address_range_type, orig_map_entry->extended_attributes)) { 308 goto failed_to_fill; 309 } 310 range_start = addr; 311 range_size = size; 312 encountered_non_contigues_regions = TRUE; 313 break; 314 } 315 else { 316 VMM_ASSERT(addr == (range_start + range_size)); 317 range_size += size; 318 } 319 } 320 if (encountered_non_contigues_regions) { 321 continue; // resume outer loop iterations. 322 } 323 if ((UINT64)range_start + range_size > orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length) { 324 continue; // There are global_case for it 325 } 326 VMM_ASSERT(mem_ranges_iter == MAM_INVALID_MEMORY_RANGES_ITERATOR); 327 if (!e820_abstraction_add_new_range(e820_map, range_start, range_size, orig_map_entry->basic_entry.address_range_type, orig_map_entry->extended_attributes)) { 328 goto failed_to_fill; 329 } 330 break; // There are no more gpm ranges 331 } 332 else if ((range_start + range_size) <= orig_map_entry->basic_entry.base_address) { 333 // Skip the range 334 if (mem_ranges_iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) { 335 break; // No more valid ranges 336 } 337 if (!gpm_get_range_details_and_advance_mam_iterator(gpa_to_hpa, &mem_ranges_iter, &range_start, &range_size)) { 338 break; 339 } 340 continue; 341 } 342 else if (orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length <= range_start) { 343 e820_iter = e820_abstraction_iterator_get_next(E820_ORIGINAL_MAP, e820_iter); 344 continue; 345 } 346 else if ((range_start < orig_map_entry->basic_entry.base_address) && 347 (range_start + range_size > orig_map_entry->basic_entry.base_address)) { 348 range_size = range_start + range_size - orig_map_entry->basic_entry.base_address; 349 range_start = orig_map_entry->basic_entry.base_address; 350 continue; 351 } 352 else { 353 UINT64 new_size = orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length - range_start; 354 VMM_ASSERT(range_start >= orig_map_entry->basic_entry.base_address); 355 VMM_ASSERT(range_start + range_size > orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length); 356 VMM_ASSERT(new_size > 0); 357 358 if (!e820_abstraction_add_new_range(e820_map, range_start, new_size, orig_map_entry->basic_entry.address_range_type, orig_map_entry->extended_attributes)) { 359 goto failed_to_fill; 360 } 361 range_start += new_size; 362 range_size -= new_size; 363 continue; 364 } 365 } 366 *e820_handle = e820_map; 367 return TRUE; 368 369 failed_to_fill: 370 e820_abstraction_destroy_map(e820_map); 371 return FALSE; 372 } 373 374 void gpm_destroy_e820_map(IN E820_HANDLE e820_handle) { 375 e820_abstraction_destroy_map(e820_handle); 376 } 377 378 379 MAM_MEMORY_RANGES_ITERATOR gpm_advance_mam_iterator_to_appropriate_range(MAM_HANDLE mam_handle, MAM_MEMORY_RANGES_ITERATOR iter) { 380 UINT64 src_addr; 381 UINT64 tgt_addr; 382 MAM_ATTRIBUTES attr; 383 MAM_MAPPING_RESULT res; 384 UINT64 size; 385 386 src_addr = mam_get_range_start_address_from_iterator(mam_handle, iter); 387 res = mam_get_mapping(mam_handle, src_addr, &tgt_addr, &attr); 388 while ((res != MAM_MAPPING_SUCCESSFUL) && 389 (res != GPM_MMIO) && 390 (iter != MAM_INVALID_MEMORY_RANGES_ITERATOR)) { 391 iter = mam_get_range_details_from_iterator(mam_handle, iter, &src_addr, &size); 392 src_addr = mam_get_range_start_address_from_iterator(mam_handle, iter); 393 res = mam_get_mapping(mam_handle, src_addr, &tgt_addr, &attr); 394 } 395 return iter; 396 } 397 398 GPM_RANGES_ITERATOR gpm_get_ranges_iterator(IN GPM_HANDLE gpm_handle) { 399 GPM* gpm = (GPM*)gpm_handle; 400 MAM_HANDLE gpa_to_hpa; 401 MAM_MEMORY_RANGES_ITERATOR iter; 402 403 if (gpm_handle == GPM_INVALID_HANDLE) { 404 return GPM_INVALID_RANGES_ITERATOR; 405 } 406 gpa_to_hpa = gpm->gpa_to_hpa; 407 iter = mam_get_memory_ranges_iterator(gpa_to_hpa); 408 if (iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) { 409 return GPM_INVALID_RANGES_ITERATOR; 410 } 411 iter = gpm_advance_mam_iterator_to_appropriate_range(gpa_to_hpa, iter); 412 if (iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) { 413 return GPM_INVALID_RANGES_ITERATOR; 414 } 415 return (GPM_RANGES_ITERATOR)iter; 416 } 417 418 GPM_RANGES_ITERATOR gpm_get_range_details_from_iterator(IN GPM_HANDLE gpm_handle, 419 IN GPM_RANGES_ITERATOR iter, OUT GPA* gpa_out, 420 OUT UINT64* size_out) { 421 GPM* gpm = (GPM*)gpm_handle; 422 MAM_HANDLE gpa_to_hpa; 423 MAM_MEMORY_RANGES_ITERATOR mam_iter = (MAM_MEMORY_RANGES_ITERATOR)iter; 424 425 // BEFORE_VMLAUNCH. CRITICAL check that should not fail. 426 VMM_ASSERT(gpm_handle != GPM_INVALID_HANDLE); 427 428 if (iter == GPM_INVALID_RANGES_ITERATOR) { 429 *gpa_out = ~((UINT64)0); 430 *size_out = 0; 431 return GPM_INVALID_RANGES_ITERATOR; 432 } 433 gpa_to_hpa = gpm->gpa_to_hpa; 434 mam_iter = mam_get_range_details_from_iterator(gpa_to_hpa, mam_iter, gpa_out, size_out); 435 mam_iter = gpm_advance_mam_iterator_to_appropriate_range(gpa_to_hpa, mam_iter); 436 if (mam_iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) { 437 return GPM_INVALID_RANGES_ITERATOR; 438 } 439 return (GPM_RANGES_ITERATOR)mam_iter; 440 } 441 442 #pragma warning (disable : 4100) 443 #pragma warning (disable : 4189) 444 445 void gpm_print(GPM_HANDLE gpm_handle USED_IN_DEBUG_ONLY) 446 { 447 VMM_DEBUG_CODE( 448 449 E820_HANDLE guest_e820 = NULL; 450 GPM_RANGES_ITERATOR gpm_iter = GPM_INVALID_RANGES_ITERATOR; 451 BOOLEAN status = FALSE; 452 GPA guest_range_addr = 0; 453 UINT64 guest_range_size = 0; 454 HPA host_range_addr = 0; 455 MAM_ATTRIBUTES attrs; 456 457 VMM_LOG(mask_anonymous, level_trace,"GPM ranges:\r\n"); 458 gpm_iter = gpm_get_ranges_iterator(gpm_handle); 459 while(GPM_INVALID_RANGES_ITERATOR != gpm_iter) { 460 gpm_iter = gpm_get_range_details_from_iterator(gpm_handle, 461 gpm_iter, &guest_range_addr, &guest_range_size); 462 status = gpm_gpa_to_hpa(gpm_handle, guest_range_addr, &host_range_addr, &attrs); 463 if(FALSE == status) { 464 VMM_LOG(mask_anonymous, level_trace,"GPM no mapping for gpa %p\r\n", guest_range_addr); 465 } 466 else { 467 VMM_LOG(mask_anonymous, level_trace," base %p size %p\r\n", guest_range_addr, guest_range_size); 468 } 469 } 470 gpm_create_e820_map(gpm_handle, &guest_e820); 471 e820_abstraction_print_memory_map(guest_e820); 472 ) 473 } 474 475 BOOLEAN gpm_copy(GPM_HANDLE src, GPM_HANDLE dst, BOOLEAN override_attrs, 476 MAM_ATTRIBUTES set_attrs) 477 { 478 GPM_RANGES_ITERATOR src_iter = GPM_INVALID_RANGES_ITERATOR; 479 GPA guest_range_addr = 0; 480 UINT64 guest_range_size = 0; 481 HPA host_range_addr = 0; 482 BOOLEAN status = FALSE; 483 MAM_ATTRIBUTES attrs; 484 485 src_iter = gpm_get_ranges_iterator(src); 486 while(GPM_INVALID_RANGES_ITERATOR != src_iter) { 487 src_iter = gpm_get_range_details_from_iterator(src, 488 src_iter, &guest_range_addr, 489 &guest_range_size); 490 status = gpm_gpa_to_hpa(src, guest_range_addr, &host_range_addr, &attrs); 491 if(FALSE == status) { // no mapping - is it mmio? 492 if(gpm_is_mmio_address(src, guest_range_addr)){ 493 status = gpm_add_mmio_range(dst, guest_range_addr, guest_range_size); 494 if(FALSE == status) { 495 goto failure; 496 } 497 } 498 else { 499 // normal memory - should not fail the mapping translation 500 goto failure; 501 } 502 } 503 else { 504 if (override_attrs) { 505 status = gpm_add_mapping(dst, guest_range_addr, host_range_addr, 506 guest_range_size, set_attrs); 507 } 508 else { 509 status = gpm_add_mapping(dst, guest_range_addr, host_range_addr, guest_range_size, attrs); 510 } 511 if(FALSE == status) { 512 goto failure; 513 } 514 } 515 } 516 return TRUE; 517 518 failure: 519 return FALSE; 520 } 521