Home | History | Annotate | Download | only in Pei
      1 /** @file
      2 Serial conole output and string formating.
      3 
      4 Copyright (c) 2013-2015 Intel Corporation.
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 #include "memory_options.h"
     16 #include "general_definitions.h"
     17 
     18 // Resource programmed to PCI bridge, 1MB bound alignment is needed.
     19 // The default value is overwritten by MRC parameter, assuming code
     20 // relocated to eSRAM.
     21 uint32_t UartMmioBase = 0;
     22 
     23 // Serial port registers based on SerialPortLib.c
     24 #define R_UART_BAUD_THR       0
     25 #define R_UART_LSR            20
     26 
     27 #define   B_UART_LSR_RXRDY    BIT0
     28 #define   B_UART_LSR_TXRDY    BIT5
     29 #define   B_UART_LSR_TEMT     BIT6
     30 
     31 // Print mask see DPF and D_Xxxx
     32 #define DPF_MASK  DpfPrintMask
     33 
     34 // Select class of messages enabled for printing
     35 uint32_t DpfPrintMask =
     36     D_ERROR |
     37     D_INFO |
     38     // D_REGRD |
     39     // D_REGWR |
     40     // D_FCALL |
     41     // D_TRN |
     42     0;
     43 
     44 #ifdef NDEBUG
     45 // Don't generate debug code
     46 void dpf( uint32_t mask, char_t* bla, ...)
     47 {
     48   return;
     49 }
     50 
     51 uint8_t mgetc(void)
     52 {
     53   return 0;
     54 }
     55 
     56 uint8_t mgetch(void)
     57 {
     58   return 0;
     59 }
     60 
     61 #else
     62 
     63 #ifdef SIM
     64 // Use Vpi console in simulation environment
     65 #include <vpi_user.h>
     66 
     67 void dpf( uint32_t mask, char_t* bla, ...)
     68 {
     69   va_list va;
     70 
     71   if( 0 == (mask & DPF_MASK)) return;
     72 
     73   va_start( va, bla);
     74   vpi_vprintf( bla, va);
     75   va_end(va);
     76 }
     77 
     78 #else
     79 
     80 #ifdef EMU
     81 // Use standard console in windows environment
     82 #include <stdio.h>
     83 #endif
     84 
     85 // Read character from serial port
     86 uint8_t mgetc(void)
     87 {
     88 #ifdef EMU
     89 
     90   // Emulation in Windows environment uses console
     91   getchar();
     92 
     93 #else
     94   uint8_t c;
     95 
     96   while ((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) == 0);
     97   c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
     98 
     99   return c;
    100 #endif
    101 }
    102 
    103 
    104 uint8_t mgetch(void)
    105 {
    106 #ifdef EMU
    107   return 0;
    108 #else
    109   uint8_t c = 0;
    110 
    111   if((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) != 0)
    112   {
    113     c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
    114   }
    115 
    116   return c;
    117 #endif
    118 }
    119 
    120 // Print single character
    121 static void printc(
    122     uint8_t c)
    123 {
    124 #ifdef EMU
    125 
    126   // Emulation in Windows environment uses console output
    127   putchar(c);
    128 
    129 #else
    130 
    131   //
    132   // Use MMIO access to serial port on PCI
    133   //   while( 0 == (0x20 & inp(0x3f8 + 5)));
    134   //   outp(0x3f8 + 0, c);
    135   //
    136   while (0
    137       == (B_UART_LSR_TEMT & *((volatile uint8_t*) (UartMmioBase + R_UART_LSR))))
    138     ;
    139   *((volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR)) = c;
    140 #endif
    141 }
    142 
    143 // Print 0 terminated string on serial console
    144 static void printstr(
    145     char_t *str)
    146 {
    147   while (*str)
    148   {
    149     printc(*str++);
    150   }
    151 }
    152 // Print 64bit number as hex string on serial console
    153 // the width parameters allows skipping leading zeros
    154 static void printhexx(
    155     uint64_t val,
    156     uint32_t width)
    157 {
    158   uint32_t i;
    159   uint8_t c;
    160   uint8_t empty = 1;
    161 
    162   // 64bit number has 16 characters in hex representation
    163   for (i = 16; i > 0; i--)
    164   {
    165     c = *(((uint8_t *)&val) + ((i - 1) >> 1));
    166     if (((i - 1) & 1) != 0)
    167       c = c >> 4;
    168     c = c & 0x0F;
    169 
    170     if (c > 9)
    171       c += 'A' - 10;
    172     else
    173       c += '0';
    174 
    175     if (c != '0')
    176     {
    177       // end of leading zeros
    178       empty = 0;
    179     }
    180 
    181     // don't print leading zero
    182     if (!empty || i <= width)
    183     {
    184       printc(c);
    185     }
    186   }
    187 }
    188 // Print 32bit number as hex string on serial console
    189 // the width parameters allows skipping leading zeros
    190 static void printhex(
    191     uint32_t val,
    192     uint32_t width)
    193 {
    194   uint32_t i;
    195   uint8_t c;
    196   uint8_t empty = 1;
    197 
    198   // 32bit number has 8 characters in hex representation
    199   for (i = 8; i > 0; i--)
    200   {
    201     c = (uint8_t) ((val >> 28) & 0x0F);
    202     if (c > 9)
    203       c += 'A' - 10;
    204     else
    205       c += '0';
    206 
    207     val = val << 4;
    208 
    209     if (c != '0')
    210     {
    211       // end of leading zeros
    212       empty = 0;
    213     }
    214 
    215     // don't print leading zero
    216     if (!empty || i <= width)
    217     {
    218       printc(c);
    219     }
    220   }
    221 }
    222 // Print 32bit number as decimal string on serial console
    223 // the width parameters allows skipping leading zeros
    224 static void printdec(
    225     uint32_t val,
    226     uint32_t width)
    227 {
    228   uint32_t i;
    229   uint8_t c = 0;
    230   uint8_t empty = 1;
    231 
    232   // Ten digits is enough for 32bit number in decimal
    233   uint8_t buf[10];
    234 
    235   for (i = 0; i < sizeof(buf); i++)
    236   {
    237     c = (uint8_t) (val % 10);
    238     buf[i] = c + '0';
    239     val = val / 10;
    240   }
    241 
    242   while (i > 0)
    243   {
    244     c = buf[--i];
    245 
    246     if (c != '0')
    247     {
    248       // end of leading zeros
    249       empty = 0;
    250     }
    251 
    252     // don't print leading zero
    253     if (!empty || i < width)
    254     {
    255       printc(c);
    256     }
    257   }
    258 }
    259 
    260 // Consume numeric substring leading the given string
    261 // Return pointer to the first non-numeric character
    262 // Buffer reference by width is updated with number
    263 // converted from the numeric substring.
    264 static char_t *getwidth(
    265     char_t *bla,
    266     uint32_t *width)
    267 {
    268   uint32_t val = 0;
    269 
    270   while (*bla >= '0' && *bla <= '9')
    271   {
    272     val = val * 10 + *bla - '0';
    273     bla += 1;
    274   }
    275 
    276   if (val > 0)
    277   {
    278     *width = val;
    279   }
    280   return bla;
    281 }
    282 
    283 // Consume print format designator from the head of given string
    284 // Return pointer to first character after format designator
    285 // input fmt
    286 // ----- ---
    287 //  s   -> s
    288 //  d   -> d
    289 //  X   -> X
    290 //  llX -> L
    291 static char_t *getformat(
    292     char_t *bla,
    293     uint8_t *fmt)
    294 {
    295   if (bla[0] == 's')
    296   {
    297     bla += 1;
    298     *fmt = 's';
    299   }
    300   else if (bla[0] == 'd')
    301   {
    302     bla += 1;
    303     *fmt = 'd';
    304   }
    305   else if (bla[0] == 'X' || bla[0] == 'x')
    306   {
    307     bla += 1;
    308     *fmt = 'X';
    309   }
    310   else if (bla[0] == 'l' && bla[1] == 'l' && bla[2] == 'X')
    311   {
    312     bla += 3;
    313     *fmt = 'L';
    314   }
    315 
    316   return bla;
    317 }
    318 
    319 // Simplified implementation of standard printf function
    320 // The output is directed to serial console. Only selected
    321 // class of messages is printed (mask has to match DpfPrintMask)
    322 // Supported print formats: %[n]s,%[n]d,%[n]X,,%[n]llX
    323 // The width is ignored for %s format.
    324 void dpf(
    325     uint32_t mask,
    326     char_t* bla,
    327     ...)
    328 {
    329   uint32_t* arg = (uint32_t*) (&bla + 1);
    330 
    331   // Check UART MMIO base configured
    332   if (0 == UartMmioBase)
    333     return;
    334 
    335   // Check event not masked
    336   if (0 == (mask & DPF_MASK))
    337     return;
    338 
    339   for (;;)
    340   {
    341     uint8_t x = *bla++;
    342     if (x == 0)
    343       break;
    344 
    345     if (x == '\n')
    346     {
    347       printc('\r');
    348       printc('\n');
    349     }
    350     else if (x == '%')
    351     {
    352       uint8_t fmt = 0;
    353       uint32_t width = 1;
    354 
    355       bla = getwidth(bla, &width);
    356       bla = getformat(bla, &fmt);
    357 
    358       // Print value
    359       if (fmt == 'd')
    360       {
    361         printdec(*arg, width);
    362         arg += 1;
    363       }
    364       else if (fmt == 'X')
    365       {
    366         printhex(*arg, width);
    367         arg += 1;
    368       }
    369       else if (fmt == 'L')
    370       {
    371         printhexx(*(uint64_t*) arg, width);
    372         arg += 2;
    373       }
    374       else if (fmt == 's')
    375       {
    376         printstr(*(char**) arg);
    377         arg += 1;
    378       }
    379     }
    380     else
    381     {
    382       printc(x);
    383     }
    384   }
    385 }
    386 
    387 #endif  //SIM
    388 #endif  //NDEBUG
    389