Software APIs
usb_logging.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/lib/testing/usb_logging.h"
6 
7 #include <ctype.h>
8 
11 #include "sw/device/lib/testing/pinmux_testutils.h"
12 #include "sw/device/lib/testing/usb_testutils.h"
13 #include "sw/device/lib/testing/usb_testutils_controlep.h"
14 
15 #define MODULE_ID MAKE_MODULE_ID('u', 's', 'l')
16 
17 enum {
18  // Size of each logging buffer; data is collected in a buffer until the buffer
19  // is full (or the periodic flush occurs) and is then transmitted as a single
20  // transfer at higher throughput.
21  kUSBLogBufferSize = 0x800u,
22 
23  // Total number of logging buffers to be shared among all active streams.
24  kUSBLogNumBuffers = 8u,
25 
26  // Maximum delay before logging data is flushed upstream to the host;
27  // microseconds.
28  kUSBLogFlushInterval = 500u * 1000u,
29 };
30 
31 // Maximum length of the configuration descriptor.
32 enum {
33  kCfgDscrLenMax =
34  (USB_CFG_DSCR_LEN +
35  kUSBLogMaxStreams * (USB_INTERFACE_DSCR_LEN + 1u * USB_EP_DSCR_LEN)),
36 };
37 
38 // Forward reference required for linked list.
39 typedef struct usb_logging_buf usb_logging_buf_t;
40 
41 // USB logging buffer description.
43  /**
44  * Link to the next buffer for this stream, or the next free buffer.
45  */
47  /**
48  * Number of used bytes; index at which next write shall occur.
49  */
50  uint16_t bytes_used;
51  /**
52  * Data buffer holding logging data.
53  */
54  uint8_t data[kUSBLogBufferSize];
55 };
56 
57 // Forwards reference to logging context.
58 typedef struct usb_logging_ctx usb_logging_ctx_t;
59 
60 // Per-stream state information.
61 typedef struct usb_logging_stream {
62  /**
63  * Context pointer; for use within callback handler.
64  */
66  /**
67  * Reliable delivery required?
68  */
69  bool reliable;
70  /**
71  * Remapping for non-printable characters required?
72  */
73  bool remap;
74  /**
75  * The USB device endpoint that we're using.
76  */
77  uint8_t ep;
78  /**
79  * Currently sending a buffer?
80  */
81  bool sending;
82  /**
83  * The oldest logging buffer filled by this stream; this is either being
84  * sent (`sending` == true) or shall be the next to send. May be NULL iff
85  * this stream has no completed buffers to send.
86  */
88  /**
89  * Time at which the most recently-populated buffer should be sent to the
90  * host; prevent log data being retained indefinitely in the event of no
91  * further log output.
92  */
94  /**
95  * The current logging buffer; may be partially-filled or full (see
96  * `bytes_used` field), or NULL iff this stream has no pending logging data.
97  */
100 
101 // USB Logging context.
103  /**
104  * Access to usb_testutils layer.
105  */
107  /**
108  * Number of logging streams.
109  */
110  uint8_t nstreams;
111  /**
112  * Linked-list of free buffers.
113  */
115  /**
116  * Per-stream state information.
117  */
118  usb_logging_stream_t streams[kUSBLogMaxStreams];
119  /**
120  * Pool of logging buffers; shared among all active streams.
121  */
122  usb_logging_buf_t buf[kUSBLogNumBuffers];
123 };
124 
125 /**
126  * USB device context types.
127  */
128 static usb_testutils_ctx_t usbdev;
129 static usb_testutils_controlep_ctx_t usbdev_control;
130 
131 // Note: for now there is a single logging context.
132 static usb_logging_ctx_t the_ctx;
133 
134 /**
135  * Pinmux handle
136  */
137 static dif_pinmux_t pinmux;
138 
139 /**
140  * Internal development logging; be careful about using this if stdout has been
141  * redirected!
142  */
143 static const bool kDevLogging = false;
144 
145 /**
146  * Character map, used to ensure that non-printable characters are dropped;
147  * isprint() available so this assumes ASCII and drops the control characters
148  * that could could issues with inappropriate terminal settings at the host.
149  */
150 static const uint32_t kCtrlChars =
151  ((uint32_t)1u << '\t') | ((uint32_t)1u << '\n') | ((uint32_t)1u << '\r');
152 static const uint32_t kMap[0x100u / 0x20u] = {
153  // suppress control characters and ASCII 127 (Delete)
154  kCtrlChars, ~0u, ~0u, 0x7fffffffu,
155  // top-bit set characters are harmless; propagate them unchanged.
156  ~0u, ~0u, ~0u, ~0u};
157 
158 // Our stdout function
159 static size_t usb_log(void *data, const char *buf, size_t len);
160 
161 /**
162  * Configuration values for USB.
163  */
164 static uint8_t config_descriptors[kCfgDscrLenMax];
165 
166 // Since isprint() is unavailable, use a simple bitmap to test whether it is
167 // safe to transmit the given ASCII character unmodified.
168 static bool isprintable(uint8_t ch) {
169  return ((kMap[ch >> 5] >> (ch & 0x1fu)) & 1u) != 0u;
170 }
171 
172 // Place all buffers into the free list
173 static void free_list_init(usb_logging_ctx_t *ctx) {
174  usb_logging_buf_t *prev = NULL; // End of list.
175  unsigned idx = kUSBLogNumBuffers;
176  // Order them such that the first buffer is initially at the head.
177  while (idx-- > 0u) {
178  ctx->buf[idx].next = prev;
179  prev = &ctx->buf[idx];
180  }
181  ctx->free = ctx->buf;
182 }
183 
184 // Attempt to claim a buffer from the free list.
185 static inline usb_logging_buf_t *buffer_claim(usb_logging_ctx_t *ctx) {
186  usb_logging_buf_t *buf = ctx->free;
187  if (buf) {
188  ctx->free = buf->next;
189  buf->next = NULL;
190  buf->bytes_used = 0u;
191  }
192  return buf;
193 }
194 
195 // Return a buffer to the free list.
196 static inline void buffer_release(usb_logging_ctx_t *ctx,
197  usb_logging_buf_t *buf) {
198  buf->next = ctx->free;
199  ctx->free = buf;
200 }
201 
202 static status_t buffer_send(usb_logging_ctx_t *ctx, usb_logging_stream_t *s) {
203  TRY_CHECK(ctx && s && s->send_buf);
204 
205  const uint8_t *data = s->send_buf->data;
206  uint16_t len = s->send_buf->bytes_used;
207 
208  if (kDevLogging) {
209  LOG_INFO("sending %p %p %u\n", ctx, data, len);
210  }
211 
212  TRY(usb_testutils_transfer_send(ctx->usbutils, s->ep, data, len,
213  kUsbTestutilsXfrDoubleBuffered));
214  // Have at least started to send the buffer...
215  s->sending = true;
216  return OK_STATUS();
217 }
218 
219 static status_t buffer_completed(usb_logging_ctx_t *ctx,
221  TRY_CHECK(s->wr_buf);
222 
223  // Make the buffer available for sending.
224  usb_logging_buf_t **prev = &s->send_buf;
225  while (*prev) {
226  prev = &(*prev)->next;
227  }
228  *prev = s->wr_buf;
229  s->wr_buf = NULL;
230 
231  // Attempt to send.
232  status_t res = OK_STATUS();
233  if (!s->sending) {
234  res = buffer_send(ctx, s);
235  }
236  return res;
237 }
238 
239 // Attempt to close a logging stream, flushing any remaining data upstream to
240 // the host if required.
241 // Returns true iff the stream has closed successfully; otherwise there is still
242 // work to be done.
243 static inline bool stream_close(usb_logging_ctx_t *ctx,
245  if (s->wr_buf) {
246  buffer_completed(ctx, s);
247  }
248  return !s->send_buf;
249 }
250 
251 // A buffer of logging data has been received by the host; we may try to
252 // send another buffer if one is available.
253 static status_t tx_done(void *s_v, usb_testutils_xfr_result_t result) {
255  usb_logging_ctx_t *ctx = s->ctx;
256 
257  s->sending = false;
258 
259  // Return this buffer to the free list.
260  usb_logging_buf_t *buf = s->send_buf;
261  TRY_CHECK(buf != NULL);
262  s->send_buf = buf->next;
263  buffer_release(ctx, buf);
264 
265  // Send the next, if there is one
266  if (s->send_buf) {
267  TRY(buffer_send(ctx, s));
268  }
269  return OK_STATUS();
270 }
271 
272 // Callback function from the usb_testutils layer; presently this is called
273 // every 16ms, provided that usb_testutils_poll is being called often.
274 static status_t tx_flush(void *s_v) {
276  usb_logging_ctx_t *ctx = s->ctx;
277 
278  // We use this to prevent incomplete buffers of log data sitting here
279  // indefinitely and not reaching the host.
280  usb_logging_buf_t *buf = s->wr_buf;
281  if (buf && ibex_timeout_check(&s->flush_time)) {
282  if (buf->bytes_used > 0u) {
283  // Send everything that we have thus far collected in this buffer,
284  buffer_completed(ctx, s);
285  }
286  // Earliest time at which we shall again attempt flushing of log data on
287  // this stream.
288  s->flush_time = ibex_timeout_init(kUSBLogFlushInterval);
289  }
290 
291  return OK_STATUS();
292 }
293 
294 // Internal function for all USB logging.
295 static status_t usb_logging_send(usb_logging_ctx_t *ctx,
296  usb_logging_stream_t *s, const uint8_t *data,
297  size_t len) {
298  do {
299  // We must poll the testutils layer to keep things going...do this even if
300  // we've somehow been asked to log zero bytes of data.
301  TRY(usb_testutils_poll(ctx->usbutils));
302 
303  // Try to ensure that we have a logging buffer.
304  if (!s->wr_buf) {
305  s->wr_buf = buffer_claim(ctx);
306  }
307  if (s->wr_buf) {
308  usb_logging_buf_t *buf = s->wr_buf;
309 
310  // Add as much as we can to the current logging buffer.
311  size_t chunk = kUSBLogBufferSize - buf->bytes_used;
312  if (chunk > len) {
313  chunk = len;
314  }
315  if (s->remap) {
316  // Remap non-printable characters, to avoid issues with accidentally
317  // stimulated software flow control (XON/XOFF) at the host.
318  uint8_t *dp = &buf->data[buf->bytes_used];
319  for (size_t i = 0u; i < chunk; ++i) {
320  dp[i] = isprintable(data[i]) ? data[i] : '.';
321  }
322  } else {
323  memcpy(&buf->data[buf->bytes_used], data, chunk);
324  }
325  // Advance beyond the chunk that we've handled.
326  data += chunk;
327  len -= chunk;
328 
329  // Initialize timeout at the point of starting to fill a buffer, since it
330  // will be sent as a complete unit.
331  if (!buf->bytes_used) {
332  s->flush_time = ibex_timeout_init(kUSBLogFlushInterval);
333  }
334 
335  // Is this packet buffer now ready to be sent?
336  buf->bytes_used += chunk;
337  if (buf->bytes_used >= kUSBLogBufferSize) {
338  buffer_completed(ctx, s);
339  }
340  } else if (!s->reliable) {
341  // Blocked awaiting another buffer; drop logging data.
342  break;
343  }
344  } while (len); // Any more to send?
345 
346  return OK_STATUS();
347 }
348 
349 // Interface for known-length (binary) data.
350 status_t usb_logging_data(uint8_t s, const uint8_t *data, size_t len) {
351  usb_logging_ctx_t *ctx = &the_ctx;
352  TRY_CHECK(s < ctx->nstreams);
353 
354  return usb_logging_send(ctx, &ctx->streams[s], data, len);
355 }
356 
357 // Interface for ASCIIZ text message.
358 status_t usb_logging_text(uint8_t s, const char *text) {
359  usb_logging_ctx_t *ctx = &the_ctx;
360  TRY_CHECK(s < ctx->nstreams);
361  TRY_CHECK(text);
362 
363  // Note: no strlen() available.
364  uint32_t len = (uint32_t)((char *)memchr(text, 0, SIZE_MAX) - text);
365  return usb_logging_send(ctx, &ctx->streams[s], (const uint8_t *)text, len);
366 }
367 
368 // stdout redirection.
369 static size_t usb_log(void *data, const char *buf, size_t len) {
371  if (s) {
372  usb_logging_ctx_t *ctx = s->ctx;
373  status_t res = usb_logging_send(ctx, s, (uint8_t *)buf, len);
374  if (status_ok(res)) {
375  return len;
376  }
377  }
378  return 0u;
379 }
380 
381 status_t usb_logging_enable(void) {
382  usb_logging_ctx_t *ctx = &the_ctx;
383 
384  // Set up a single reliable logging stream; if `ctx->usbutils` is non-zero
385  // then the usb_testutils has already been initialized.
386  // Should be no need to incur the performance hit of remapping characters,
387  // if base_printf/usage is well-behaved.
388  TRY(usb_logging_init(ctx->usbutils, 1u, 1u, 1u, false));
389 
390  // Construct the descriptor of our USB sink function for stdout.
391  buffer_sink_t sink;
392  sink.data = &ctx->streams[0];
393  sink.sink = usb_log;
394  // Redirect stdout to us
395  base_set_stdout(sink);
396 
397  return OK_STATUS();
398 }
399 
400 status_t usb_logging_init(usb_testutils_ctx_t *usbutils, uint8_t ep_first,
401  uint8_t nstreams, uint32_t reliable, bool remap) {
402  usb_logging_ctx_t *ctx = &the_ctx;
403 
404  // Validate input arguments.
405  TRY_CHECK(nstreams > 0u && nstreams <= kUSBLogMaxStreams);
406 
407  // Set up the software layers, if required.
408  if (usbutils) {
409  // usb_testutils layer already initialized, so an endpoint number must be
410  // supplied.
411  ctx->usbutils = usbutils;
412  TRY_CHECK(ep_first >= 1u && USBDEV_NUM_ENDPOINTS >= ep_first + nstreams);
413  } else {
414  // Pointers to context for lower software layers.
415  ctx->usbutils = &usbdev;
416  ep_first = 1u;
417 
418  TRY(dif_pinmux_init(
420  pinmux_testutils_init(&pinmux);
421  TRY(dif_pinmux_input_select(&pinmux,
424 
425  // Total length of the configuration descriptor; validate caller buffer.
426  size_t cfg_len = USB_CFG_DSCR_LEN +
427  nstreams * (USB_INTERFACE_DSCR_LEN + USB_EP_DSCR_LEN);
428  TRY_CHECK(cfg_len <= sizeof(config_descriptors));
429 
430  // Configuration Descriptor header.
431  uint8_t *cfg = config_descriptors;
432  uint8_t head[USB_CFG_DSCR_LEN] = {
433  USB_CFG_DSCR_HEAD((uint16_t)cfg_len, (uint8_t)nstreams)};
434  memcpy(cfg, head, USB_CFG_DSCR_LEN);
435  cfg += USB_CFG_DSCR_LEN;
436 
437  // Followed by programmatically-generated list of interface descriptors.
438  for (uint8_t id = 0U; id < nstreams; ++id) {
439  uint8_t ep_in = ep_first + id;
440  // Description of a single interface.
441  uint8_t int_dscr[USB_INTERFACE_DSCR_LEN + USB_EP_DSCR_LEN] = {
442  VEND_INTERFACE_DSCR(id, 1, 0x50, 1),
443  // Declare only an IN endpoint because we don't require OUT traffic
444  // and any character echo would just be wasting bus bandwidth.
445  USB_EP_DSCR(1, ep_in, (uint8_t)kUsbTransferTypeBulk,
446  USBDEV_MAX_PACKET_SIZE, 0),
447  };
448 
449  // Append interface descriptor to the configuration descriptor.
450  memcpy(cfg, int_dscr, sizeof(int_dscr));
451  cfg += sizeof(int_dscr);
452  }
453 
454  // Call `usbdev_init` here so that DPI will not start until the
455  // simulation has finished all of the printing, which takes a while
456  // if `--trace` was passed in.
457  TRY(usb_testutils_init(ctx->usbutils, /*pinflip=*/false,
458  /*en_diff_rcvr=*/true,
459  /*tx_use_d_se0=*/false));
460  TRY(usb_testutils_controlep_init(&usbdev_control, ctx->usbutils, 0,
461  config_descriptors, cfg_len, NULL,
462  0u)); // No need for test descriptor.
463  }
464 
465  // Initialize list of free buffers.
466  free_list_init(ctx);
467 
468  // Initialize the time of the next flush on each stream; stagger them to
469  // avoid all flush operations coinciding and producing traffic that is more
470  // bursty.
471  const uint32_t flush_inc = kUSBLogFlushInterval / nstreams;
472  uint32_t interval_us = kUSBLogFlushInterval / 2u;
473 
474  for (uint8_t s = 0u; s < nstreams; ++s) {
475  usb_logging_stream_t *stream = &ctx->streams[s];
476  // Context pointer, for use within callback handler.
477  stream->ctx = ctx;
478  // Reliable delivery required?
479  stream->reliable = (((reliable >> s) & 1u) != 0u);
480  // Remapping required?
481  stream->remap = remap;
482  // Endpoint(s) to be used.
483  // Note: this could be modified to permit concurrent operation with other
484  // interfaces.
485  stream->ep = 1u + s;
486  // Sending state; nothing to send or being sent.
487  stream->sending = false;
488  stream->send_buf = NULL;
489  // Earliest time of next flush attempt.
490  stream->flush_time = ibex_timeout_init(interval_us);
491  interval_us += flush_inc;
492  // Writing state; no buffer initially.
493  stream->wr_buf = NULL;
494 
495  TRY(usb_testutils_in_endpoint_setup(ctx->usbutils, stream->ep,
496  kUsbTransferTypeBulk, stream, tx_done,
497  tx_flush, NULL));
498  }
499 
500  if (!usbutils) {
501  // Proceed only when the device has been configured; this allows host-side
502  // software to establish communication.
503  const uint32_t kTimeoutUsecs = 30 * 1000000;
504  ibex_timeout_t timeout = ibex_timeout_init(kTimeoutUsecs);
505  while (usbdev_control.device_state != kUsbTestutilsDeviceConfigured &&
506  !ibex_timeout_check(&timeout)) {
507  TRY(usb_testutils_poll(ctx->usbutils));
508  }
509  if (usbdev_control.device_state != kUsbTestutilsDeviceConfigured) {
510  // Don't wait indefinitely because there may be no usable connection.
511  return UNAVAILABLE();
512  }
513  }
514 
515  // Remember the stream count, now that everything is configured.
516  ctx->nstreams = nstreams;
517 
518  return OK_STATUS();
519 }
520 
521 status_t usb_logging_fin(bool wait, bool disconnect) {
522  usb_logging_ctx_t *ctx = &the_ctx;
523 
524  // Wait for captured logging traffic to be transmitted?
525  if (wait) {
526  uint8_t s = 0u;
527  while (s < ctx->nstreams) {
528  usb_logging_stream_t *stream = &ctx->streams[s];
529  if (!stream_close(ctx, stream)) {
530  TRY(usb_testutils_poll(ctx->usbutils));
531  // Stay with this logging stream until it completes.
532  continue;
533  }
534  // Check the next logging stream.
535  ++s;
536  }
537  }
538 
539  // Optionally finalize the testutils layer, disconnecting us from the USB.
540  if (disconnect) {
541  TRY(usb_testutils_fin(ctx->usbutils));
542  ctx->usbutils = NULL;
543  }
544 
545  return OK_STATUS();
546 }