github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/host/hw/machinesupport.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 "local_apic.h" 17 #include "em64t_defs.h" 18 #include "hw_utils.h" 19 #include "vmm_dbg.h" 20 #include "host_memory_manager_api.h" 21 #include "memory_allocator.h" 22 #include "file_codes.h" 23 #include "hw_vmx_utils.h" 24 #ifdef JLMDEBUG 25 #include "jlmdebug.h" 26 #endif 27 28 29 UINT64 hw_rdtsc(void) 30 { 31 UINT64 out; 32 UINT64* pout= &out; 33 34 __asm__ volatile ( 35 "\trdtsc\n" 36 "\tmovq %[pout],%%rcx\n" 37 "\tmovl %%eax, (%%rcx)\n" 38 "\tmovl %%edx, 4(%%rcx)\n" 39 :[out] "=g" (out) 40 :[pout] "m" (pout): "%rcx"); 41 return out; 42 } 43 44 45 UINT8 hw_read_port_8( UINT16 port ) 46 { 47 UINT8 out; 48 49 __asm__ volatile( 50 "\tinb %[port], %[out]\n" 51 :[out] "=a" (out) 52 :[port] "Nd" (port) 53 :); 54 return out; 55 } 56 57 58 UINT16 hw_read_port_16( UINT16 port ) 59 { 60 UINT16 out; 61 62 __asm__ volatile( 63 "\tinw %[port], %[out]\n" 64 :[out] "=a" (out) 65 :[port] "Nd" (port) :); 66 return out; 67 } 68 69 70 UINT32 hw_read_port_32( UINT16 port ) 71 { 72 UINT32 out; 73 74 __asm__ volatile( 75 "\tinl %[port], %[out]\n" 76 :[out] "=a" (out) 77 :[port] "Nd" (port) :); 78 return out; 79 } 80 81 82 void hw_write_port_8(UINT16 port, UINT8 val) 83 { 84 __asm__ volatile( 85 "\toutb %[val], %[port]\n" 86 ::[val] "a" (val), [port] "Nd" (port) :); 87 return; 88 } 89 90 91 void hw_write_port_16( UINT16 port, UINT16 val) 92 { 93 __asm__ volatile( 94 "\toutw %[val], %[port]\n" 95 ::[val] "a" (val), [port] "Nd" (port) :); 96 return; 97 } 98 99 100 void hw_write_port_32( UINT16 port, UINT32 val) 101 { 102 __asm__ volatile( 103 "\toutl %[val], %[port]\n" 104 ::[val] "a" (val), [port] "Nd" (port) :); 105 return; 106 } 107 108 109 void hw_write_msr(UINT32 msr_id, UINT64 val) 110 { 111 UINT32 low = (val & (UINT32)-1); 112 UINT32 high = (UINT32)(val >> 32); 113 __asm__ volatile ( 114 "\twrmsr\n" 115 :: "a" (low), "d" (high), "c" (msr_id):); 116 return; 117 } 118 119 120 UINT64 hw_read_msr(UINT32 msr_id) 121 { 122 UINT32 high; 123 UINT32 low; 124 125 // RDMSR reads the processor (MSR) whose index is stored in ECX, 126 // and stores the result in EDX:EAX. 127 __asm__ volatile ( 128 "\trdmsr\n" 129 : "=a" (low), "=d" (high) 130 : "c" (msr_id):); 131 132 return ((UINT64)high << 32) | low; 133 } 134 135 136 UINT64 hw_read_cr0(void) 137 { 138 UINT64 out; 139 __asm__ volatile ( 140 "\tmovq %%cr0, %[out]\n" 141 :[out] "=r" (out) ::); 142 return out; 143 } 144 145 146 UINT64 hw_read_cr2(void) 147 { 148 UINT64 out; 149 __asm__ volatile ( 150 "\tmovq %%cr2, %[out]\n" 151 :[out] "=r" (out) ::); 152 return out; 153 } 154 155 156 UINT64 hw_read_cr3(void) 157 { 158 UINT64 out; 159 __asm__ volatile ( 160 "\tmovq %%cr3, %[out]\n" 161 :[out] "=r" (out) ::); 162 return out; 163 } 164 165 166 UINT64 hw_read_cr4(void) 167 { 168 UINT64 out; 169 __asm__ volatile ( 170 "\tmovq %%cr4, %[out]\n" 171 :[out] "=r" (out) ::); 172 return out; 173 } 174 175 176 UINT64 hw_read_cr8(void) 177 { 178 UINT64 out; 179 __asm__ volatile ( 180 "\tmovq %%cr8, %[out]\n" 181 :[out] "=r" (out) ::); 182 return out; 183 } 184 185 186 void hw_write_cr0(UINT64 data) 187 { 188 __asm__ volatile ( 189 "\tmovq %[data], %%cr0\n" 190 ::[data] "r" (data):); 191 return; 192 } 193 194 195 void hw_write_cr3(UINT64 data) 196 { 197 __asm__ volatile ( 198 "\tmovq %[data], %%cr3\n" 199 ::[data] "r" (data):); 200 return; 201 } 202 203 204 void hw_write_cr4(UINT64 data) 205 { 206 __asm__ volatile ( 207 "\tmovq %[data], %%cr4\n" 208 ::[data] "r" (data):); 209 return; 210 } 211 212 213 void hw_write_cr8(UINT64 data) 214 { 215 __asm__ volatile ( 216 "\tmovq %[data], %%cr8\n" 217 ::[data] "r" (data):); 218 return; 219 } 220 221 222 UINT64 hw_read_dr0(void) 223 { 224 UINT64 out; 225 __asm__ volatile ( 226 "\tmovq %%dr0, %[out]\n" 227 :[out] "=r" (out) ::); 228 return out; 229 } 230 231 232 UINT64 hw_read_dr1(void) 233 { 234 UINT64 out; 235 __asm__ volatile ( 236 "\tmovq %%dr1, %[out]\n" 237 :[out] "=r" (out) ::); 238 return out; 239 } 240 241 242 UINT64 hw_read_dr2(void) 243 { 244 UINT64 out; 245 __asm__ volatile ( 246 "\tmovq %%dr2, %[out]\n" 247 :[out] "=r" (out) ::); 248 return out; 249 } 250 251 252 UINT64 hw_read_dr3(void) 253 { 254 UINT64 out; 255 __asm__ volatile ( 256 "\tmovq %%dr3, %[out]\n" 257 :[out] "=r" (out) ::); 258 return out; 259 } 260 261 262 UINT64 hw_read_dr4(void) 263 { 264 UINT64 out; 265 __asm__ volatile ( 266 "\tmovq %%dr4, %[out]\n" 267 :[out] "=r" (out) ::); 268 return out; 269 } 270 271 272 UINT64 hw_read_dr5(void) 273 { 274 UINT64 out; 275 __asm__ volatile ( 276 "\tmovq %%dr5, %[out]\n" 277 :[out] "=r" (out) ::); 278 return out; 279 } 280 281 282 UINT64 hw_read_dr6(void) 283 { 284 UINT64 out; 285 __asm__ volatile ( 286 "\tmovq %%dr6, %[out]\n" 287 :[out] "=r" (out) ::); 288 return out; 289 } 290 291 292 UINT64 hw_read_dr7(void) 293 { 294 UINT64 out; 295 __asm__ volatile ( 296 "\tmovq %%dr7, %[out]\n" 297 :[out] "=r" (out) ::); 298 return out; 299 } 300 301 302 void hw_write_dr0(UINT64 value) 303 { 304 __asm__ volatile ( 305 "\tmovq %[value], %%dr0\n" 306 ::[value] "r" (value):); 307 return; 308 } 309 310 311 void hw_write_dr1(UINT64 value) 312 { 313 __asm__ volatile ( 314 "\tmovq %[value], %%dr1\n" 315 ::[value] "r" (value):); 316 return; 317 } 318 319 320 void hw_write_dr2(UINT64 value) 321 { 322 __asm__ volatile ( 323 "\tmovq %[value], %%dr2\n" 324 ::[value] "r" (value):); 325 return; 326 } 327 328 329 void hw_write_dr3(UINT64 value) 330 { 331 __asm__ volatile ( 332 "\tmovq %[value], %%dr3\n" 333 ::[value] "r" (value):); 334 return; 335 } 336 337 338 void hw_write_dr4(UINT64 value) 339 { 340 __asm__ volatile ( 341 "\tmovq %[value], %%dr4\n" 342 ::[value] "r" (value):); 343 return; 344 } 345 346 347 void hw_write_dr5(UINT64 value) 348 { 349 __asm__ volatile ( 350 "\tmovq %[value], %%dr5\n" 351 ::[value] "r" (value):); 352 return; 353 } 354 355 356 void hw_write_dr6(UINT64 value) 357 { 358 __asm__ volatile ( 359 "\tmovq %[value], %%dr6\n" 360 ::[value] "r" (value):); 361 return; 362 } 363 364 365 void hw_write_dr7(UINT64 value) 366 { 367 __asm__ volatile ( 368 "\tmovq %[value], %%dr7\n" 369 ::[value] "r" (value):); 370 return; 371 } 372 373 374 void hw_invlpg(void *address) 375 { 376 __asm__ volatile ( 377 "\tinvlpg %[address]\n" 378 ::[address] "m" (address):); 379 return; 380 } 381 382 383 void hw_wbinvd(void) 384 { 385 __asm__ volatile( 386 "\twbinvd\n" 387 : : :); 388 return; 389 } 390 391 392 void hw_halt( void ) 393 { 394 __asm__ volatile( 395 "\thlt\n" 396 :::); 397 return; 398 } 399 400 401 void hw_lidt(void *source) 402 { 403 __asm__ volatile( 404 "\tlidt (%[source])\n" 405 ::[source] "p" (source):); 406 return; 407 } 408 409 410 void hw_sidt(void *destination) 411 { 412 __asm__ volatile( 413 "\tsidt (%[destination])\n" 414 ::[destination] "p" (destination) 415 :); 416 return; 417 } 418 419 420 INT32 hw_interlocked_increment(INT32 *addend) 421 { 422 __asm__ volatile( 423 "\tlock; incl (%[addend])\n" 424 : 425 :[addend] "p" (addend) 426 :"memory"); 427 return *addend; 428 } 429 430 431 UINT64 hw_interlocked_increment64(INT64* addend) 432 { 433 __asm__ volatile( 434 "\tlock; incq (%[addend])\n" 435 : :[addend] "p" (addend) 436 :"memory"); 437 return *addend; 438 } 439 440 INT32 hw_interlocked_decrement(INT32 * minuend) 441 { 442 __asm__ volatile( 443 "\tlock; decl (%[minuend])\n" 444 : :[minuend] "p" (minuend) 445 :"memory"); 446 return *minuend; 447 } 448 449 INT32 hw_interlocked_add(INT32 volatile * addend, INT32 value) 450 { 451 __asm__ volatile( 452 "\tmovq %[addend], %%rbx\n" 453 "\tmovl %[value], %%eax\n" 454 "\tlock; addl %%eax, (%%rbx)\n" 455 : 456 : [addend] "p" (addend), [value] "r" (value) 457 : "%eax", "%rbx"); 458 return *addend; 459 } 460 461 INT32 hw_interlocked_or(INT32 volatile * value, INT32 mask) 462 { 463 __asm__ volatile( 464 "\tmovq %[value], %%rbx\n" 465 "\tmovl %[mask], %%eax\n" 466 "\tlock; orl %%eax, (%%rbx)\n" 467 : 468 : [mask] "m" (mask), [value] "r" (value) 469 : "%eax", "%rbx"); 470 return *value; 471 } 472 473 INT32 hw_interlocked_xor(INT32 volatile * value, INT32 mask) 474 { 475 __asm__ volatile( 476 "\tmovq %[value], %%rbx\n" 477 "\tmovl %[mask], %%eax\n" 478 "\tlock; xorl %%eax, (%%rbx)\n" 479 : 480 : [mask] "m" (mask), [value] "r" (value) 481 : "%eax", "%rbx"); 482 return *value; 483 } 484 485 void hw_store_fence(void) 486 { 487 __asm__ volatile( 488 "\tsfence\n" 489 :::); 490 return; 491 } 492 493 494 INT32 hw_interlocked_compare_exchange(INT32 volatile * destination, 495 INT32 expected, INT32 comperand) 496 { 497 #ifdef JLMDEBUG1 498 bprint("expected: %d, new: %d --- ", expected, comperand); 499 #endif 500 INT32 old = *destination; 501 __asm__ volatile( 502 "\tmovq %[destination], %%r15\n" 503 "\tmovl (%%r15), %%edx\n" 504 "\tmovl %[expected], %%eax\n" 505 "\tmovl %[comperand], %%ecx\n" 506 "\tcmpxchgl %%ecx, %%edx\n" 507 "\tmovl %%edx, (%%r15)\n" 508 : 509 : [expected] "m" (expected), [comperand] "m" (comperand), 510 [destination] "m" (destination) 511 :"%eax", "%ecx", "%edx", "%rbx", "%r15"); 512 #ifdef JLMDEBUG1 513 bprint("destination: %d\n", *destination); 514 #endif 515 return old; 516 } 517 518 519 INT8 hw_interlocked_compare_exchange_8(INT8 volatile * destination, 520 INT8 expected, INT8 comperand) 521 { 522 __asm__ volatile( 523 "\tmovq %[destination], %%r15\n" 524 "\tmovb (%%r15), %%dl\n" 525 "\tmovb %[expected], %%al\n" 526 "\tmovb %[comperand], %%cl\n" 527 "\tcmpxchgb %%cl, %%dl\n" 528 "\tmovb %%dl, (%%r15)\n" 529 : 530 : [expected] "m" (expected), [comperand] "m" (comperand), 531 [destination] "m" (destination) 532 :"%rax", "%rcx", "%rbx", "%r15"); 533 return *destination; 534 } 535 536 537 INT64 hw_interlocked_compare_exchange_64(INT64 volatile * destination, 538 INT64 expected, INT64 comperand) 539 { 540 __asm__ volatile( 541 "\tmovq %[destination], %%r15\n" 542 "\tmovq (%%r15), %%rdx\n" 543 "\tmovq %[expected], %%rax\n" 544 "\tmovq %[comperand], %%rcx\n" 545 "\tcmpxchgq %%rcx, %%rdx\n" 546 "\tmovq %%rdx, (%%r15)\n" 547 : 548 : [expected] "m" (expected), [comperand] "m" (comperand), 549 [destination] "m" (destination) 550 :"%rax", "%rcx", "%rbx", "%r15"); 551 return *destination; 552 } 553 554 555 INT32 hw_interlocked_assign(INT32 volatile * target, INT32 new_value) 556 { 557 __asm__ volatile( 558 "\tmovq %[target], %%rbx\n" 559 "\tmovl %[new_value], %%eax\n" 560 "\txchgl %%eax, (%%rbx)\n" 561 : 562 : [new_value] "m" (new_value), [target] "r" (target) 563 : "%eax", "%rbx"); 564 return *target; 565 } 566 567 568 // find first bit set 569 // forward: LSB->MSB 570 // backward: MSB->LSB 571 // Return 0 if no bits set 572 // Fills "bit_number" with the set bit position zero based 573 // BOOLEAN hw_scan_bit_forward( UINT32& bit_number, UINT32 bitset ) 574 // BOOLEAN hw_scan_bit_backward( UINT32& bit_number, UINT32 bitset ) 575 // BOOLEAN hw_scan_bit_forward64( UINT32& bit_number, UINT64 bitset ) 576 // BOOLEAN hw_scan_bit_backward64( UINT32& bit_number, UINT64 bitset ) 577 578 579 BOOLEAN hw_scan_bit_forward(UINT32 *bit_number_ptr, UINT32 bitset) 580 { 581 __asm__ volatile( 582 "\tbsfl %[bitset], %%eax\n" 583 "\tmovq %[bit_number_ptr], %%rbx\n" 584 "\tmovl %%eax, (%%rbx)\n" 585 :: [bit_number_ptr] "p" (bit_number_ptr), [bitset] "g" (bitset) 586 : "%rax", "%eax", "%rbx"); 587 return bitset ? TRUE : FALSE; 588 } 589 590 BOOLEAN hw_scan_bit_forward64(UINT32 *bit_number_ptr, UINT64 bitset) 591 { 592 __asm__ volatile( 593 "\tbsfq %[bitset], %%rax\n" 594 "\tmovq %[bit_number_ptr], %%rbx\n" 595 "\tmovl %%eax, (%%rbx)\n" 596 : 597 : [bit_number_ptr] "p" (bit_number_ptr), [bitset] "g" (bitset) 598 : "%rax", "%eax", "%rbx"); 599 return bitset ? TRUE : FALSE; 600 } 601 602 BOOLEAN hw_scan_bit_backward(UINT32 *bit_number_ptr, UINT32 bitset) 603 { 604 __asm__ volatile( 605 "\tbsrl %[bitset], %%eax\n" 606 "\tmovq %[bit_number_ptr], %%rbx\n" 607 "\tmovl %%eax, (%%rbx)\n" 608 : 609 : [bit_number_ptr] "p" (bit_number_ptr), [bitset] "g" (bitset) 610 : "%eax", "%rbx"); 611 return bitset ? TRUE : FALSE; 612 } 613 614 615 BOOLEAN hw_scan_bit_backward64(UINT32 *bit_number_ptr, UINT64 bitset) 616 { 617 __asm__ volatile( 618 "\tbsrq %[bitset], %%rax\n" 619 "\tmovq %[bit_number_ptr], %%rbx\n" 620 "\tmovl %%eax, (%%rbx)\n" 621 : :[bit_number_ptr] "p" (bit_number_ptr), [bitset] "m" (bitset) 622 :"%rax", "%eax", "%rbx"); 623 return bitset ? TRUE : FALSE; 624 } 625 626 627 // from fpu2 628 629 // Read FPU status word, this doesnt seem to be called 630 void hw_fnstsw (UINT16* loc) { 631 __asm__ volatile( 632 "\tmovq %[loc], %%rax\n" 633 "\tfnstsw (%%rax)\n" 634 : : [loc] "m"(loc) 635 :"%rax"); 636 return; 637 } 638 639 640 // Read FPU control word 641 void hw_fnstcw ( UINT16 * loc ) 642 { 643 __asm__ volatile( 644 "\tmovq %[loc], %%rax\n" 645 "\tfnstcw (%%rax)\n" 646 : 647 : [loc] "m"(loc) 648 :"%rax"); 649 return; 650 } 651 652 653 // Init FP Unit 654 void hw_fninit() 655 { 656 __asm__ volatile( 657 "\tfninit\n" 658 :::); 659 return; 660 } 661 662 663 // from em64t_utils2.c 664 typedef struct { 665 unsigned long P_RAX; 666 unsigned long P_RBX; 667 unsigned long P_RCX; 668 unsigned long P_RDX; 669 unsigned long P_RSI; 670 unsigned long P_RDI; 671 unsigned long P_RFLAGS; 672 } PACKED SMI_PORT_PARAMS; 673 SMI_PORT_PARAMS spp; 674 CPUID_PARAMS cp; 675 676 void hw_lgdt (void *gdtr) { 677 __asm__ volatile( 678 "lgdt (%[gdtr])\n" 679 : :[gdtr] "p" (gdtr) 680 :); 681 return; 682 } 683 684 void hw_sgdt (void * gdtr) { 685 // Store GDTR (to buffer pointed by RCX) 686 __asm__ volatile( 687 "\tsgdt (%[gdtr])\n" 688 : :[gdtr] "p" (gdtr) 689 :); 690 return; 691 } 692 693 694 // Read Command Segment Selector 695 // Stack offsets on entry: 696 // ax register will contain result 697 UINT16 hw_read_cs () { 698 699 UINT16 ret = 0; 700 701 __asm__ volatile( 702 "\txor %%rax, %%rax\n" 703 "\tmovw %%cs, %%ax\n" 704 "\tmovw %%ax, %[ret]\n" 705 :"=rm" (ret) 706 :[ret] "rm" (ret) 707 :"cc", "rax", "memory"); 708 return ret; 709 } 710 711 712 void hw_write_cs (UINT16 i) { 713 // push segment selector 714 __asm__ volatile ( 715 "\txor %%rax, %%rax\n" 716 "\tmovw %[i], %%ax\n" 717 "\tshlq $32, %%rax\n" 718 "\tlea L_CONT_WITH_NEW_CS, %%rdx\n" 719 "\tadd %%rdx, %%rax\n" 720 "\tpush %%rax\n" 721 "\tlret\n" //brings IP to CONT_WITH_NEW_CS 722 "L_CONT_WITH_NEW_CS:\n" 723 "\tret\n" 724 : :[i] "m" (i) 725 :"rax", "rdx"); 726 } 727 728 729 // UINT16 hw_read_ds ( void); 730 // Read Data Segment Selector 731 // Stack offsets on entry: 732 // ax register will contain result 733 UINT16 hw_read_ds () { 734 UINT16 ret = 0; 735 736 __asm__ volatile( 737 "\txor %%rax, %%rax\n" 738 "\tmovw %%ds, %%ax\n" 739 "\tmovw %%ax, %[ret]\n" 740 :[ret] "=g" (ret) 741 : :"cc", "memory"); 742 return ret; 743 } 744 745 746 // void hw_write_ds ( UINT16); 747 // Write to Data Segment Selector 748 void hw_write_ds(UINT16 i) { 749 __asm__ volatile( 750 "\tmovw %[i], %%ds\n" 751 : 752 :[i] "g" (i) :); 753 return; 754 } 755 756 757 // UINT16 hw_read_es ( void); 758 // Read ES Segment Selector 759 // Stack offsets on entry: 760 // ax register will contain result 761 UINT16 hw_read_es() { 762 763 UINT16 ret = 0; 764 765 __asm__ volatile( 766 "\txor %%rax, %%rax\n" 767 "\tmovw %%es, %%ax\n" 768 "\tmovw %%ax, %[ret]\n" 769 :[ret] "=g" (ret) 770 ::); 771 return ret; 772 } 773 774 775 // void hw_write_es ( UINT16); 776 // Write to ES Segment Selector 777 void hw_write_es (UINT16 i) { 778 __asm__ volatile( 779 "\tmovw %[i], %%es\n" 780 : 781 :[i] "g" (i) 782 :); 783 return; 784 } 785 786 787 // UINT16 hw_read_ss ( void); 788 // Read Stack Segment Selector 789 // ax register will contain result 790 UINT16 hw_read_ss() { 791 UINT16 ret = 0; 792 793 __asm__ volatile( 794 "\txor %%rax, %%rax\n" 795 "\tmovw %%es, %%ax\n" 796 "\tmovw %%ax, %[ret]\n" 797 :[ret] "=g" (ret) 798 ::); 799 return ret; 800 } 801 802 803 // void hw_write_ss ( UINT16); 804 // Write to Stack Segment Selector 805 void hw_write_ss (UINT16 i) { 806 __asm__ volatile( 807 "\tmovw %[i], %%ss\n" 808 : :[i] "g" (i) 809 :); 810 return; 811 } 812 813 814 // UINT16 hw_read_fs ( void); 815 // Read FS 816 // ax register will contain result 817 UINT16 hw_read_fs() { 818 UINT16 ret = 0; 819 820 __asm__ volatile( 821 "\txor %%rax, %%rax\n" 822 "\tmovw %%fs, %%ax\n" 823 "\tmovw %%ax, %[ret]\n" 824 :[ret] "=g" (ret) 825 : 826 :"rax"); 827 return ret; 828 } 829 830 831 // void hw_write_fs ( UINT16); 832 // Write to FS 833 void hw_write_fs (UINT16 i) { 834 __asm__ volatile( 835 "\tmovw %[i], %%fs\n" 836 : 837 :[i] "r" (i) 838 :); 839 return; 840 } 841 842 843 // UINT16 hw_read_gs ( void); 844 // Read GS 845 // ax register will contain result 846 UINT16 hw_read_gs() { 847 UINT16 ret = 0; 848 849 __asm__ volatile( 850 "\txor %%rax, %%rax\n" 851 "\tmovw %%gs, %%ax\n" 852 "\tmovw %%ax, %[ret]\n" 853 :[ret] "=rm" (ret) 854 ::"rax"); 855 return ret; 856 } 857 858 859 // void hw_write_gs ( UINT16); 860 // Write to GS 861 void hw_write_gs (UINT16 i) { 862 __asm__ volatile( 863 "\tmovw %[i], %%gs\n" 864 : 865 :[i] "r" (i) 866 :); 867 return; 868 } 869 870 871 // UINT64 hw_read_rsp (void); 872 UINT64 hw_read_rsp () { 873 UINT64 ret = 0; 874 __asm__ volatile( 875 "\tmovq %%rsp, %%rax\n" 876 "\tadd $8,%%rax\n" 877 "\tmovq %%rax, %[ret]\n" 878 :[ret] "=rm"(ret) 879 :: "cc", "memory"); 880 return ret; 881 } 882 883 884 // CHECK the args/offsets need to be double-checked 885 void hw_write_to_smi_port( 886 UINT64 * p_rax, // rcx 887 UINT64 * p_rbx, // rdx 888 UINT64 * p_rcx, // r8 889 UINT64 * p_rdx, // r9 890 UINT64 * p_rsi, // on the stack 891 UINT64 * p_rdi, // on the stack 892 UINT64 * p_rflags) // on the stack 893 { 894 #ifdef JLMDEBUG 895 bprint("hw_write_to_smi_port\n"); 896 LOOP_FOREVER 897 #endif 898 (void)p_rax; 899 (void)p_rbx; 900 (void)p_rcx; 901 (void)p_rdx; 902 (void)p_rsi; 903 (void)p_rdi; 904 (void)p_rflags; 905 // save callee saved registers 906 __asm__ volatile( 907 "\tpush %%rbp\n" 908 "\tmovq %%rbp, %%rsp\n" //setup stack frame pointer 909 "\tpush %%rbx\n" 910 "\tpush %%rdi\n" 911 "\tpush %%rsi\n" 912 "\tpush %%r12\n" 913 "\tpush %%r13\n" 914 "\tpush %%r14\n" 915 "\tpush %%r15\n" 916 "\tlea 16(%%rbp), %%r15\n"//set r15 to point to SMI_PORT_PARAMS struct 917 // normalize stack\n"\t 918 "\tmovq %%rcx, (%%r15)\n" 919 "\tmovq %%rdx, 8(%%r15)\n" 920 "\tmovq %%r8, 16(%%r15)\n" 921 "\tmovq %%r9, 24(%%r15)\n" 922 //copy emulator registers into CPU 923 "\tmovq (%%r15), %%r8\n" 924 "\tmovq (%%r8), %%rax\n" 925 "\tmovq 8(%%r15), %%r8\n" 926 "\tmovq (%%r8), %%rbx\n" 927 "\tmovq 16(%%r15), %%r8\n" 928 "\tmovq (%%r8), %%rcx\n" 929 "\tmovq 24(%%r15), %%r8\n" 930 "\tmovq (%%r8), %%rdx\n" 931 "\tmovq 32(%%r15), %%r8\n" 932 "\tmovq (%%r8), %%rsi\n" 933 "\tmovq 40(%%r15), %%r8\n" 934 "\tmovq (%%r8), %%rdi\n" 935 "\tmovq 48(%%r15), %%r8\n" 936 "\tpush (%%r8)\n" 937 "\tpopfq\n" //rflags = *p_rflags 938 939 //we assume that sp will not change after SMI 940 941 "\tpush %%rbp\n" 942 "\tpush %%r15\n" 943 // "\tout %%dx, %%al\n" 944 "\tout %%al, %%dx\n" 945 "\tpop %%r15\n" 946 "\tpop %%rbp\n" 947 //fill emulator registers from CPU 948 "\tmovq (%%r15), %%r8\n" 949 "\tmovq %%rax, (%%r8)\n" 950 "\tmovq 8(%%r15), %%r8\n" 951 "\tmovq %%rbx, (%%r8)\n" 952 "\tmovq 16(%%r15), %%r8\n" 953 "\tmovq %%rcx, (%%r8)\n" 954 "\tmovq 24(%%r15), %%r8\n" 955 "\tmovq %%rdx, (%%r8)\n" 956 "\tmovq 32(%%r15), %%r8\n" 957 "\tmovq %%rsi, (%%r8)\n" 958 "\tmovq 40(%%r15), %%r8\n" 959 "\tmovq %%rdi, (%%r8)\n" 960 "\tmovq 48(%%r15), %%r8\n" 961 "\tpushfq\n" 962 "\tpop (%%r8)\n" // *p_rflags = rflags 963 //restore callee saved registers 964 "\tpop %%r15\n" 965 "\tpop %%r14\n" 966 "\tpop %%r13\n" 967 "\tpop %%r12\n" 968 "\tpop %%rsi\n" 969 "\tpop %%rdi\n" 970 "\tpop %%rbx\n" 971 "\tpop %%rbp\n" 972 :::); 973 return; 974 } 975 976 // void hw_enable_interrupts (void); 977 void hw_enable_interrupts () { 978 __asm__ volatile("\tsti\n"); 979 return; 980 } 981 982 // void hw_disable_interrupts (void); 983 void hw_disable_interrupts () { 984 __asm__ volatile("\tcli\n"); 985 return; 986 } 987 988 // void hw_fxsave (void* buffer); 989 void hw_fxsave (void *buffer) { 990 __asm__ volatile( 991 "\tmovq %[buffer], %%rbx\n" 992 "\tfxsave (%%rbx)\n" 993 : 994 :[buffer] "g" (buffer) 995 :"%rbx"); 996 return; 997 } 998 999 1000 // void hw_fxrestore (void* buffer); 1001 void hw_fxrestore (void *buffer) { 1002 __asm__ volatile( 1003 "\tmovq %[buffer], %%rbx\n" 1004 "\tfxrstor (%%rbx)\n" 1005 : 1006 :[buffer] "m" (buffer) 1007 : "%rbx"); 1008 return; 1009 } 1010 1011 1012 // void hw_write_cr2 (UINT64 value); 1013 void hw_write_cr2 (UINT64 value) { 1014 __asm__ volatile( 1015 "\tmovq %%cr2, %[value]\n" 1016 :[value] "=g" (value) 1017 : :"cc", "memory"); 1018 return; 1019 } 1020 1021 1022 // UINT16 * hw_cpu_id ( void * ); 1023 // Read TR and calculate cpu_id 1024 // ax register will contain result 1025 // IMPORTANT NOTE: only RAX regsiter may be used here !!!! 1026 // This assumption is used in gcpu_regs_save_restore.asm 1027 #define CPU_LOCATOR_GDT_ENTRY_OFFSET 32 1028 #define TSS_ENTRY_SIZE_SHIFT 4 1029 1030 __asm__( 1031 ".text\n" 1032 ".globl hw_cpu_id\n" 1033 ".type hw_cpu_id,@function\n" 1034 "hw_cpu_id:\n" 1035 "\txor %rax, %rax\n" 1036 "\tstr %ax\n" 1037 "\tsubw $32, %ax\n" // CPU_LOCATOR_GDT_ENTRY_OFFSET == 32 1038 "\tshrw $4, %ax\n" // TSS_ENTRY_SIZE_SHIFT == 4 1039 "\tret\n" 1040 ); 1041 1042 1043 // UINT16 hw_read_tr ( void); 1044 // Read Task Register 1045 // ax register will contain result 1046 UINT16 hw_read_tr() { 1047 UINT16 ret = 0; 1048 1049 __asm__ volatile( 1050 "\tstr %%ax\n" 1051 "\tmovw %%ax, %[ret]\n" 1052 :[ret] "=g" (ret) 1053 : :"%rax"); 1054 return ret; 1055 } 1056 1057 1058 // void hw_write_tr ( UINT16); 1059 // Write Task Register 1060 void hw_write_tr (UINT16 i) { 1061 __asm__ volatile( 1062 "\tltr %[i]\n" 1063 : :[i] "g" (i) 1064 :); 1065 return; 1066 } 1067 1068 1069 // UINT16 hw_read_ldtr ( void); 1070 // Read LDT Register 1071 // ax register will contain result 1072 UINT16 hw_read_ldtr () { 1073 UINT16 ret = 0; 1074 __asm__ volatile ( 1075 "\tsldt %[ret]\n" 1076 :[ret] "=g" (ret) 1077 : :); 1078 return ret; 1079 } 1080 1081 1082 // void hw_write_ldtr ( UINT16); 1083 // Write LDT Register 1084 void hw_write_ldtr (UINT16 i) { 1085 __asm__ volatile( 1086 "\tlldt %[i]\n" 1087 : 1088 :[i] "r" (i) :); 1089 return; 1090 } 1091 1092 1093 // void hw_cpuid (CPUID_PARAMS *) 1094 // Execute cpuid instruction 1095 void hw_cpuid (CPUID_PARAMS *cp) { 1096 __asm__ volatile( 1097 "\tmovq %[cp], %%r8\n" 1098 //# fill regs for cpuid 1099 "\tmovq (%%r8), %%rax\n" 1100 "\tmovq 8(%%r8), %%rbx\n" 1101 "\tmovq 16(%%r8), %%rcx\n" 1102 "\tmovq 24(%%r8), %%rdx\n" 1103 "\tcpuid\n" 1104 "\tmovq %%rax, (%%r8)\n" 1105 "\tmovq %%rbx, 8(%%r8)\n" 1106 "\tmovq %%rcx, 16(%%r8)\n" 1107 "\tmovq %%rdx, 24(%%r8)\n" 1108 : 1109 :[cp] "g" (cp) 1110 :"%r8", "%rax", "%rbx", "%rcx", "%rdx", "memory"); 1111 return; 1112 } 1113 1114 1115 /* 1116 * void 1117 * hw_perform_asm_iret(void); 1118 * Transforms stack from entry to regular procedure: 1119 * 1120 * [ RIP ] <= RSP 1121 * 1122 * To stack to perform iret instruction: 1123 * 1124 * [ SS ] 1125 * [ RSP ] 1126 * [ RFLAGS ] 1127 * [ CS ] 1128 * [ RIP ] <= RSP should point prior iret 1129 */ 1130 void hw_perform_asm_iret () { 1131 __asm__ volatile( 1132 "\tsubq $0x20, %%rsp\n" //prepare space for "interrupt stack" 1133 "\tpush %%rax\n" //save scratch registers 1134 "\tpush %%rbx\n" 1135 "\tpush %%rcx\n" 1136 "\tpush %%rdx\n" 1137 "\taddq $0x40, %%rsp\n" // get rsp back to RIP 1138 "\tpop %%rax\n" //RIP -> RAX 1139 "\tmovq %%cs, %%rbx\n" //CS -> RBX 1140 "\tmovq %%rsp, %%rcx\n" //good RSP -> RCX 1141 "\tmovq %%ss, %%rdx\n" //CS -> RDX 1142 "\tpush %%rdx\n" //[ SS ] 1143 "\tpush %%rcx\n" //[ RSP ] 1144 "\tpushfq\n" //[ RFLAGS ] 1145 "\tpush %%rbx\n" //[ CS ] 1146 "\tpush %%rax\n" //[ RIP ] 1147 1148 "\tsubq $0x20, %%rsp\n" //restore scratch registers 1149 "\tpop %%rdx\n" 1150 "\tpop %%rcx\n" 1151 "\tpop %%rbx\n" 1152 "\tpop %%rax\n" // now RSP is in right position 1153 "\tiretq " //perform IRET 1154 :::); 1155 } 1156 1157 1158 void hw_set_stack_pointer (HVA new_stack_pointer, main_continue_fn func, 1159 void *params) 1160 { 1161 __asm__ volatile( 1162 "L1:\n" 1163 "\tmovq %[new_stack_pointer], %%rsp\n" 1164 "\tmovq %[params], %[new_stack_pointer]\n" 1165 "\tsubq $32, %%rsp\n" // allocate home space for 4 input params 1166 "\tcall *%[func]\n" 1167 "\tjmp L1\n" 1168 : 1169 :[new_stack_pointer] "g"(new_stack_pointer), 1170 [func] "g" (func), [params] "p"(params) 1171 :"cc"); 1172 return; 1173 } 1174 1175 1176 // from em64t_interlocked2.c 1177 1178 // Execute assembler 'pause' instruction 1179 void hw_pause( void ) { 1180 __asm__ volatile( 1181 "\tpause\n" 1182 :::); 1183 return; 1184 } 1185 1186 1187 // Execute assembler 'monitor' instruction 1188 // CHECK 1189 void hw_monitor( void* addr, UINT32 extension, UINT32 hint) { 1190 #ifdef JLMDEBUG 1191 bprint("hw_monitor\n"); 1192 LOOP_FOREVER 1193 #endif 1194 __asm__ volatile( 1195 "\tmovq %[addr], %%rcx\n" 1196 "\tmovq %[extension], %%rdx\n" 1197 "\tmovq %[hint], %%r8\n" 1198 "\tmovq %%rcx, %%rax\n" 1199 "\tmovq %%rdx, %%rcx\n" 1200 "\tmovq %%r8, %%rdx\n" 1201 "\tmonitor\n" 1202 : : [addr] "m" (addr), [extension] "m" (extension), [hint] "m" (hint) 1203 :"rax", "rcx", "rdx", "r8"); 1204 return; 1205 } 1206 1207 // Execute assembler 'mwait' instruction 1208 void hw_mwait( UINT32 extension, UINT32 hint ) { 1209 #ifdef JLMDEBUG 1210 bprint("hw_mwait\n"); 1211 LOOP_FOREVER 1212 #endif 1213 __asm__ volatile( 1214 "\tmovq %[extension], %%rcx\n" 1215 "\tmovq %[hint], %%rdx\n" 1216 "\tmovq %%rdx, %%rax\n" 1217 // changed the macro .byte... to mwait instruction for better portability. 1218 "\tmwait %%rax, %%rcx\n" 1219 : : [extension] "m" (extension), [hint] "m" (hint) 1220 :"rax", "rbx", "rcx", "rdx"); 1221 return; 1222 } 1223 1224 // from em64t_gcpu_regs_save_restore.c 1225 #include "guest_save_area.h" 1226 1227 // pointer to the array of pointers to the GUEST_CPU_SAVE_AREA 1228 extern GUEST_CPU_SAVE_AREA** g_guest_regs_save_area; 1229 1230 // Utility function for getting the save area pointer into rbx, using the host cpu id 1231 // from a call to hw_cpu_id 1232 __asm__( 1233 ".text\n" 1234 ".globl load_save_area_into_rbx\n" 1235 ".type load_save_area_into_rbx,@function\n" 1236 "load_save_area_into_rbx:\n" 1237 "\tpush %rax\n" // save rax, since it's used by hw_cpu_id 1238 "\tcall hw_cpu_id\n" // no arguments, and this only uses rax 1239 "\tmov g_guest_regs_save_area, %rbx\n" // get g_guest_regs_save_area 1240 // the original code has this, but it's one indirection too many 1241 // "\tmov (%rbx), %rbx\n" 1242 "\tmov (%rbx, %rax, 8), %rbx\n" // SIZEOF QWORD == 8 for multiplier 1243 "\tpop %rax\n" 1244 "\tret\n" 1245 ); 1246 1247 1248 /* 1249 * This functions are part of the GUEST_CPU class. They are called by 1250 * assembler-lever VmExit/VmResume functions to save all registers that are not 1251 * saved in VMCS but may be used immediately by C-language VMM code. 1252 * The following registers are NOT saved here 1253 * RIP part of VMCS 1254 * RSP part of VMCS 1255 * RFLAGS part of VMCS 1256 * segment regs part of VMCS 1257 * control regs saved in C-code later 1258 * debug regs saved in C-code later 1259 * FP/MMX regs saved in C-code later 1260 * 1261 * Assumptions: 1262 * No free registers except for RSP/RFLAGS. 1263 * All are saved on return. 1264 */ 1265 __asm__( 1266 ".text\n" 1267 ".globl gcpu_save_registers\n" 1268 ".type gcpu_save_registers,@function\n" 1269 "gcpu_save_registers:\n" 1270 "\tpush %rbx\n" // get rbx out of the way so it can be used as a base 1271 "\tcall load_save_area_into_rbx\n" 1272 "\tmovq %rax, (%rbx)\n" 1273 "\tpop %rax\n" // get the original rbx into rax to save it 1274 "\tmovq %rax, 8(%rbx)\n" // save original rbx 1275 "\tmovq %rcx, 16(%rbx)\n" 1276 "\tmovq %rdx, 24(%rbx)\n" 1277 "\tmovq %rdi, 32(%rbx)\n" 1278 "\tmovq %rsi, 40(%rbx)\n" 1279 "\tmovq %rbp, 48(%rbx)\n" 1280 "\tmovq %r8, 64(%rbx)\n" 1281 "\tmovq %r9, 72(%rbx)\n" 1282 "\tmovq %r10, 80(%rbx)\n" 1283 "\tmovq %r11, 88(%rbx)\n" 1284 "\tmovq %r12, 96(%rbx)\n" 1285 "\tmovq %r13, 104(%rbx)\n" 1286 "\tmovq %r14, 112(%rbx)\n" 1287 "\tmovq %r15, 120(%rbx)\n" 1288 // skip RIP and RFLAGS here (16 missing bytes) 1289 // Note that the XMM registers require 16-byte alignment 1290 "\tmovaps %xmm0, 144(%rbx)\n" 1291 "\tmovaps %xmm1, 160(%rbx)\n" 1292 "\tmovaps %xmm2, 176(%rbx)\n" 1293 "\tmovaps %xmm3, 192(%rbx)\n" 1294 "\tmovaps %xmm4, 208(%rbx)\n" 1295 "\tmovaps %xmm5, 224(%rbx)\n" 1296 "\tret\n" 1297 ); 1298 1299 1300 __asm__( 1301 ".globl gcpu_restore_registers\n" 1302 ".type gcpu_restore_registers,@function\n" 1303 "gcpu_restore_registers:\n" 1304 "\tcall load_save_area_into_rbx\n" 1305 // restore XMM registers first 1306 // These are aligned on 16-byte boundaries 1307 "\tmovaps 144(%rbx), %xmm0\n" 1308 "\tmovaps 160(%rbx), %xmm1\n" 1309 "\tmovaps 176(%rbx), %xmm2\n" 1310 "\tmovaps 192(%rbx), %xmm3\n" 1311 "\tmovaps 208(%rbx), %xmm4\n" 1312 "\tmovaps 224(%rbx), %xmm5\n" 1313 1314 "\tmovq (%rbx), %rax\n" 1315 // rbx is restored at the end 1316 "\tmovq 16(%rbx), %rcx\n" 1317 "\tmovq 24(%rbx), %rdx\n" 1318 "\tmovq 32(%rbx), %rdi\n" 1319 "\tmovq 40(%rbx), %rsi\n" 1320 "\tmovq 48(%rbx), %rbp\n" 1321 // rsp is not restored 1322 "\tmovq 64(%rbx), %r8\n" 1323 "\tmovq 72(%rbx), %r9\n" 1324 "\tmovq 80(%rbx), %r10\n" 1325 "\tmovq 88(%rbx), %r11\n" 1326 "\tmovq 96(%rbx), %r12\n" 1327 "\tmovq 104(%rbx), %r13\n" 1328 "\tmovq 112(%rbx), %r14\n" 1329 "\tmovq 120(%rbx), %r15\n" 1330 // skip RIP and RFLAGS 1331 1332 // restore rbx now that we're done using it as a base register 1333 "\tmovq 8(%rbx), %rbx\n" 1334 "\tret\n" 1335 ); 1336 1337 1338 1339 #if 0 // never ported 1340 void hw_leave_64bit_mode (unsigned int compatibility_segment, 1341 unsigned short int port_id, 1342 unsigned short int value, 1343 unsigned int cr3_value) 1344 { 1345 1346 jmp $ 1347 shl rcx, 32 ;; prepare segment:offset pair for retf by shifting 1348 ;; compatibility segment in high address 1349 lea rax, compat_code ;; and 1350 add rcx, rax ;; placing offset into low address 1351 push rcx ;; push ret address onto stack 1352 mov rsi, rdx ;; rdx will be used during EFER access 1353 mov rdi, r8 ;; r8 will be unaccessible, so use rsi instead 1354 mov rbx, r9 ;; save CR3 in RBX. this function is the last called, so we have not to save rbx 1355 retf ;; jump to compatibility mode 1356 compat_code: ;; compatibility mode starts right here 1357 1358 mov rax, cr0 ;; only 32-bit are relevant 1359 btc eax, 31 ;; disable IA32e paging (64-bits) 1360 mov cr0, rax ;; 1361 1362 ;; now in protected mode 1363 mov ecx, 0C0000080h ;; EFER MSR register 1364 rdmsr ;; read EFER into EAX 1365 btc eax, 8 ;; clear EFER.LME 1366 wrmsr ;; write EFER back 1367 1368 ; mov cr3, rbx ;; load CR3 for 32-bit mode 1369 ; 1370 ; mov rax, cr0 ;; use Rxx notation for compiler, only 32-bit are valuable 1371 ; bts eax, 31 ;; enable IA32 paging (32-bits) 1372 ; mov cr0, rax ;; 1373 ; jmp @f 1374 1375 ;; now in 32-bit paging mode 1376 mov rdx, rsi 1377 mov rax, rdi 1378 out dx, ax ;; write to PM register 1379 ret ;; should never get here 1380 } //hw_leave_64bit_mode 1381 #endif // never ported 1382