UEFI: serial debugging support.
Signed-off-by: Jessica Hamilton <jessica.l.hamilton@gmail.com>
This commit is contained in:
parent
17b2a3cfcb
commit
9e487d8d74
@ -33,6 +33,7 @@ local platform_src =
|
||||
hpet.cpp
|
||||
cpu.cpp
|
||||
smp.cpp
|
||||
serial.cpp
|
||||
smp_trampoline.S
|
||||
support.S
|
||||
;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
137
src/system/boot/platform/efi/serial.cpp
Normal file
137
src/system/boot/platform/efi/serial.cpp
Normal 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
|
||||
}
|
31
src/system/boot/platform/efi/serial.h
Normal file
31
src/system/boot/platform/efi/serial.h
Normal 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 */
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user