[lib] Add base_uart_stdout() to print.h

This library provides a replacement for uart.h's stdout initialization
code, the only thing it's still used for.

Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/sw/device/lib/meson.build b/sw/device/lib/meson.build
index 740748d..aacf57e 100644
--- a/sw/device/lib/meson.build
+++ b/sw/device/lib/meson.build
@@ -4,8 +4,8 @@
 
 subdir('base')
 subdir('arch')
-subdir('runtime')
 subdir('dif')
+subdir('runtime')
 
 # UART library (sw_lib_uart)
 sw_lib_uart = declare_dependency(
diff --git a/sw/device/lib/runtime/meson.build b/sw/device/lib/runtime/meson.build
index 8369588..179cb91 100644
--- a/sw/device/lib/runtime/meson.build
+++ b/sw/device/lib/runtime/meson.build
@@ -36,6 +36,7 @@
     sources: ['print.c'],
     dependencies: [
       sw_lib_mem,
+      sw_lib_dif_uart,
     ],
   )
 )
diff --git a/sw/device/lib/runtime/print.c b/sw/device/lib/runtime/print.c
index d2d1edf..f2f8ae0 100644
--- a/sw/device/lib/runtime/print.c
+++ b/sw/device/lib/runtime/print.c
@@ -59,6 +59,21 @@
   base_stdout = out;
 }
 
+static size_t base_dev_uart(void *data, const char *buf, size_t len) {
+  const dif_uart_t *uart = (const dif_uart_t *)data;
+  for (size_t i = 0; i < len; ++i) {
+    if (dif_uart_byte_send_polled(uart, (uint8_t)buf[i]) != kDifUartOk) {
+      return i;
+    }
+  }
+  return len;
+}
+
+void base_uart_stdout(const dif_uart_t *uart) {
+  base_set_stdout(
+      (buffer_sink_t){.data = (void *)uart, .sink = &base_dev_uart});
+}
+
 size_t base_printf(const char *format, ...) {
   va_list args;
   va_start(args, format);
diff --git a/sw/device/lib/runtime/print.h b/sw/device/lib/runtime/print.h
index 8975c72..63731c6 100644
--- a/sw/device/lib/runtime/print.h
+++ b/sw/device/lib/runtime/print.h
@@ -8,6 +8,8 @@
 #include <stdarg.h>
 #include <stddef.h>
 
+#include "sw/device/lib/dif/dif_uart.h"
+
 /**
  * @file
  * @brief Libc-like printing facilities.
@@ -175,4 +177,14 @@
  */
 void base_set_stdout(buffer_sink_t out);
 
+/**
+ * Configures UART stdout for `base_print.h` to use.
+ *
+ * Note that this function will save `uart` in a global variable, so the pointer
+ * must have static storage duration.
+ *
+ * @param uart The UART handle to use for stdout.
+ */
+void base_uart_stdout(const dif_uart_t *uart);
+
 #endif  // OPENTITAN_SW_DEVICE_LIB_RUNTIME_PRINT_H_
diff --git a/sw/device/tests/runtime/meson.build b/sw/device/tests/runtime/meson.build
index 21e2137..f2fcc8d 100644
--- a/sw/device/tests/runtime/meson.build
+++ b/sw/device/tests/runtime/meson.build
@@ -6,7 +6,7 @@
   'runtime_print_unittest',
   sources: [
     meson.source_root() / 'sw/device/lib/runtime/print.c',
-    'print_unittest.cc'
+    'print_unittest.cc',
   ],
   dependencies: [
     sw_vendor_gtest,
diff --git a/sw/device/tests/runtime/print_unittest.cc b/sw/device/tests/runtime/print_unittest.cc
index 3eac04c..4013292 100644
--- a/sw/device/tests/runtime/print_unittest.cc
+++ b/sw/device/tests/runtime/print_unittest.cc
@@ -14,6 +14,14 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "sw/device/lib/dif/dif_uart.h"
+
+// NOTE: This is only present so that print.c can link without pulling in
+// dif_uart.c.
+extern "C" dif_uart_result_t dif_uart_byte_send_polled(const dif_uart *,
+                                                       uint8_t) {
+  return kDifUartOk;
+}
 
 namespace base {
 namespace {