github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/arch/e820_abstraction.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 "file_codes.h" 16 #define VMM_DEADLOOP() VMM_DEADLOOP_LOG(E820_ABSTRACTION_C) 17 #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(E820_ABSTRACTION_C, __condition) 18 #include <vmm_defs.h> 19 #include <vmm_arch_defs.h> 20 #include <e820_abstraction.h> 21 #include <heap.h> 22 #include <common_libc.h> 23 #include "vmm_dbg.h" 24 #ifdef ENABLE_INT15_VIRTUALIZATION 25 #include "vmm_objects.h" 26 #include "gpm_api.h" 27 #include "guest_cpu.h" 28 #include "guest.h" 29 #include "host_memory_manager_api.h" 30 #include "../guest/guest_cpu/unrestricted_guest.h" 31 #ifdef JLMDEBUG 32 #include "jlmdebug.h" 33 #endif 34 35 36 UINT32 g_int15_trapped_page = 0; 37 UINT32 g_int15_orignal_vector = 0; 38 E820MAP_STATE *g_emap; 39 #endif // ENABLE_INT15_VIRTUALIZATION 40 41 42 static INT15_E820_MEMORY_MAP* g_e820_map = NULL; 43 44 // static 45 const char* g_int15_e820_type_name[] = { 46 "UNKNOWN", // 0 47 "MEMORY", // 1 48 "RESERVED",// 2 49 "ACPI", // 3 50 "NVS", // 4 51 "UNUSABLE" // 5 52 }; 53 #ifdef ENABLE_INT15_VIRTUALIZATION 54 static UINT8 int15_handler_code[] = 55 { 56 0x3d,0x20,0xe8, // cmp ax, 0xe820 57 0x74,0x05, // jz Handler 58 0xea,0x00,0x00,0x00,0x00, // jmp orig_handler 59 0x0f,0x01,0xc1, // Handler: vmcall 60 0xcf // iret 61 }; 62 // conditional jump can be only 63 // near jump, hence too jumps in 64 // this assembly code 65 #endif // ENABLE_INT15_VIRTUALIZATION 66 #define E820_NAMES_COUNT (sizeof(g_int15_e820_type_name)/sizeof(const char*)) 67 68 #ifdef ENABLE_INT15_VIRTUALIZATION 69 70 /* 71 * This function is supposed to setup int15 handling 72 * it will write its own handling code to vector area which is 73 * not being used or known to not being used. So we only 74 * handle E820 type INT15 interrupt, any other type of 75 * INT15 will be handled by the original vector. 76 */ 77 void update_int15_handling(void) 78 { 79 UINT32 int15_vector, i; 80 UINT32 *int15_vector_offset = (UINT32*)((UINT64)INT15_VECTOR_LOCATION); 81 82 // save original vector location to use in vmexit 83 g_int15_orignal_vector = *(int15_vector_offset); 84 85 int15_vector = INT15_HANDLER_ADDR; //use some location in INT vector table which is not being used 86 87 g_int15_trapped_page = int15_vector; //CS:IP format vector 88 *(int15_vector_offset) = g_int15_trapped_page; //hookup our INT15 vector(seg:offset) 89 90 //patch the original vector 91 *(UINT32*)&int15_handler_code[ORIG_HANDLER_OFFSET] = g_int15_orignal_vector; 92 93 // put out warning if the vector area is being used 94 // vectors we are using are user defined, it is possible 95 // some user might decide to use. Nothing we could do about 96 // but would like to through some indication that those vectors 97 // were non-zero 98 for (i=0; i<sizeof(int15_handler_code); i=i+4) { 99 if (*(UINT32*)(UINT64)(int15_vector+i) != 0) 100 VMM_LOG(mask_anonymous, level_error, "WARNING: User defined Interrupts being over written (0x%x)\n",*(UINT32*)(UINT64)(int15_vector+i) ); 101 } 102 103 //write patched code to the interrupt 15 handling location 104 for (i=0; i<sizeof(int15_handler_code); i++) 105 *(UINT8*)(UINT64)(int15_vector+i) = int15_handler_code[i]; 106 107 VMM_LOG(mask_anonymous, level_trace, "E820 Original vector:0x%x\n",g_int15_orignal_vector ); 108 VMM_LOG(mask_anonymous, level_trace, "E820 int15 handler vector:0x%x\n",g_int15_trapped_page ); 109 } 110 #endif //ENABLE_INT15_VIRTUALIZATION 111 #ifdef DEBUG 112 INLINE const char* e820_get_type_name( INT15_E820_RANGE_TYPE type ) 113 { 114 return (type < E820_NAMES_COUNT) ? g_int15_e820_type_name[type] : "UNKNOWN"; 115 } 116 #endif 117 118 BOOLEAN e820_abstraction_initialize(const INT15_E820_MEMORY_MAP* e820_memory_map) 119 { 120 #ifdef ENABLE_INT15_VIRTUALIZATION 121 if(is_unrestricted_guest_supported()) 122 //initialize int15 handling vectors 123 update_int15_handling(); 124 #endif 125 if (e820_memory_map != NULL) { 126 UINT32 size = e820_memory_map->memory_map_size + sizeof(e820_memory_map->memory_map_size); 127 g_e820_map = (INT15_E820_MEMORY_MAP*)vmm_memory_alloc(size); 128 if (g_e820_map == NULL) { 129 return FALSE; 130 } 131 vmm_memcpy(g_e820_map, e820_memory_map, size); 132 VMM_DEBUG_CODE(e820_abstraction_print_memory_map(E820_ORIGINAL_MAP)); 133 return TRUE; 134 } 135 return FALSE; 136 } 137 138 BOOLEAN e820_abstraction_is_initialized(void) { 139 return (g_e820_map != NULL); 140 } 141 142 const INT15_E820_MEMORY_MAP* e820_abstraction_get_map(E820_HANDLE e820_handle) { 143 if (e820_handle == E820_ORIGINAL_MAP) { 144 return g_e820_map; 145 } 146 return (const INT15_E820_MEMORY_MAP*)e820_handle; 147 } 148 149 150 E820_ABSTRACTION_RANGE_ITERATOR e820_abstraction_iterator_get_first(E820_HANDLE e820_handle) { 151 INT15_E820_MEMORY_MAP* e820_map; 152 153 if (e820_handle == E820_ORIGINAL_MAP) { 154 e820_map = g_e820_map; 155 } 156 else { 157 e820_map = (INT15_E820_MEMORY_MAP*)e820_handle; 158 } 159 160 if (e820_map == NULL) { 161 return E820_ABSTRACTION_NULL_ITERATOR; 162 } 163 164 if (e820_map->memory_map_size == 0) { 165 return E820_ABSTRACTION_NULL_ITERATOR; 166 } 167 168 return(E820_ABSTRACTION_RANGE_ITERATOR)(&(e820_map->memory_map_entry[0])); 169 } 170 171 E820_ABSTRACTION_RANGE_ITERATOR 172 e820_abstraction_iterator_get_next(E820_HANDLE e820_handle, E820_ABSTRACTION_RANGE_ITERATOR iter) { 173 UINT64 iter_hva = (UINT64)iter; 174 INT15_E820_MEMORY_MAP* e820_map; 175 UINT64 e820_entries_hva; 176 177 if (iter == (E820_ABSTRACTION_RANGE_ITERATOR)NULL) { 178 return E820_ABSTRACTION_NULL_ITERATOR; 179 } 180 if (e820_handle == E820_ORIGINAL_MAP) { 181 e820_map = g_e820_map; 182 } 183 else { 184 e820_map = (INT15_E820_MEMORY_MAP*)e820_handle; 185 } 186 if(e820_map == NULL){ 187 return E820_ABSTRACTION_NULL_ITERATOR; 188 } 189 e820_entries_hva = (UINT64)(&(e820_map->memory_map_entry[0])); 190 iter_hva += sizeof(INT15_E820_MEMORY_MAP_ENTRY_EXT); 191 if (iter_hva >= (e820_entries_hva + e820_map->memory_map_size)) { 192 return E820_ABSTRACTION_NULL_ITERATOR; 193 } 194 return (E820_ABSTRACTION_RANGE_ITERATOR*)iter_hva; 195 } 196 197 const INT15_E820_MEMORY_MAP_ENTRY_EXT* 198 e820_abstraction_iterator_get_range_details(IN E820_ABSTRACTION_RANGE_ITERATOR iter) { 199 if (iter == (E820_ABSTRACTION_RANGE_ITERATOR)NULL) { 200 return NULL; 201 } 202 return (INT15_E820_MEMORY_MAP_ENTRY_EXT*)iter; 203 } 204 205 206 BOOLEAN e820_abstraction_create_new_map(OUT E820_HANDLE* handle) { 207 INT15_E820_MEMORY_MAP* e820_map = (INT15_E820_MEMORY_MAP*)vmm_page_alloc(1); 208 if (e820_map == NULL) { 209 return FALSE; 210 } 211 e820_map->memory_map_size = 0; 212 *handle = (E820_HANDLE)e820_map; 213 return TRUE; 214 } 215 216 void e820_abstraction_destroy_map(IN E820_HANDLE handle) { 217 if (handle == E820_ORIGINAL_MAP) { 218 // Destroying of original map is forbidden 219 VMM_ASSERT(0); 220 return; 221 } 222 vmm_page_free((void*)handle); 223 } 224 225 BOOLEAN e820_abstraction_add_new_range(IN E820_HANDLE handle, 226 IN UINT64 base_address, IN UINT64 length, 227 IN INT15_E820_RANGE_TYPE address_range_type, 228 IN INT15_E820_MEMORY_MAP_EXT_ATTRIBUTES extended_attributes) { 229 INT15_E820_MEMORY_MAP* e820_map = (INT15_E820_MEMORY_MAP*)handle; 230 INT15_E820_MEMORY_MAP_ENTRY_EXT* new_entry; 231 UINT32 new_entry_index; 232 233 if (handle == E820_ORIGINAL_MAP) { 234 VMM_ASSERT(0); 235 return FALSE; 236 } 237 if ((e820_map->memory_map_size + sizeof(INT15_E820_MEMORY_MAP_ENTRY_EXT)) >= PAGE_4KB_SIZE) { 238 return FALSE; 239 } 240 if (length == 0) { 241 return FALSE; 242 } 243 new_entry_index = e820_map->memory_map_size / sizeof(INT15_E820_MEMORY_MAP_ENTRY_EXT); 244 if (new_entry_index > 0) { 245 INT15_E820_MEMORY_MAP_ENTRY_EXT* last_entry = &(e820_map->memory_map_entry[new_entry_index - 1]); 246 if ((last_entry->basic_entry.base_address >= base_address) || 247 (last_entry->basic_entry.base_address + last_entry->basic_entry.length > base_address)) { 248 return FALSE; 249 } 250 } 251 new_entry = &(e820_map->memory_map_entry[new_entry_index]); 252 new_entry->basic_entry.base_address = base_address; 253 new_entry->basic_entry.length = length; 254 new_entry->basic_entry.address_range_type = address_range_type; 255 new_entry->extended_attributes.uint32 = extended_attributes.uint32; 256 e820_map->memory_map_size += sizeof(INT15_E820_MEMORY_MAP_ENTRY_EXT); 257 return TRUE; 258 } 259 260 261 #ifdef ENABLE_INT15_VIRTUALIZATION 262 // handle int15 from real mode code 263 // we use CS:IP for vmcall instruction to get indication that there is int15 264 // check for E820 function, if true, then handle it 265 // no other int15 function should come here 266 BOOLEAN handle_int15_vmcall(GUEST_CPU_HANDLE gcpu) 267 { 268 UINT16 selector=0; 269 UINT64 base=0; 270 UINT32 limit=0; 271 UINT32 attr=0; 272 UINT32 expected_lnr_addr; 273 UINT32 vmcall_lnr_addr; 274 volatile UINT64 r_rax=0, r_rdx=0, r_rip=0; 275 276 // PE = 0? then real mode 277 if(!(0x1 & gcpu_get_guest_visible_control_reg(gcpu, IA32_CTRL_CR0))) { 278 //need to get CS:IP to make sure that this VMCALL from INT15 handler 279 gcpu_get_segment_reg(gcpu,IA32_SEG_CS, &selector,&base,&limit,&attr); 280 r_rip = gcpu_get_gp_reg(gcpu, IA32_REG_RIP); 281 282 expected_lnr_addr = SEGMENT_OFFSET_TO_LINEAR(g_int15_trapped_page >> 16, 283 g_int15_trapped_page + VMCALL_OFFSET); 284 vmcall_lnr_addr = SEGMENT_OFFSET_TO_LINEAR((UINT32)selector, (UINT32)r_rip); 285 //check to see if the CS:IP is same as expected for VMCALL in INT15 handler 286 if (expected_lnr_addr == vmcall_lnr_addr) { 287 r_rax = gcpu_get_gp_reg(gcpu, IA32_REG_RAX); 288 r_rdx = gcpu_get_gp_reg(gcpu, IA32_REG_RDX); 289 if ((0xE820 == r_rax) && ('SMAP' == r_rdx)) { 290 if (g_emap == NULL) { 291 g_emap = vmm_malloc(sizeof(E820MAP_STATE)); 292 VMM_ASSERT(g_emap != NULL); 293 vmm_memset(g_emap, 0, sizeof(E820MAP_STATE)); 294 } 295 e820_save_guest_state(gcpu, g_emap); 296 g_emap->guest_handle = gcpu_guest_handle(gcpu); 297 e820_int15_handler(g_emap); 298 e820_restore_guest_state(gcpu, g_emap); 299 gcpu_skip_guest_instruction(gcpu); 300 return TRUE; 301 } else { 302 VMM_LOG(mask_anonymous, level_error,"INT15 wasn't handled for function 0x%x\n", r_rax); 303 VMM_DEADLOOP(); // Should not get here 304 return FALSE; 305 } 306 } 307 } 308 return FALSE; 309 } 310 311 //save Guest state for registers we might be using 312 // when handling INT15 E820 313 void 314 e820_save_guest_state(GUEST_CPU_HANDLE gcpu, E820MAP_STATE *emap) 315 { 316 UINT16 selector; 317 UINT64 base; 318 UINT32 limit; 319 UINT32 attr; 320 E820_GUEST_STATE *p_arch = &emap->e820_guest_state; 321 322 //only registers needed for handling int15 are saved 323 p_arch->em_rax = gcpu_get_gp_reg(gcpu, IA32_REG_RAX); 324 p_arch->em_rbx = gcpu_get_gp_reg(gcpu, IA32_REG_RBX); 325 p_arch->em_rcx = gcpu_get_gp_reg(gcpu, IA32_REG_RCX); 326 p_arch->em_rdx = gcpu_get_gp_reg(gcpu, IA32_REG_RDX); 327 p_arch->em_rdi = gcpu_get_gp_reg(gcpu, IA32_REG_RDI); 328 p_arch->em_rsp = gcpu_get_gp_reg(gcpu, IA32_REG_RSP); 329 p_arch->em_rflags = gcpu_get_gp_reg(gcpu, IA32_REG_RFLAGS); 330 gcpu_get_segment_reg(gcpu,IA32_SEG_ES, &selector,&base,&limit,&attr); 331 p_arch->em_es = selector; p_arch->es_base = base; p_arch->es_lim = limit; 332 p_arch->es_attr = attr; 333 gcpu_get_segment_reg(gcpu,IA32_SEG_SS, &selector,&base,&limit,&attr); 334 p_arch->em_ss = selector; p_arch->ss_base = base; p_arch->ss_lim = limit; 335 p_arch->ss_attr = attr; 336 } 337 338 //update VMCS state after handling INT15 E820 339 void 340 e820_restore_guest_state( GUEST_CPU_HANDLE gcpu, E820MAP_STATE *emap) 341 { 342 E820_GUEST_STATE *p_arch = &emap->e820_guest_state; 343 GPA sp_gpa_addr; 344 HVA sp_hva_addr; 345 UINT16 sp_gpa_val; 346 347 //only registers which could be modified by the handler 348 //will be restored. 349 gcpu_set_gp_reg(gcpu, IA32_REG_RAX,p_arch->em_rax); 350 gcpu_set_gp_reg(gcpu, IA32_REG_RBX,p_arch->em_rbx); 351 gcpu_set_gp_reg(gcpu, IA32_REG_RCX,p_arch->em_rcx); 352 gcpu_set_gp_reg(gcpu, IA32_REG_RDX,p_arch->em_rdx); 353 gcpu_set_gp_reg(gcpu, IA32_REG_RDI,p_arch->em_rdi); 354 355 // we need to change the modify EFLAGS saved in stack 356 // as when we do IRET, EFLAGS are restored from the stack 357 //only IRET, CPU does pop IP, pop CS_Segment, Pop EFLAGS 358 // in real mode these pos are only 2bytes 359 sp_gpa_addr = SEGMENT_OFFSET_TO_LINEAR((UINT32)p_arch->em_ss, p_arch->em_rsp); 360 sp_gpa_addr +=4; //RSP points to RIP:SEGMENT:EFLAGS so we increment 4 to get to EFLAGS register 361 362 if (FALSE == gpm_gpa_to_hva(emap->guest_phy_memory, sp_gpa_addr, &sp_hva_addr)) { 363 VMM_LOG(mask_anonymous, level_trace,"Translation failed for physical address %P \n", sp_gpa_addr); 364 VMM_DEADLOOP(); 365 return; 366 } 367 sp_gpa_val = *(UINT16*)(UINT64)sp_hva_addr; 368 if (p_arch->em_rflags & RFLAGS_CARRY) 369 BITMAP_SET(sp_gpa_val, RFLAGS_CARRY); 370 else 371 BITMAP_CLR(sp_gpa_val, RFLAGS_CARRY); 372 *(UINT16*)(UINT64)sp_hva_addr = sp_gpa_val; 373 } 374 375 //handle INT15 E820 map 376 BOOLEAN e820_int15_handler(E820MAP_STATE *emap) 377 { 378 UINT64 dest_gpa; 379 E820_GUEST_STATE *p_arch = &emap->e820_guest_state; 380 const INT15_E820_MEMORY_MAP *p_mmap=NULL; 381 382 if (emap->guest_phy_memory == NULL) 383 emap->guest_phy_memory = gcpu_get_current_gpm(emap->guest_handle); 384 VMM_ASSERT(emap->guest_phy_memory != NULL); 385 if (NULL == emap->emu_e820_handle) { 386 if (FALSE == (gpm_create_e820_map(emap->guest_phy_memory, (E820_HANDLE)&emap->emu_e820_handle))) { 387 VMM_LOG(mask_anonymous, level_error,"FATAL ERROR: No E820 Memory Map was found\n"); 388 return FALSE; 389 } 390 p_mmap = e820_abstraction_get_map(emap->emu_e820_handle); 391 emap->emu_e820_memory_map = p_mmap->memory_map_entry; 392 emap->emu_e820_memory_map_size = 393 (UINT16) (p_mmap->memory_map_size / sizeof(INT15_E820_MEMORY_MAP_ENTRY_EXT)); 394 VMM_ASSERT(NULL != emap->emu_e820_memory_map && 0 != emap->emu_e820_memory_map_size); 395 emap->emu_e820_continuation_value = 0; 396 VMM_LOG(mask_anonymous, level_trace,"INT15 vmcall for E820 map initialized!\n" ); 397 } 398 // Make sure all the arguments are valid 399 if ((p_arch->em_rcx < sizeof(INT15_E820_MEMORY_MAP_ENTRY)) || 400 (p_arch->em_rbx >= emap->emu_e820_memory_map_size) || 401 (p_arch->em_rbx != 0 && p_arch->em_rbx != emap->emu_e820_continuation_value)) { 402 // Set the carry flag 403 BITMAP_SET(p_arch->em_rflags, RFLAGS_CARRY); 404 VMM_LOG(mask_anonymous, level_error, "ERROR>>>>> E820 INT15 rbx=0x%x rcx:0x%x\n",p_arch->em_rbx,p_arch->em_rcx); 405 } 406 else { 407 HVA dest_hva=0; 408 409 // CX contains number of bytes to write. 410 // here we select between basic entry and extended 411 p_arch->em_rcx = (p_arch->em_rcx >= sizeof(INT15_E820_MEMORY_MAP_ENTRY_EXT)) ? 412 sizeof(INT15_E820_MEMORY_MAP_ENTRY_EXT) : sizeof(INT15_E820_MEMORY_MAP_ENTRY); 413 414 // where to put the result 415 dest_gpa = SEGMENT_OFFSET_TO_LINEAR((UINT32) p_arch->em_es, p_arch->em_rdi); 416 if (FALSE == gpm_gpa_to_hva(emap->guest_phy_memory, dest_gpa, &dest_hva)) { 417 VMM_LOG(mask_anonymous, level_trace,"Translation failed for physical address %P \n", dest_gpa); 418 BITMAP_SET(p_arch->em_rflags, RFLAGS_CARRY); 419 return FALSE; 420 } 421 vmm_memcpy((void*)dest_hva, (unsigned char *) &emap->emu_e820_memory_map[p_arch->em_rbx], 422 (unsigned int) p_arch->em_rcx); 423 424 // keep, to validate next instruction 425 emap->emu_e820_continuation_value = (UINT16) p_arch->em_rbx + 1; 426 427 // prepare output parameters 428 p_arch->em_rax = 'SMAP'; 429 430 // Clear the carry flag which means error absence 431 BITMAP_CLR(p_arch->em_rflags, RFLAGS_CARRY); 432 433 if (emap->emu_e820_continuation_value >= emap->emu_e820_memory_map_size) { 434 // Clear EBX to indicate that this is the last entry in the memory map 435 p_arch->em_rbx = 0; 436 emap->emu_e820_continuation_value = 0; 437 } 438 else { 439 // Update the EBX continuation value to indicate there are more entries 440 p_arch->em_rbx = emap->emu_e820_continuation_value; 441 } 442 } 443 return TRUE; 444 } 445 #endif //ENABLE_INT15_VIRTUALIZATION 446 447 #ifdef DEBUG 448 void e820_abstraction_print_memory_map(IN E820_HANDLE handle) { 449 INT15_E820_MEMORY_MAP* e820_map = (INT15_E820_MEMORY_MAP*)handle; 450 UINT32 num_of_entries; 451 UINT32 i; 452 453 if (e820_map == E820_ORIGINAL_MAP) { 454 e820_map = g_e820_map; 455 } 456 VMM_LOG(mask_anonymous, level_trace,"\nE820 Memory Map\n"); 457 VMM_LOG(mask_anonymous, level_trace,"-------------------\n"); 458 if (e820_map == NULL) { 459 VMM_LOG(mask_anonymous, level_trace,"DOESN'T EXIST!!!\n"); 460 } 461 num_of_entries = e820_map->memory_map_size / sizeof(e820_map->memory_map_entry[0]); 462 for (i = 0; i < num_of_entries; i++) { 463 INT15_E820_MEMORY_MAP_ENTRY_EXT* entry = &(e820_map->memory_map_entry[i]); 464 VMM_LOG(mask_anonymous, level_trace,"%2d: [%P : %P] ; type = 0x%x(%8s) ; ext_attr = 0x%x\n", 465 i, entry->basic_entry.base_address, 466 entry->basic_entry.base_address + entry->basic_entry.length, 467 entry->basic_entry.address_range_type, 468 e820_get_type_name(entry->basic_entry.address_range_type), 469 entry->extended_attributes.uint32); 470 } 471 VMM_LOG(mask_anonymous, level_trace,"-------------------\n"); 472 } 473 #endif