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