]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/GdbStub/SerialIo.c
EmbeddedPkg: Fix typos in comments
[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
1e57a462 3 running GDB. One consle for error information and another console for user input/output.\r
3402aac7
RC
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
1e57a462 8\r
9 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
3402aac7 10\r
1e57a462 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
3402aac7 25// here we need to wait for the periodic callback to do this.\r
1e57a462 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
3402aac7
RC
37 Process a control-C break message.\r
38\r
39 Currently a place holder, remove the ASSERT when it gets implemented.\r
1e57a462 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
3402aac7
RC
65 @retval -1 Error, not a valid F reply packet\r
66 @retval other Return the return code from the F reply packet\r
1e57a462 67\r
68**/\r
69INTN\r
70GdbParseFReplyPacket (\r
71 IN CHAR8 *Packet,\r
3402aac7 72 OUT UINTN *ErrNo\r
1e57a462 73 )\r
74{\r
75 INTN RetCode;\r
3402aac7 76\r
1e57a462 77 if (Packet[0] != 'F') {\r
78 // A valid responce would be an F packet\r
79 return -1;\r
80 }\r
3402aac7 81\r
1e57a462 82 RetCode = AsciiStrHexToUintn (&Packet[1]);\r
3402aac7
RC
83\r
84 // Find 1st comma\r
85 for (;*Packet != '\0' && *Packet != ','; Packet++);\r
1e57a462 86 if (*Packet == '\0') {\r
87 *ErrNo = 0;\r
88 return RetCode;\r
89 }\r
3402aac7 90\r
1e57a462 91 *ErrNo = AsciiStrHexToUintn (++Packet);\r
92\r
3402aac7
RC
93 // Find 2nd comma\r
94 for (;*Packet != '\0' && *Packet != ','; Packet++);\r
1e57a462 95 if (*Packet == '\0') {\r
96 return RetCode;\r
97 }\r
3402aac7 98\r
1e57a462 99 if (*(++Packet) == 'C') {\r
3402aac7 100 GdbCtrlCBreakMessage (*ErrNo);\r
1e57a462 101 }\r
3402aac7 102\r
1e57a462 103 return RetCode;\r
104}\r
105\r
106\r
107/**\r
3402aac7 108 Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates\r
1e57a462 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
3402aac7 113 @param Count Number of bytes to transfer.\r
1e57a462 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
3402aac7 131\r
1e57a462 132 // Send:\r
133 // "Fread,XX,YYYYYYYY,XX\r
134 //\r
135 // XX - FileDescriptor in ASCII\r
3402aac7 136 // YYYYYYYY - Buffer address in ASCII\r
1e57a462 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
3402aac7 143\r
1e57a462 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
3402aac7 178\r
1e57a462 179 if (ErrNo > 0) {\r
180 //Send error to the host if there is any.\r
181 SendError ((UINT8)ErrNo);\r
182 }\r
3402aac7 183\r
1e57a462 184 gProcessingFPacket = FALSE;\r
185\r
186 return RetCode;\r
3402aac7
RC
187}\r
188\r
1e57a462 189\r
190/**\r
3402aac7
RC
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
1e57a462 193\r
194 @param FileDescriptor Device to talk to.\r
195 @param Buffer Buffer to hold Count bytes that are to be written\r
3402aac7 196 @param Count Number of bytes to transfer.\r
1e57a462 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
3402aac7 219 // YYYYYYYY - Buffer address in ASCII\r
1e57a462 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
3402aac7 226\r
1e57a462 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
3402aac7 238 //m addr,length.\r
1e57a462 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
3402aac7 246 //Once target receives F reply packet that means the previous\r
1e57a462 247 //transactions are finished.\r
248 ReceiveDone = TRUE;\r
249 break;\r
3402aac7 250\r
1e57a462 251 //Send empty buffer\r
3402aac7 252 default :\r
1e57a462 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
3402aac7 265\r
1e57a462 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
3402aac7 274\r
1e57a462 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
3402aac7 290 Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,\r
1e57a462 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
3402aac7 358\r
1e57a462 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
3402aac7 399\r
1e57a462 400 Return = GdbWrite (SerialDev->OutFileDescriptor, Buffer, *BufferSize);\r
401 if (Return == (UINTN)-1) {\r
402 return EFI_DEVICE_ERROR;\r
403 }\r
3402aac7 404\r
1e57a462 405 if (Return != *BufferSize) {\r
406 *BufferSize = Return;\r
407 }\r
3402aac7 408\r
1e57a462 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
3402aac7 438\r
1e57a462 439 Return = GdbRead (SerialDev->InFileDescriptor, Buffer, *BufferSize);\r
440 if (Return == (UINTN)-1) {\r
441 return EFI_DEVICE_ERROR;\r
442 }\r
3402aac7 443\r
1e57a462 444 if (Return != *BufferSize) {\r
445 *BufferSize = Return;\r
446 }\r
3402aac7 447\r
1e57a462 448 return EFI_SUCCESS;\r
449}\r
450\r
451\r
3402aac7 452//\r
1e57a462 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
3402aac7 458\r
1e57a462 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
3402aac7 507\r
1e57a462 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
3402aac7 523\r
1e57a462 524 // Fixup pointer after the copy\r
525 StdOutSerialDev->SerialIo.Mode = &StdOutSerialDev->SerialMode;\r
3402aac7 526\r
1e57a462 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
3402aac7 531 StdErrSerialDev->SerialIo.Mode = &StdErrSerialDev->SerialMode;\r
1e57a462 532 StdErrSerialDev->DevicePath.Index = 1;\r
533 StdErrSerialDev->OutFileDescriptor = GDB_STDERR;\r
3402aac7 534\r
1e57a462 535 // Make a new handle with Serial IO protocol and its device path on it.\r
536 Status = gBS->InstallMultipleProtocolInterfaces (\r
3402aac7 537 &StdOutSerialDev->Handle,\r
1e57a462 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
3402aac7 546 &StdErrSerialDev->Handle,\r
1e57a462 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