1 /* 2 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2013-2014, Fredrik Holmqvist, fredrik.holmqvist@gmail.com. 4 * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "efi_platform.h" 10 #include <efi/protocol/serial-io.h> 11 #include "serial.h" 12 13 #include <boot/platform.h> 14 #include <arch/cpu.h> 15 #include <arch/generic/debug_uart.h> 16 #include <arch/generic/debug_uart_8250.h> 17 #include <boot/stage2.h> 18 #include <boot/stdio.h> 19 20 #include <string.h> 21 22 23 static efi_guid sSerialIOProtocolGUID = EFI_SERIAL_IO_PROTOCOL_GUID; 24 static const uint32 kSerialBaudRate = 115200; 25 26 static efi_serial_io_protocol *sEFISerialIO = NULL; 27 static bool sSerialEnabled = false; 28 static bool sEFIAvailable = true; 29 30 31 DebugUART* gUART = NULL; 32 33 34 static void 35 serial_putc(char ch) 36 { 37 if (!sSerialEnabled) 38 return; 39 40 // First we use EFI serial_io output if available 41 if (sEFISerialIO != NULL) { 42 size_t bufSize = 1; 43 sEFISerialIO->Write(sEFISerialIO, &bufSize, &ch); 44 return; 45 } 46 47 #ifdef DEBUG 48 // If we don't have EFI serial_io, fallback to EFI stdio 49 if (sEFIAvailable) { 50 char16_t ucsBuffer[2]; 51 ucsBuffer[0] = ch; 52 ucsBuffer[1] = 0; 53 kSystemTable->ConOut->OutputString(kSystemTable->ConOut, ucsBuffer); 54 return; 55 } 56 #endif 57 58 // If EFI services are unavailable... try any UART 59 // this can happen when serial_io is unavailable, or EFI 60 // is exiting 61 if (gUART != NULL) { 62 gUART->PutChar(ch); 63 return; 64 } 65 } 66 67 68 extern "C" void 69 serial_puts(const char* string, size_t size) 70 { 71 if (!sSerialEnabled) 72 return; 73 74 while (size-- != 0) { 75 char ch = string[0]; 76 77 if (ch == '\n') { 78 serial_putc('\r'); 79 serial_putc('\n'); 80 } else if (ch != '\r') 81 serial_putc(ch); 82 83 string++; 84 } 85 } 86 87 88 extern "C" void 89 serial_disable(void) 90 { 91 sSerialEnabled = false; 92 } 93 94 95 extern "C" void 96 serial_enable(void) 97 { 98 sSerialEnabled = true; 99 if (gUART != NULL) 100 gUART->InitPort(kSerialBaudRate); 101 } 102 103 104 extern "C" void 105 serial_init(void) 106 { 107 // Check for EFI Serial 108 efi_status status = kSystemTable->BootServices->LocateProtocol( 109 &sSerialIOProtocolGUID, NULL, (void**)&sEFISerialIO); 110 111 if (status != EFI_SUCCESS) 112 sEFISerialIO = NULL; 113 114 if (sEFISerialIO != NULL) { 115 // Setup serial, 0, 0 = Default Receive FIFO queue and default timeout 116 status = sEFISerialIO->SetAttributes(sEFISerialIO, kSerialBaudRate, 0, 0, NoParity, 8, 117 OneStopBit); 118 119 if (status != EFI_SUCCESS) 120 sEFISerialIO = NULL; 121 122 // serial_io was successful. 123 } 124 125 #if defined(__i386__) || defined(__x86_64__) 126 // On x86, we can try to setup COM1 as a gUART too 127 // while this serial port may not physically exist, 128 // the location is fixed on the x86 arch. 129 // TODO: We could also try to pull from acpi? 130 if (gUART == NULL) { 131 gUART = arch_get_uart_8250(0x3f8, 1843200); 132 gUART->InitEarly(); 133 } 134 #endif 135 } 136 137 138 extern "C" void 139 serial_kernel_handoff(void) 140 { 141 // The console was provided by boot services, disable it ASAP 142 stdout = NULL; 143 stderr = NULL; 144 145 // Disconnect from EFI serial_io services is important as we leave the bootloader 146 sEFISerialIO = NULL; 147 sEFIAvailable = false; 148 149 #if defined(__i386__) || defined(__x86_64__) 150 // TODO: convert over to exclusively arch_args.uart? 151 memset(gKernelArgs.platform_args.serial_base_ports, 0, 152 sizeof(uint16) * MAX_SERIAL_PORTS); 153 gKernelArgs.platform_args.serial_base_ports[0] = 0x3f8; 154 #endif 155 } 156