1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 8 * See "LICENSE_GPLv2.txt" for details. 9 * 10 * @TAG(DATA61_GPL) 11 */ 12 13#include <config.h> 14 15#ifdef CONFIG_VTX 16 17#include <model/statedata.h> 18#include <arch/kernel/ept.h> 19#include <arch/api/invocation.h> 20 21struct lookupEPTPDPTSlot_ret { 22 exception_t status; 23 ept_pdpte_t* pdptSlot; 24}; 25typedef struct lookupEPTPDPTSlot_ret lookupEPTPDPTSlot_ret_t; 26 27struct lookupEPTPDSlot_ret { 28 exception_t status; 29 ept_pde_t* pdSlot; 30}; 31typedef struct lookupEPTPDSlot_ret lookupEPTPDSlot_ret_t; 32 33struct lookupEPTPTSlot_ret { 34 exception_t status; 35 ept_pte_t* ptSlot; 36}; 37typedef struct lookupEPTPTSlot_ret lookupEPTPTSlot_ret_t; 38 39enum ept_cache_options { 40 EPTUncacheable = 0, 41 EPTWriteCombining = 1, 42 EPTWriteThrough = 4, 43 EPTWriteProtected = 5, 44 EPTWriteBack = 6 45}; 46typedef enum ept_cache_options ept_cache_options_t; 47 48void 49deleteEPTASID(asid_t asid, ept_pml4e_t *ept) 50{ 51 asid_pool_t* poolPtr; 52 53 poolPtr = x86KSASIDTable[asid >> asidLowBits]; 54 if (poolPtr != NULL) { 55 asid_map_t asid_map = poolPtr->array[asid & MASK(asidLowBits)]; 56 if (asid_map_get_type(asid_map) == asid_map_asid_map_ept && 57 (ept_pml4e_t*)asid_map_asid_map_ept_get_ept_root(asid_map) == ept) { 58 poolPtr->array[asid & MASK(asidLowBits)] = asid_map_asid_map_none_new(); 59 } 60 } 61} 62 63exception_t 64performX86EPTPageInvocationUnmap(cap_t cap, cte_t *ctSlot) 65{ 66 unmapEPTPage( 67 cap_frame_cap_get_capFSize(cap), 68 cap_frame_cap_get_capFMappedASID(cap), 69 cap_frame_cap_get_capFMappedAddress(cap), 70 (void *)cap_frame_cap_get_capFBasePtr(cap) 71 ); 72 73 cap_frame_cap_ptr_set_capFMappedAddress(&ctSlot->cap, 0); 74 cap_frame_cap_ptr_set_capFMappedASID(&ctSlot->cap, asidInvalid); 75 cap_frame_cap_ptr_set_capFMapType(&ctSlot->cap, X86_MappingNone); 76 77 return EXCEPTION_NONE; 78} 79 80findEPTForASID_ret_t 81findEPTForASID(asid_t asid) 82{ 83 findEPTForASID_ret_t ret; 84 asid_map_t asid_map; 85 86 asid_map = findMapForASID(asid); 87 if (asid_map_get_type(asid_map) != asid_map_asid_map_ept) { 88 current_lookup_fault = lookup_fault_invalid_root_new(); 89 90 ret.ept = NULL; 91 ret.status = EXCEPTION_LOOKUP_FAULT; 92 return ret; 93 } 94 95 ret.ept = (ept_pml4e_t*)asid_map_asid_map_ept_get_ept_root(asid_map); 96 ret.status = EXCEPTION_NONE; 97 return ret; 98} 99 100static ept_pml4e_t* CONST 101lookupEPTPML4Slot(ept_pml4e_t *pml4, vptr_t vptr) 102{ 103 return pml4 + GET_EPT_PML4_INDEX(vptr); 104} 105 106static lookupEPTPDPTSlot_ret_t CONST 107lookupEPTPDPTSlot(ept_pml4e_t *pml4, vptr_t vptr) 108{ 109 lookupEPTPDPTSlot_ret_t ret; 110 ept_pml4e_t *pml4Slot; 111 112 pml4Slot = lookupEPTPML4Slot(pml4, vptr); 113 114 if (!ept_pml4e_ptr_get_read(pml4Slot)) { 115 current_lookup_fault = lookup_fault_missing_capability_new(22); 116 117 ret.pdptSlot = NULL; 118 ret.status = EXCEPTION_LOOKUP_FAULT; 119 return ret; 120 } 121 122 ept_pdpte_t *pdpt = paddr_to_pptr(ept_pml4e_ptr_get_pdpt_base_address(pml4Slot)); 123 uint32_t index = GET_EPT_PDPT_INDEX(vptr); 124 ret.pdptSlot = pdpt + index; 125 ret.status = EXCEPTION_NONE; 126 return ret; 127} 128 129static lookupEPTPDSlot_ret_t 130lookupEPTPDSlot(ept_pml4e_t* pml4, vptr_t vptr) 131{ 132 lookupEPTPDSlot_ret_t ret; 133 lookupEPTPDPTSlot_ret_t lu_ret; 134 135 lu_ret = lookupEPTPDPTSlot(pml4, vptr); 136 if (lu_ret.status != EXCEPTION_NONE) { 137 current_syscall_error.type = seL4_FailedLookup; 138 current_syscall_error.failedLookupWasSource = false; 139 /* current_lookup_fault will have been set by lookupEPTPDPTSlot */ 140 ret.pdSlot = NULL; 141 ret.status = EXCEPTION_LOOKUP_FAULT; 142 return ret; 143 } 144 145 if (!ept_pdpte_ptr_get_read(lu_ret.pdptSlot)) { 146 current_lookup_fault = lookup_fault_missing_capability_new(22); 147 148 ret.pdSlot = NULL; 149 ret.status = EXCEPTION_LOOKUP_FAULT; 150 return ret; 151 } 152 153 ept_pde_t *pd = paddr_to_pptr(ept_pdpte_ptr_get_pd_base_address(lu_ret.pdptSlot)); 154 uint32_t index = GET_EPT_PD_INDEX(vptr); 155 ret.pdSlot = pd + index; 156 ret.status = EXCEPTION_NONE; 157 return ret; 158} 159 160static lookupEPTPTSlot_ret_t 161lookupEPTPTSlot(ept_pml4e_t* pml4, vptr_t vptr) 162{ 163 lookupEPTPTSlot_ret_t ret; 164 lookupEPTPDSlot_ret_t lu_ret; 165 166 lu_ret = lookupEPTPDSlot(pml4, vptr); 167 if (lu_ret.status != EXCEPTION_NONE) { 168 current_syscall_error.type = seL4_FailedLookup; 169 current_syscall_error.failedLookupWasSource = false; 170 /* current_lookup_fault will have been set by lookupEPTPDSlot */ 171 ret.ptSlot = NULL; 172 ret.status = EXCEPTION_LOOKUP_FAULT; 173 return ret; 174 } 175 176 if ((ept_pde_ptr_get_page_size(lu_ret.pdSlot) != ept_pde_ept_pde_pt) || 177 !ept_pde_ept_pde_pt_ptr_get_read(lu_ret.pdSlot)) { 178 current_lookup_fault = lookup_fault_missing_capability_new(22); 179 180 ret.ptSlot = NULL; 181 ret.status = EXCEPTION_LOOKUP_FAULT; 182 return ret; 183 } 184 185 ept_pte_t *pt = paddr_to_pptr(ept_pde_ept_pde_pt_ptr_get_pt_base_address(lu_ret.pdSlot)); 186 uint32_t index = GET_EPT_PT_INDEX(vptr); 187 188 ret.ptSlot = pt + index; 189 ret.status = EXCEPTION_NONE; 190 return ret; 191} 192 193static ept_cache_options_t 194eptCacheFromVmAttr(vm_attributes_t vmAttr) 195{ 196 /* PAT cache options are 1-1 with ept_cache_options. But need to 197 verify user has specified a sensible option */ 198 ept_cache_options_t option = vmAttr.words[0]; 199 if (option != EPTUncacheable || 200 option != EPTWriteCombining || 201 option != EPTWriteThrough || 202 option != EPTWriteBack) { 203 /* No failure mode is supported here, vmAttr settings should be verified earlier */ 204 option = EPTWriteBack; 205 } 206 return option; 207} 208 209EPTPDPTMapped_ret_t 210EPTPDPTMapped(asid_t asid, vptr_t vptr, ept_pdpte_t *pdpt) 211{ 212 EPTPDPTMapped_ret_t ret; 213 findEPTForASID_ret_t asid_ret; 214 ept_pml4e_t *pml4Slot; 215 216 asid_ret = findEPTForASID(asid); 217 if (asid_ret.status != EXCEPTION_NONE) { 218 ret.pml4 = NULL; 219 ret.pml4Slot = NULL; 220 ret.status = asid_ret.status; 221 return ret; 222 } 223 224 pml4Slot = lookupEPTPML4Slot(asid_ret.ept, vptr); 225 226 if (ept_pml4e_ptr_get_read(pml4Slot) 227 && ptrFromPAddr(ept_pml4e_ptr_get_pdpt_base_address(pml4Slot)) == pdpt) { 228 ret.pml4 = asid_ret.ept; 229 ret.pml4Slot = pml4Slot; 230 ret.status = EXCEPTION_NONE; 231 return ret; 232 } else { 233 ret.pml4 = NULL; 234 ret.pml4Slot = NULL; 235 ret.status = EXCEPTION_LOOKUP_FAULT; 236 return ret; 237 } 238} 239 240void 241unmapEPTPDPT(asid_t asid, vptr_t vaddr, ept_pdpte_t *pdpt) 242{ 243 EPTPDPTMapped_ret_t lu_ret; 244 245 lu_ret = EPTPDPTMapped(asid, vaddr, pdpt); 246 247 if (lu_ret.status == EXCEPTION_NONE) { 248 *lu_ret.pml4Slot = ept_pml4e_new(0, 0, 0, 0); 249 invept(lu_ret.pml4); 250 } 251} 252 253static exception_t 254performEPTPDPTInvocationUnmap(cap_t cap, cte_t *cte) 255{ 256 if (cap_ept_pdpt_cap_get_capPDPTIsMapped(cap)) { 257 ept_pdpte_t *pdpt = (ept_pdpte_t*)cap_ept_pdpt_cap_get_capPDPTBasePtr(cap); 258 unmapEPTPDPT( 259 cap_ept_pdpt_cap_get_capPDPTMappedASID(cap), 260 cap_ept_pdpt_cap_get_capPDPTMappedAddress(cap), 261 pdpt); 262 clearMemory((void *)pdpt, cap_get_capSizeBits(cap)); 263 } 264 cap_ept_pdpt_cap_ptr_set_capPDPTIsMapped(&(cte->cap), 0); 265 266 return EXCEPTION_NONE; 267} 268 269static exception_t 270performEPTPDPTInvocationMap(cap_t cap, cte_t *cte, ept_pml4e_t pml4e, ept_pml4e_t *pml4Slot, ept_pml4e_t *pml4) 271{ 272 cte->cap = cap; 273 *pml4Slot = pml4e; 274 invept(pml4); 275 276 return EXCEPTION_NONE; 277} 278 279static exception_t 280decodeX86EPTPDPTInvocation( 281 word_t invLabel, 282 word_t length, 283 cte_t *cte, 284 cap_t cap, 285 extra_caps_t excaps, 286 word_t *buffer 287) 288{ 289 word_t vaddr; 290 cap_t pml4Cap; 291 ept_pml4e_t* pml4; 292 ept_pml4e_t pml4e; 293 paddr_t paddr; 294 asid_t asid; 295 findEPTForASID_ret_t find_ret; 296 ept_pml4e_t* pml4Slot; 297 298 if (invLabel == X86EPTPDPTUnmap) { 299 if (!isFinalCapability(cte)) { 300 current_syscall_error.type = seL4_RevokeFirst; 301 return EXCEPTION_SYSCALL_ERROR; 302 } 303 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 304 return performEPTPDPTInvocationUnmap(cap, cte); 305 } 306 307 if (invLabel != X86EPTPDPTMap) { 308 userError("X86EPTPDPT Illegal operation."); 309 current_syscall_error.type = seL4_IllegalOperation; 310 return EXCEPTION_SYSCALL_ERROR; 311 } 312 313 if (length < 2 || excaps.excaprefs[0] == NULL) { 314 userError("X86EPTPDPTMap: Truncated message."); 315 current_syscall_error.type = seL4_TruncatedMessage; 316 return EXCEPTION_SYSCALL_ERROR; 317 } 318 319 if (cap_ept_pdpt_cap_get_capPDPTIsMapped(cap)) { 320 userError("X86EPTPDPTMap: EPT PDPT is already mapped to a PML4."); 321 current_syscall_error.type = seL4_InvalidCapability; 322 current_syscall_error.invalidCapNumber = 0; 323 324 return EXCEPTION_SYSCALL_ERROR; 325 } 326 327 vaddr = getSyscallArg(0, buffer); 328 /* cannot use ~MASK(EPT_PML4_INDEX_OFFSET) because on 32-bit compilations 329 * this results in an error shifting by greater than 31 bits, so we manually 330 * force a 64-bit variable to do the shifting with */ 331 vaddr = vaddr & ~(((uint64_t)1 << EPT_PML4_INDEX_OFFSET) - 1); 332 pml4Cap = excaps.excaprefs[0]->cap; 333 334 if (cap_get_capType(pml4Cap) != cap_ept_pml4_cap) { 335 userError("X86EPTPDPTMap: Not a valid EPT PML4."); 336 current_syscall_error.type = seL4_InvalidCapability; 337 current_syscall_error.invalidCapNumber = 1; 338 339 return EXCEPTION_SYSCALL_ERROR; 340 } 341 342 pml4 = (ept_pml4e_t*)cap_ept_pml4_cap_get_capPML4BasePtr(pml4Cap); 343 asid = cap_ept_pml4_cap_get_capPML4MappedASID(pml4Cap); 344 345 find_ret = findEPTForASID(asid); 346 if (find_ret.status != EXCEPTION_NONE) { 347 current_syscall_error.type = seL4_FailedLookup; 348 current_syscall_error.failedLookupWasSource = false; 349 350 return EXCEPTION_SYSCALL_ERROR; 351 } 352 353 if (find_ret.ept != pml4) { 354 current_syscall_error.type = seL4_InvalidCapability; 355 current_syscall_error.invalidCapNumber = 1; 356 357 return EXCEPTION_SYSCALL_ERROR; 358 } 359 360 pml4Slot = lookupEPTPML4Slot(pml4, vaddr); 361 362 if (ept_pml4e_ptr_get_read(pml4Slot)) { 363 userError("X86EPTPDPTMap: PDPT already mapped here."); 364 current_syscall_error.type = seL4_DeleteFirst; 365 return EXCEPTION_SYSCALL_ERROR; 366 } 367 368 paddr = pptr_to_paddr((void*)cap_ept_pdpt_cap_get_capPDPTBasePtr(cap)); 369 pml4e = ept_pml4e_new( 370 paddr, 371 1, 372 1, 373 1 374 ); 375 376 cap = cap_ept_pdpt_cap_set_capPDPTIsMapped(cap, 1); 377 cap = cap_ept_pdpt_cap_set_capPDPTMappedASID(cap, asid); 378 cap = cap_ept_pdpt_cap_set_capPDPTMappedAddress(cap, vaddr); 379 380 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 381 return performEPTPDPTInvocationMap(cap, cte, pml4e, pml4Slot, pml4); 382} 383 384exception_t 385decodeX86EPTInvocation( 386 word_t invLabel, 387 word_t length, 388 cptr_t cptr, 389 cte_t* cte, 390 cap_t cap, 391 extra_caps_t excaps, 392 word_t* buffer 393) 394{ 395 switch (cap_get_capType(cap)) { 396 case cap_ept_pdpt_cap: 397 return decodeX86EPTPDPTInvocation(invLabel, length, cte, cap, excaps, buffer); 398 case cap_ept_pd_cap: 399 return decodeX86EPTPDInvocation(invLabel, length, cte, cap, excaps, buffer); 400 case cap_ept_pt_cap: 401 return decodeX86EPTPTInvocation(invLabel, length, cte, cap, excaps, buffer); 402 default: 403 fail("Invalid cap type"); 404 } 405} 406 407EPTPageDirectoryMapped_ret_t 408EPTPageDirectoryMapped(asid_t asid, vptr_t vaddr, ept_pde_t *pd) 409{ 410 EPTPageDirectoryMapped_ret_t ret; 411 lookupEPTPDPTSlot_ret_t find_ret; 412 findEPTForASID_ret_t asid_ret; 413 414 asid_ret = findEPTForASID(asid); 415 if (asid_ret.status != EXCEPTION_NONE) { 416 ret.pml4 = NULL; 417 ret.pdptSlot = NULL; 418 ret.status = asid_ret.status; 419 return ret; 420 } 421 422 find_ret = lookupEPTPDPTSlot(asid_ret.ept, vaddr); 423 if (find_ret.status != EXCEPTION_NONE) { 424 ret.pml4 = NULL; 425 ret.pdptSlot = NULL; 426 ret.status = find_ret.status; 427 return ret; 428 } 429 430 if (ept_pdpte_ptr_get_read(find_ret.pdptSlot) 431 && ptrFromPAddr(ept_pdpte_ptr_get_pd_base_address(find_ret.pdptSlot)) == pd) { 432 ret.pml4 = asid_ret.ept; 433 ret.pdptSlot = find_ret.pdptSlot; 434 ret.status = EXCEPTION_NONE; 435 return ret; 436 } else { 437 ret.pml4 = NULL; 438 ret.pdptSlot = NULL; 439 ret.status = EXCEPTION_LOOKUP_FAULT; 440 return ret; 441 } 442} 443 444void 445unmapEPTPageDirectory(asid_t asid, vptr_t vaddr, ept_pde_t *pd) 446{ 447 EPTPageDirectoryMapped_ret_t lu_ret; 448 449 lu_ret = EPTPageDirectoryMapped(asid, vaddr, pd); 450 451 if (lu_ret.status == EXCEPTION_NONE) { 452 *lu_ret.pdptSlot = ept_pdpte_new( 453 0, /* pd_base_address */ 454 0, /* avl_cte_depth */ 455 0, /* execute */ 456 0, /* write */ 457 0 /* read */ 458 ); 459 invept(lu_ret.pml4); 460 } 461} 462 463static exception_t 464performEPTPDInvocationUnmap(cap_t cap, cte_t *cte) 465{ 466 if (cap_ept_pd_cap_get_capPDIsMapped(cap)) { 467 ept_pde_t *pd = (ept_pde_t*)cap_ept_pd_cap_get_capPDBasePtr(cap); 468 unmapEPTPageDirectory( 469 cap_ept_pd_cap_get_capPDMappedASID(cap), 470 cap_ept_pd_cap_get_capPDMappedAddress(cap), 471 pd); 472 clearMemory((void*)pd, cap_get_capSizeBits(cap)); 473 } 474 cap_ept_pd_cap_ptr_set_capPDIsMapped(&(cte->cap), 0); 475 476 return EXCEPTION_NONE; 477} 478 479static exception_t 480performEPTPDInvocationMap(cap_t cap, cte_t *cte, ept_pdpte_t pdpte, ept_pdpte_t *pdptSlot, ept_pml4e_t *pml4) 481{ 482 cte->cap = cap; 483 *pdptSlot = pdpte; 484 invept(pml4); 485 486 return EXCEPTION_NONE; 487} 488 489exception_t 490decodeX86EPTPDInvocation( 491 word_t invLabel, 492 word_t length, 493 cte_t* cte, 494 cap_t cap, 495 extra_caps_t excaps, 496 word_t* buffer 497) 498{ 499 word_t vaddr; 500 cap_t pml4Cap; 501 ept_pml4e_t* pml4; 502 ept_pdpte_t pdpte; 503 paddr_t paddr; 504 asid_t asid; 505 findEPTForASID_ret_t find_ret; 506 lookupEPTPDPTSlot_ret_t lu_ret; 507 508 if (invLabel == X86EPTPDUnmap) { 509 if (!isFinalCapability(cte)) { 510 current_syscall_error.type = seL4_RevokeFirst; 511 return EXCEPTION_SYSCALL_ERROR; 512 } 513 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 514 return performEPTPDInvocationUnmap(cap, cte); 515 } 516 517 if (invLabel != X86EPTPDMap) { 518 userError("X86EPTPD Illegal operation."); 519 current_syscall_error.type = seL4_IllegalOperation; 520 return EXCEPTION_SYSCALL_ERROR; 521 } 522 523 if (length < 2 || excaps.excaprefs[0] == NULL) { 524 userError("X86EPTPDMap: Truncated message."); 525 current_syscall_error.type = seL4_TruncatedMessage; 526 return EXCEPTION_SYSCALL_ERROR; 527 } 528 529 if (cap_ept_pd_cap_get_capPDIsMapped(cap)) { 530 userError("X86EPTPDMap: EPT Page directory is already mapped to a PDPT."); 531 current_syscall_error.type = 532 seL4_InvalidCapability; 533 current_syscall_error.invalidCapNumber = 0; 534 535 return EXCEPTION_SYSCALL_ERROR; 536 } 537 538 vaddr = getSyscallArg(0, buffer); 539 vaddr = vaddr & ~MASK(EPT_PDPT_INDEX_OFFSET); 540 pml4Cap = excaps.excaprefs[0]->cap; 541 542 if (cap_get_capType(pml4Cap) != cap_ept_pml4_cap) { 543 userError("X86EPTPDMap: Not a valid EPT pml4."); 544 current_syscall_error.type = seL4_InvalidCapability; 545 current_syscall_error.invalidCapNumber = 1; 546 547 return EXCEPTION_SYSCALL_ERROR; 548 } 549 550 pml4 = (ept_pml4e_t*)cap_ept_pml4_cap_get_capPML4BasePtr(pml4Cap); 551 asid = cap_ept_pml4_cap_get_capPML4MappedASID(pml4Cap); 552 553 find_ret = findEPTForASID(asid); 554 if (find_ret.status != EXCEPTION_NONE) { 555 userError("X86EPTPDMap: EPT PML4 is not mapped."); 556 current_syscall_error.type = seL4_FailedLookup; 557 current_syscall_error.failedLookupWasSource = false; 558 559 return EXCEPTION_SYSCALL_ERROR; 560 } 561 562 if (find_ret.ept != pml4) { 563 userError("X86EPTPDMap: EPT PML4 asid is invalid."); 564 current_syscall_error.type = seL4_InvalidCapability; 565 current_syscall_error.invalidCapNumber = 1; 566 567 return EXCEPTION_SYSCALL_ERROR; 568 } 569 570 lu_ret = lookupEPTPDPTSlot(pml4, vaddr); 571 if (lu_ret.status != EXCEPTION_NONE) { 572 current_syscall_error.type = seL4_FailedLookup; 573 current_syscall_error.failedLookupWasSource = false; 574 return EXCEPTION_SYSCALL_ERROR; 575 } 576 577 if (ept_pdpte_ptr_get_read(lu_ret.pdptSlot)) { 578 userError("X86EPTPDMap: Page directory already mapped here."); 579 current_syscall_error.type = seL4_DeleteFirst; 580 return EXCEPTION_SYSCALL_ERROR; 581 } 582 583 paddr = pptr_to_paddr((void*)(cap_ept_pd_cap_get_capPDBasePtr(cap))); 584 pdpte = ept_pdpte_new( 585 paddr, /* pd_base_address */ 586 0, /* avl_cte_depth */ 587 1, /* execute */ 588 1, /* write */ 589 1 /* read */ 590 ); 591 592 cap = cap_ept_pd_cap_set_capPDIsMapped(cap, 1); 593 cap = cap_ept_pd_cap_set_capPDMappedASID(cap, asid); 594 cap = cap_ept_pd_cap_set_capPDMappedAddress(cap, vaddr); 595 596 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 597 return performEPTPDInvocationMap(cap, cte, pdpte, lu_ret.pdptSlot, pml4); 598} 599 600EPTPageTableMapped_ret_t 601EPTPageTableMapped(asid_t asid, vptr_t vaddr, ept_pte_t *pt) 602{ 603 EPTPageTableMapped_ret_t ret; 604 lookupEPTPDSlot_ret_t find_ret; 605 findEPTForASID_ret_t asid_ret; 606 607 asid_ret = findEPTForASID(asid); 608 if (asid_ret.status != EXCEPTION_NONE) { 609 ret.pml4 = NULL; 610 ret.pdSlot = NULL; 611 ret.status = asid_ret.status; 612 return ret; 613 } 614 615 find_ret = lookupEPTPDSlot(asid_ret.ept, vaddr); 616 if (find_ret.status != EXCEPTION_NONE) { 617 ret.pml4 = NULL; 618 ret.pdSlot = NULL; 619 ret.status = find_ret.status; 620 return ret; 621 } 622 623 if (ept_pde_ptr_get_page_size(find_ret.pdSlot) == ept_pde_ept_pde_pt 624 && ptrFromPAddr(ept_pde_ept_pde_pt_ptr_get_pt_base_address(find_ret.pdSlot)) == pt) { 625 ret.pml4 = asid_ret.ept; 626 ret.pdSlot = find_ret.pdSlot; 627 ret.status = EXCEPTION_NONE; 628 return ret; 629 } else { 630 ret.pml4 = NULL; 631 ret.pdSlot = NULL; 632 ret.status = EXCEPTION_LOOKUP_FAULT; 633 return ret; 634 } 635} 636 637void 638unmapEPTPageTable(asid_t asid, vptr_t vaddr, ept_pte_t *pt) 639{ 640 EPTPageTableMapped_ret_t lu_ret; 641 642 lu_ret = EPTPageTableMapped(asid, vaddr, pt); 643 644 if (lu_ret.status == EXCEPTION_NONE) { 645 *lu_ret.pdSlot = ept_pde_ept_pde_pt_new( 646 0, /* pt_base_address */ 647 0, /* avl_cte_depth */ 648 0, /* execute */ 649 0, /* write */ 650 0 /* read */ 651 ); 652 invept(lu_ret.pml4); 653 } 654} 655 656static exception_t 657performEPTPTInvocationUnmap(cap_t cap, cte_t *cte) 658{ 659 if (cap_ept_pt_cap_get_capPTIsMapped(cap)) { 660 ept_pte_t *pt = (ept_pte_t*)cap_ept_pt_cap_get_capPTBasePtr(cap); 661 unmapEPTPageTable( 662 cap_ept_pt_cap_get_capPTMappedASID(cap), 663 cap_ept_pt_cap_get_capPTMappedAddress(cap), 664 pt); 665 clearMemory((void *)pt, cap_get_capSizeBits(cap)); 666 } 667 cap_ept_pt_cap_ptr_set_capPTIsMapped(&(cte->cap), 0); 668 669 return EXCEPTION_NONE; 670} 671 672static exception_t 673performEPTPTInvocationMap(cap_t cap, cte_t *cte, ept_pde_t pde, ept_pde_t *pdSlot, ept_pml4e_t *pml4) 674{ 675 cte->cap = cap; 676 *pdSlot = pde; 677 invept(pml4); 678 679 return EXCEPTION_NONE; 680} 681 682exception_t 683decodeX86EPTPTInvocation( 684 word_t invLabel, 685 word_t length, 686 cte_t* cte, 687 cap_t cap, 688 extra_caps_t excaps, 689 word_t* buffer 690) 691{ 692 word_t vaddr; 693 cap_t pml4Cap; 694 ept_pml4e_t* pml4; 695 ept_pde_t pde; 696 paddr_t paddr; 697 asid_t asid; 698 findEPTForASID_ret_t find_ret; 699 lookupEPTPDSlot_ret_t lu_ret; 700 701 if (invLabel == X86EPTPTUnmap) { 702 if (!isFinalCapability(cte)) { 703 current_syscall_error.type = seL4_RevokeFirst; 704 return EXCEPTION_SYSCALL_ERROR; 705 } 706 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 707 return performEPTPTInvocationUnmap(cap, cte); 708 } 709 710 if (invLabel != X86EPTPTMap) { 711 userError("X86EPTPT Illegal operation."); 712 current_syscall_error.type = seL4_IllegalOperation; 713 return EXCEPTION_SYSCALL_ERROR; 714 } 715 716 if (length < 2 || excaps.excaprefs[0] == NULL) { 717 userError("X86EPTPT: Truncated message."); 718 current_syscall_error.type = seL4_TruncatedMessage; 719 return EXCEPTION_SYSCALL_ERROR; 720 } 721 722 if (cap_ept_pt_cap_get_capPTIsMapped(cap)) { 723 userError("X86EPTPT EPT Page table is already mapped to an EPT page directory."); 724 current_syscall_error.type = 725 seL4_InvalidCapability; 726 current_syscall_error.invalidCapNumber = 0; 727 728 return EXCEPTION_SYSCALL_ERROR; 729 } 730 731 vaddr = getSyscallArg(0, buffer); 732 vaddr = vaddr & ~MASK(EPT_PD_INDEX_OFFSET); 733 pml4Cap = excaps.excaprefs[0]->cap; 734 735 if (cap_get_capType(pml4Cap) != cap_ept_pml4_cap || 736 !cap_ept_pml4_cap_get_capPML4IsMapped(pml4Cap)) { 737 userError("X86EPTPTMap: Not a valid EPT pml4."); 738 current_syscall_error.type = seL4_InvalidCapability; 739 current_syscall_error.invalidCapNumber = 1; 740 741 return EXCEPTION_SYSCALL_ERROR; 742 } 743 744 pml4 = (ept_pml4e_t*)(cap_ept_pml4_cap_get_capPML4BasePtr(pml4Cap)); 745 asid = cap_ept_pml4_cap_get_capPML4MappedASID(pml4Cap); 746 747 find_ret = findEPTForASID(asid); 748 if (find_ret.status != EXCEPTION_NONE) { 749 current_syscall_error.type = seL4_FailedLookup; 750 current_syscall_error.failedLookupWasSource = false; 751 752 return EXCEPTION_SYSCALL_ERROR; 753 } 754 755 if (find_ret.ept != pml4) { 756 current_syscall_error.type = seL4_InvalidCapability; 757 current_syscall_error.invalidCapNumber = 1; 758 759 return EXCEPTION_SYSCALL_ERROR; 760 } 761 762 lu_ret = lookupEPTPDSlot(pml4, vaddr); 763 if (lu_ret.status != EXCEPTION_NONE) { 764 current_syscall_error.type = seL4_FailedLookup; 765 current_syscall_error.failedLookupWasSource = false; 766 /* current_lookup_fault will have been set by lookupPTSlot */ 767 return EXCEPTION_SYSCALL_ERROR; 768 } 769 770 if (((ept_pde_ptr_get_page_size(lu_ret.pdSlot) == ept_pde_ept_pde_pt) && 771 ept_pde_ept_pde_pt_ptr_get_read(lu_ret.pdSlot)) || 772 ((ept_pde_ptr_get_page_size(lu_ret.pdSlot) == ept_pde_ept_pde_2m) && 773 ept_pde_ept_pde_2m_ptr_get_read(lu_ret.pdSlot))) { 774 userError("X86EPTPTMap: Page table already mapped here"); 775 current_syscall_error.type = seL4_DeleteFirst; 776 return EXCEPTION_SYSCALL_ERROR; 777 } 778 779 paddr = pptr_to_paddr((void*)(cap_ept_pt_cap_get_capPTBasePtr(cap))); 780 pde = ept_pde_ept_pde_pt_new( 781 paddr,/* pt_base_address */ 782 0, /* avl_cte_depth */ 783 1, /* execute */ 784 1, /* write */ 785 1 /* read */ 786 ); 787 788 cap = cap_ept_pt_cap_set_capPTIsMapped(cap, 1); 789 cap = cap_ept_pt_cap_set_capPTMappedASID(cap, asid); 790 cap = cap_ept_pt_cap_set_capPTMappedAddress(cap, vaddr); 791 792 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 793 return performEPTPTInvocationMap(cap, cte, pde, lu_ret.pdSlot, pml4); 794} 795 796static exception_t 797performEPTPageMapPTE(cap_t cap, cte_t *cte, ept_pte_t *ptSlot, ept_pte_t pte, ept_pml4e_t *pml4) 798{ 799 *ptSlot = pte; 800 cte->cap = cap; 801 invept(pml4); 802 803 return EXCEPTION_NONE; 804} 805 806static exception_t 807performEPTPageMapPDE(cap_t cap, cte_t *cte, ept_pde_t *pdSlot, ept_pde_t pde1, ept_pde_t pde2, ept_pml4e_t *pml4) 808{ 809 pdSlot[0] = pde1; 810 if (LARGE_PAGE_BITS == 22) { 811 pdSlot[1] = pde2; 812 } 813 cte->cap = cap; 814 invept(pml4); 815 816 return EXCEPTION_NONE; 817} 818 819exception_t 820decodeX86EPTPageMap( 821 word_t invLabel, 822 word_t length, 823 cte_t* cte, 824 cap_t cap, 825 extra_caps_t excaps, 826 word_t* buffer) 827{ 828 word_t vaddr; 829 word_t w_rightsMask; 830 paddr_t paddr; 831 cap_t pml4Cap; 832 ept_pml4e_t* pml4; 833 vm_rights_t capVMRights; 834 vm_rights_t vmRights; 835 vm_attributes_t vmAttr; 836 vm_page_size_t frameSize; 837 asid_t asid; 838 839 frameSize = cap_frame_cap_get_capFSize(cap); 840 vaddr = getSyscallArg(0, buffer); 841 vaddr = vaddr & ~MASK(EPT_PT_INDEX_OFFSET); 842 w_rightsMask = getSyscallArg(1, buffer); 843 vmAttr = vmAttributesFromWord(getSyscallArg(2, buffer)); 844 pml4Cap = excaps.excaprefs[0]->cap; 845 846 capVMRights = cap_frame_cap_get_capFVMRights(cap); 847 848 if (cap_frame_cap_get_capFMappedASID(cap) != asidInvalid) { 849 userError("X86EPTPageMap: Frame already mapped."); 850 current_syscall_error.type = seL4_InvalidCapability; 851 current_syscall_error.invalidCapNumber = 0; 852 853 return EXCEPTION_SYSCALL_ERROR; 854 } 855 856 assert(cap_frame_cap_get_capFMapType(cap) == X86_MappingNone); 857 858 if (cap_get_capType(pml4Cap) != cap_ept_pml4_cap || 859 !cap_ept_pml4_cap_get_capPML4IsMapped(pml4Cap)) { 860 userError("X86EPTPageMap: Attempting to map frame into invalid ept pml4."); 861 current_syscall_error.type = seL4_InvalidCapability; 862 current_syscall_error.invalidCapNumber = 1; 863 864 return EXCEPTION_SYSCALL_ERROR; 865 } 866 867 pml4 = (ept_pml4e_t*)(cap_ept_pml4_cap_get_capPML4BasePtr(pml4Cap)); 868 asid = cap_ept_pml4_cap_get_capPML4MappedASID(pml4Cap); 869 870 findEPTForASID_ret_t find_ret = findEPTForASID(asid); 871 if (find_ret.status != EXCEPTION_NONE) { 872 current_syscall_error.type = seL4_FailedLookup; 873 current_syscall_error.failedLookupWasSource = false; 874 875 return EXCEPTION_SYSCALL_ERROR; 876 } 877 878 if (find_ret.ept != pml4) { 879 current_syscall_error.type = seL4_InvalidCapability; 880 current_syscall_error.invalidCapNumber = 1; 881 882 return EXCEPTION_SYSCALL_ERROR; 883 } 884 885 886 vmRights = maskVMRights(capVMRights, rightsFromWord(w_rightsMask)); 887 888 if (!checkVPAlignment(frameSize, vaddr)) { 889 current_syscall_error.type = seL4_AlignmentError; 890 891 return EXCEPTION_SYSCALL_ERROR; 892 } 893 894 paddr = pptr_to_paddr((void*)cap_frame_cap_get_capFBasePtr(cap)); 895 896 cap = cap_frame_cap_set_capFMappedASID(cap, asid); 897 cap = cap_frame_cap_set_capFMappedAddress(cap, vaddr); 898 cap = cap_frame_cap_set_capFMapType(cap, X86_MappingEPT); 899 900 switch (frameSize) { 901 /* PTE mappings */ 902 case X86_SmallPage: { 903 lookupEPTPTSlot_ret_t lu_ret; 904 ept_pte_t pte; 905 906 lu_ret = lookupEPTPTSlot(pml4, vaddr); 907 if (lu_ret.status != EXCEPTION_NONE) { 908 current_syscall_error.type = seL4_FailedLookup; 909 current_syscall_error.failedLookupWasSource = false; 910 /* current_lookup_fault will have been set by lookupEPTPTSlot */ 911 return EXCEPTION_SYSCALL_ERROR; 912 } 913 914 if (ept_pte_ptr_get_read(lu_ret.ptSlot)) { 915 userError("X86EPTPageMap: Mapping already present."); 916 current_syscall_error.type = seL4_DeleteFirst; 917 return EXCEPTION_SYSCALL_ERROR; 918 } 919 920 pte = ept_pte_new( 921 paddr, 922 0, 923 0, 924 eptCacheFromVmAttr(vmAttr), 925 1, 926 WritableFromVMRights(vmRights), 927 1); 928 929 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 930 return performEPTPageMapPTE(cap, cte, lu_ret.ptSlot, pte, pml4); 931 } 932 933 /* PDE mappings */ 934 case X86_LargePage: { 935 lookupEPTPDSlot_ret_t lu_ret; 936 937 lu_ret = lookupEPTPDSlot(pml4, vaddr); 938 if (lu_ret.status != EXCEPTION_NONE) { 939 userError("X86EPTPageMap: Need a page directory first."); 940 current_syscall_error.type = seL4_FailedLookup; 941 current_syscall_error.failedLookupWasSource = false; 942 /* current_lookup_fault will have been set by lookupEPTPDSlot */ 943 return EXCEPTION_SYSCALL_ERROR; 944 } 945 946 947 if ((ept_pde_ptr_get_page_size(lu_ret.pdSlot) == ept_pde_ept_pde_pt) && 948 ept_pde_ept_pde_pt_ptr_get_read(lu_ret.pdSlot)) { 949 userError("X86EPTPageMap: Page table already present."); 950 current_syscall_error.type = seL4_DeleteFirst; 951 return EXCEPTION_SYSCALL_ERROR; 952 } 953 if (LARGE_PAGE_BITS != EPT_PD_INDEX_OFFSET && 954 (ept_pde_ptr_get_page_size(lu_ret.pdSlot + 1) == ept_pde_ept_pde_pt) && 955 ept_pde_ept_pde_pt_ptr_get_read(lu_ret.pdSlot + 1)) { 956 userError("X86EPTPageMap: Page table already present."); 957 current_syscall_error.type = seL4_DeleteFirst; 958 return EXCEPTION_SYSCALL_ERROR; 959 } 960 if ((ept_pde_ptr_get_page_size(lu_ret.pdSlot) == ept_pde_ept_pde_2m) && 961 ept_pde_ept_pde_2m_ptr_get_read(lu_ret.pdSlot)) { 962 userError("X86EPTPageMap: Mapping already present."); 963 current_syscall_error.type = seL4_DeleteFirst; 964 return EXCEPTION_SYSCALL_ERROR; 965 } 966 967 ept_pde_t pde1 = ept_pde_ept_pde_2m_new( 968 paddr, 969 0, 970 0, 971 eptCacheFromVmAttr(vmAttr), 972 1, 973 WritableFromVMRights(vmRights), 974 1); 975 976 ept_pde_t pde2 = ept_pde_ept_pde_2m_new( 977 paddr + BIT(EPT_PD_INDEX_OFFSET), 978 0, 979 0, 980 eptCacheFromVmAttr(vmAttr), 981 1, 982 WritableFromVMRights(vmRights), 983 1); 984 985 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 986 return performEPTPageMapPDE(cap, cte, lu_ret.pdSlot, pde1, pde2, pml4); 987 } 988 989 default: 990 /* When initializing EPT we only checked for support for 4K and 2M 991 * pages, so we must disallow attempting to use any other */ 992 userError("X86EPTPageMap: Attempted to map unsupported page size."); 993 current_syscall_error.type = seL4_InvalidCapability; 994 current_syscall_error.invalidCapNumber = 0; 995 return EXCEPTION_SYSCALL_ERROR; 996 } 997} 998 999void 1000unmapEPTPage(vm_page_size_t page_size, asid_t asid, vptr_t vptr, void *pptr) 1001{ 1002 findEPTForASID_ret_t find_ret; 1003 paddr_t addr = addrFromPPtr(pptr); 1004 1005 find_ret = findEPTForASID(asid); 1006 if (find_ret.status != EXCEPTION_NONE) { 1007 return; 1008 } 1009 1010 switch (page_size) { 1011 case X86_SmallPage: { 1012 lookupEPTPTSlot_ret_t lu_ret; 1013 1014 lu_ret = lookupEPTPTSlot(find_ret.ept, vptr); 1015 if (lu_ret.status != EXCEPTION_NONE) { 1016 return; 1017 } 1018 if (!ept_pte_ptr_get_read(lu_ret.ptSlot)) { 1019 return; 1020 } 1021 if (ept_pte_ptr_get_page_base_address(lu_ret.ptSlot) != addr) { 1022 return; 1023 } 1024 1025 *lu_ret.ptSlot = ept_pte_new(0, 0, 0, 0, 0, 0, 0); 1026 break; 1027 } 1028 case X86_LargePage: { 1029 lookupEPTPDSlot_ret_t lu_ret; 1030 1031 lu_ret = lookupEPTPDSlot(find_ret.ept, vptr); 1032 if (lu_ret.status != EXCEPTION_NONE) { 1033 return; 1034 } 1035 if (ept_pde_ptr_get_page_size(lu_ret.pdSlot) != ept_pde_ept_pde_2m) { 1036 return; 1037 } 1038 if (!ept_pde_ept_pde_2m_ptr_get_read(lu_ret.pdSlot)) { 1039 return; 1040 } 1041 if (ept_pde_ept_pde_2m_ptr_get_page_base_address(lu_ret.pdSlot) != addr) { 1042 return; 1043 } 1044 1045 lu_ret.pdSlot[0] = ept_pde_ept_pde_2m_new(0, 0, 0, 0, 0, 0, 0); 1046 1047 if (LARGE_PAGE_BITS != EPT_PD_INDEX_OFFSET) { 1048 assert(ept_pde_ptr_get_page_size(lu_ret.pdSlot + 1) == ept_pde_ept_pde_2m); 1049 assert(ept_pde_ept_pde_2m_ptr_get_read(lu_ret.pdSlot + 1)); 1050 assert(ept_pde_ept_pde_2m_ptr_get_page_base_address(lu_ret.pdSlot + 1) == addr + BIT(21)); 1051 1052 lu_ret.pdSlot[1] = ept_pde_ept_pde_2m_new(0, 0, 0, 0, 0, 0, 0); 1053 } 1054 break; 1055 } 1056 default: 1057 /* we did not allow mapping additional page sizes into EPT objects, 1058 * so this should not happen. As we have no way to return an error 1059 * all we can do is assert */ 1060 assert(!"Invalid page size for unmap"); 1061 } 1062} 1063 1064#endif /* CONFIG_VTX */ 1065