]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/GdbStub/SerialIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / GdbStub / SerialIo.c
... / ...
CommitLineData
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 console for error information and another console for user input/output.\r
4\r
5 Basic packet format is $packet-data#checksum. So every command 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 SPDX-License-Identifier: BSD-2-Clause-Patent\r
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
19// here we need to wait for the periodic callback to do this.\r
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
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
27//\r
28BOOLEAN gProcessingFPacket = FALSE;\r
29\r
30/**\r
31 Process a control-C break message.\r
32\r
33 Currently a place holder, remove the ASSERT when it gets implemented.\r
34\r
35 @param ErrNo Error information from the F reply packet or other source\r
36\r
37**/\r
38VOID\r
39GdbCtrlCBreakMessage (\r
40 IN UINTN ErrNo\r
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
47 // Turn on the global Ctrl-C flag.\r
48 gCtrlCBreakFlag = TRUE;\r
49}\r
50\r
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
57 @retval -1 Error, not a valid F reply packet\r
58 @retval other Return the return code from the F reply packet\r
59\r
60**/\r
61INTN\r
62GdbParseFReplyPacket (\r
63 IN CHAR8 *Packet,\r
64 OUT UINTN *ErrNo\r
65 )\r
66{\r
67 INTN RetCode;\r
68\r
69 if (Packet[0] != 'F') {\r
70 // A valid response would be an F packet\r
71 return -1;\r
72 }\r
73\r
74 RetCode = AsciiStrHexToUintn (&Packet[1]);\r
75\r
76 // Find 1st comma\r
77 for ( ; *Packet != '\0' && *Packet != ','; Packet++) {\r
78 }\r
79\r
80 if (*Packet == '\0') {\r
81 *ErrNo = 0;\r
82 return RetCode;\r
83 }\r
84\r
85 *ErrNo = AsciiStrHexToUintn (++Packet);\r
86\r
87 // Find 2nd comma\r
88 for ( ; *Packet != '\0' && *Packet != ','; Packet++) {\r
89 }\r
90\r
91 if (*Packet == '\0') {\r
92 return RetCode;\r
93 }\r
94\r
95 if (*(++Packet) == 'C') {\r
96 GdbCtrlCBreakMessage (*ErrNo);\r
97 }\r
98\r
99 return RetCode;\r
100}\r
101\r
102/**\r
103 Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates\r
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
108 @param Count Number of bytes to transfer.\r
109\r
110 @retval -1 Error\r
111 @retval {other} Number of bytes read.\r
112\r
113**/\r
114INTN\r
115GdbRead (\r
116 IN INTN FileDescriptor,\r
117 OUT VOID *Buffer,\r
118 IN UINTN Count\r
119 )\r
120{\r
121 CHAR8 Packet[128];\r
122 UINTN Size;\r
123 INTN RetCode;\r
124 UINTN ErrNo;\r
125 BOOLEAN ReceiveDone = FALSE;\r
126\r
127 // Send:\r
128 // "Fread,XX,YYYYYYYY,XX\r
129 //\r
130 // XX - FileDescriptor in ASCII\r
131 // YYYYYYYY - Buffer address in ASCII\r
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
138\r
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
150 // Write memory command.\r
151 // M addr,length:XX...\r
152 case 'M':\r
153 WriteToMemory (Packet);\r
154 break;\r
155\r
156 // Fretcode, errno, Ctrl-C flag\r
157 // retcode - Count read\r
158 case 'F':\r
159 // Once target receives F reply packet that means the previous\r
160 // transactions are finished.\r
161 ReceiveDone = TRUE;\r
162 break;\r
163\r
164 // Send empty buffer\r
165 default:\r
166 SendNotSupported ();\r
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
173\r
174 if (ErrNo > 0) {\r
175 // Send error to the host if there is any.\r
176 SendError ((UINT8)ErrNo);\r
177 }\r
178\r
179 gProcessingFPacket = FALSE;\r
180\r
181 return RetCode;\r
182}\r
183\r
184/**\r
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
187\r
188 @param FileDescriptor Device to talk to.\r
189 @param Buffer Buffer to hold Count bytes that are to be written\r
190 @param Count Number of bytes to transfer.\r
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
213 // YYYYYYYY - Buffer address in ASCII\r
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
220\r
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
232 // m addr,length.\r
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
240 // Once target receives F reply packet that means the previous\r
241 // transactions are finished.\r
242 ReceiveDone = TRUE;\r
243 break;\r
244\r
245 // Send empty buffer\r
246 default:\r
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
259\r
260 return RetCode;\r
261}\r
262\r
263/**\r
264 Reset the serial device.\r
265\r
266 @param This Protocol instance pointer.\r
267\r
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
281/**\r
282 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,\r
283 data buts, and stop bits on a serial device.\r
284\r
285 @param This Protocol instance pointer.\r
286 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the\r
287 device's default interface speed.\r
288 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the\r
289 serial interface. A ReceiveFifoDepth value of 0 will use\r
290 the device's default FIFO depth.\r
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
298 value of 0 will use the device's default data bit setting.\r
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
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
343/**\r
344 Retrieves the status of the control bits on a serial device\r
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
348\r
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
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
385 UINTN Return;\r
386\r
387 SerialDev = GDB_SERIAL_DEV_FROM_THIS (This);\r
388\r
389 Return = GdbWrite (SerialDev->OutFileDescriptor, Buffer, *BufferSize);\r
390 if (Return == (UINTN)-1) {\r
391 return EFI_DEVICE_ERROR;\r
392 }\r
393\r
394 if (Return != *BufferSize) {\r
395 *BufferSize = Return;\r
396 }\r
397\r
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
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
423 UINTN Return;\r
424\r
425 SerialDev = GDB_SERIAL_DEV_FROM_THIS (This);\r
426\r
427 Return = GdbRead (SerialDev->InFileDescriptor, Buffer, *BufferSize);\r
428 if (Return == (UINTN)-1) {\r
429 return EFI_DEVICE_ERROR;\r
430 }\r
431\r
432 if (Return != *BufferSize) {\r
433 *BufferSize = Return;\r
434 }\r
435\r
436 return EFI_SUCCESS;\r
437}\r
438\r
439//\r
440// Template used to initialize the GDB Serial IO protocols\r
441//\r
442GDB_SERIAL_DEV gdbSerialDevTemplate = {\r
443 GDB_SERIAL_DEV_SIGNATURE,\r
444 NULL,\r
445\r
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
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
464 },\r
465 {\r
466 {\r
467 {\r
468 HARDWARE_DEVICE_PATH,\r
469 HW_VENDOR_DP,\r
470 {\r
471 (UINT8)(sizeof (VENDOR_DEVICE_PATH) + sizeof (UINT32)),\r
472 (UINT8)((sizeof (VENDOR_DEVICE_PATH) + sizeof (UINT32)) >> 8)\r
473 },\r
474 },\r
475 EFI_SERIAL_IO_PROTOCOL_GUID\r
476 },\r
477 0,\r
478 {\r
479 END_DEVICE_PATH_TYPE,\r
480 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
481 {\r
482 (UINT8)(sizeof (EFI_DEVICE_PATH_PROTOCOL)),\r
483 (UINT8)(sizeof (EFI_DEVICE_PATH_PROTOCOL) >> 8)\r
484 }\r
485 },\r
486 },\r
487 GDB_STDIN,\r
488 GDB_STDOUT\r
489};\r
490\r
491/**\r
492 Make two serial consoles: 1) StdIn and StdOut via GDB. 2) StdErr via GDB.\r
493\r
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
507 StdOutSerialDev = AllocateCopyPool (sizeof (GDB_SERIAL_DEV), &gdbSerialDevTemplate);\r
508 ASSERT (StdOutSerialDev != NULL);\r
509\r
510 // Fixup pointer after the copy\r
511 StdOutSerialDev->SerialIo.Mode = &StdOutSerialDev->SerialMode;\r
512\r
513 StdErrSerialDev = AllocateCopyPool (sizeof (GDB_SERIAL_DEV), &gdbSerialDevTemplate);\r
514 ASSERT (StdErrSerialDev != NULL);\r
515\r
516 // Fixup pointer and modify stuff that is different for StdError\r
517 StdErrSerialDev->SerialIo.Mode = &StdErrSerialDev->SerialMode;\r
518 StdErrSerialDev->DevicePath.Index = 1;\r
519 StdErrSerialDev->OutFileDescriptor = GDB_STDERR;\r
520\r
521 // Make a new handle with Serial IO protocol and its device path on it.\r
522 Status = gBS->InstallMultipleProtocolInterfaces (\r
523 &StdOutSerialDev->Handle,\r
524 &gEfiSerialIoProtocolGuid,\r
525 &StdOutSerialDev->SerialIo,\r
526 &gEfiDevicePathProtocolGuid,\r
527 &StdOutSerialDev->DevicePath,\r
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
534 &StdErrSerialDev->Handle,\r
535 &gEfiSerialIoProtocolGuid,\r
536 &StdErrSerialDev->SerialIo,\r
537 &gEfiDevicePathProtocolGuid,\r
538 &StdErrSerialDev->DevicePath,\r
539 NULL\r
540 );\r
541 ASSERT_EFI_ERROR (Status);\r
542}\r