summaryrefslogtreecommitdiffstats
path: root/tboot/printk.c
diff options
context:
space:
mode:
Diffstat (limited to 'tboot/printk.c')
-rw-r--r--tboot/printk.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/tboot/printk.c b/tboot/printk.c
new file mode 100644
index 0000000..0bc4531
--- /dev/null
+++ b/tboot/printk.c
@@ -0,0 +1,195 @@
+/*
+ * printk.c: printk() output fn and helpers
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <compiler.h>
+#include <string.h>
+#include <mutex.h>
+#include <misc.h>
+#include <printk.h>
+#include <eficore.h>
+#include <cmdline.h>
+#include <tb_error.h>
+#include <tboot.h>
+
+uint8_t g_log_level = TBOOT_LOG_LEVEL_NONE;
+uint8_t g_log_targets = TBOOT_LOG_TARGET_NONE;
+
+static struct mutex print_lock;
+
+/*
+ * memory logging
+ */
+
+/* memory-based serial log (ensure in .data section so that not cleared) */
+__data tboot_log_t g_log = {0};
+
+static void memlog_init(void)
+{
+ if ( !g_log.is_init ) {
+ g_log.uuid = (uuid_t)TBOOT_LOG_UUID;
+ g_log.curr_pos = 0;
+ g_log.max_size = TBOOT_MEM_LOG_SIZE;
+ g_log.is_init = true;
+ }
+
+ /* initialize these post-launch as well, since bad/malicious values */
+ /* could compromise environment */
+ g_log.uuid = (uuid_t)TBOOT_LOG_UUID;
+ g_log.max_size = TBOOT_MEM_LOG_SIZE;
+
+ /* if we're calling this post-launch, verify that curr_pos is valid */
+ if ( g_log.curr_pos > g_log.max_size )
+ g_log.curr_pos = 0;
+}
+
+static void memlog_write(const char *str, unsigned int count)
+{
+ if ( count > g_log.max_size )
+ return;
+
+ /* wrap to beginning if too big to fit */
+ if ( g_log.curr_pos + count >= g_log.max_size )
+ g_log.curr_pos = 0;
+
+ memcpy(&g_log.buf[g_log.curr_pos], str, count);
+ g_log.curr_pos += count;
+
+ /* if the string wasn't NULL-terminated, then NULL-terminate the log */
+ if ( str[count-1] != '\0' )
+ g_log.buf[g_log.curr_pos] = '\0';
+ else {
+ /* so that curr_pos will point to the NULL and be overwritten */
+ /* on next copy */
+ g_log.curr_pos--;
+ }
+}
+
+void printk_init(printk_init_t init_type)
+{
+ if (init_type == INIT_EARLY_EFI || init_type == INIT_POST_LAUNCH)
+ mtx_init(&print_lock);
+
+ if (init_type == INIT_EARLY_EFI) {
+ /* Default to EFI logging at early startup */
+#ifdef EFI_EARLY_PRINTK
+ g_log_targets = TBOOT_LOG_TARGET_EFI;
+ g_log_level = TBOOT_LOG_LEVEL_ALL;
+#endif
+ return;
+ }
+
+ /* parse loglvl from string to int */
+ get_tboot_loglvl();
+
+ /* parse logging targets */
+ get_tboot_log_targets();
+
+ if (init_type == INIT_POST_EBS || init_type == INIT_POST_LAUNCH) {
+ /* now we can use VGA logging, EFI console is gone */
+ if ( g_log_targets & TBOOT_LOG_TARGET_VGA ) {
+ vga_init();
+ get_tboot_vga_delay(); /* parse vga delay time */
+ }
+
+ /* cannot use EFI logging any longer also */
+ g_log_targets &= ~TBOOT_LOG_TARGET_EFI;
+ }
+
+ if (init_type == INIT_PRE_LAUNCH || init_type == INIT_POST_LAUNCH) {
+ /* parse serial settings */
+ if ( !get_tboot_serial() )
+ g_log_targets &= ~TBOOT_LOG_TARGET_SERIAL;
+
+ if ( g_log_targets & TBOOT_LOG_TARGET_SERIAL )
+ serial_init();
+
+ if ( g_log_targets & TBOOT_LOG_TARGET_MEMORY )
+ memlog_init();
+ }
+}
+
+#define WRITE_LOGS(s, n) \
+ do { \
+ if (g_log_targets & TBOOT_LOG_TARGET_EFI) efi_write(s, n); \
+ if (g_log_targets & TBOOT_LOG_TARGET_MEMORY) memlog_write(s, n); \
+ if (g_log_targets & TBOOT_LOG_TARGET_SERIAL) serial_write(s, n); \
+ if (g_log_targets & TBOOT_LOG_TARGET_VGA) vga_write(s, n); \
+ } while (0)
+
+void printk(const char *fmt, ...)
+{
+ char buf[TBOOT_LOGBUF_SIZE];
+ char *pbuf = buf;
+ int n;
+ va_list ap;
+ uint8_t log_level;
+ static bool last_line_cr = true;
+
+ memset(buf, '\0', sizeof(buf));
+ va_start(ap, fmt);
+ n = vscnprintf(buf, sizeof(buf), fmt, ap);
+
+ log_level = get_loglvl_prefix(&pbuf, &n);
+
+ if ( !(g_log_level & log_level) )
+ goto exit;
+
+ mtx_enter(&print_lock);
+ /* prepend "TBOOT: " if the last line that was printed ended with a '\n' */
+ if ( last_line_cr )
+ WRITE_LOGS("TBOOT: ", 8);
+
+ last_line_cr = (n > 0 && (*(pbuf+n-1) == '\n'));
+ WRITE_LOGS(pbuf, n);
+ mtx_leave(&print_lock);
+
+exit:
+ va_end(ap);
+}
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */