1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#include <config.h> 8#include <types.h> 9#include <api/failures.h> 10#include <kernel/vspace.h> 11#include <object/structures.h> 12#include <arch/machine.h> 13#include <arch/model/statedata.h> 14#include <machine/fpu.h> 15#include <arch/object/objecttype.h> 16#include <arch/object/ioport.h> 17#include <plat/machine/devices.h> 18 19#include <arch/object/iospace.h> 20#include <arch/object/vcpu.h> 21#include <plat/machine/intel-vtd.h> 22 23deriveCap_ret_t Arch_deriveCap(cte_t *slot, cap_t cap) 24{ 25 deriveCap_ret_t ret; 26 27 switch (cap_get_capType(cap)) { 28 case cap_page_table_cap: 29 if (cap_page_table_cap_get_capPTIsMapped(cap)) { 30 ret.cap = cap; 31 ret.status = EXCEPTION_NONE; 32 } else { 33 userError("Deriving an unmapped PT cap"); 34 current_syscall_error.type = seL4_IllegalOperation; 35 ret.cap = cap_null_cap_new(); 36 ret.status = EXCEPTION_SYSCALL_ERROR; 37 } 38 return ret; 39 40 case cap_page_directory_cap: 41 if (cap_page_directory_cap_get_capPDIsMapped(cap)) { 42 ret.cap = cap; 43 ret.status = EXCEPTION_NONE; 44 } else { 45 userError("Deriving a PD cap without an assigned ASID"); 46 current_syscall_error.type = seL4_IllegalOperation; 47 ret.cap = cap_null_cap_new(); 48 ret.status = EXCEPTION_SYSCALL_ERROR; 49 } 50 return ret; 51 52 case cap_asid_control_cap: 53 case cap_asid_pool_cap: 54 ret.cap = cap; 55 ret.status = EXCEPTION_NONE; 56 return ret; 57 case cap_io_port_control_cap: 58 ret.status = EXCEPTION_NONE; 59 ret.cap = cap_null_cap_new(); 60 return ret; 61 case cap_io_port_cap: 62 ret.cap = cap; 63 ret.status = EXCEPTION_NONE; 64 return ret; 65 66#ifdef CONFIG_IOMMU 67 case cap_io_space_cap: 68 ret.cap = cap; 69 ret.status = EXCEPTION_NONE; 70 return ret; 71 case cap_io_page_table_cap: 72 if (cap_io_page_table_cap_get_capIOPTIsMapped(cap)) { 73 ret.cap = cap; 74 ret.status = EXCEPTION_NONE; 75 } else { 76 current_syscall_error.type = seL4_IllegalOperation; 77 ret.cap = cap_null_cap_new(); 78 ret.status = EXCEPTION_SYSCALL_ERROR; 79 } 80 return ret; 81#endif 82 83#ifdef CONFIG_VTX 84 case cap_vcpu_cap: 85 ret.cap = cap; 86 ret.status = EXCEPTION_NONE; 87 return ret; 88 case cap_ept_pml4_cap: 89 if (cap_ept_pml4_cap_get_capPML4IsMapped(cap)) { 90 ret.cap = cap; 91 ret.status = EXCEPTION_NONE; 92 } else { 93 userError("Deriving a EPT PML4 cap without an assigned ASID."); 94 current_syscall_error.type = seL4_IllegalOperation; 95 ret.cap = cap_null_cap_new(); 96 ret.status = EXCEPTION_SYSCALL_ERROR; 97 } 98 return ret; 99 case cap_ept_pdpt_cap: 100 if (cap_ept_pdpt_cap_get_capPDPTIsMapped(cap)) { 101 ret.cap = cap; 102 ret.status = EXCEPTION_NONE; 103 } else { 104 userError("Deriving an unmapped EPT PDPT cap."); 105 current_syscall_error.type = seL4_IllegalOperation; 106 ret.cap = cap_null_cap_new(); 107 ret.status = EXCEPTION_SYSCALL_ERROR; 108 } 109 return ret; 110 111 case cap_ept_pd_cap: 112 if (cap_ept_pd_cap_get_capPDIsMapped(cap)) { 113 ret.cap = cap; 114 ret.status = EXCEPTION_NONE; 115 } else { 116 userError("Deriving an unmapped EPT PD cap."); 117 current_syscall_error.type = seL4_IllegalOperation; 118 ret.cap = cap_null_cap_new(); 119 ret.status = EXCEPTION_SYSCALL_ERROR; 120 } 121 return ret; 122 123 case cap_ept_pt_cap: 124 if (cap_ept_pt_cap_get_capPTIsMapped(cap)) { 125 ret.cap = cap; 126 ret.status = EXCEPTION_NONE; 127 } else { 128 userError("Deriving an unmapped EPT PT cap."); 129 current_syscall_error.type = seL4_IllegalOperation; 130 ret.cap = cap_null_cap_new(); 131 ret.status = EXCEPTION_SYSCALL_ERROR; 132 } 133 return ret; 134#endif 135 136 default: 137 return Mode_deriveCap(slot, cap); 138 } 139} 140 141cap_t CONST Arch_updateCapData(bool_t preserve, word_t data, cap_t cap) 142{ 143 /* Avoid a switch statement with just a 'default' case as the C parser does not like this */ 144#ifdef CONFIG_IOMMU 145 switch (cap_get_capType(cap)) { 146 case cap_io_space_cap: { 147 io_space_capdata_t w = { { data } }; 148 uint16_t PCIDevice = io_space_capdata_get_PCIDevice(w); 149 uint16_t domainID = io_space_capdata_get_domainID(w); 150 if (!preserve && cap_io_space_cap_get_capPCIDevice(cap) == 0 && 151 domainID >= x86KSFirstValidIODomain && 152 domainID != 0 && 153 domainID <= MASK(x86KSnumIODomainIDBits)) { 154 return cap_io_space_cap_new(domainID, PCIDevice); 155 } else { 156 return cap_null_cap_new(); 157 } 158 } 159 160 default: 161 return cap; 162 } 163#endif 164 return cap; 165} 166 167cap_t CONST Arch_maskCapRights(seL4_CapRights_t cap_rights_mask, cap_t cap) 168{ 169 if (cap_get_capType(cap) == cap_frame_cap) { 170 vm_rights_t vm_rights; 171 172 vm_rights = vmRightsFromWord(cap_frame_cap_get_capFVMRights(cap)); 173 vm_rights = maskVMRights(vm_rights, cap_rights_mask); 174 return cap_frame_cap_set_capFVMRights(cap, wordFromVMRights(vm_rights)); 175 } else { 176 return cap; 177 } 178} 179 180finaliseCap_ret_t Arch_finaliseCap(cap_t cap, bool_t final) 181{ 182 finaliseCap_ret_t fc_ret; 183 184 switch (cap_get_capType(cap)) { 185 case cap_page_directory_cap: 186 if (final && cap_page_directory_cap_get_capPDIsMapped(cap)) { 187 unmapPageDirectory( 188 cap_page_directory_cap_get_capPDMappedASID(cap), 189 cap_page_directory_cap_get_capPDMappedAddress(cap), 190 PDE_PTR(cap_page_directory_cap_get_capPDBasePtr(cap)) 191 ); 192 } 193 break; 194 195 case cap_page_table_cap: 196 if (final && cap_page_table_cap_get_capPTIsMapped(cap)) { 197 unmapPageTable( 198 cap_page_table_cap_get_capPTMappedASID(cap), 199 cap_page_table_cap_get_capPTMappedAddress(cap), 200 PT_PTR(cap_page_table_cap_get_capPTBasePtr(cap)) 201 ); 202 } 203 break; 204 205 case cap_asid_pool_cap: 206 if (final) { 207 deleteASIDPool( 208 cap_asid_pool_cap_get_capASIDBase(cap), 209 ASID_POOL_PTR(cap_asid_pool_cap_get_capASIDPool(cap)) 210 ); 211 } 212 break; 213 case cap_asid_control_cap: 214 case cap_io_port_control_cap: 215 break; 216 case cap_io_port_cap: 217#ifdef CONFIG_VTX 218 clearVPIDIOPortMappings(cap_io_port_cap_get_capIOPortVPID(cap), 219 cap_io_port_cap_get_capIOPortFirstPort(cap), 220 cap_io_port_cap_get_capIOPortLastPort(cap)); 221#endif 222 if (final) { 223 fc_ret.remainder = cap_null_cap_new(); 224 fc_ret.cleanupInfo = cap; 225 return fc_ret; 226 } 227 break; 228#ifdef CONFIG_IOMMU 229 case cap_io_space_cap: 230 if (final) { 231 unmapVTDContextEntry(cap); 232 } 233 break; 234 235 case cap_io_page_table_cap: 236 if (final && cap_io_page_table_cap_get_capIOPTIsMapped(cap)) { 237 deleteIOPageTable(cap); 238 } 239 break; 240#endif 241 242#ifdef CONFIG_VTX 243 case cap_vcpu_cap: 244 if (final) { 245 vcpu_finalise(VCPU_PTR(cap_vcpu_cap_get_capVCPUPtr(cap))); 246 } 247 break; 248 case cap_ept_pml4_cap: 249 if (final && cap_ept_pml4_cap_get_capPML4IsMapped(cap)) { 250 deleteEPTASID(cap_ept_pml4_cap_get_capPML4MappedASID(cap), 251 (ept_pml4e_t *)cap_ept_pml4_cap_get_capPML4BasePtr(cap)); 252 } 253 break; 254 255 case cap_ept_pdpt_cap: 256 if (final && cap_ept_pdpt_cap_get_capPDPTIsMapped(cap)) { 257 unmapEPTPDPT( 258 cap_ept_pdpt_cap_get_capPDPTMappedASID(cap), 259 cap_ept_pdpt_cap_get_capPDPTMappedAddress(cap), 260 (ept_pdpte_t *)cap_ept_pdpt_cap_get_capPDPTBasePtr(cap)); 261 } 262 break; 263 264 case cap_ept_pd_cap: 265 if (final && cap_ept_pd_cap_get_capPDIsMapped(cap)) { 266 unmapEPTPageDirectory( 267 cap_ept_pd_cap_get_capPDMappedASID(cap), 268 cap_ept_pd_cap_get_capPDMappedAddress(cap), 269 (ept_pde_t *)cap_ept_pd_cap_get_capPDBasePtr(cap)); 270 } 271 break; 272 273 case cap_ept_pt_cap: 274 if (final && cap_ept_pt_cap_get_capPTIsMapped(cap)) { 275 unmapEPTPageTable( 276 cap_ept_pt_cap_get_capPTMappedASID(cap), 277 cap_ept_pt_cap_get_capPTMappedAddress(cap), 278 (ept_pte_t *)cap_ept_pt_cap_get_capPTBasePtr(cap)); 279 } 280 break; 281#endif 282 283 default: 284 return Mode_finaliseCap(cap, final); 285 } 286 287 fc_ret.remainder = cap_null_cap_new(); 288 fc_ret.cleanupInfo = cap_null_cap_new(); 289 return fc_ret; 290} 291 292bool_t CONST Arch_sameRegionAs(cap_t cap_a, cap_t cap_b) 293{ 294 switch (cap_get_capType(cap_a)) { 295 case cap_frame_cap: 296 if (cap_get_capType(cap_b) == cap_frame_cap) { 297 word_t botA, botB, topA, topB; 298 botA = cap_frame_cap_get_capFBasePtr(cap_a); 299 botB = cap_frame_cap_get_capFBasePtr(cap_b); 300 topA = botA + MASK(pageBitsForSize(cap_frame_cap_get_capFSize(cap_a))); 301 topB = botB + MASK(pageBitsForSize(cap_frame_cap_get_capFSize(cap_b))); 302 return ((botA <= botB) && (topA >= topB) && (botB <= topB)); 303 } 304 break; 305 306 case cap_page_table_cap: 307 if (cap_get_capType(cap_b) == cap_page_table_cap) { 308 return cap_page_table_cap_get_capPTBasePtr(cap_a) == 309 cap_page_table_cap_get_capPTBasePtr(cap_b); 310 } 311 break; 312 313 case cap_page_directory_cap: 314 if (cap_get_capType(cap_b) == cap_page_directory_cap) { 315 return cap_page_directory_cap_get_capPDBasePtr(cap_a) == 316 cap_page_directory_cap_get_capPDBasePtr(cap_b); 317 } 318 break; 319 320 case cap_asid_control_cap: 321 if (cap_get_capType(cap_b) == cap_asid_control_cap) { 322 return true; 323 } 324 break; 325 326 case cap_asid_pool_cap: 327 if (cap_get_capType(cap_b) == cap_asid_pool_cap) { 328 return cap_asid_pool_cap_get_capASIDPool(cap_a) == 329 cap_asid_pool_cap_get_capASIDPool(cap_b); 330 } 331 break; 332 333 case cap_io_port_control_cap: 334 if (cap_get_capType(cap_b) == cap_io_port_control_cap || 335 cap_get_capType(cap_b) == cap_io_port_cap) { 336 return true; 337 } 338 break; 339 340 case cap_io_port_cap: 341 if (cap_get_capType(cap_b) == cap_io_port_cap) { 342 return cap_io_port_cap_get_capIOPortFirstPort(cap_a) == 343 cap_io_port_cap_get_capIOPortFirstPort(cap_b) && 344 cap_io_port_cap_get_capIOPortLastPort(cap_a) == 345 cap_io_port_cap_get_capIOPortLastPort(cap_b); 346 } 347 break; 348 349#ifdef CONFIG_IOMMU 350 case cap_io_space_cap: 351 if (cap_get_capType(cap_b) == cap_io_space_cap) { 352 return cap_io_space_cap_get_capPCIDevice(cap_a) == 353 cap_io_space_cap_get_capPCIDevice(cap_b); 354 } 355 break; 356 357 case cap_io_page_table_cap: 358 if (cap_get_capType(cap_b) == cap_io_page_table_cap) { 359 return cap_io_page_table_cap_get_capIOPTBasePtr(cap_a) == 360 cap_io_page_table_cap_get_capIOPTBasePtr(cap_b); 361 } 362 break; 363#endif 364 365#ifdef CONFIG_VTX 366 case cap_vcpu_cap: 367 if (cap_get_capType(cap_b) == cap_vcpu_cap) { 368 return cap_vcpu_cap_get_capVCPUPtr(cap_a) == 369 cap_vcpu_cap_get_capVCPUPtr(cap_b); 370 } 371 break; 372 373 case cap_ept_pml4_cap: 374 if (cap_get_capType(cap_b) == cap_ept_pml4_cap) { 375 return cap_ept_pml4_cap_get_capPML4BasePtr(cap_a) == 376 cap_ept_pml4_cap_get_capPML4BasePtr(cap_b); 377 } 378 break; 379 380 case cap_ept_pdpt_cap: 381 if (cap_get_capType(cap_b) == cap_ept_pdpt_cap) { 382 return cap_ept_pdpt_cap_get_capPDPTBasePtr(cap_a) == 383 cap_ept_pdpt_cap_get_capPDPTBasePtr(cap_b); 384 } 385 break; 386 387 case cap_ept_pd_cap: 388 if (cap_get_capType(cap_b) == cap_ept_pd_cap) { 389 return cap_ept_pd_cap_get_capPDBasePtr(cap_a) == 390 cap_ept_pd_cap_get_capPDBasePtr(cap_b); 391 } 392 break; 393 394 case cap_ept_pt_cap: 395 if (cap_get_capType(cap_b) == cap_ept_pt_cap) { 396 return cap_ept_pt_cap_get_capPTBasePtr(cap_a) == 397 cap_ept_pt_cap_get_capPTBasePtr(cap_b); 398 } 399 break; 400 401#endif 402 403 } 404 405 return Mode_sameRegionAs(cap_a, cap_b); 406} 407 408bool_t CONST Arch_sameObjectAs(cap_t cap_a, cap_t cap_b) 409{ 410 if (cap_get_capType(cap_a) == cap_io_port_control_cap && 411 cap_get_capType(cap_b) == cap_io_port_cap) { 412 return false; 413 } 414 if (cap_get_capType(cap_a) == cap_frame_cap) { 415 if (cap_get_capType(cap_b) == cap_frame_cap) { 416 return ((cap_frame_cap_get_capFBasePtr(cap_a) == 417 cap_frame_cap_get_capFBasePtr(cap_b)) && 418 (cap_frame_cap_get_capFSize(cap_a) == 419 cap_frame_cap_get_capFSize(cap_b)) && 420 ((cap_frame_cap_get_capFIsDevice(cap_a) == 0) == 421 (cap_frame_cap_get_capFIsDevice(cap_b) == 0))); 422 } 423 } 424 return Arch_sameRegionAs(cap_a, cap_b); 425} 426 427word_t Arch_getObjectSize(word_t t) 428{ 429 switch (t) { 430 case seL4_X86_4K: 431 return pageBitsForSize(X86_SmallPage); 432 case seL4_X86_LargePageObject: 433 return pageBitsForSize(X86_LargePage); 434 case seL4_X86_PageTableObject: 435 return seL4_PageTableBits; 436 case seL4_X86_PageDirectoryObject: 437 return seL4_PageDirBits; 438 case seL4_IA32_PDPTObject: 439 return seL4_PDPTBits; 440 case seL4_X86_IOPageTableObject: 441 return seL4_IOPageTableBits; 442#ifdef CONFIG_VTX 443 case seL4_X86_VCPUObject: 444 return seL4_X86_VCPUBits; 445 case seL4_X86_EPTPML4Object: 446 return seL4_X86_EPTPML4Bits; 447 case seL4_X86_EPTPDPTObject: 448 return seL4_X86_EPTPDPTBits; 449 case seL4_X86_EPTPDObject: 450 return seL4_X86_EPTPDBits; 451 case seL4_X86_EPTPTObject: 452 return seL4_X86_EPTPTBits; 453#endif 454 default: 455 return Mode_getObjectSize(t); 456 } 457} 458 459cap_t Arch_createObject(object_t t, void *regionBase, word_t userSize, bool_t deviceMemory) 460{ 461#ifdef CONFIG_VTX 462 switch (t) { 463 case seL4_X86_VCPUObject: { 464 vcpu_t *vcpu; 465 vcpu = VCPU_PTR((word_t)regionBase); 466 vcpu_init(vcpu); 467 return cap_vcpu_cap_new(VCPU_REF(vcpu)); 468 } 469 case seL4_X86_EPTPML4Object: 470 return cap_ept_pml4_cap_new( 471 0, /* capPML4IsMapped */ 472 VPID_INVALID, /* capPML4MappedASID */ 473 (word_t)regionBase /* capPML4BasePtr */ 474 ); 475 case seL4_X86_EPTPDPTObject: 476 return cap_ept_pdpt_cap_new( 477 0, /* capPDPTMappedAddress */ 478 0, /* capPDPTIsMapped */ 479 VPID_INVALID, /* capPDPTMappedASID */ 480 (word_t)regionBase /* capPDPTBasePtr */ 481 ); 482 case seL4_X86_EPTPDObject: 483 return cap_ept_pd_cap_new( 484 0, /* capPDMappedAddress */ 485 0, /* capPDIsMapped */ 486 VPID_INVALID, /* capPDMappedASID */ 487 (word_t)regionBase /* capPDBasePtr */ 488 ); 489 case seL4_X86_EPTPTObject: 490 return cap_ept_pt_cap_new( 491 0, /* capPTMappedAddress */ 492 0, /* capPTIsMapped */ 493 VPID_INVALID, /* capPTMappedASID */ 494 (word_t)regionBase /* capPTBasePtr */ 495 ); 496 default: 497#endif 498 return Mode_createObject(t, regionBase, userSize, deviceMemory); 499#ifdef CONFIG_VTX 500 } 501#endif 502} 503 504exception_t Arch_decodeInvocation( 505 word_t invLabel, 506 word_t length, 507 cptr_t cptr, 508 cte_t *slot, 509 cap_t cap, 510 extra_caps_t excaps, 511 bool_t call, 512 word_t *buffer 513) 514{ 515 switch (cap_get_capType(cap)) { 516 case cap_asid_control_cap: 517 case cap_asid_pool_cap: 518 return decodeX86MMUInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); 519 case cap_io_port_control_cap: 520 return decodeX86PortControlInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); 521 case cap_io_port_cap: 522 return decodeX86PortInvocation(invLabel, length, cptr, slot, cap, excaps, call, buffer); 523#ifdef CONFIG_IOMMU 524 case cap_io_space_cap: 525 return decodeX86IOSpaceInvocation(invLabel, cap); 526 case cap_io_page_table_cap: 527 return decodeX86IOPTInvocation(invLabel, length, slot, cap, excaps, buffer); 528#endif 529#ifdef CONFIG_VTX 530 case cap_vcpu_cap: 531 return decodeX86VCPUInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); 532 case cap_ept_pml4_cap: 533 case cap_ept_pdpt_cap: 534 case cap_ept_pd_cap: 535 case cap_ept_pt_cap: 536 return decodeX86EPTInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); 537#endif 538 default: 539 return Mode_decodeInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); 540 } 541} 542 543void Arch_prepareThreadDelete(tcb_t *thread) 544{ 545 /* Notify the lazy FPU module about this thread's deletion. */ 546 fpuThreadDelete(thread); 547} 548 549void Arch_postCapDeletion(cap_t cap) 550{ 551 if (cap_get_capType(cap) == cap_io_port_cap) { 552 uint16_t first_port = cap_io_port_cap_get_capIOPortFirstPort(cap); 553 uint16_t last_port = cap_io_port_cap_get_capIOPortLastPort(cap); 554 555 freeIOPortRange(first_port, last_port); 556 } 557} 558