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 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 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 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 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 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 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 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 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 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 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 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