SerialIo.c 15 KB

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