SerialIo.c 15 KB

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