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