• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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