UEFI: serial debugging support.

Signed-off-by: Jessica Hamilton <jessica.l.hamilton@gmail.com>
This commit is contained in:
Fredrik Holmqvist 2016-12-16 16:46:15 +13:00 committed by Jessica Hamilton
parent 17b2a3cfcb
commit 9e487d8d74
5 changed files with 196 additions and 4 deletions

View File

@ -33,6 +33,7 @@ local platform_src =
hpet.cpp
cpu.cpp
smp.cpp
serial.cpp
smp_trampoline.S
support.S
;

View File

@ -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);
}

View File

@ -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_legacy(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
}

View File

@ -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_legacy(void);
#ifdef __cplusplus
}
#endif
#endif /* SERIAL_H */

View File

@ -25,6 +25,7 @@
#include "hpet.h"
#include "cpu.h"
#include "mmu.h"
#include "serial.h"
#include "smp.h"
@ -223,6 +224,12 @@ 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;
// Also switch to legacy serial output (may not work on all systems)
serial_switch_to_legacy();
dprintf("Switched to legacy serial output\n");
break;
}
@ -231,10 +238,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 +282,8 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable)
call_ctors();
console_init();
serial_init();
serial_enable();
sBootOptions = console_check_boot_keys();