github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/host/hw/em64t/em64t_gdt.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  
    16  #include "vmm_defs.h"
    17  #include "common_libc.h"
    18  #include "heap.h"
    19  #include "hw_utils.h"
    20  #include "em64t_defs.h"
    21  #include "ia32_defs.h"
    22  #include "gdt.h"
    23  #include "vmm_dbg.h"
    24  #include "file_codes.h"
    25  #define VMM_DEADLOOP()          VMM_DEADLOOP_LOG(EM64T_GDT_C)
    26  #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(EM64T_GDT_C, __condition)
    27  #ifdef JLMDEBUG
    28  #include "jlmdebug.h"
    29  #endif
    30  
    31  
    32  static UINT8 *gdt = NULL;
    33  static EM64T_TASK_STATE_SEGMENT *p_tss = NULL;
    34  static UINT16 gdt_size;
    35  static CPU_ID gdt_number_of_cpus = 0;
    36  
    37  typedef struct {
    38      UINT32 lo;
    39      UINT32 hi;
    40  } UINT64_EMULATED;
    41  
    42  
    43  static void setup_data32_segment_descriptor( void)
    44  {
    45      IA32_DATA_SEGMENT_DESCRIPTOR *p_data32 = (IA32_DATA_SEGMENT_DESCRIPTOR *) &gdt[DATA32_GDT_ENTRY_OFFSET];
    46  
    47      p_data32->lo.limit_15_00 = 0xFFFF;
    48      p_data32->lo.base_address_15_00    = 0;
    49      p_data32->hi.base_address_23_16    = 0;
    50      p_data32->hi.accessed = 0;
    51      p_data32->hi.writable = 1;
    52      p_data32->hi.expansion_direction   = 0;    // up
    53      p_data32->hi.mbz_11 = 0;
    54      p_data32->hi.mbo_12 = 1;
    55      p_data32->hi.dpl = 0;    // privileged
    56      p_data32->hi.present  = 1;
    57      p_data32->hi.limit_19_16  = 0xF;
    58      p_data32->hi.avl = 0;    // available to SW
    59      p_data32->hi.mbz_21 = 0;
    60      p_data32->hi.big = 1;    // 32-bit access
    61      p_data32->hi.granularity = 1;    // segment limit measured in 4K units
    62      p_data32->hi.base_address_31_24  = 0;
    63  }
    64  
    65  
    66  static void setup_code32_segment_descriptor(void)
    67  {
    68      IA32_CODE_SEGMENT_DESCRIPTOR *p_code32 = (IA32_CODE_SEGMENT_DESCRIPTOR *) &gdt[CODE32_GDT_ENTRY_OFFSET];
    69      p_code32->lo.limit_15_00           = 0xFFFF;
    70      p_code32->lo.base_address_15_00    = 0;
    71  
    72      p_code32->hi.base_address_23_16    = 0;
    73      p_code32->hi.accessed              = 0;
    74      p_code32->hi.readable              = 1;
    75      p_code32->hi.conforming            = 0;    // strict privilege checkings
    76      p_code32->hi.mbo_11                = 1;
    77      p_code32->hi.mbo_12                = 1;
    78      p_code32->hi.dpl                   = 0;    // privileged
    79      p_code32->hi.present               = 1;
    80      p_code32->hi.limit_19_16           = 0xF;
    81      p_code32->hi.avl                   = 0;    // available to SW
    82      p_code32->hi.mbz_21                = 0;
    83      p_code32->hi.default_size          = 1;    // 32-bit access
    84      p_code32->hi.granularity           = 1;    // segment limit measured in 4K units
    85      p_code32->hi.base_address_31_24    = 0;
    86  }
    87  
    88  
    89  static void setup_code64_segment_descriptor(void)
    90  {
    91      EM64T_CODE_SEGMENT_DESCRIPTOR *p_code64 = (EM64T_CODE_SEGMENT_DESCRIPTOR *) &gdt[CODE64_GDT_ENTRY_OFFSET];
    92  
    93      // low 32-bit word is reserved, configure only high word
    94      p_code64->hi.accessed       = 0;
    95      p_code64->hi.readable       = 1;
    96      p_code64->hi.conforming     = 1; /// ??? 0;
    97      p_code64->hi.mbo_11         = 1;
    98      p_code64->hi.mbo_12         = 1;
    99      p_code64->hi.dpl            = 0;
   100      p_code64->hi.present        = 1;
   101      p_code64->hi.long_mode      = 1;    // important !!!
   102      p_code64->hi.default_size   = 0;    // important !!!
   103      p_code64->hi.granularity    = 0;
   104  }
   105  
   106  static void setup_tss_with_descriptor(CPU_ID cpu_id)
   107  {
   108      EM64T_TSS_SEGMENT_DESCRIPTOR *p_tss_dx = (EM64T_TSS_SEGMENT_DESCRIPTOR *) &gdt[TSS_ENTRY_OFFSET(cpu_id)];
   109      UINT64  base_address    = (UINT64) &p_tss[cpu_id];
   110      UINT32  segment_limit   = OFFSET_OF(EM64T_TASK_STATE_SEGMENT, io_bitmap_last_byte);
   111  
   112      p_tss_dx->q0.segment_limit_00_15    = segment_limit & 0xFFFF;
   113      p_tss_dx->q0.base_address_00_15     = (UINT32) (base_address & 0xFFFF);
   114  
   115      p_tss_dx->q1.base_address_23_16     = ((UINT32) (base_address >> 16)) & 0xFF;
   116      p_tss_dx->q1.type                   = 9;    // means TSS descriptor
   117      p_tss_dx->q1.mbz_12                 = 0;
   118      p_tss_dx->q1.dpl                    = 0;
   119      p_tss_dx->q1.present                = 1;
   120      p_tss_dx->q1.segment_limit_16_19    = (segment_limit >> 16) & 0xF;
   121      p_tss_dx->q1.avl                    = 0;
   122      p_tss_dx->q1.mbz_21_22              = 0;
   123      p_tss_dx->q1.granularity            = 0;
   124      p_tss_dx->q1.base_address_31_24     = ((UINT32) (base_address >> 24)) & 0xFF;
   125      p_tss_dx->q2.base_address_32_63     = (UINT32) (base_address >> 32);
   126      p_tss_dx->q3 = 0;
   127      // that means no IO ports are blocked
   128      p_tss[cpu_id].io_bitmap_address = OFFSET_OF(EM64T_TASK_STATE_SEGMENT, io_bitmap_last_byte);
   129      p_tss[cpu_id].io_bitmap_last_byte = 0xFF;
   130  }
   131  
   132  
   133  //  FUNCTION   : hw_gdt_setup()
   134  //  PURPOSE    : Setup GDT for all CPUs. Including entries for:
   135  //             : 64-bit code segment
   136  //             : 32-bit code segment (for compatibility mode)
   137  //             : 32-bit data segment (in compatibility mode, for both data and stack)
   138  //             : one 64-bit for FS, which limit is used like index CPU ID
   139  //  ARGUMENTS  : IN CPU_ID number_of_cpus - number of CPUs in the system
   140  void hw_gdt_setup(IN CPU_ID number_of_cpus)
   141  {
   142      CPU_ID cpu_id= 0;
   143      gdt= NULL;
   144  
   145  #ifdef JLMDEBUG
   146      bprint("at hw_gdt_setup(%d, %lu)\n",
   147             number_of_cpus, TSS_ENTRY_OFFSET(number_of_cpus));
   148  #endif
   149      if (NULL == gdt) {
   150  #ifdef JLMDEBUG
   151          bprint("hw_gdt_setup NULL case\n");
   152  #endif
   153          // Offset of next after last entry will give us the size
   154          gdt_size = TSS_ENTRY_OFFSET(number_of_cpus);
   155          gdt = vmm_memory_alloc(gdt_size);
   156          VMM_ASSERT(NULL != gdt);
   157  #ifdef JLMDEBUG
   158          bprint("gdt right after alloc %p\n", gdt);
   159  #endif
   160          p_tss = vmm_memory_alloc(sizeof(EM64T_TASK_STATE_SEGMENT) * number_of_cpus);
   161          VMM_ASSERT(NULL != p_tss);
   162      }
   163      gdt_number_of_cpus = number_of_cpus;
   164  #ifdef JLMDEBUG
   165      bprint("hw_gdt_setup about to setup segment descriptors, gdt= %p\n",
   166             gdt);
   167  #endif
   168      setup_data32_segment_descriptor();
   169      setup_code32_segment_descriptor();
   170      setup_code64_segment_descriptor();
   171  #ifdef JLMDEBUG
   172      bprint("hw_gdt_setup about to setup tss descriptor\n");
   173  #endif
   174      for (cpu_id = 0; cpu_id < number_of_cpus; ++cpu_id) {
   175          setup_tss_with_descriptor(cpu_id);
   176      }
   177  }
   178  
   179  
   180  #ifdef DEBUG
   181  void gdt_show(void)
   182  {
   183      EM64T_GDTR gdtr;
   184      UINT64_EMULATED *p_base;
   185      unsigned i;
   186  
   187      hw_sgdt(&gdtr);
   188      p_base = (UINT64_EMULATED *) gdtr.base;
   189      VMM_LOG(mask_anonymous, level_trace,"Limit = %04X\n", gdtr.limit);
   190      for (i = 0; i < (gdtr.limit + 1) / sizeof(UINT64_EMULATED); ++i) {
   191          VMM_LOG(mask_anonymous, level_trace,"%02X %08X %08X\n", i, p_base[i].lo, p_base[i].hi);
   192      }
   193  }
   194  #endif
   195  
   196  
   197  //  FUNCTION     : hw_gdt_load()
   198  //  PURPOSE      : Load GDT on given CPU
   199  //  ARGUMENTS    : IN CPU_ID cpu_id
   200  //  RETURNS      : void
   201  void hw_gdt_load(IN CPU_ID cpu_id)
   202  {
   203      EM64T_GDTR gdtr;
   204  
   205      VMM_ASSERT(NULL != gdt);
   206      VMM_ASSERT(cpu_id < gdt_number_of_cpus);
   207  
   208      gdtr.limit = gdt_size - 1;
   209      gdtr.base  = (UINT64) gdt;
   210      hw_lgdt(&gdtr);
   211      hw_write_ds(DATA32_GDT_ENTRY_OFFSET);
   212      hw_write_ss(DATA32_GDT_ENTRY_OFFSET);
   213      hw_write_cs(CODE64_GDT_ENTRY_OFFSET);
   214      setup_tss_with_descriptor(cpu_id); // do it again here, in case we called after S3
   215      hw_write_tr(TSS_ENTRY_OFFSET(cpu_id));
   216      hw_write_ldtr(0);
   217      hw_write_es(0);
   218      hw_write_fs(0);
   219      hw_write_gs(0);
   220  }
   221  
   222  
   223  //  FUNCTION     : hw_gdt_set_ist_pointer()
   224  //  PURPOSE      : Assign address to specified IST
   225  //  ARGUMENTS    : CPU_ID cpu_id
   226  //               : UINT8 ist_no - in range [0..7]
   227  //               : ADDRESS address - of specified Interrupt Stack
   228  void hw_gdt_set_ist_pointer(CPU_ID cpu_id, UINT8 ist_no, ADDRESS address)
   229  {
   230      VMM_ASSERT(ist_no <= 7);
   231      VMM_ASSERT(cpu_id < gdt_number_of_cpus);
   232      VMM_ASSERT(NULL != p_tss);
   233      p_tss[cpu_id].ist[ist_no] = address;
   234  }
   235  
   236  
   237  VMM_STATUS hw_gdt_parse_entry( IN UINT8 *p_gdt, IN UINT16 selector,
   238         OUT ADDRESS *p_base, OUT UINT32 *p_limit, OUT UINT32  *p_attributes)
   239  {
   240      UINT32 *p_entry = (UINT32 *) &p_gdt[selector];
   241      VMM_STATUS status = VMM_OK;
   242  
   243      switch (selector) {
   244      case NULL_GDT_ENTRY_OFFSET:
   245          *p_base = 0;
   246          *p_limit = 0;
   247          *p_attributes = EM64T_SEGMENT_IS_UNUSABLE_ATTRUBUTE_VALUE; // set "unusable" bit to 1
   248          break;
   249      case CODE64_GDT_ENTRY_OFFSET:
   250          *p_base       = 0;
   251          *p_limit      = 0;
   252          *p_attributes = (p_entry[1] >> 8) & 0xF0FF;
   253          break;
   254      case DATA32_GDT_ENTRY_OFFSET:
   255      case CODE32_GDT_ENTRY_OFFSET:
   256          *p_base =  (p_entry[1] & 0xFF000000) |
   257                     ((p_entry[1] << 16) & 0x00FF0000) |
   258                     ((p_entry[0] >> 16) & 0x0000FFFF);
   259          *p_limit      = (p_entry[0] & 0xFFFF) | (p_entry[1] & 0x000F0000);
   260          *p_attributes = (p_entry[1] >> 8) & 0xF0FF;
   261          break;
   262  
   263      default:    // Task Switch Segment
   264          if (selector > TSS_ENTRY_OFFSET(gdt_number_of_cpus-1) ||    // exceeds limit or
   265              0 != (selector & 0xF)) {            // not aligned on 16 bytes
   266              status = VMM_ERROR;
   267          }
   268          else {
   269              *p_base = p_entry[2];
   270              *p_base <<= 32;
   271              *p_base |=  (p_entry[1] & 0xFF000000) | ((p_entry[1] << 16) & 0x00FF0000) |
   272                          ((p_entry[0] >> 16) & 0x0000FFFF);
   273              *p_limit = (p_entry[0] & 0xFFFF) | (p_entry[1] & 0x000F0000);
   274              *p_attributes = (p_entry[1] >> 8) & 0xF0FF;
   275          }
   276          break;
   277      }
   278      return status;
   279  }
   280