Skip to content

Instantly share code, notes, and snippets.

@jessicah
Created December 16, 2016 03:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jessicah/fa26155c8e3236d9e4ede64f7105d90a to your computer and use it in GitHub Desktop.
Save jessicah/fa26155c8e3236d9e4ede64f7105d90a to your computer and use it in GitHub Desktop.
From d05604aff2b85fa99df1c6f91ee61bf3c6213b8e Mon Sep 17 00:00:00 2001
From: Jessica Hamilton <jessica.l.hamilton@gmail.com>
Date: Fri, 16 Dec 2016 16:46:15 +1300
Subject: [PATCH] UEFI: serial debugging support.
---
src/system/boot/platform/efi/Jamfile | 1 +
src/system/boot/platform/efi/debug.cpp | 18 +++++
src/system/boot/platform/efi/serial.cpp | 137 ++++++++++++++++++++++++++++++++
src/system/boot/platform/efi/serial.h | 31 ++++++++
src/system/boot/platform/efi/start.cpp | 12 ++-
5 files changed, 195 insertions(+), 4 deletions(-)
create mode 100644 src/system/boot/platform/efi/serial.cpp
create mode 100644 src/system/boot/platform/efi/serial.h
diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile
index 8356f76..c74fa82 100644
--- a/src/system/boot/platform/efi/Jamfile
+++ b/src/system/boot/platform/efi/Jamfile
@@ -33,6 +33,7 @@ local platform_src =
hpet.cpp
cpu.cpp
smp.cpp
+ serial.cpp
smp_trampoline.S
support.S
;
diff --git a/src/system/boot/platform/efi/debug.cpp b/src/system/boot/platform/efi/debug.cpp
index 0a40169..809af30 100644
--- a/src/system/boot/platform/efi/debug.cpp
+++ b/src/system/boot/platform/efi/debug.cpp
@@ -11,11 +11,29 @@
#include <boot/stdio.h>
#include "efi_platform.h"
+#include "serial.h"
+
+
+static void
+dprintf_args(const char *format, va_list args)
+{
+ char buffer[512];
+ int length = vsnprintf(buffer, sizeof(buffer), format, args);
+ if (length == 0)
+ return;
+
+ serial_puts(buffer, length);
+}
extern "C" void
dprintf(const char *format, ...)
{
+ va_list args;
+
+ va_start(args, format);
+ dprintf_args(format, args);
+ va_end(args);
}
diff --git a/src/system/boot/platform/efi/serial.cpp b/src/system/boot/platform/efi/serial.cpp
new file mode 100644
index 0000000..5dc683f
--- /dev/null
+++ b/src/system/boot/platform/efi/serial.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2013-2014, Fredrik Holmqvist, fredrik.holmqvist@gmail.com.
+ * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "efi_platform.h"
+#include "efiser.h"
+#include "serial.h"
+
+#include <boot/platform.h>
+#include <arch/cpu.h>
+#include <boot/stage2.h>
+#include <boot/stdio.h>
+
+#include <string.h>
+
+
+static EFI_GUID sSerialIOProtocolGUID = SERIAL_IO_PROTOCOL;
+static const uint32 kSerialBaudRate = 115200;
+
+static SERIAL_IO_INTERFACE *sSerial = NULL;
+static bool sSerialEnabled = false;
+static bool sSerialUsesEFI = true;
+
+
+enum serial_register_offsets {
+ SERIAL_TRANSMIT_BUFFER = 0,
+ SERIAL_RECEIVE_BUFFER = 0,
+ SERIAL_DIVISOR_LATCH_LOW = 0,
+ SERIAL_DIVISOR_LATCH_HIGH = 1,
+ SERIAL_FIFO_CONTROL = 2,
+ SERIAL_LINE_CONTROL = 3,
+ SERIAL_MODEM_CONTROL = 4,
+ SERIAL_LINE_STATUS = 5,
+ SERIAL_MODEM_STATUS = 6,
+};
+
+static uint16 sSerialBasePort = 0x3f8;
+
+
+static void
+serial_putc(char ch)
+{
+ if (!sSerialEnabled)
+ return;
+
+ if (sSerialUsesEFI) {
+ UINTN bufSize = 1;
+ sSerial->Write(sSerial, &bufSize, &ch);
+ } else {
+ while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x20) == 0)
+ asm volatile ("pause;");
+
+ out8(ch, sSerialBasePort + SERIAL_TRANSMIT_BUFFER);
+ }
+}
+
+
+extern "C" void
+serial_puts(const char* string, size_t size)
+{
+ if (!sSerialEnabled || (sSerial == NULL && sSerialUsesEFI))
+ return;
+
+ while (size-- != 0) {
+ char ch = string[0];
+
+ if (ch == '\n') {
+ serial_putc('\r');
+ serial_putc('\n');
+ } else if (ch != '\r')
+ serial_putc(ch);
+
+ string++;
+ }
+}
+
+
+extern "C" void
+serial_disable(void)
+{
+ sSerialEnabled = false;
+}
+
+
+extern "C" void
+serial_enable(void)
+{
+ sSerialEnabled = true;
+}
+
+
+extern "C" void
+serial_init(void)
+{
+ EFI_STATUS status = kSystemTable->BootServices->LocateProtocol(
+ &sSerialIOProtocolGUID, NULL, (void**)&sSerial);
+
+ if (status != EFI_SUCCESS || sSerial == NULL) {
+ sSerial = NULL;
+ return;
+ }
+
+ // Setup serial, 0, 0 = Default Receive FIFO queue and default timeout
+ status = sSerial->SetAttributes(sSerial, kSerialBaudRate, 0, 0, NoParity, 8,
+ OneStopBit);
+
+ if (status != EFI_SUCCESS) {
+ sSerial = NULL;
+ return;
+ }
+}
+
+
+extern "C" void
+serial_switch_to_bios(void)
+{
+ sSerial = NULL;
+ sSerialUsesEFI = false;
+
+ memset(gKernelArgs.platform_args.serial_base_ports, 0,
+ sizeof(uint16) * MAX_SERIAL_PORTS);
+
+ gKernelArgs.platform_args.serial_base_ports[0] = sSerialBasePort;
+
+ uint16 divisor = uint16(115200 / kSerialBaudRate);
+
+ out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL);
+ // set divisor latch access bit
+ out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW);
+ out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH);
+ out8(3, sSerialBasePort + SERIAL_LINE_CONTROL);
+ // 8N1
+}
diff --git a/src/system/boot/platform/efi/serial.h b/src/system/boot/platform/efi/serial.h
new file mode 100644
index 0000000..ee2bf2a
--- /dev/null
+++ b/src/system/boot/platform/efi/serial.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef SERIAL_H
+#define SERIAL_H
+
+
+#include <SupportDefs.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void serial_init(void);
+extern void serial_init_post_mmu(void);
+extern void serial_cleanup(void);
+
+extern void serial_puts(const char *string, size_t size);
+
+extern void serial_disable(void);
+extern void serial_enable(void);
+
+extern void serial_switch_to_bios(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SERIAL_H */
diff --git a/src/system/boot/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp
index 1c035c7..f578c00 100644
--- a/src/system/boot/platform/efi/start.cpp
+++ b/src/system/boot/platform/efi/start.cpp
@@ -25,6 +25,7 @@
#include "hpet.h"
#include "cpu.h"
#include "mmu.h"
+#include "serial.h"
#include "smp.h"
@@ -223,6 +224,11 @@ platform_start_kernel(void)
dprintf("Calling ExitBootServices. So long, EFI!\n");
while (true) {
if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) {
+ // The console was provided by boot services, disable it.
+ stdout = NULL;
+ stderr = NULL;
+ serial_switch_to_bios();
+ dprintf("Switched to legacy serial output\n");
break;
}
@@ -231,10 +237,6 @@ platform_start_kernel(void)
panic("Unable to fetch system memory map.");
}
}
- // We're on our own now...
-
- // The console was provided by boot services, disable it.
- stdout = NULL;
// Update EFI, generate final kernel physical memory map, etc.
mmu_post_efi_setup(memory_map_size, memory_map, descriptor_size, descriptor_version);
@@ -279,6 +281,8 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable)
call_ctors();
console_init();
+ serial_init();
+ serial_enable();
sBootOptions = console_check_boot_keys();
--
2.5.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment