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