audk/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c

383 lines
7.0 KiB
C

/** @file
Serial conole output and string formating.
Copyright (c) 2013-2015 Intel Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "memory_options.h"
#include "general_definitions.h"
// Resource programmed to PCI bridge, 1MB bound alignment is needed.
// The default value is overwritten by MRC parameter, assuming code
// relocated to eSRAM.
uint32_t UartMmioBase = 0;
// Serial port registers based on SerialPortLib.c
#define R_UART_BAUD_THR 0
#define R_UART_LSR 20
#define B_UART_LSR_RXRDY BIT0
#define B_UART_LSR_TXRDY BIT5
#define B_UART_LSR_TEMT BIT6
// Print mask see DPF and D_Xxxx
#define DPF_MASK DpfPrintMask
// Select class of messages enabled for printing
uint32_t DpfPrintMask =
D_ERROR |
D_INFO |
// D_REGRD |
// D_REGWR |
// D_FCALL |
// D_TRN |
0;
#ifdef NDEBUG
// Don't generate debug code
void dpf( uint32_t mask, char_t* bla, ...)
{
return;
}
uint8_t mgetc(void)
{
return 0;
}
uint8_t mgetch(void)
{
return 0;
}
#else
#ifdef SIM
// Use Vpi console in simulation environment
#include <vpi_user.h>
void dpf( uint32_t mask, char_t* bla, ...)
{
va_list va;
if( 0 == (mask & DPF_MASK)) return;
va_start( va, bla);
vpi_vprintf( bla, va);
va_end(va);
}
#else
#ifdef EMU
// Use standard console in windows environment
#include <stdio.h>
#endif
// Read character from serial port
uint8_t mgetc(void)
{
#ifdef EMU
// Emulation in Windows environment uses console
getchar();
#else
uint8_t c;
while ((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) == 0);
c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
return c;
#endif
}
uint8_t mgetch(void)
{
#ifdef EMU
return 0;
#else
uint8_t c = 0;
if((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) != 0)
{
c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
}
return c;
#endif
}
// Print single character
static void printc(
uint8_t c)
{
#ifdef EMU
// Emulation in Windows environment uses console output
putchar(c);
#else
//
// Use MMIO access to serial port on PCI
// while( 0 == (0x20 & inp(0x3f8 + 5)));
// outp(0x3f8 + 0, c);
//
while (0
== (B_UART_LSR_TEMT & *((volatile uint8_t*) (UartMmioBase + R_UART_LSR))))
;
*((volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR)) = c;
#endif
}
// Print 0 terminated string on serial console
static void printstr(
char_t *str)
{
while (*str)
{
printc(*str++);
}
}
// Print 64bit number as hex string on serial console
// the width parameters allows skipping leading zeros
static void printhexx(
uint64_t val,
uint32_t width)
{
uint32_t i;
uint8_t c;
uint8_t empty = 1;
// 64bit number has 16 characters in hex representation
for (i = 16; i > 0; i--)
{
c = *(((uint8_t *)&val) + ((i - 1) >> 1));
if (((i - 1) & 1) != 0)
c = c >> 4;
c = c & 0x0F;
if (c > 9)
c += 'A' - 10;
else
c += '0';
if (c != '0')
{
// end of leading zeros
empty = 0;
}
// don't print leading zero
if (!empty || i <= width)
{
printc(c);
}
}
}
// Print 32bit number as hex string on serial console
// the width parameters allows skipping leading zeros
static void printhex(
uint32_t val,
uint32_t width)
{
uint32_t i;
uint8_t c;
uint8_t empty = 1;
// 32bit number has 8 characters in hex representation
for (i = 8; i > 0; i--)
{
c = (uint8_t) ((val >> 28) & 0x0F);
if (c > 9)
c += 'A' - 10;
else
c += '0';
val = val << 4;
if (c != '0')
{
// end of leading zeros
empty = 0;
}
// don't print leading zero
if (!empty || i <= width)
{
printc(c);
}
}
}
// Print 32bit number as decimal string on serial console
// the width parameters allows skipping leading zeros
static void printdec(
uint32_t val,
uint32_t width)
{
uint32_t i;
uint8_t c = 0;
uint8_t empty = 1;
// Ten digits is enough for 32bit number in decimal
uint8_t buf[10];
for (i = 0; i < sizeof(buf); i++)
{
c = (uint8_t) (val % 10);
buf[i] = c + '0';
val = val / 10;
}
while (i > 0)
{
c = buf[--i];
if (c != '0')
{
// end of leading zeros
empty = 0;
}
// don't print leading zero
if (!empty || i < width)
{
printc(c);
}
}
}
// Consume numeric substring leading the given string
// Return pointer to the first non-numeric character
// Buffer reference by width is updated with number
// converted from the numeric substring.
static char_t *getwidth(
char_t *bla,
uint32_t *width)
{
uint32_t val = 0;
while (*bla >= '0' && *bla <= '9')
{
val = val * 10 + *bla - '0';
bla += 1;
}
if (val > 0)
{
*width = val;
}
return bla;
}
// Consume print format designator from the head of given string
// Return pointer to first character after format designator
// input fmt
// ----- ---
// s -> s
// d -> d
// X -> X
// llX -> L
static char_t *getformat(
char_t *bla,
uint8_t *fmt)
{
if (bla[0] == 's')
{
bla += 1;
*fmt = 's';
}
else if (bla[0] == 'd')
{
bla += 1;
*fmt = 'd';
}
else if (bla[0] == 'X' || bla[0] == 'x')
{
bla += 1;
*fmt = 'X';
}
else if (bla[0] == 'l' && bla[1] == 'l' && bla[2] == 'X')
{
bla += 3;
*fmt = 'L';
}
return bla;
}
// Simplified implementation of standard printf function
// The output is directed to serial console. Only selected
// class of messages is printed (mask has to match DpfPrintMask)
// Supported print formats: %[n]s,%[n]d,%[n]X,,%[n]llX
// The width is ignored for %s format.
void dpf(
uint32_t mask,
char_t* bla,
...)
{
uint32_t* arg = (uint32_t*) (&bla + 1);
// Check UART MMIO base configured
if (0 == UartMmioBase)
return;
// Check event not masked
if (0 == (mask & DPF_MASK))
return;
for (;;)
{
uint8_t x = *bla++;
if (x == 0)
break;
if (x == '\n')
{
printc('\r');
printc('\n');
}
else if (x == '%')
{
uint8_t fmt = 0;
uint32_t width = 1;
bla = getwidth(bla, &width);
bla = getformat(bla, &fmt);
// Print value
if (fmt == 'd')
{
printdec(*arg, width);
arg += 1;
}
else if (fmt == 'X')
{
printhex(*arg, width);
arg += 1;
}
else if (fmt == 'L')
{
printhexx(*(uint64_t*) arg, width);
arg += 2;
}
else if (fmt == 's')
{
printstr(*(char**) arg);
arg += 1;
}
}
else
{
printc(x);
}
}
}
#endif //SIM
#endif //NDEBUG