Software APIs
dbg_print.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/silicon_creator/lib/dbg_print.h"
6 
7 #include <assert.h>
8 #include <stdarg.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 
13 #include "sw/device/lib/base/csr.h"
14 #include "sw/device/silicon_creator/lib/drivers/uart.h"
15 #include "sw/device/silicon_creator/lib/epmp_defs.h"
16 
17 static const char kHexTable[16] = "0123456789abcdef";
18 
19 static void print_integer(unsigned value, bool is_signed) {
20  char buf[12];
21  char *b = buf + sizeof(buf);
22  if (is_signed && (int)value < 0) {
23  uart_putchar('-');
24  value = (unsigned)(-(int)value);
25  }
26  *--b = '\0';
27  do {
28  *--b = '0' + value % 10;
29  value /= 10;
30  } while (value);
31  while (*b) {
32  uart_putchar(*b++);
33  }
34 }
35 
36 void dbg_puts(const char *str) {
37  while (*str) {
38  uart_putchar(*str++);
39  }
40 }
41 
42 void dbg_printf(const char *format, ...) {
43  va_list args;
44  va_start(args, format);
45 
46  for (; *format != '\0'; ++format) {
47  if (*format != '%') {
48  uart_putchar(*format);
49  continue;
50  }
51 
52  ++format; // Skip over the '%'.
53  switch (*format) {
54  case '%':
55  uart_putchar(*format);
56  break;
57  case 'c': {
58  int ch = va_arg(args, int);
59  uart_putchar((char)ch);
60  break;
61  }
62  case 'C': {
63  uint32_t val = va_arg(args, uint32_t);
64  for (size_t i = 0; i < sizeof(uint32_t); ++i, val >>= 8) {
65  uint8_t ch = (uint8_t)val;
66  if (ch >= 32 && ch < 127) {
67  uart_putchar((char)ch);
68  } else {
69  uart_putchar('\\');
70  uart_putchar('x');
71  uart_putchar(kHexTable[ch >> 4]);
72  uart_putchar(kHexTable[ch & 15]);
73  }
74  }
75  break;
76  }
77  case 's': {
78  // Print a null-terminated string.
79  const char *str = va_arg(args, const char *);
80  while (*str != '\0') {
81  uart_putchar(*str++);
82  }
83  break;
84  }
85  case 'd':
86  // `print_integer` will handle the sign bit of the value.
87  print_integer(va_arg(args, unsigned), true);
88  break;
89  case 'u':
90  print_integer(va_arg(args, unsigned), false);
91  break;
92  case 'p':
94  case 'x': {
95  // Print an `unsigned int` in hexadecimal.
96  unsigned int v = va_arg(args, unsigned int);
97  for (int i = 0; i < sizeof(v) * 2; ++i) {
98  int shift = sizeof(v) * 8 - 4;
99  uart_putchar(kHexTable[v >> shift]);
100  v <<= 4;
101  }
102  break;
103  }
104  default:
105  // For an invalid format specifier, back up one char and allow the
106  // output via the normal mechanism.
107  uart_putchar('%');
108  --format;
109  }
110  }
111  va_end(args);
112 }
113 
114 void dbg_print_epmp(void) {
115  uint32_t pmpaddr[16];
116  uint32_t pmpcfg[4];
117  uint32_t mseccfg;
118  uint8_t *cfg = (uint8_t *)pmpcfg;
119 
120  // Get address registers.
121  CSR_READ(CSR_REG_PMPADDR0, &pmpaddr[0]);
122  CSR_READ(CSR_REG_PMPADDR1, &pmpaddr[1]);
123  CSR_READ(CSR_REG_PMPADDR2, &pmpaddr[2]);
124  CSR_READ(CSR_REG_PMPADDR3, &pmpaddr[3]);
125  CSR_READ(CSR_REG_PMPADDR4, &pmpaddr[4]);
126  CSR_READ(CSR_REG_PMPADDR5, &pmpaddr[5]);
127  CSR_READ(CSR_REG_PMPADDR6, &pmpaddr[6]);
128  CSR_READ(CSR_REG_PMPADDR7, &pmpaddr[7]);
129  CSR_READ(CSR_REG_PMPADDR8, &pmpaddr[8]);
130  CSR_READ(CSR_REG_PMPADDR9, &pmpaddr[9]);
131  CSR_READ(CSR_REG_PMPADDR10, &pmpaddr[10]);
132  CSR_READ(CSR_REG_PMPADDR11, &pmpaddr[11]);
133  CSR_READ(CSR_REG_PMPADDR12, &pmpaddr[12]);
134  CSR_READ(CSR_REG_PMPADDR13, &pmpaddr[13]);
135  CSR_READ(CSR_REG_PMPADDR14, &pmpaddr[14]);
136  CSR_READ(CSR_REG_PMPADDR15, &pmpaddr[15]);
137 
138  // Get configuration registers.
139  CSR_READ(CSR_REG_PMPCFG0, &pmpcfg[0]);
140  CSR_READ(CSR_REG_PMPCFG1, &pmpcfg[1]);
141  CSR_READ(CSR_REG_PMPCFG2, &pmpcfg[2]);
142  CSR_READ(CSR_REG_PMPCFG3, &pmpcfg[3]);
143 
144  // Get mseccfg.
145  CSR_READ(CSR_REG_MSECCFG, &mseccfg);
146 
147  for (int i = 0; i < 16; ++i) {
148  uint32_t mode = cfg[i] & EPMP_CFG_A_MASK;
149  uint32_t addr = pmpaddr[i];
150  uint32_t size = 0;
151  if (mode == EPMP_CFG_A_NAPOT) {
152  size = 1 << bitfield_count_trailing_zeroes32(~addr);
153  addr = addr & ~(size - 1);
154  size <<= 3;
155  } else if (mode == EPMP_CFG_A_TOR) {
156  size = (addr - pmpaddr[i - 1]) << 2;
157  } else if (mode == EPMP_CFG_A_NA4) {
158  size = 4;
159  }
160  addr <<= 2;
161  dbg_printf("%d: %x %s %c%c%c%c sz=%x\r\n", i, addr,
162  (mode == EPMP_CFG_A_TOR) ? " TOR"
163  : (mode == EPMP_CFG_A_NA4) ? " NA4"
164  : (mode == EPMP_CFG_A_NAPOT) ? "NAPOT"
165  : "-----",
166  cfg[i] & EPMP_CFG_L ? 'L' : '-', cfg[i] & EPMP_CFG_X ? 'X' : '-',
167  cfg[i] & EPMP_CFG_W ? 'W' : '-', cfg[i] & EPMP_CFG_R ? 'R' : '-',
168  size);
169  }
170  dbg_printf("mseccfg = %x\r\n", mseccfg);
171 }
172 
173 void dbg_hexdump(const void *data, size_t len) {
174  const uint8_t *p = (const uint8_t *)data;
175  size_t j = 0;
176 
177  while (j < len) {
178  // hexbuf is initialized as 48 spaces followed by a nul byte.
179  char hexbuf[] = " ";
180  // ascii is initialized as 17 nul bytes.
181  char ascii[17] = {
182  0,
183  };
184  dbg_printf("%p: ", p);
185  for (size_t i = 0; i < 16 && j < len; ++p, ++i, ++j) {
186  uint8_t val = *p;
187  hexbuf[i * 3 + 0] = kHexTable[val >> 4];
188  hexbuf[i * 3 + 1] = kHexTable[val & 15];
189  ascii[i] = (val >= 32 && val < 127) ? (char)val : '.';
190  }
191  dbg_printf("%s %s\r\n", hexbuf, ascii);
192  }
193 }