]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/GdbStub/SerialIo.c
ARM Packages: Fixed missing braces (the warning was disabled by GCC)
[mirror_edk2.git] / EmbeddedPkg / GdbStub / SerialIo.c
CommitLineData
1e57a462 1/** @file\r
2 Serial IO Abstraction for GDB stub. This allows an EFI consoles that shows up on the system \r
3 running GDB. One consle for error information and another console for user input/output.\r
4 \r
5 Basic packet format is $packet-data#checksum. So every comand has 4 bytes of overhead: $, \r
6 #, 0, 0. The 0 and 0 are the ascii characters for the checksum. \r
7 \r
8\r
9 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
10 \r
11 This program and the accompanying materials\r
12 are licensed and made available under the terms and conditions of the BSD License\r
13 which accompanies this distribution. The full text of the license may be found at\r
14 http://opensource.org/licenses/bsd-license.php\r
15\r
16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
18\r
19**/\r
20\r
21#include <GdbStubInternal.h>\r
22\r
23//\r
24// Set TRUE if F Reply package signals a ctrl-c. We can not process the Ctrl-c\r
25// here we need to wait for the periodic callback to do this. \r
26//\r
27BOOLEAN gCtrlCBreakFlag = FALSE;\r
28\r
29//\r
30// If the periodic callback is called while we are processing an F packet we need\r
31// to let the callback know to not read from the serail stream as it could steal\r
32// characters from the F reponse packet\r
33//\r
34BOOLEAN gProcessingFPacket = FALSE;\r
35\r
36/**\r
37 Process a control-C break message. \r
38 \r
39 Currently a place holder, remove the ASSERT when it gets implemented. \r
40\r
41 @param ErrNo Error infomration from the F reply packet or other source\r
42\r
43**/\r
44\r
45VOID\r
46GdbCtrlCBreakMessage (\r
47 IN UINTN ErrNo\r
48 )\r
49{\r
50 // See D.10.5 of gdb.pdf\r
51 // This should look like a break message. Should look like SIGINT\r
52\r
53 /* TODO: Make sure if we should do anything with ErrNo */\r
54 //Turn on the global Ctrl-C flag.\r
55 gCtrlCBreakFlag = TRUE;\r
56}\r
57\r
58\r
59/**\r
60 Parse the F reply packet and extract the return value and an ErrNo if it exists.\r
61\r
62 @param Packet Packet to parse like an F reply packet\r
63 @param ErrNo Buffer to hold Count bytes that were read\r
64\r
65 @retval -1 Error, not a valid F reply packet \r
66 @retval other Return the return code from the F reply packet \r
67\r
68**/\r
69INTN\r
70GdbParseFReplyPacket (\r
71 IN CHAR8 *Packet,\r
72 OUT UINTN *ErrNo \r
73 )\r
74{\r
75 INTN RetCode;\r
76 \r
77 if (Packet[0] != 'F') {\r
78 // A valid responce would be an F packet\r
79 return -1;\r
80 }\r
81 \r
82 RetCode = AsciiStrHexToUintn (&Packet[1]);\r
83 \r
84 // Find 1st comma \r
85 for (;*Packet != '\0' && *Packet != ','; Packet++); \r
86 if (*Packet == '\0') {\r
87 *ErrNo = 0;\r
88 return RetCode;\r
89 }\r
90 \r
91 *ErrNo = AsciiStrHexToUintn (++Packet);\r
92\r
93 // Find 2nd comma \r
94 for (;*Packet != '\0' && *Packet != ','; Packet++); \r
95 if (*Packet == '\0') {\r
96 return RetCode;\r
97 }\r
98 \r
99 if (*(++Packet) == 'C') {\r
100 GdbCtrlCBreakMessage (*ErrNo); \r
101 }\r
102 \r
103 return RetCode;\r
104}\r
105\r
106\r
107/**\r
108 Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates \r
109 the end of a file. On error -1 is returned. If count is zero, GdbRead returns zero.\r
110\r
111 @param FileDescriptor Device to talk to.\r
112 @param Buffer Buffer to hold Count bytes that were read\r
113 @param Count Number of bytes to transfer. \r
114\r
115 @retval -1 Error\r
116 @retval {other} Number of bytes read.\r
117\r
118**/\r
119INTN\r
120GdbRead (\r
121 IN INTN FileDescriptor,\r
122 OUT VOID *Buffer,\r
123 IN UINTN Count\r
124 )\r
125{\r
126 CHAR8 Packet[128];\r
127 UINTN Size;\r
128 INTN RetCode;\r
129 UINTN ErrNo;\r
130 BOOLEAN ReceiveDone = FALSE;\r
131 \r
132 // Send:\r
133 // "Fread,XX,YYYYYYYY,XX\r
134 //\r
135 // XX - FileDescriptor in ASCII\r
136 // YYYYYYYY - Buffer address in ASCII \r
137 // XX - Count in ASCII\r
138 // SS - check sum\r
139 //\r
140 Size = AsciiSPrint (Packet, sizeof (Packet), "Fread,%x,%x,%x", FileDescriptor, Buffer, Count);\r
141 // Packet array is too small if you got this ASSERT\r
142 ASSERT (Size < sizeof (Packet));\r
143 \r
144 gProcessingFPacket = TRUE;\r
145 SendPacket (Packet);\r
146 Print ((CHAR16 *)L"Packet sent..\n");\r
147\r
148 do {\r
149 // Reply:\r
150 ReceivePacket (Packet, sizeof (Packet));\r
151 Print ((CHAR16 *)L"Command received..%c\n", Packet[0]);\r
152\r
153 // Process GDB commands\r
154 switch (Packet[0]) {\r
155 //Write memory command.\r
156 //M addr,length:XX...\r
157 case 'M':\r
158 WriteToMemory (Packet);\r
159 break;\r
160\r
161 //Fretcode, errno, Ctrl-C flag\r
162 //retcode - Count read\r
163 case 'F':\r
164 //Once target receives F reply packet that means the previous\r
165 //transactions are finished.\r
166 ReceiveDone = TRUE;\r
167 break;\r
168\r
169 //Send empty buffer\r
170 default :\r
171 SendNotSupported();\r
172 break;\r
173 }\r
174 } while (ReceiveDone == FALSE);\r
175\r
176 RetCode = GdbParseFReplyPacket (Packet, &ErrNo);\r
177 Print ((CHAR16 *)L"RetCode: %x..ErrNo: %x..\n", RetCode, ErrNo);\r
178 \r
179 if (ErrNo > 0) {\r
180 //Send error to the host if there is any.\r
181 SendError ((UINT8)ErrNo);\r
182 }\r
183 \r
184 gProcessingFPacket = FALSE;\r
185\r
186 return RetCode;\r
187} \r
188 \r
189\r
190/**\r
191 Write data to a FileDescriptor. On success number of bytes written is returned. Zero indicates \r
192 nothing was written. On error -1 is returned. \r
193\r
194 @param FileDescriptor Device to talk to.\r
195 @param Buffer Buffer to hold Count bytes that are to be written\r
196 @param Count Number of bytes to transfer. \r
197\r
198 @retval -1 Error\r
199 @retval {other} Number of bytes written.\r
200\r
201**/\r
202INTN\r
203GdbWrite (\r
204 IN INTN FileDescriptor,\r
205 OUT CONST VOID *Buffer,\r
206 IN UINTN Count\r
207 )\r
208{\r
209 CHAR8 Packet[128];\r
210 UINTN Size;\r
211 INTN RetCode;\r
212 UINTN ErrNo;\r
213 BOOLEAN ReceiveDone = FALSE;\r
214\r
215 // Send:\r
216 // #Fwrite,XX,YYYYYYYY,XX$SS\r
217 //\r
218 // XX - FileDescriptor in ASCII\r
219 // YYYYYYYY - Buffer address in ASCII \r
220 // XX - Count in ASCII\r
221 // SS - check sum\r
222 //\r
223 Size = AsciiSPrint (Packet, sizeof (Packet), "Fwrite,%x,%x,%x", FileDescriptor, Buffer, Count);\r
224 // Packet array is too small if you got this ASSERT\r
225 ASSERT (Size < sizeof (Packet));\r
226 \r
227 SendPacket (Packet);\r
228 Print ((CHAR16 *)L"Packet sent..\n");\r
229\r
230 do {\r
231 // Reply:\r
232 ReceivePacket (Packet, sizeof (Packet));\r
233 Print ((CHAR16 *)L"Command received..%c\n", Packet[0]);\r
234\r
235 // Process GDB commands\r
236 switch (Packet[0]) {\r
237 //Read memory command.\r
238 //m addr,length. \r
239 case 'm':\r
240 ReadFromMemory (Packet);\r
241 break;\r
242\r
243 //Fretcode, errno, Ctrl-C flag\r
244 //retcode - Count read\r
245 case 'F':\r
246 //Once target receives F reply packet that means the previous \r
247 //transactions are finished.\r
248 ReceiveDone = TRUE;\r
249 break;\r
250 \r
251 //Send empty buffer\r
252 default : \r
253 SendNotSupported();\r
254 break;\r
255 }\r
256 } while (ReceiveDone == FALSE);\r
257\r
258 RetCode = GdbParseFReplyPacket (Packet, &ErrNo);\r
259 Print ((CHAR16 *)L"RetCode: %x..ErrNo: %x..\n", RetCode, ErrNo);\r
260\r
261 //Send error to the host if there is any.\r
262 if (ErrNo > 0) {\r
263 SendError((UINT8)ErrNo);\r
264 }\r
265 \r
266 return RetCode;\r
267}\r
268\r
269\r
270/**\r
271 Reset the serial device.\r
272\r
273 @param This Protocol instance pointer.\r
274 \r
275 @retval EFI_SUCCESS The device was reset.\r
276 @retval EFI_DEVICE_ERROR The serial device could not be reset.\r
277\r
278**/\r
279EFI_STATUS\r
280EFIAPI\r
281GdbSerialReset (\r
282 IN EFI_SERIAL_IO_PROTOCOL *This\r
283 )\r
284{\r
285 return EFI_SUCCESS;\r
286}\r
287\r
288\r
289/**\r
290 Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, \r
291 data buts, and stop bits on a serial device.\r
292\r
293 @param This Protocol instance pointer.\r
294 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the\r
295 device's default interface speed.\r
296 @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the\r
297 serial interface. A ReceiveFifoDepth value of 0 will use\r
298 the device's dfault FIFO depth.\r
299 @param Timeout The requested time out for a single character in microseconds.\r
300 This timeout applies to both the transmit and receive side of the\r
301 interface. A Timeout value of 0 will use the device's default time\r
302 out value.\r
303 @param Parity The type of parity to use on this serial device. A Parity value of\r
304 DefaultParity will use the device's default parity value.\r
305 @param DataBits The number of data bits to use on the serial device. A DataBits\r
306 vaule of 0 will use the device's default data bit setting.\r
307 @param StopBits The number of stop bits to use on this serial device. A StopBits\r
308 value of DefaultStopBits will use the device's default number of\r
309 stop bits.\r
310\r
311 @retval EFI_SUCCESS The device was reset.\r
312 @retval EFI_DEVICE_ERROR The serial device could not be reset.\r
313\r
314**/\r
315EFI_STATUS\r
316EFIAPI\r
317GdbSerialSetAttributes (\r
318 IN EFI_SERIAL_IO_PROTOCOL *This,\r
319 IN UINT64 BaudRate,\r
320 IN UINT32 ReceiveFifoDepth,\r
321 IN UINT32 Timeout,\r
322 IN EFI_PARITY_TYPE Parity,\r
323 IN UINT8 DataBits,\r
324 IN EFI_STOP_BITS_TYPE StopBits\r
325 )\r
326{\r
327 return EFI_UNSUPPORTED;\r
328}\r
329\r
330\r
331/**\r
332 Set the control bits on a serial device\r
333\r
334 @param This Protocol instance pointer.\r
335 @param Control Set the bits of Control that are settable.\r
336\r
337 @retval EFI_SUCCESS The new control bits were set on the serial device.\r
338 @retval EFI_UNSUPPORTED The serial device does not support this operation.\r
339 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
340\r
341**/\r
342EFI_STATUS\r
343EFIAPI\r
344GdbSerialSetControl (\r
345 IN EFI_SERIAL_IO_PROTOCOL *This,\r
346 IN UINT32 Control\r
347 )\r
348{\r
349 return EFI_UNSUPPORTED;\r
350}\r
351\r
352\r
353/**\r
354 Retrieves the status of thecontrol bits on a serial device\r
355\r
356 @param This Protocol instance pointer.\r
357 @param Control A pointer to return the current Control signals from the serial device.\r
358 \r
359 @retval EFI_SUCCESS The control bits were read from the serial device.\r
360 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
361\r
362**/\r
363EFI_STATUS\r
364EFIAPI\r
365GdbSerialGetControl (\r
366 IN EFI_SERIAL_IO_PROTOCOL *This,\r
367 OUT UINT32 *Control\r
368 )\r
369{\r
370 return EFI_UNSUPPORTED;\r
371}\r
372\r
373\r
374/**\r
375 Writes data to a serial device.\r
376\r
377 @param This Protocol instance pointer.\r
378 @param BufferSize On input, the size of the Buffer. On output, the amount of\r
379 data actually written.\r
380 @param Buffer The buffer of data to write\r
381\r
382 @retval EFI_SUCCESS The data was written.\r
383 @retval EFI_DEVICE_ERROR The device reported an error.\r
384 @retval EFI_TIMEOUT The data write was stopped due to a timeout.\r
385\r
386**/\r
387EFI_STATUS\r
388EFIAPI\r
389GdbSerialWrite (\r
390 IN EFI_SERIAL_IO_PROTOCOL *This,\r
391 IN OUT UINTN *BufferSize,\r
392 IN VOID *Buffer\r
393 )\r
394{\r
395 GDB_SERIAL_DEV *SerialDev;\r
396 UINTN Return;\r
397\r
398 SerialDev = GDB_SERIAL_DEV_FROM_THIS (This);\r
399 \r
400 Return = GdbWrite (SerialDev->OutFileDescriptor, Buffer, *BufferSize);\r
401 if (Return == (UINTN)-1) {\r
402 return EFI_DEVICE_ERROR;\r
403 }\r
404 \r
405 if (Return != *BufferSize) {\r
406 *BufferSize = Return;\r
407 }\r
408 \r
409 return EFI_SUCCESS;\r
410}\r
411\r
412/**\r
413 Writes data to a serial device.\r
414\r
415 @param This Protocol instance pointer.\r
416 @param BufferSize On input, the size of the Buffer. On output, the amount of\r
417 data returned in Buffer.\r
418 @param Buffer The buffer to return the data into.\r
419\r
420 @retval EFI_SUCCESS The data was read.\r
421 @retval EFI_DEVICE_ERROR The device reported an error.\r
422 @retval EFI_TIMEOUT The data write was stopped due to a timeout.\r
423\r
424**/\r
425\r
426EFI_STATUS\r
427EFIAPI\r
428GdbSerialRead (\r
429 IN EFI_SERIAL_IO_PROTOCOL *This,\r
430 IN OUT UINTN *BufferSize,\r
431 OUT VOID *Buffer\r
432 )\r
433{\r
434 GDB_SERIAL_DEV *SerialDev;\r
435 UINTN Return;\r
436\r
437 SerialDev = GDB_SERIAL_DEV_FROM_THIS (This);\r
438 \r
439 Return = GdbRead (SerialDev->InFileDescriptor, Buffer, *BufferSize);\r
440 if (Return == (UINTN)-1) {\r
441 return EFI_DEVICE_ERROR;\r
442 }\r
443 \r
444 if (Return != *BufferSize) {\r
445 *BufferSize = Return;\r
446 }\r
447 \r
448 return EFI_SUCCESS;\r
449}\r
450\r
451\r
452// \r
453// Template used to initailize the GDB Serial IO protocols\r
454//\r
455GDB_SERIAL_DEV gdbSerialDevTemplate = {\r
456 GDB_SERIAL_DEV_SIGNATURE,\r
457 NULL,\r
458 \r
459 { // SerialIo\r
460 SERIAL_IO_INTERFACE_REVISION,\r
461 GdbSerialReset,\r
462 GdbSerialSetAttributes,\r
463 GdbSerialSetControl,\r
464 GdbSerialGetControl,\r
465 GdbSerialWrite,\r
466 GdbSerialRead,\r
467 NULL\r
468 },\r
469 { // SerialMode\r
470 0, // ControlMask\r
471 0, // Timeout\r
472 0, // BaudRate\r
473 1, // RceiveFifoDepth\r
474 0, // DataBits\r
475 0, // Parity\r
476 0 // StopBits\r
477 },\r
b0fdce95 478 {\r
1e57a462 479 {\r
1e57a462 480 {\r
b0fdce95
OM
481 HARDWARE_DEVICE_PATH,\r
482 HW_VENDOR_DP,\r
483 {\r
484 (UINT8) (sizeof (VENDOR_DEVICE_PATH) + sizeof (UINT32)),\r
485 (UINT8) ((sizeof (VENDOR_DEVICE_PATH) + sizeof (UINT32)) >> 8)\r
486 },\r
1e57a462 487 },\r
b0fdce95 488 EFI_SERIAL_IO_PROTOCOL_GUID\r
1e57a462 489 },\r
490 0,\r
491 {\r
492 END_DEVICE_PATH_TYPE,\r
493 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
494 {\r
495 (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),\r
496 (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL) >> 8)\r
497 }\r
498 },\r
499 },\r
500 GDB_STDIN,\r
501 GDB_STDOUT\r
502};\r
503\r
504\r
505/**\r
506 Make two serial consoles: 1) StdIn and StdOut via GDB. 2) StdErr via GDB.\r
507 \r
508 These console show up on the remote system running GDB\r
509\r
510**/\r
511VOID\r
512GdbInitializeSerialConsole (\r
513 VOID\r
514 )\r
515{\r
516 EFI_STATUS Status;\r
517 GDB_SERIAL_DEV *StdOutSerialDev;\r
518 GDB_SERIAL_DEV *StdErrSerialDev;\r
519\r
520 // Use the template to make a copy of the Serial Console private data structure.\r
521 StdOutSerialDev = AllocateCopyPool (sizeof (GDB_SERIAL_DEV), &gdbSerialDevTemplate);\r
522 ASSERT (StdOutSerialDev != NULL);\r
523 \r
524 // Fixup pointer after the copy\r
525 StdOutSerialDev->SerialIo.Mode = &StdOutSerialDev->SerialMode;\r
526 \r
527 StdErrSerialDev = AllocateCopyPool (sizeof (GDB_SERIAL_DEV), &gdbSerialDevTemplate);\r
528 ASSERT (StdErrSerialDev != NULL);\r
529\r
530 // Fixup pointer and modify stuff that is different for StdError\r
531 StdErrSerialDev->SerialIo.Mode = &StdErrSerialDev->SerialMode; \r
532 StdErrSerialDev->DevicePath.Index = 1;\r
533 StdErrSerialDev->OutFileDescriptor = GDB_STDERR;\r
534 \r
535 // Make a new handle with Serial IO protocol and its device path on it.\r
536 Status = gBS->InstallMultipleProtocolInterfaces (\r
537 &StdOutSerialDev->Handle, \r
538 &gEfiSerialIoProtocolGuid, &StdOutSerialDev->SerialIo,\r
539 &gEfiDevicePathProtocolGuid, &StdOutSerialDev->DevicePath,\r
540 NULL\r
541 );\r
542 ASSERT_EFI_ERROR (Status);\r
543\r
544 // Make a new handle with Serial IO protocol and its device path on it.\r
545 Status = gBS->InstallMultipleProtocolInterfaces (\r
546 &StdErrSerialDev->Handle, \r
547 &gEfiSerialIoProtocolGuid, &StdErrSerialDev->SerialIo,\r
548 &gEfiDevicePathProtocolGuid, &StdErrSerialDev->DevicePath,\r
549 NULL\r
550 );\r
551 ASSERT_EFI_ERROR (Status);\r
552}\r
553\r