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