Created
December 16, 2016 03:46
-
-
Save jessicah/fa26155c8e3236d9e4ede64f7105d90a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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