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