github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/libc/vmm_serial.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_serial.h"
    17  #include "hw_utils.h"
    18  #include "vmm_dbg.h"
    19  #include "cli.h"
    20  #include "file_codes.h"
    21  
    22  #define VMM_DEADLOOP()          VMM_DEADLOOP_LOG(VMM_SERIAL_LIBC)
    23  #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(VMM_SERIAL_LIBC, __condition)
    24  
    25  
    26  // Private Definitions
    27  
    28  
    29  #define VMM_SERIAL_DEVICES_MAX 8
    30  
    31  typedef struct
    32  {
    33      UINT16              io_base;
    34      UINT8               reserved[2];
    35      UART_PROG_IF_TYPE   prog_if;
    36      UART_HANDSHAKE_MODE handshake_mode;
    37                                   // Handshake mode, as set on initialization
    38      UINT32              hw_fifo_size;
    39                                   // FIFO size of the UART h/w.  Set according to
    40                                   // prog_if.
    41      UINT32              chars_in_tx_fifo;
    42                                   // Current # of chars in h/w transmit FIFO.
    43                                   // Note that this is a maximum estimate, actual
    44                                   // number may be lower - this is the case where
    45                                   // vmm_serial_putc() is interrupted by
    46                                   // vmm_serial_putc_nolock().
    47      BOOLEAN             puts_lock;
    48                                   // Used by puts_nolocked() to lock out regular
    49                                   // prints
    50      BOOLEAN             in_putc; // Flags that putc() is executing
    51      BOOLEAN             in_puts; // Flags that puts() is executing
    52      UINT32              hw_handshake_stopped_count;
    53                                   // Counts the number of consecutive times h/w
    54                                   // handshake has been found to be "stop"
    55      BOOLEAN             is_initialized;
    56                                   // Indicates that the device has been
    57                                   // initialized.  Used for sanity checks.
    58  
    59      // Statistics - Used Mainly for Debug
    60  
    61      UINT32              num_tx_chars_lock;
    62      UINT32              num_tx_chars_nolock;
    63                                   // Counters of transmitted characters in locked
    64                                   // mode (normal) and nolock mode
    65      UINT32              num_rx_chars;
    66                                   // Counter of received characters
    67      UINT32              wait_for_tx_ready_max;
    68                                   // Max number of times tx paused until tx
    69                                   // ready (for any reason).
    70      UINT32              wait_for_tx_ready_avg;
    71                                   // Average number of times tx paused until tx
    72                                   // ready (for any reason).  In units of
    73                                   // 1 / 2^16 (i.e., upper 16 bits is the whole
    74                                   // number part, lower 16 bit is the fraction
    75      UINT32              wait_for_tx_fifo_empty_max;
    76                                   // Max number of times tx paused until tx
    77                                   // FIFO was empty.  In units of
    78      UINT32              wait_for_tx_fifo_empty_avg;
    79                                   // Average number of times tx paused until tx
    80                                   // FIFO was empty.  In units of
    81                                   // 1 / 2^16 (i.e., upper 16 bits is the whole
    82                                   // number part, lower 16 bit is the fraction
    83                                   // part).
    84      UINT32              num_puts_interrupted_by_putc_nolock;
    85      UINT32              num_puts_interrupted_by_puts_nolock;
    86                                   // Count the number of times the normal puts()
    87                                   // was interrupted by puts_nolock() and
    88                                   // puts_nolock()
    89      UINT32              num_putc_blocked_by_puts_nolock;
    90                                   // Counts the number of times the normal putc()
    91                                   // was blocked by puts_nolock()
    92      UINT32              num_chars_hw_handshake_stopped;
    93                                   // Number of characters for which tx stopped
    94                                   // due to h/w handshake
    95      UINT32              num_chars_hw_handshake_auto_go;
    96                                   // Number of characters for which tx h/w
    97                                   // handshake stop was auto-released
    98      UINT32              hw_handshake_stopped_count_max;
    99                                   // Maximum value of hw_handshake_stopped_count,
   100                                   // for statistics & debug
   101      UINT32              hw_handshake_stopped_count_avg;
   102                                   // Average value of hw_handshake_stopped_count,
   103                                   // for statistics & debug.  In units of
   104                                   // 1 / 2^16 (i.e., upper 16 bits is the whole
   105                                   // number part, lower 16 bit is the fraction
   106                                   // part).
   107  } VMM_SERIAL_DEVICE;
   108  
   109  
   110  // Static Variables
   111  
   112  
   113  static VMM_SERIAL_DEVICE serial_devices[VMM_SERIAL_DEVICES_MAX];
   114  static UINT32            initialized_serial_devices = 0;
   115  static const UINT32      serial_tx_stall_usec       = 100;
   116                                   // Number of usecs to stall between tx
   117                                   // attempts if not ready.  at 115200 baud,
   118                                   // each character is about 87 usec.
   119                                   // TODO: tune for tx fifo size
   120  static const UINT32      hw_handshake_stopped_limit = 50000;   // 5 sec
   121                                   // In auto mode, number of stalls at h/w
   122                                   // handshake stop until thestatus is
   123                                   // considered "go"
   124  static const UINT32      avg_factor = 16;
   125                                   // Factor for averaging pause counters.  In
   126                                   // units of 1 / 2^16
   127  
   128  
   129  // Static Functions
   130  
   131  // Updates the maximum of a counter
   132  
   133  static
   134  void
   135  update_max(UINT32 *p_max,   // Maximum
   136             UINT32  count)   // New input
   137  
   138  {
   139      if (count > *p_max)
   140          *p_max = count;
   141  }
   142  
   143  
   144  // Updates the running average of a counter, using a simple 1-stage IIR
   145  // algorithm
   146  static void update_avg(UINT32 *p_avg,   // Running average, as UINT16.UINT16
   147             UINT32  count)   // New input
   148  
   149  {
   150      UINT64       avg;
   151  
   152      // Extend to 64 bits to prevent overflow during calculation
   153      avg = (UINT64)(*p_avg);
   154  
   155      // Do the IIR.  The formula is:
   156      //    avg = (1 - f) * avg + f * counter
   157      // Here the calculation is factored to UINT48.UINT16 representation
   158      avg = ((((1 << 16) - avg_factor) *                   avg) +
   159             (             avg_factor  * ((UINT64)count << 16))
   160            ) >> 16;
   161  
   162      // Assign back, taking care of overflows
   163      if (avg > (UINT32)-1)
   164          *p_avg = (UINT32)-1;
   165      else
   166          *p_avg = (UINT32)avg;
   167  }
   168  
   169  
   170  // Updates the running average and maximum of a counter
   171  static void update_max_and_avg(UINT32 *p_max,   // Maximum
   172                     UINT32 *p_avg,   // Running average, as UINT16.UINT16
   173                     UINT32  count)   // New input
   174  
   175  {
   176      update_max(p_max, count);
   177      update_avg(p_avg, count);
   178  }
   179  
   180  
   181  // Checks h/w handshake lines for "go" status.  Count the number of times it
   182  // was "stop".  In UART_HANDSHAKE_AUTO mode, after a limit is reached force
   183  // the status to "go".
   184  static BOOLEAN is_hw_tx_handshake_go(VMM_SERIAL_DEVICE *p_device)
   185  
   186  {
   187      UART_MSR msr;               // Modem Status Register image
   188      BOOLEAN  hw_handshake_go;   // Flags transmit "go" by h/w handshake
   189  
   190      if ((p_device->handshake_mode == UART_HANDSHAKE_AUTO) ||
   191          (p_device->handshake_mode == UART_HANDSHAKE_HW)) {
   192          // Read the h/w handshake signals
   193  
   194          msr.data = hw_read_port_8(p_device->io_base + UART_REGISTER_MSR);
   195          hw_handshake_go = (msr.bits.CTS == 1) && (msr.bits.DSR == 1);
   196  
   197          if (hw_handshake_go) {
   198              // Other side set h/w handshake to "go".  Reset the counter.
   199  
   200              update_avg(&p_device->hw_handshake_stopped_count_avg,
   201                         p_device->hw_handshake_stopped_count);
   202              p_device->hw_handshake_stopped_count = 0;
   203          }
   204  
   205          else if (p_device->hw_handshake_stopped_count >= hw_handshake_stopped_limit) {
   206              // Other side has indicated h/w handshake "stop" for too long.
   207  
   208              if (p_device->handshake_mode == UART_HANDSHAKE_AUTO) {
   209                  // In auto mode, assume the h/w handshake is stuck and force
   210                  // the status to "go"
   211  
   212                  hw_handshake_go = TRUE;
   213                  p_device->num_chars_hw_handshake_auto_go++;
   214                  if (p_device->hw_handshake_stopped_count == hw_handshake_stopped_limit) {
   215                      // Update the statistic only on the first character
   216                      // we decided to auto-go
   217  
   218                      update_avg(&p_device->hw_handshake_stopped_count_avg,
   219                                 p_device->hw_handshake_stopped_count);
   220                      p_device->hw_handshake_stopped_count++;
   221                  }
   222              }
   223          }
   224          else {
   225              // Increment the stop count and update the statistics
   226  
   227              if (p_device->hw_handshake_stopped_count == 0) {
   228                  // We just stopped, increment the stops statistics counter
   229  
   230                  p_device->num_chars_hw_handshake_stopped++;
   231              }
   232  
   233              p_device->hw_handshake_stopped_count++;
   234  
   235              update_max(&p_device->hw_handshake_stopped_count_max,
   236                         p_device->hw_handshake_stopped_count);
   237          }
   238      }
   239  
   240      else {
   241          // No h/w handshake, always "go"
   242          hw_handshake_go = TRUE;
   243      }
   244  
   245      return hw_handshake_go;
   246  }
   247  
   248  
   249  // Display serial ports' information on the CLI
   250  #ifdef DEBUG
   251  #pragma warning(push )
   252  #pragma warning(disable : 4100)  // Supress warnings about unreferenced formal parameter
   253  static
   254  int
   255  cli_display_serial_info(unsigned argc UNUSED, char *args[] UNUSED)
   256  {
   257      UINT32 i;
   258  
   259      CLI_PRINT("Serial Device #                :");
   260      for (i = 0; i < initialized_serial_devices; i++)
   261          CLI_PRINT("        %1d     ", i);
   262  
   263      CLI_PRINT("\nI/O Base                       :");
   264      for (i = 0; i < initialized_serial_devices; i++)
   265          CLI_PRINT("   0x%04x     ", serial_devices[i].io_base);
   266  
   267      CLI_PRINT("\nChars Tx (lock)                :");
   268      for (i = 0; i < initialized_serial_devices; i++)
   269          CLI_PRINT(" %8d     ", serial_devices[i].num_tx_chars_lock);
   270  
   271      CLI_PRINT("\nChars Tx (nolock)              :");
   272      for (i = 0; i < initialized_serial_devices; i++)
   273          CLI_PRINT(" %8d     ", serial_devices[i].num_tx_chars_nolock);
   274  
   275      CLI_PRINT("\nChars Rx                       :");
   276      for (i = 0; i < initialized_serial_devices; i++)
   277          CLI_PRINT(" %8d     ", serial_devices[i].num_rx_chars);
   278  
   279      CLI_PRINT("\nTx Ready Wait Time (max)       :");
   280      for (i = 0; i < initialized_serial_devices; i++)
   281          CLI_PRINT(" %8d uSec",
   282                    serial_devices[i].wait_for_tx_ready_max *
   283                    serial_tx_stall_usec);
   284  
   285      CLI_PRINT("\nTx Ready Wait Time (avg)       :");
   286      for (i = 0; i < initialized_serial_devices; i++)
   287          CLI_PRINT(" %8d uSec",
   288                    (serial_devices[i].wait_for_tx_ready_avg >> 16) *
   289                    serial_tx_stall_usec);
   290  
   291      CLI_PRINT("\nTx FIFO Empty Wait Time (max)  :");
   292      for (i = 0; i < initialized_serial_devices; i++)
   293          CLI_PRINT(" %8d uSec",
   294                    serial_devices[i].wait_for_tx_fifo_empty_max *
   295                    serial_tx_stall_usec);
   296  
   297      CLI_PRINT("\nTx FIFO Empty Wait Time (avg)  :");
   298      for (i = 0; i < initialized_serial_devices; i++)
   299          CLI_PRINT(" %8d uSec",
   300                    (serial_devices[i].wait_for_tx_fifo_empty_avg >> 16) *
   301                    serial_tx_stall_usec);
   302  
   303      CLI_PRINT("\nTx H/S Mode                    :");
   304      for (i = 0; i < initialized_serial_devices; i++) {
   305          switch (serial_devices[i].handshake_mode) {
   306              case UART_HANDSHAKE_AUTO:
   307                  if (serial_devices[i].hw_handshake_stopped_count <
   308                                             hw_handshake_stopped_limit) {
   309                      CLI_PRINT("     Auto-H/W ");
   310                  }
   311                  else {
   312                      CLI_PRINT("     Auto-None");
   313                  }
   314                  break;
   315  
   316              caseUART_HANDSHAKE_HW:
   317                  CLI_PRINT("      H/W     ");
   318                  break;
   319  
   320              case UART_HANDSHAKE_NONE:
   321                  CLI_PRINT("     None     ");
   322                  break;
   323  
   324              default:
   325                  CLI_PRINT(" ?????????????");
   326          }
   327      }
   328  
   329      CLI_PRINT("\nTx H/S Stopped Chars           :");
   330      for (i = 0; i < initialized_serial_devices; i++)
   331          CLI_PRINT(" %8d     ",
   332                    serial_devices[i].num_chars_hw_handshake_stopped);
   333  
   334      CLI_PRINT("\nTx H/S Auto-Go Chars           :");
   335      for (i = 0; i < initialized_serial_devices; i++)
   336          CLI_PRINT(" %8d     ",
   337                    serial_devices[i].num_chars_hw_handshake_auto_go);
   338  
   339      CLI_PRINT("\nTx H/S Stopped Time (max)      :");
   340      for (i = 0; i < initialized_serial_devices; i++)
   341          CLI_PRINT(" %8d mSec",
   342                    serial_devices[i].hw_handshake_stopped_count_max *
   343                    serial_tx_stall_usec /
   344                    1000);
   345  
   346      CLI_PRINT("\nTx H/S Stopped Time (avg)      :");
   347      for (i = 0; i < initialized_serial_devices; i++)
   348          CLI_PRINT(" %8d mSec",
   349                    (serial_devices[i].hw_handshake_stopped_count_avg >> 16) *
   350                    serial_tx_stall_usec /
   351                    1000);
   352  
   353      CLI_PRINT("\nString Tx inter. by putc_nolock:");
   354      for (i = 0; i < initialized_serial_devices; i++)
   355          CLI_PRINT(" %8d     ",
   356                    serial_devices[i].num_puts_interrupted_by_putc_nolock);
   357  
   358      CLI_PRINT("\nString Tx inter. by puts_nolock:");
   359      for (i = 0; i < initialized_serial_devices; i++)
   360          CLI_PRINT(" %8d     ",
   361                    serial_devices[i].num_puts_interrupted_by_puts_nolock);
   362  
   363      CLI_PRINT("\nChars Tx blocked by puts_nolock:");
   364      for (i = 0; i < initialized_serial_devices; i++)
   365          CLI_PRINT(" %8d     ",
   366                    serial_devices[i].num_putc_blocked_by_puts_nolock);
   367  
   368      CLI_PRINT("\n");
   369  
   370      return 0;
   371  }
   372  #pragma warning(pop)
   373  #endif //DEBUG
   374  
   375  // Initialize a new serial device's parameters
   376  void *  vmm_serial_new( UINT16 io_base,        // In:  I/O Base Address
   377      UART_PROG_IF_TYPE   prog_if,        // In:  Programming interface
   378      UART_HANDSHAKE_MODE handshake_mode  // In:  Handshake mode
   379  )
   380  
   381  {
   382      VMM_SERIAL_DEVICE *p_device;
   383  
   384      if (initialized_serial_devices >= VMM_SERIAL_DEVICES_MAX)
   385          return NULL;
   386  
   387      p_device = &serial_devices[initialized_serial_devices++];
   388  
   389      p_device->io_base = io_base;
   390      p_device->prog_if = prog_if;
   391      switch (prog_if)
   392      {
   393          case UART_PROG_IF_GENERIC:
   394          case UART_PROG_IF_16450  :
   395              p_device->hw_fifo_size = 1;
   396              break;
   397  
   398          case UART_PROG_IF_16550  :
   399          case UART_PROG_IF_16650  :
   400          case UART_PROG_IF_16750  :
   401          case UART_PROG_IF_16850  :
   402          case UART_PROG_IF_16950  :
   403              p_device->hw_fifo_size = 16;   // TODO: correct sizes
   404              break;
   405  
   406          default:
   407              return NULL;
   408      };
   409      p_device->chars_in_tx_fifo = p_device->hw_fifo_size;
   410                                      // This forces polling of the transmit
   411                                      // empty status bit
   412      p_device->handshake_mode = handshake_mode;
   413  
   414      p_device->num_tx_chars_lock = 0;
   415      p_device->num_tx_chars_nolock = 0;
   416      p_device->num_rx_chars = 0;
   417  
   418      p_device->wait_for_tx_ready_max = 0;
   419      p_device->wait_for_tx_ready_avg = 0;
   420      p_device->wait_for_tx_fifo_empty_max = 0;
   421      p_device->wait_for_tx_fifo_empty_avg = 0;
   422  
   423      p_device->puts_lock = FALSE;
   424      p_device->in_putc = FALSE;
   425      p_device->in_puts = FALSE;
   426      p_device->num_puts_interrupted_by_putc_nolock = 0;
   427      p_device->num_puts_interrupted_by_puts_nolock = 0;
   428      p_device->num_putc_blocked_by_puts_nolock = 0;
   429  
   430      p_device->num_chars_hw_handshake_stopped = 0;
   431      p_device->num_chars_hw_handshake_auto_go = 0;
   432      p_device->hw_handshake_stopped_count = 0;
   433      p_device->hw_handshake_stopped_count_max = 0;
   434      p_device->hw_handshake_stopped_count_avg = 0;
   435  
   436      p_device->is_initialized = FALSE;
   437  
   438      return p_device;
   439  }
   440  
   441  
   442  // Initialize a serial device
   443  
   444  void vmm_serial_init(void   *h_device)   // In:  Handle of the device
   445  {
   446      VMM_SERIAL_DEVICE *p_device;
   447      UART_IER           ier;
   448      UART_FCR           fcr;
   449      UART_LCR           lcr;
   450      UART_MCR           mcr;
   451  
   452      p_device = h_device;
   453      VMM_ASSERT(p_device);
   454      VMM_ASSERT(! p_device->is_initialized);
   455  
   456      // MCR: Reset DTR, RTS, Out1, Out2 & Loop
   457      mcr.bits.DTRC     = 0;
   458      mcr.bits.RTS      = 0;
   459      mcr.bits.OUT1     = 0;
   460      mcr.bits.OUT2     = 0;
   461      mcr.bits.LME      = 0;
   462      mcr.bits.Reserved = 0;
   463      hw_write_port_8(p_device->io_base + UART_REGISTER_MCR, mcr.data);
   464  
   465      // LCR: Reset DLAB
   466      lcr.bits.SERIALDB   = 0x03;   // 8 data bits
   467      lcr.bits.STOPB      = 0;      // 1 stop bit
   468      lcr.bits.PAREN      = 0;      // No parity
   469      lcr.bits.EVENPAR    = 0;      // N/A
   470      lcr.bits.STICPAR    = 0;      // N/A
   471      lcr.bits.BRCON      = 0;      // No break
   472      lcr.bits.DLAB       = 0;
   473      hw_write_port_8(p_device->io_base + UART_REGISTER_LCR, lcr.data);
   474  
   475      // IER: Disable interrupts
   476      ier.bits.RAVIE    = 0;
   477      ier.bits.THEIE    = 0;
   478      ier.bits.RIE      = 0;
   479      ier.bits.MIE      = 0;
   480      ier.bits.Reserved = 0;
   481      hw_write_port_8(p_device->io_base + UART_REGISTER_IER, ier.data);
   482  
   483      // FCR: Disable FIFOs
   484      fcr.bits.TRFIFOE  = 0;
   485      fcr.bits.RESETRF  = 0;
   486      fcr.bits.RESETTF  = 0;
   487      fcr.bits.DMS      = 0;
   488      fcr.bits.Reserved = 0;
   489      fcr.bits.RTB      = 0;
   490      hw_write_port_8(p_device->io_base + UART_REGISTER_FCR, fcr.data);
   491  
   492      // SCR: Scratch register
   493      hw_write_port_8(p_device->io_base + UART_REGISTER_SCR, 0x00);
   494  
   495      // LCR: Set DLAB
   496      lcr.bits.DLAB = 1;
   497      hw_write_port_8(p_device->io_base + UART_REGISTER_LCR, lcr.data);
   498  
   499      // DLL & DLM: Divisor value 1 for 115200 baud
   500      hw_write_port_8(p_device->io_base + UART_REGISTER_DLL, 0x01);
   501      hw_write_port_8(p_device->io_base + UART_REGISTER_DLM, 0x00);
   502  
   503      // LCR: Reset DLAB
   504      lcr.bits.DLAB = 0;
   505      hw_write_port_8(p_device->io_base + UART_REGISTER_LCR, lcr.data);
   506  
   507      // FCR: Enable and reset Rx & Tx FIFOs
   508      fcr.bits.TRFIFOE  = 1;
   509      fcr.bits.RESETRF  = 1;
   510      fcr.bits.RESETTF  = 1;
   511      hw_write_port_8(p_device->io_base + UART_REGISTER_FCR, fcr.data);
   512  
   513      // MCR: Set DTR, RTS
   514      mcr.bits.DTRC     = 1;
   515      mcr.bits.RTS      = 1;
   516      hw_write_port_8(p_device->io_base + UART_REGISTER_MCR, mcr.data);
   517  
   518      p_device->is_initialized = TRUE;
   519  }
   520  
   521  void vmm_serial_reset(void *h_device)
   522  {
   523      VMM_SERIAL_DEVICE *p_device;
   524  
   525      p_device = h_device;
   526      p_device->is_initialized = FALSE;
   527  }
   528  
   529  // Returns the I/O range occupied by the device
   530  void vmm_serial_get_io_range(void   *h_device,   // In:  Handle of the device
   531                          UINT16 *p_io_base,  // Out: Base of I/O range
   532                          UINT16 *p_io_end)   // Out: End of I/O range
   533  
   534  {
   535      VMM_SERIAL_DEVICE *p_device;
   536  
   537      p_device = h_device;
   538      *p_io_base = p_device->io_base;
   539      *p_io_end = p_device->io_base + 7;
   540  }
   541  
   542  // Write a single character to a serial device in a non-locked mode.
   543  // This function is reentrant, and can be safely called even while the normal
   544  // vmm_serial_putc() runs.  However, it is not optimized for performance and
   545  // should only be used when necessary, e.g., from an exception handler.
   546  
   547  char vmm_serial_putc_nolock(void *h_device,   // In:  Handle of the device
   548                         char  c)          // In:  Character to send
   549  {
   550      VMM_SERIAL_DEVICE *p_device;
   551      UART_LSR           lsr;   // Line Status Register image
   552      BOOLEAN            is_ready;
   553                                // The Tx FIFO is empty and hw handshake is "go"
   554      UINT32             num_wait_for_tx_ready;
   555  
   556      p_device = h_device;
   557  
   558      VMM_ASSERT(p_device->is_initialized);
   559  
   560      if (p_device->in_puts)
   561          p_device->num_puts_interrupted_by_putc_nolock++;
   562  
   563      // Another instance of the vmm_serial_putc*() functions can be running in
   564      // parallel (e.g., on another h/w thread).  We rely on the Tx FIFO to
   565      // be deed enough absorb the writes (and hope for the best...).  Thus, we
   566      // first loop until the Tx FIFO is empty and h/w handshake is OK
   567      // (if applicable)
   568  
   569      num_wait_for_tx_ready = 0;
   570      do {
   571          lsr.data = hw_read_port_8(p_device->io_base + UART_REGISTER_LSR);
   572          is_ready = (lsr.bits.THRE == 1) && is_hw_tx_handshake_go(p_device);
   573          if (! is_ready) {
   574              hw_stall_using_tsc(serial_tx_stall_usec);
   575              num_wait_for_tx_ready++;
   576          }
   577      } while (! is_ready);
   578  
   579      update_max_and_avg(&p_device->wait_for_tx_fifo_empty_max,
   580                         &p_device->wait_for_tx_fifo_empty_avg,
   581                         num_wait_for_tx_ready);
   582      update_max_and_avg(&p_device->wait_for_tx_ready_max,
   583                         &p_device->wait_for_tx_ready_avg,
   584                         num_wait_for_tx_ready);
   585  
   586      // Now write the output character
   587      hw_write_port_8(p_device->io_base + UART_REGISTER_THR, c);
   588  
   589      // Update the statistics
   590      p_device->num_tx_chars_nolock++;
   591  
   592      // Loop again until the Tx FIFO is empty and h/w handshake is OK
   593      // (if applicable).  This is done so normal vmm_serial_putc() that we may
   594      // have interrupted can safely resume.
   595  
   596      num_wait_for_tx_ready = 0;
   597      do {
   598          lsr.data = hw_read_port_8(p_device->io_base + UART_REGISTER_LSR);
   599          is_ready = is_hw_tx_handshake_go(p_device) && (lsr.bits.THRE == 1);
   600          if (! is_ready) {
   601              hw_stall_using_tsc(serial_tx_stall_usec);
   602              num_wait_for_tx_ready++;
   603          }
   604      } while (! is_ready);
   605  
   606      update_max_and_avg(&p_device->wait_for_tx_fifo_empty_max,
   607                         &p_device->wait_for_tx_fifo_empty_avg, num_wait_for_tx_ready);
   608      update_max_and_avg(&p_device->wait_for_tx_ready_max,
   609                         &p_device->wait_for_tx_ready_avg,
   610                         num_wait_for_tx_ready);
   611  
   612      // Note that we do NOT update chars_in_tx_fifo to be 0.  This allows
   613      // parallel putc's that will be absorbed by the FIFO.
   614  
   615      return c;
   616  }
   617  
   618  
   619  // Write a single character to a serial device.
   620  // This function is not reentrant, and is for use in the normal case, where the
   621  // serial device has been previously locked.  It may be interrupted by
   622  // vmm_serial_putc_nolock().  The function attempts to use the full depth of
   623  // the UART's transmit FIFO to avoid busy loops.
   624  char vmm_serial_putc(void *h_device,   // In:  Handle of the device
   625                  char  c)          // In:  Character to send
   626  {
   627      VMM_SERIAL_DEVICE *p_device;
   628      UART_LSR           lsr;   // Line Status Register image
   629      BOOLEAN            is_ready;
   630                                // The Tx FIFO is not full and hw handshake is "go"
   631      BOOLEAN            locked_out = FALSE;
   632                                // Indicate that the function was locked out at
   633                                // least once by puts_lock
   634      UINT32             num_wait_for_tx_ready;
   635      UINT32             num_wait_for_tx_fifo_empty;
   636  
   637      p_device = h_device;
   638      VMM_ASSERT(p_device->is_initialized);
   639  
   640      // Loop until there's room in the Tx FIFO, h/w handshake is OK
   641      // (if applicable), and there is no lock by vmm_serial_puts_nolock().
   642      num_wait_for_tx_ready = 0;
   643      num_wait_for_tx_fifo_empty = 0;
   644  
   645      do {
   646          lsr.data = hw_read_port_8(p_device->io_base + UART_REGISTER_LSR);
   647          if (lsr.bits.THRE == 1)        // The Tx FIFO is empty
   648              p_device->chars_in_tx_fifo = 0;
   649          is_ready = is_hw_tx_handshake_go(p_device);
   650          if (is_ready) {
   651              if (p_device->chars_in_tx_fifo >= p_device->hw_fifo_size) {
   652                  is_ready = FALSE;
   653                  num_wait_for_tx_fifo_empty++;
   654              }
   655          }
   656          if (is_ready && p_device->puts_lock) {
   657              // There's an on going string print by vmm_serial_puts_nolock()
   658              is_ready = FALSE;
   659              locked_out = TRUE;
   660          }
   661          if (! is_ready) {
   662              hw_stall_using_tsc(serial_tx_stall_usec);
   663              num_wait_for_tx_ready++;
   664          }
   665      } while (! is_ready);
   666  
   667      update_max_and_avg(&p_device->wait_for_tx_ready_max,
   668                         &p_device->wait_for_tx_ready_avg, num_wait_for_tx_ready);
   669      update_max_and_avg(&p_device->wait_for_tx_fifo_empty_max,
   670                         &p_device->wait_for_tx_fifo_empty_avg, num_wait_for_tx_fifo_empty);
   671  
   672      // Now write the output character
   673      hw_write_port_8(p_device->io_base + UART_REGISTER_THR, c);
   674      p_device->chars_in_tx_fifo++;
   675  
   676      // Update the statistics
   677      p_device->num_tx_chars_lock++;
   678      if (locked_out)
   679          p_device->num_putc_blocked_by_puts_nolock++;
   680      return c;
   681  }
   682  
   683  
   684  // Write a string to a serial device in a non-locked mode.
   685  // This function is reentrant, and can be safely called even while the normal
   686  // vmm_serial_putc() runs.  However, it should be used only when necessary,
   687  // e.g. from an exception handler.
   688  int vmm_serial_puts_nolock(void       *h_device,   // In:  Handle of the device
   689                             const char  string[])   // In:  String to send
   690  {
   691      VMM_SERIAL_DEVICE *p_device;
   692      UINT32             i;
   693  
   694      p_device = h_device;
   695      p_device->puts_lock = TRUE;   // Block the normal putc()
   696                                    // Not reliable in case this function is
   697                                    // called by two h/w threads in parallel, but
   698                                    // the impact is not fatal
   699      if (p_device->in_puts)
   700          p_device->num_puts_interrupted_by_puts_nolock++;
   701      for (i = 0; string[i] != 0; i++)
   702          vmm_serial_putc_nolock(h_device, string[i]);
   703      p_device->puts_lock = FALSE;   // Unblock the normal putc()
   704      return 1;   // return any nonnegative value
   705  }
   706  
   707  
   708  // Write a string to a serial device
   709  // This function is not reentrant, and is for use in the normal case, where the
   710  // serial device has been previously locked.  It may be interrupted by
   711  // vmm_serial_put*_nolock().
   712  int vmm_serial_puts(void       *h_device,   // In:  Handle of the device
   713                  const char  string[])   // In:  String to send
   714  {
   715      VMM_SERIAL_DEVICE *p_device;
   716      UINT32 i;
   717  
   718      p_device = h_device;
   719      for (i = 0; string[i] != 0; i++) {
   720          vmm_serial_putc(h_device, string[i]);
   721          p_device->in_puts = TRUE;
   722      }
   723      p_device->in_puts = FALSE;
   724      return 1;   // return any nonnegative value
   725  }
   726  
   727  
   728  // Poll the serial device and read a single character if ready.
   729  // This function is not reentrant.  Calling it while it runs in another thread
   730  // may result in a junk character returned, but the s/w will not crash.
   731  
   732  char vmm_serial_getc(void *h_device)   // In:  Handle of the device
   733  
   734  {
   735      VMM_SERIAL_DEVICE *p_device;
   736      UART_LSR           lsr;
   737      char               c;
   738  
   739      p_device = h_device;
   740      VMM_ASSERT(p_device->is_initialized);
   741      lsr.data = hw_read_port_8(p_device->io_base + UART_REGISTER_LSR);
   742      if (lsr.bits.DR)  {
   743          c = hw_read_port_8(p_device->io_base + UART_REGISTER_RBR);
   744          p_device->num_rx_chars++;
   745      }
   746      else
   747          c = 0;
   748      return c;
   749  }
   750  
   751  
   752  // Initialize CLI command(s) for serial ports
   753  void vmm_serial_cli_init(void)
   754  {
   755  #ifdef DEBUG
   756      CLI_AddCommand(cli_display_serial_info, "debug serial info",
   757                     "Print serial ports information", "", CLI_ACCESS_LEVEL_SYSTEM);
   758  #endif
   759  }
   760