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