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