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