github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/libc/vmm_io.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 "vmm_dbg.h" 17 #include "libc_internal.h" 18 #include "hw_interlocked.h" 19 #include "vmcall.h" 20 #include "emulator_if.h" 21 #include "host_memory_manager_api.h" 22 #include "vmm_globals.h" 23 #include "vmm_serial.h" 24 25 26 #define __builtin_va_end(p) 27 #define __builtin_stdarg_start(a,b) 28 #define __builtin_va_arg(a,p) 0 29 30 31 extern int CLI_active(void); 32 33 // C-written CRT routines should be put here 34 35 #define PRINTF_BUFFER_SIZE 512 36 37 #ifdef VMM_DEBUG_SCREEN 38 #define SCREEN_MAX_ROWS 49 // There are actually 50, but we start to count from 0 39 #define SCREEN_MAX_COLOUMNS 80 40 41 #define SCREEN_VGA_BASE_ADDRESS 0xB8000 42 43 static UINT8 *screen_cursor = (UINT8*)SCREEN_VGA_BASE_ADDRESS; 44 #endif 45 46 static UINT32 printf_lock = 0; // Used to guard the print function. 47 // 0 : not locked 48 // 1 or more : locked 49 50 51 // These functions are used for doing lock/unlock 52 // without CPU identification/validation 53 // The reason is to have the lock facility at the stage when cpu ID is unknown 54 // e.g. for LOGs at the bootstrap time 55 static void raw_lock(volatile UINT32 *p_lock_var) 56 { 57 UINT32 old_value; 58 59 60 for (;;) { 61 // Loop until the successfully incremented the lock variable 62 // from 0 to 1 (i.e., we are the only lockers 63 old_value = hw_interlocked_compare_exchange((INT32 *)p_lock_var, 64 0, // Expected 65 1); // New 66 if (0 == old_value) 67 break; 68 hw_pause(); 69 } 70 } 71 72 73 static void raw_force_lock(volatile UINT32 *p_lock_var) 74 { 75 INT32 old_value; 76 77 for (;;) { 78 // Loop until successfully incremented the lock variable 79 old_value = *p_lock_var; 80 if (old_value == 81 hw_interlocked_compare_exchange((INT32 *)p_lock_var, 82 old_value, // Expected 83 old_value + 1)) // New 84 break; 85 hw_pause(); 86 } 87 } 88 89 static void raw_unlock(volatile UINT32 *p_lock_var) 90 { 91 INT32 old_value; 92 93 for (;;) { 94 // Loop until successfully decremented the lock variable 95 96 old_value = *p_lock_var; 97 if (old_value == 98 hw_interlocked_compare_exchange((INT32 *)p_lock_var, 99 old_value, // Expected 100 old_value - 1)) // New 101 break; 102 hw_pause(); 103 } 104 } 105 106 107 static VMM_DEBUG_PORT_TYPE debug_port_type = VMM_DEBUG_PORT_NONE; 108 static VMM_DEBUG_PORT_VIRT_MODE debug_port_virt_mode = VMM_DEBUG_PORT_VIRT_NONE; 109 static void *debug_port_handle = NULL; 110 111 112 113 BOOLEAN vmm_debug_port_init_params(const VMM_DEBUG_PORT_PARAMS *p_params) 114 115 { 116 BOOLEAN err = FALSE; 117 UINT16 debug_port_io_base = VMM_DEBUG_PORT_SERIAL_IO_BASE_DEFAULT; 118 119 debug_port_handle = NULL; 120 debug_port_type = VMM_DEBUG_PORT_SERIAL; 121 debug_port_virt_mode = VMM_DEBUG_PORT_VIRT_HIDE; 122 123 if (p_params) { 124 // Valid parameters structure, use it 125 // Only a serial debug port is currently supported. Furtheremore, 126 // only I/O-based serial port is supported. 127 128 if (p_params->type == VMM_DEBUG_PORT_SERIAL) { 129 debug_port_type = (VMM_DEBUG_PORT_TYPE)p_params->type; 130 switch (p_params->ident_type) { 131 case VMM_DEBUG_PORT_IDENT_IO: 132 debug_port_io_base = p_params->ident.io_base; 133 break; 134 135 case VMM_DEBUG_PORT_IDENT_DEFAULT: 136 debug_port_io_base = VMM_DEBUG_PORT_SERIAL_IO_BASE_DEFAULT; 137 break; 138 139 default: 140 debug_port_io_base = VMM_DEBUG_PORT_SERIAL_IO_BASE_DEFAULT; 141 err = TRUE; 142 } 143 debug_port_virt_mode = (VMM_DEBUG_PORT_VIRT_MODE)p_params->virt_mode; 144 } 145 else { 146 // No debug port 147 debug_port_type = VMM_DEBUG_PORT_NONE; 148 debug_port_virt_mode = VMM_DEBUG_PORT_VIRT_NONE; 149 } 150 } 151 if (debug_port_type == VMM_DEBUG_PORT_SERIAL) 152 debug_port_handle = vmm_serial_new(debug_port_io_base, 153 UART_PROG_IF_DEFAULT, UART_HANDSHAKE_DEFAULT); 154 return err; 155 } 156 157 158 static void vmm_debug_port_init(void) 159 { 160 if (debug_port_type == VMM_DEBUG_PORT_SERIAL) 161 vmm_serial_init(debug_port_handle); 162 } 163 164 165 void vmm_debug_port_clear(void) 166 { 167 if (debug_port_type == VMM_DEBUG_PORT_SERIAL) 168 vmm_serial_reset(debug_port_handle); 169 } 170 171 172 static VMM_DEBUG_PORT_TYPE vmm_debug_port_get_type(void) 173 174 { 175 return debug_port_type; 176 } 177 178 VMM_DEBUG_PORT_VIRT_MODE vmm_debug_port_get_virt_mode(void) 179 180 { 181 return debug_port_virt_mode; 182 } 183 184 185 // If the debug port uses an I/O range, returns its base address. 186 // Otherwise, returns 0 187 UINT16 vmm_debug_port_get_io_base(void) 188 189 { 190 UINT16 io_base = 0; 191 UINT16 io_end = 0; 192 193 if (debug_port_type == VMM_DEBUG_PORT_SERIAL) 194 vmm_serial_get_io_range(debug_port_handle, &io_base, &io_end); 195 return io_base; 196 } 197 198 199 // If the debug port uses an I/O range, returns its end address. 200 // Otherwise, returns 0 201 UINT16 vmm_debug_port_get_io_end(void) 202 203 { 204 UINT16 io_base = 0; 205 UINT16 io_end = 0; 206 207 if (debug_port_type == VMM_DEBUG_PORT_SERIAL) 208 vmm_serial_get_io_range(debug_port_handle, &io_base, &io_end); 209 return io_end; 210 } 211 212 213 // Multiplexers to debug port, according to its type (none, serial etc.). 214 static UINT8 vmm_debug_port_getc(void) 215 { 216 if (vmm_debug_port_get_type() == VMM_DEBUG_PORT_SERIAL) 217 return vmm_serial_getc(debug_port_handle); 218 else 219 return 0; 220 } 221 222 223 static UINT8 vmm_debug_port_putc_nolock( UINT8 Char ) 224 { 225 if (vmm_debug_port_get_type() == VMM_DEBUG_PORT_SERIAL) 226 return vmm_serial_putc_nolock(debug_port_handle, Char); 227 else 228 return Char; 229 } 230 231 static UINT8 vmm_debug_port_putc( UINT8 Char ) 232 { 233 if (vmm_debug_port_get_type() == VMM_DEBUG_PORT_SERIAL) 234 return vmm_serial_putc(debug_port_handle, Char); 235 else 236 return Char; 237 } 238 239 static int vmm_debug_port_puts_direct(BOOLEAN is_locked, const char *string) 240 { 241 int ret = 1; 242 243 if (vmm_debug_port_get_type() == VMM_DEBUG_PORT_SERIAL) { 244 if (is_locked) { 245 // Print using the regular function 246 ret = vmm_serial_puts(debug_port_handle, string); 247 } 248 else { 249 // Force lock, so that regular (locked) prints will not interfere 250 // until we're done. Note that here we may interfere with ongoing 251 // regular prints - but this is the nature of "nolock". 252 raw_force_lock(&printf_lock); 253 254 // Print using the "nolock" function 255 ret = vmm_serial_puts_nolock(debug_port_handle, string); 256 257 // Unlock 258 raw_unlock(&printf_lock); 259 } 260 } 261 262 return ret; 263 } 264 265 266 // Writes a string to the debug port, according to its type (none, serial etc.). 267 // Takes care of the case where running as guest 268 static int vmm_debug_port_puts(BOOLEAN is_locked, const char *string) 269 { 270 int ret = 1; 271 272 if (emulator_is_running_as_guest()) 273 hw_vmcall(VMCALL_EMULATOR_PUTS, (void*)string, 0, 0); 274 else 275 ret = vmm_debug_port_puts_direct(is_locked, string); 276 return ret; 277 } 278 279 280 // Emulator debug support functions 281 282 #ifdef DEBUG 283 #pragma warning(push) 284 #pragma warning(disable : 4100) // Supress warnings about unreferenced formal parameter 285 static VMM_STATUS vmm_io_vmcall_puts_handler( GUEST_CPU_HANDLE gcpu UNUSED, 286 ADDRESS *arg1, ADDRESS *arg2 UNUSED, ADDRESS *arg3 UNUSED) 287 { 288 const char *string = (const char *)*arg1; 289 290 raw_lock(&printf_lock); 291 vmm_debug_port_puts_direct(TRUE, string); 292 raw_unlock(&printf_lock); 293 return VMM_OK; 294 } 295 #pragma warning(pop) 296 #endif 297 298 299 static void printf_init( void ) 300 { 301 } 302 303 304 static int vmm_printf_int(BOOLEAN use_lock, char *buffer, UINT32 buffer_size, 305 const char *format, va_list args ) 306 { 307 UINT32 printed_size = 0; 308 309 if (use_lock) { 310 raw_lock(&printf_lock); 311 } 312 printed_size = vmm_vsprintf_s (buffer, buffer_size, format, args); 313 if (printed_size && (printed_size != UINT32_ALL_ONES)) { 314 printed_size = vmm_debug_port_puts(use_lock, buffer); 315 } 316 if (use_lock) { 317 raw_unlock(&printf_lock); 318 } 319 return printed_size; 320 } 321 322 323 static int vmm_printf_nolock_alloc_buffer(const char *format, va_list args) 324 { 325 // use buffer on the stack 326 char buffer[PRINTF_BUFFER_SIZE]; 327 328 return vmm_printf_int ( FALSE, buffer, PRINTF_BUFFER_SIZE, format, args); 329 } 330 331 332 #ifdef VMM_DEBUG_SCREEN 333 static void vmm_printf_screen_int(char* buffer, UINT32 buffer_size, 334 const char *format, va_list args) { 335 UINT32 printed_size = 0; 336 337 raw_lock(&printf_lock); 338 printed_size = vmm_vsprintf_s (buffer, buffer_size, format, args); 339 340 if (printed_size && (printed_size != UINT32_ALL_ONES)) { 341 UINT32 i; 342 for (i = 0 ; buffer[i] != 0 ; i++) { 343 if (buffer[i] == '\n') { 344 UINT64 line_number; 345 346 line_number = ((UINT64)screen_cursor - SCREEN_VGA_BASE_ADDRESS) / (SCREEN_MAX_COLOUMNS*2); 347 line_number++; 348 screen_cursor = (UINT8*)(line_number * SCREEN_MAX_COLOUMNS * 2) + SCREEN_VGA_BASE_ADDRESS; 349 } 350 else { 351 *screen_cursor = buffer[i]; 352 screen_cursor += 2; 353 } 354 } 355 } 356 raw_unlock(&printf_lock); 357 } 358 #endif 359 360 361 void vmm_io_init( void ) 362 { 363 vmm_debug_port_init(); 364 printf_init(); 365 } 366 367 int vmm_puts_nolock(const char *string ) 368 { 369 int ret = 1; 370 371 ret = vmm_debug_port_puts(FALSE, string); 372 // According to the spec, puts always ends with new line 373 if (ret != EOF) 374 vmm_debug_port_puts(FALSE, "\n\r"); 375 return ret; 376 } 377 378 379 int vmm_puts(const char *string ) 380 { 381 int ret = 1; 382 383 raw_lock(&printf_lock); 384 ret = vmm_debug_port_puts(TRUE, string); 385 // According to the spec, puts always ends with new line 386 if (ret != EOF) 387 vmm_debug_port_puts(TRUE, "\n\r"); 388 raw_unlock(&printf_lock); 389 return ret; 390 } 391 392 393 UINT8 vmm_getc(void) 394 { 395 if (CLI_active()) 396 return vmm_debug_port_getc(); 397 else 398 return 0; 399 } 400 401 UINT8 vmm_putc_nolock( UINT8 Char ) 402 { 403 Char = vmm_debug_port_putc_nolock(Char); 404 return Char; 405 } 406 407 408 UINT8 vmm_putc( UINT8 Char ) 409 { 410 raw_lock(&printf_lock); 411 Char = vmm_debug_port_putc(Char); 412 raw_unlock(&printf_lock); 413 return Char; 414 } 415 416 417 int vmm_vprintf(const char *format, va_list args) 418 { 419 // use static buffer to save stack space 420 static char buffer[PRINTF_BUFFER_SIZE]; 421 422 if (emulator_is_running_as_guest()) { 423 // To avoid deadlocks use nolock version in guest environment. 424 // This will eventually do a VMCALL that will use the locked 425 // printf. 426 427 return vmm_printf_nolock_alloc_buffer(format, args); 428 } 429 else { 430 return vmm_printf_int(TRUE, buffer, PRINTF_BUFFER_SIZE, format, args); 431 } 432 } 433 434 435 int vmm_printf( const char *format, ... ) 436 { 437 va_list args; 438 va_start (args, format); 439 440 return vmm_vprintf(format, args); 441 } 442 443 #ifdef DEBUG 444 // printf without taking any locks - use from NMI handlers 445 int vmm_printf_nolock(const char *format, ...) 446 { 447 va_list args; 448 va_start (args, format); 449 450 return vmm_printf_nolock_alloc_buffer(format, args); 451 } 452 453 void vmm_io_emulator_register( GUEST_ID guest_id ) 454 { 455 vmcall_register( guest_id, VMCALL_EMULATOR_PUTS, 456 (VMCALL_HANDLER)vmm_io_vmcall_puts_handler, FALSE ); 457 } 458 #endif 459 460 #ifdef VMM_DEBUG_SCREEN 461 void vmm_printf_screen( const char *format, ... ) 462 { 463 static char buffer[PRINTF_BUFFER_SIZE]; 464 va_list args; 465 466 va_start (args, format); 467 vmm_printf_screen_int(buffer, PRINTF_BUFFER_SIZE, format, args); 468 } 469 470 471 void vmm_clear_screen(void) 472 { 473 UINT32 i; 474 for (screen_cursor = (UINT8*)SCREEN_VGA_BASE_ADDRESS, i = 0; 475 i < SCREEN_MAX_COLOUMNS*SCREEN_MAX_ROWS; 476 screen_cursor+=2, i++) { 477 *screen_cursor = ' '; 478 } 479 screen_cursor = (UINT8*) SCREEN_VGA_BASE_ADDRESS; 480 } 481 #endif 482 483 // Test function, active only if #ifdef'ed in 484 485 #pragma warning(push) 486 #pragma warning(disable : 4100) // Supress warnings about unreferenced formal parameter 487 void vmm_print_test(UINT32 id UNUSED) 488 489 { 490 #ifdef VMM_PUT_TEST 491 UINT32 i; 492 493 for (i = 0; i < 200; i++) { 494 switch (((hw_rdtsc() / 31) + id) & 0x7) { 495 case 0: 496 vmm_printf( "[%02d] %06d 0 l\n", id, i); // Short, should fit in Tx FIFO 497 break; 498 case 1: 499 vmm_printf( "[%02d] %06d 1 l : The Quick Brown Fox Jumps Over The Lazy Dog\n", id, i); 500 break; 501 case 2: 502 vmm_printf( "[%02d] %06d 2 l : 0123456789 abcdefghijklmnopqrstuvwxyz\n", id, i); 503 break; 504 case 3: 505 vmm_printf( "[%02d] %06d 3 l : the quick brown fox jumps over the lazy dog\n", id, i); 506 break; 507 case 4: 508 vmm_printf( "[%02d] %06d 4 l : 0123456789 abcdefghijklmnopqrstuvwxyz\n", id, i); 509 break; 510 case 5: 511 vmm_printf_nolock("{%02d}_%06d_5_NL\n", id, i); // Short, should fit in Tx FIFO 512 break; 513 case 6: 514 vmm_printf_nolock("{%02d}_%06d_6_NL_:_THE_QUICK_BROWN_FOX_JUMPS_OVER_THE_LAZY_DOG\n", id, i); 515 break; 516 default: 517 vmm_printf_nolock("{%02d}_%06d_7_NL_:_0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", id, i); 518 } 519 } 520 #endif 521 } 522 #pragma warning(pop) 523 524