7ea976ff9d17c01f92cebb9e3d1a45d0c40bb640
[mirror_edk2.git] / EmbeddedPkg / Library / GdbSerialLib / GdbSerialLib.c
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