1 /** @file 2 Basic serial IO abstaction for GDB 3 4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include <Uefi.h> 17 #include <Library/GdbSerialLib.h> 18 #include <Library/PcdLib.h> 19 #include <Library/IoLib.h> 20 #include <Library/DebugLib.h> 21 22 23 //--------------------------------------------- 24 // UART Register Offsets 25 //--------------------------------------------- 26 #define BAUD_LOW_OFFSET 0x00 27 #define BAUD_HIGH_OFFSET 0x01 28 #define IER_OFFSET 0x01 29 #define LCR_SHADOW_OFFSET 0x01 30 #define FCR_SHADOW_OFFSET 0x02 31 #define IR_CONTROL_OFFSET 0x02 32 #define FCR_OFFSET 0x02 33 #define EIR_OFFSET 0x02 34 #define BSR_OFFSET 0x03 35 #define LCR_OFFSET 0x03 36 #define MCR_OFFSET 0x04 37 #define LSR_OFFSET 0x05 38 #define MSR_OFFSET 0x06 39 40 //--------------------------------------------- 41 // UART Register Bit Defines 42 //--------------------------------------------- 43 #define LSR_TXRDY 0x20 44 #define LSR_RXDA 0x01 45 #define DLAB 0x01 46 #define ENABLE_FIFO 0x01 47 #define CLEAR_FIFOS 0x06 48 49 50 51 // IO Port Base for the UART 52 UINTN gPort; 53 54 55 /** 56 The constructor function initializes the UART. 57 58 @param ImageHandle The firmware allocated handle for the EFI image. 59 @param SystemTable A pointer to the EFI System Table. 60 61 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. 62 63 **/ 64 RETURN_STATUS 65 EFIAPI 66 GdbSerialLibConstructor ( 67 IN EFI_HANDLE ImageHandle, 68 IN EFI_SYSTEM_TABLE *SystemTable 69 ) 70 { 71 UINT64 BaudRate; 72 UINT8 DataBits; 73 UINT8 Parity; 74 UINT8 StopBits; 75 76 gPort = (UINTN)PcdGet32 (PcdGdbUartPort); 77 78 BaudRate = PcdGet64 (PcdGdbBaudRate); 79 Parity = PcdGet8 (PcdGdbParity); 80 DataBits = PcdGet8 (PcdGdbDataBits); 81 StopBits = PcdGet8 (PcdGdbStopBits); 82 83 return GdbSerialInit (BaudRate, Parity, DataBits, StopBits); 84 } 85 86 87 88 /** 89 Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, 90 data buts, and stop bits on a serial device. This call is optional as the serial 91 port will be set up with defaults base on PCD values. 92 93 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the 94 device's default interface speed. 95 @param Parity The type of parity to use on this serial device. A Parity value of 96 DefaultParity will use the device's default parity value. 97 @param DataBits The number of data bits to use on the serial device. A DataBits 98 vaule of 0 will use the device's default data bit setting. 99 @param StopBits The number of stop bits to use on this serial device. A StopBits 100 value of DefaultStopBits will use the device's default number of 101 stop bits. 102 103 @retval EFI_SUCCESS The device was configured. 104 @retval EFI_DEVICE_ERROR The serial device could not be coonfigured. 105 106 **/ 107 RETURN_STATUS 108 EFIAPI 109 GdbSerialInit ( 110 IN UINT64 BaudRate, 111 IN UINT8 Parity, 112 IN UINT8 DataBits, 113 IN UINT8 StopBits 114 ) 115 { 116 UINTN Divisor; 117 UINT8 OutputData; 118 UINT8 Data; 119 UINT8 BreakSet = 0; 120 121 // 122 // We assume the UART has been turned on to decode gPort address range 123 // 124 125 // 126 // Map 5..8 to 0..3 127 // 128 Data = (UINT8) (DataBits - (UINT8)5); 129 130 // 131 // Calculate divisor for baud generator 132 // 133 Divisor = 115200/(UINTN)BaudRate; 134 135 // 136 // Set communications format 137 // 138 OutputData = (UINT8)((DLAB << 7) | ((BreakSet << 6) | ((Parity << 3) | ((StopBits << 2) | Data)))); 139 IoWrite8 (gPort + LCR_OFFSET, OutputData); 140 141 // 142 // Configure baud rate 143 // 144 IoWrite8 (gPort + BAUD_HIGH_OFFSET, (UINT8)(Divisor >> 8)); 145 IoWrite8 (gPort + BAUD_LOW_OFFSET, (UINT8)(Divisor & 0xff)); 146 147 148 // 149 // Switch back to bank 0 150 // 151 OutputData = (UINT8)((~DLAB<<7)|((BreakSet<<6)|((Parity<<3)|((StopBits<<2)| Data)))); 152 IoWrite8 (gPort + LCR_OFFSET, OutputData); 153 154 // Not sure this is the right place to enable the FIFOs.... 155 // We probably need the FIFO enabled to not drop input 156 IoWrite8 (gPort + FCR_SHADOW_OFFSET, ENABLE_FIFO); 157 158 159 // Configure the UART hardware here 160 return RETURN_SUCCESS; 161 } 162 163 164 /** 165 Check to see if a character is available from GDB. Do not read the character as that is 166 done via GdbGetChar(). 167 168 @return TRUE - Character availible 169 @return FALSE - Character not availible 170 171 **/ 172 BOOLEAN 173 EFIAPI 174 GdbIsCharAvailable ( 175 VOID 176 ) 177 { 178 UINT8 Data; 179 180 Data = IoRead8 (gPort + LSR_OFFSET); 181 182 return ((Data & LSR_RXDA) == LSR_RXDA); 183 } 184 185 186 /** 187 Get a character from GDB. This function must be able to run in interrupt context. 188 189 @return A character from GDB 190 191 **/ 192 CHAR8 193 EFIAPI 194 GdbGetChar ( 195 VOID 196 ) 197 { 198 UINT8 Data; 199 CHAR8 Char; 200 201 // Wait for the serial port to be ready 202 do { 203 Data = IoRead8 (gPort + LSR_OFFSET); 204 } while ((Data & LSR_RXDA) == 0); 205 206 Char = IoRead8 (gPort); 207 208 // Make this an EFI_D_INFO after we get everything debugged. 209 DEBUG ((EFI_D_ERROR, "<%c<", Char)); 210 return Char; 211 } 212 213 214 /** 215 Send a character to GDB. This function must be able to run in interrupt context. 216 217 218 @param Char Send a character to GDB 219 220 **/ 221 222 VOID 223 EFIAPI 224 GdbPutChar ( 225 IN CHAR8 Char 226 ) 227 { 228 UINT8 Data; 229 230 // Make this an EFI_D_INFO after we get everything debugged. 231 DEBUG ((EFI_D_ERROR, ">%c>", Char)); 232 233 // Wait for the serial port to be ready 234 do { 235 Data = IoRead8 (gPort + LSR_OFFSET); 236 } while ((Data & LSR_TXRDY) == 0); 237 238 IoWrite8 (gPort, Char); 239 } 240 241 /** 242 Send an ASCII string to GDB. This function must be able to run in interrupt context. 243 244 245 @param String Send a string to GDB 246 247 **/ 248 249 VOID 250 GdbPutString ( 251 IN CHAR8 *String 252 ) 253 { 254 while (*String != '\0') { 255 GdbPutChar (*String); 256 String++; 257 } 258 } 259 260 261 262 263