Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1261 lines
34 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. port.c
  5. Abstract:
  6. This modules implements com port code to support reading/writing from com ports.
  7. Author:
  8. Allen M. Kay (allen.m.kay@intel.com) 27-Jan-2000
  9. Revision History:
  10. --*/
  11. #include "bldr.h"
  12. #include "string.h"
  13. #include "stdlib.h"
  14. #include "stdio.h"
  15. #include "ntverp.h"
  16. #include "efi.h"
  17. #include "efip.h"
  18. #include "bldria64.h"
  19. #include "acpitabl.h"
  20. #include "extern.h"
  21. #if DBG
  22. extern EFI_SYSTEM_TABLE *EfiST;
  23. #define DBG_TRACE(_X) EfiST->ConOut->OutputString(EfiST->ConOut, (_X))
  24. #else
  25. #define DBG_TRACE(_X)
  26. #endif // for FORCE_CD_BOOT
  27. //
  28. // Headless boot defines
  29. //
  30. ULONG BlTerminalDeviceId = 0;
  31. BOOLEAN BlTerminalConnected = FALSE;
  32. ULONG BlTerminalDelay = 0;
  33. HEADLESS_LOADER_BLOCK LoaderRedirectionInformation;
  34. //
  35. // Define COM Port registers.
  36. //
  37. #define COM_DAT 0x00
  38. #define COM_IEN 0x01 // interrupt enable register
  39. #define COM_LCR 0x03 // line control registers
  40. #define COM_MCR 0x04 // modem control reg
  41. #define COM_LSR 0x05 // line status register
  42. #define COM_MSR 0x06 // modem status register
  43. #define COM_DLL 0x00 // divisor latch least sig
  44. #define COM_DLM 0x01 // divisor latch most sig
  45. #define COM_BI 0x10
  46. #define COM_FE 0x08
  47. #define COM_PE 0x04
  48. #define COM_OE 0x02
  49. #define LC_DLAB 0x80 // divisor latch access bit
  50. #define CLOCK_RATE 0x1C200 // USART clock rate
  51. #define MC_DTRRTS 0x03 // Control bits to assert DTR and RTS
  52. #define MS_DSRCTSCD 0xB0 // Status bits for DSR, CTS and CD
  53. #define MS_CD 0x80
  54. #define COM_OUTRDY 0x20
  55. #define COM_DATRDY 0x01
  56. //
  57. // Define Serial IO Protocol
  58. //
  59. EFI_GUID EfiSerialIoProtocol = SERIAL_IO_PROTOCOL;
  60. SERIAL_IO_INTERFACE *SerialIoInterface;
  61. //
  62. // Define debugger port initial state.
  63. //
  64. typedef struct _CPPORT {
  65. PUCHAR Address;
  66. ULONG Baud;
  67. USHORT Flags;
  68. } CPPORT, *PCPPORT;
  69. #define PORT_DEFAULTRATE 0x0001 // baud rate not specified, using default
  70. #define PORT_MODEMCONTROL 0x0002 // using modem controls
  71. CPPORT Port[4] = {
  72. {NULL, 0, PORT_DEFAULTRATE},
  73. {NULL, 0, PORT_DEFAULTRATE},
  74. {NULL, 0, PORT_DEFAULTRATE},
  75. {NULL, 0, PORT_DEFAULTRATE}
  76. };
  77. //
  78. // This is how we find table information from
  79. // the ACPI table index.
  80. //
  81. extern PDESCRIPTION_HEADER
  82. BlFindACPITable(
  83. IN PCHAR TableName,
  84. IN ULONG TableLength
  85. );
  86. LOGICAL
  87. BlRetrieveBIOSRedirectionInformation(
  88. VOID
  89. )
  90. /*++
  91. Routine Description:
  92. This functions retrieves the COM port information from the ACPI
  93. table.
  94. Arguments:
  95. We'll be filling in the LoaderRedirectionInformation structure.
  96. Returned Value:
  97. TRUE - If a debug port is found.
  98. --*/
  99. {
  100. PDEBUG_PORT_TABLE pPortTable = NULL;
  101. LOGICAL ReturnValue = FALSE;
  102. LOGICAL FoundIt = FALSE;
  103. EFI_DEVICE_PATH *DevicePath = NULL;
  104. EFI_DEVICE_PATH *RootDevicePath = NULL;
  105. EFI_DEVICE_PATH *StartOfDevicePath = NULL;
  106. EFI_STATUS Status = EFI_UNSUPPORTED;
  107. ACPI_HID_DEVICE_PATH *AcpiDevicePath;
  108. UART_DEVICE_PATH *UartDevicePath;
  109. EFI_DEVICE_PATH_ALIGNED DevicePathAligned;
  110. UINTN reqd;
  111. EFI_GUID EfiGlobalVariable = EFI_GLOBAL_VARIABLE;
  112. PUCHAR CurrentAddress = NULL;
  113. UCHAR Checksum;
  114. ULONG i;
  115. ULONG CheckLength;
  116. pPortTable = (PDEBUG_PORT_TABLE)BlFindACPITable( "SPCR",
  117. sizeof(DEBUG_PORT_TABLE) );
  118. if( pPortTable ) {
  119. //
  120. // generate a checksum for later validation.
  121. //
  122. CurrentAddress = (PUCHAR)pPortTable;
  123. CheckLength = pPortTable->Header.Length;
  124. Checksum = 0;
  125. for( i = 0; i < CheckLength; i++ ) {
  126. Checksum += CurrentAddress[i];
  127. }
  128. if(
  129. // checksum is okay?
  130. (Checksum == 0) &&
  131. // device address defined?
  132. ((UCHAR UNALIGNED *)pPortTable->BaseAddress.Address.QuadPart != (UCHAR *)NULL) &&
  133. // he better be in system or memory I/O
  134. // note: 0 - systemI/O
  135. // 1 - memory mapped I/O
  136. ((pPortTable->BaseAddress.AddressSpaceID == 0) ||
  137. (pPortTable->BaseAddress.AddressSpaceID == 1))
  138. ) {
  139. if( pPortTable->BaseAddress.AddressSpaceID == 0 ) {
  140. LoaderRedirectionInformation.IsMMIODevice = TRUE;
  141. } else {
  142. LoaderRedirectionInformation.IsMMIODevice = FALSE;
  143. }
  144. //
  145. // We got the table. Now dig out the information we want.
  146. // See definitiion of DEBUG_PORT_TABLE (acpitabl.h)
  147. //
  148. LoaderRedirectionInformation.UsedBiosSettings = TRUE;
  149. LoaderRedirectionInformation.PortNumber = 3;
  150. LoaderRedirectionInformation.PortAddress = (UCHAR UNALIGNED *)(pPortTable->BaseAddress.Address.QuadPart);
  151. if( pPortTable->BaudRate == 7 ) {
  152. LoaderRedirectionInformation.BaudRate = BD_115200;
  153. } else if( pPortTable->BaudRate == 6 ) {
  154. LoaderRedirectionInformation.BaudRate = BD_57600;
  155. } else if( pPortTable->BaudRate == 4 ) {
  156. LoaderRedirectionInformation.BaudRate = BD_19200;
  157. } else {
  158. LoaderRedirectionInformation.BaudRate = BD_9600;
  159. }
  160. LoaderRedirectionInformation.Parity = pPortTable->Parity;
  161. LoaderRedirectionInformation.StopBits = pPortTable->StopBits;
  162. LoaderRedirectionInformation.TerminalType = pPortTable->TerminalType;
  163. //
  164. // If this is a new DEBUG_PORT_TABLE, then it's got the PCI device
  165. // information.
  166. //
  167. if( pPortTable->Header.Length >= sizeof(DEBUG_PORT_TABLE) ) {
  168. LoaderRedirectionInformation.PciDeviceId = *((USHORT UNALIGNED *)(&pPortTable->PciDeviceId));
  169. LoaderRedirectionInformation.PciVendorId = *((USHORT UNALIGNED *)(&pPortTable->PciVendorId));
  170. LoaderRedirectionInformation.PciBusNumber = (UCHAR)pPortTable->PciBusNumber;
  171. LoaderRedirectionInformation.PciSlotNumber = (UCHAR)pPortTable->PciSlotNumber;
  172. LoaderRedirectionInformation.PciFunctionNumber = (UCHAR)pPortTable->PciFunctionNumber;
  173. LoaderRedirectionInformation.PciFlags = *((ULONG UNALIGNED *)(&pPortTable->PciFlags));
  174. } else {
  175. //
  176. // There's no PCI device information in this table.
  177. //
  178. LoaderRedirectionInformation.PciDeviceId = (USHORT)0xFFFF;
  179. LoaderRedirectionInformation.PciVendorId = (USHORT)0xFFFF;
  180. LoaderRedirectionInformation.PciBusNumber = 0;
  181. LoaderRedirectionInformation.PciSlotNumber = 0;
  182. LoaderRedirectionInformation.PciFunctionNumber = 0;
  183. LoaderRedirectionInformation.PciFlags = 0;
  184. }
  185. return TRUE;
  186. }
  187. }
  188. //
  189. // We didn't get anything from the ACPI table. Look
  190. // for the ConsoleOutHandle and see if someone configured
  191. // the EFI firmware to redirect. If so, we can pickup
  192. // those settings and carry them forward.
  193. //
  194. //
  195. // EFI requires all calls in physical mode.
  196. //
  197. FlipToPhysical();
  198. DBG_TRACE( L"BlRetrieveBIOSRedirectionInformation: didn't find SPCR table\r\n");
  199. FoundIt = FALSE;
  200. //
  201. // Get the CONSOLE Device Paths.
  202. //
  203. reqd = 0;
  204. Status = EfiST->RuntimeServices->GetVariable(
  205. L"ConOut",
  206. &EfiGlobalVariable,
  207. NULL,
  208. &reqd,
  209. NULL );
  210. if( Status == EFI_BUFFER_TOO_SMALL ) {
  211. DBG_TRACE( L"BlRetrieveBIOSRedirectionInformation: GetVariable(ConOut) success\r\n");
  212. #ifndef DONT_USE_EFI_MEMORY
  213. Status = EfiBS->AllocatePool(
  214. EfiLoaderData,
  215. reqd,
  216. (VOID **) &StartOfDevicePath);
  217. if( Status != EFI_SUCCESS ) {
  218. WCHAR DebugBuffer[120];
  219. wsprintf( DebugBuffer, L"BlRetreiveBIOSRedirectionInformation: AllocatePool returned (%x)\r\n", Status );
  220. DBG_TRACE( DebugBuffer );
  221. StartOfDevicePath = NULL;
  222. }
  223. #else
  224. //
  225. // go back to virtual mode to allocate some memory
  226. //
  227. FlipToVirtual();
  228. StartOfDevicePath = BlAllocateHeapAligned( (ULONG)reqd );
  229. if( StartOfDevicePath ) {
  230. //
  231. // convert the address into a physical address
  232. //
  233. StartOfDevicePath = (EFI_DEVICE_PATH *) ((ULONGLONG)StartOfDevicePath & ~KSEG0_BASE);
  234. }
  235. //
  236. // go back into physical mode
  237. //
  238. FlipToPhysical();
  239. #endif
  240. if (StartOfDevicePath) {
  241. DBG_TRACE( L"BlRetrieveBIOSRedirectionInformation: allocated pool for variable\r\n");
  242. Status = EfiST->RuntimeServices->GetVariable(
  243. L"ConOut",
  244. &EfiGlobalVariable,
  245. NULL,
  246. &reqd,
  247. (VOID *)StartOfDevicePath);
  248. DBG_TRACE( L"BlRetrieveBIOSRedirectionInformation: GetVariable returned\r\n");
  249. } else {
  250. DBG_TRACE( L"BlRetrieveBIOSRedirectionInformation: Failed to allocate memory for CONOUT variable.\r\n");
  251. }
  252. } else {
  253. WCHAR DebugBuffer[120];
  254. wsprintf( DebugBuffer, L"BlRetreiveBIOSRedirectionInformation: GetVariable returned (%x)\r\n", Status );
  255. DBG_TRACE( DebugBuffer );
  256. Status = EFI_BAD_BUFFER_SIZE;
  257. }
  258. if( !EFI_ERROR(Status) ) {
  259. DBG_TRACE( L"BlRetrieveBIOSRedirectionInformation: retrieved ConOut successfully\r\n");
  260. //
  261. // Preserve StartOfDevicePath so we can free the memory later.
  262. //
  263. DevicePath = StartOfDevicePath;
  264. EfiAlignDp(&DevicePathAligned,
  265. DevicePath,
  266. DevicePathNodeLength(DevicePath));
  267. //
  268. // Keep looking until we get to the end of the entire Device Path.
  269. //
  270. while( !((DevicePathAligned.DevPath.Type == END_DEVICE_PATH_TYPE) &&
  271. (DevicePathAligned.DevPath.SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)) &&
  272. (!FoundIt) ) {
  273. //
  274. // Remember the address he's holding. This is the root
  275. // of this device path and we may need to look at this
  276. // guy again if down the path we find a UART.
  277. //
  278. RootDevicePath = DevicePath;
  279. //
  280. // Keep looking until we get to the end of this subpath.
  281. //
  282. while( !((DevicePathAligned.DevPath.Type == END_DEVICE_PATH_TYPE) &&
  283. ((DevicePathAligned.DevPath.SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) ||
  284. (DevicePathAligned.DevPath.SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE))) ) {
  285. if( (DevicePathAligned.DevPath.Type == MESSAGING_DEVICE_PATH) &&
  286. (DevicePathAligned.DevPath.SubType == MSG_UART_DP) &&
  287. (FoundIt == FALSE) ) {
  288. //
  289. // We got a UART. Pickup the settings.
  290. //
  291. UartDevicePath = (UART_DEVICE_PATH *)&DevicePathAligned;
  292. LoaderRedirectionInformation.BaudRate = (ULONG)UartDevicePath->BaudRate;
  293. LoaderRedirectionInformation.Parity = (BOOLEAN)UartDevicePath->Parity;
  294. LoaderRedirectionInformation.StopBits = (UCHAR)UartDevicePath->StopBits;
  295. //
  296. // Fixup BaudRate if necessary. If it's 0, then we're
  297. // supposed to use the default for this h/w. We're going
  298. // to override to 9600 though.
  299. //
  300. if( LoaderRedirectionInformation.BaudRate == 0 ) {
  301. LoaderRedirectionInformation.BaudRate = BD_9600;
  302. }
  303. if( LoaderRedirectionInformation.BaudRate > BD_115200 ) {
  304. LoaderRedirectionInformation.BaudRate = BD_115200;
  305. }
  306. DBG_TRACE(L"BlRetrieveBIOSRedirectionInformation: found a UART\r\n");
  307. //
  308. // Remember that we found a UART and quit searching.
  309. //
  310. FoundIt = TRUE;
  311. }
  312. if( (FoundIt == TRUE) && // we already found a UART, so we're on the right track.
  313. (DevicePathAligned.DevPath.Type == MESSAGING_DEVICE_PATH) &&
  314. (DevicePathAligned.DevPath.SubType == MSG_VENDOR_DP) ) {
  315. VENDOR_DEVICE_PATH *VendorDevicePath = (VENDOR_DEVICE_PATH *)&DevicePathAligned;
  316. EFI_GUID PcAnsiGuid = DEVICE_PATH_MESSAGING_PC_ANSI;
  317. //
  318. // See if the UART is a VT100 or ANSI or whatever.
  319. //
  320. if( memcmp( &VendorDevicePath->Guid, &PcAnsiGuid, sizeof(EFI_GUID)) == 0 ) {
  321. LoaderRedirectionInformation.TerminalType = 3;
  322. } else {
  323. // Default to VT100
  324. LoaderRedirectionInformation.TerminalType = 0;
  325. }
  326. }
  327. //
  328. // Get the next structure in our packed array.
  329. //
  330. DevicePath = NextDevicePathNode( DevicePath );
  331. EfiAlignDp(&DevicePathAligned,
  332. DevicePath,
  333. DevicePathNodeLength(DevicePath));
  334. }
  335. //
  336. // Do we need to keep going? Check to make sure we're not at the
  337. // end of the entire packed array of device paths.
  338. //
  339. if( !((DevicePathAligned.DevPath.Type == END_DEVICE_PATH_TYPE) &&
  340. (DevicePathAligned.DevPath.SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)) ) {
  341. //
  342. // Yes. Get the next entry.
  343. //
  344. DevicePath = NextDevicePathNode( DevicePath );
  345. EfiAlignDp(&DevicePathAligned,
  346. DevicePath,
  347. DevicePathNodeLength(DevicePath));
  348. }
  349. }
  350. } else {
  351. DBG_TRACE( L"BlRetrieveBIOSRedirectionInformation: failed to get CONOUT variable\r\n");
  352. }
  353. if( FoundIt ) {
  354. //
  355. // We found a UART, but we were already too far down the list
  356. // in the device map to get the address, which is really what
  357. // we're after. Start looking at the device map again from the
  358. // root of the path where we found the UART.
  359. //
  360. DevicePath = RootDevicePath;
  361. //
  362. // Reset this guy so we'll know if we found a reasonable
  363. // ACPI_DEVICE_PATH entry.
  364. //
  365. FoundIt = FALSE;
  366. EfiAlignDp(&DevicePathAligned,
  367. RootDevicePath,
  368. DevicePathNodeLength(DevicePath));
  369. //
  370. // Keep looking until we get to the end, or until we run
  371. // into our UART again.
  372. //
  373. while( (DevicePathAligned.DevPath.Type != END_DEVICE_PATH_TYPE) &&
  374. (!FoundIt) ) {
  375. if( DevicePathAligned.DevPath.Type == ACPI_DEVICE_PATH ) {
  376. //
  377. // Remember the address he's holding.
  378. //
  379. AcpiDevicePath = (ACPI_HID_DEVICE_PATH *)&DevicePathAligned;
  380. if( AcpiDevicePath->UID ) {
  381. LoaderRedirectionInformation.PortAddress = (PUCHAR)ULongToPtr(AcpiDevicePath->UID);
  382. LoaderRedirectionInformation.PortNumber = 3;
  383. FoundIt = TRUE;
  384. }
  385. }
  386. //
  387. // Get the next structure in our packed array.
  388. //
  389. DevicePath = NextDevicePathNode( DevicePath );
  390. EfiAlignDp(&DevicePathAligned,
  391. DevicePath,
  392. DevicePathNodeLength(DevicePath));
  393. }
  394. }
  395. if( FoundIt ) {
  396. DBG_TRACE( L"BlRetrieveBIOSRedirectionInformation: returning TRUE\r\n");
  397. ReturnValue = TRUE;
  398. }
  399. #ifndef DONT_USE_EFI_MEMORY
  400. //
  401. // Free the memory we allocated for StartOfDevicePath.
  402. //
  403. if( StartOfDevicePath != NULL ) {
  404. EfiBS->FreePool( (VOID *)StartOfDevicePath );
  405. }
  406. #endif
  407. //
  408. // Restore the processor to virtual mode.
  409. //
  410. FlipToVirtual();
  411. return( ReturnValue );
  412. }
  413. LOGICAL
  414. BlPortInitialize(
  415. IN ULONG BaudRate,
  416. IN ULONG PortNumber,
  417. IN PUCHAR PortAddress OPTIONAL,
  418. IN BOOLEAN ReInitialize,
  419. OUT PULONG BlFileId
  420. )
  421. /*++
  422. Routine Description:
  423. This functions initializes the com port.
  424. Arguments:
  425. BaudRate - Supplies an optional baud rate.
  426. PortNumber - supplies an optinal port number.
  427. ReInitialize - Set to TRUE if we already have this port open, but for some
  428. reason need to completely reset the port. Otw it should be FALSE.
  429. BlFileId - A place to store a fake file Id, if successful.
  430. Returned Value:
  431. TRUE - If a debug port is found, and BlFileId will point to a location within Port[].
  432. --*/
  433. {
  434. UCHAR DebugMessage[80];
  435. LOGICAL Found = FALSE;
  436. ULONG HandleCount;
  437. EFI_HANDLE *SerialIoHandles;
  438. EFI_HANDLE DeviceHandle = NULL;
  439. EFI_DEVICE_PATH *DevicePath;
  440. EFI_DEVICE_PATH_ALIGNED DevicePathAligned;
  441. ACPI_HID_DEVICE_PATH *AcpiDevicePath;
  442. ULONG i;
  443. ULONG Control;
  444. EFI_STATUS Status;
  445. ARC_STATUS ArcStatus;
  446. ArcStatus = BlGetEfiProtocolHandles(
  447. &EfiSerialIoProtocol,
  448. &SerialIoHandles,
  449. &HandleCount
  450. );
  451. if (ArcStatus != ESUCCESS) {
  452. return FALSE;
  453. }
  454. //
  455. // If the baud rate is not specified, then default the baud rate to 19.2.
  456. //
  457. if (BaudRate == 0) {
  458. BaudRate = BD_19200;
  459. }
  460. //
  461. // If the user didn't send us a port address, then
  462. // guess based on the COM port number.
  463. //
  464. if( PortAddress == 0 ) {
  465. switch (PortNumber) {
  466. case 1:
  467. PortAddress = (PUCHAR)COM1_PORT;
  468. break;
  469. case 2:
  470. PortAddress = (PUCHAR)COM2_PORT;
  471. break;
  472. case 3:
  473. PortAddress = (PUCHAR)COM3_PORT;
  474. break;
  475. default:
  476. PortNumber = 4;
  477. PortAddress = (PUCHAR)COM4_PORT;
  478. }
  479. }
  480. //
  481. // EFI requires all calls in physical mode.
  482. //
  483. FlipToPhysical();
  484. //
  485. // Get the device path
  486. //
  487. for (i = 0; i < HandleCount; i++) {
  488. DBG_TRACE( L"About to HandleProtocol\r\n");
  489. Status = EfiBS->HandleProtocol (
  490. SerialIoHandles[i],
  491. &EfiDevicePathProtocol,
  492. &DevicePath
  493. );
  494. if (EFI_ERROR(Status)) {
  495. DBG_TRACE( L"HandleProtocol failed\r\n");
  496. Found = FALSE;
  497. goto e0;
  498. }
  499. EfiAlignDp(&DevicePathAligned,
  500. DevicePath,
  501. DevicePathNodeLength(DevicePath));
  502. AcpiDevicePath = (ACPI_HID_DEVICE_PATH *) &DevicePathAligned;
  503. if (PortNumber = 0) {
  504. Found = TRUE;
  505. break;
  506. } else if (AcpiDevicePath->UID == PtrToUlong(PortAddress)) {
  507. Found = TRUE;
  508. break;
  509. }
  510. }
  511. if (Found == TRUE) {
  512. DBG_TRACE( L"found the port device\r\n");
  513. //
  514. // Check if the port is already in use, and this is a first init.
  515. //
  516. if (!ReInitialize && (Port[PortNumber].Address != NULL)) {
  517. DBG_TRACE( L"found the port device but it's already in use\r\n");
  518. Found = FALSE;
  519. goto e0;
  520. }
  521. //
  522. // Check if someone tries to reinit a port that is not open.
  523. //
  524. if (ReInitialize && (Port[PortNumber].Address == NULL)) {
  525. DBG_TRACE( L"found the port device but we're reinitializing a port that hasn't been opened\r\n");
  526. Found = FALSE;
  527. goto e0;
  528. }
  529. DBG_TRACE( L"about to HandleProtocol for SerialIO\r\n");
  530. //
  531. // Get the interface for the serial IO protocol.
  532. //
  533. Status = EfiBS->HandleProtocol(SerialIoHandles[i],
  534. &EfiSerialIoProtocol,
  535. &SerialIoInterface
  536. );
  537. if (EFI_ERROR(Status)) {
  538. DBG_TRACE( L"HandleProtocol for SerialIO failed\r\n");
  539. Found = FALSE;
  540. goto e0;
  541. }
  542. Status = SerialIoInterface->SetAttributes(SerialIoInterface,
  543. BaudRate,
  544. 0,
  545. 0,
  546. DefaultParity,
  547. 0,
  548. DefaultStopBits
  549. );
  550. if (EFI_ERROR(Status)) {
  551. DBG_TRACE( L"SerialIO: SetAttributes failed\r\n");
  552. Found = FALSE;
  553. goto e0;
  554. }
  555. Control = EFI_SERIAL_DATA_TERMINAL_READY | EFI_SERIAL_CLEAR_TO_SEND;
  556. Status = SerialIoInterface->SetControl(SerialIoInterface,
  557. Control
  558. );
  559. if (EFI_ERROR(Status)) {
  560. DBG_TRACE( L"SerialIO: SetControl failed\r\n");
  561. Found = FALSE;
  562. goto e0;
  563. }
  564. } else {
  565. DBG_TRACE( L"didn't find a port device\r\n");
  566. Found = FALSE;
  567. goto e0;
  568. }
  569. //
  570. // Initialize Port[] structure.
  571. //
  572. Port[PortNumber].Address = PortAddress;
  573. Port[PortNumber].Baud = BaudRate;
  574. *BlFileId = PortNumber;
  575. DBG_TRACE( L"success, we're done.\r\n");
  576. e0:
  577. //
  578. // Restore the processor to virtual mode.
  579. //
  580. FlipToVirtual();
  581. BlFreeDescriptor( (ULONG)((ULONGLONG)SerialIoHandles >> PAGE_SHIFT) );
  582. return Found;
  583. }
  584. VOID
  585. BlInitializeHeadlessPort(
  586. VOID
  587. )
  588. /*++
  589. Routine Description:
  590. Does x86-specific initialization of a dumb terminal connected to a serial port. Currently,
  591. it assumes baud rate and com port are pre-initialized, but this can be changed in the future
  592. by reading the values from boot.ini or someplace.
  593. Arguments:
  594. None.
  595. Return Value:
  596. None.
  597. --*/
  598. {
  599. UINTN reqd;
  600. EFI_GUID EfiGlobalVariable = EFI_GLOBAL_VARIABLE;
  601. EFI_STATUS Status = EFI_UNSUPPORTED;
  602. if( (LoaderRedirectionInformation.PortNumber == 0) ||
  603. !(LoaderRedirectionInformation.PortAddress) ) {
  604. //
  605. // This means that no one has filled in the LoaderRedirectionInformation
  606. // structure, which means that we aren't redirecting right now.
  607. // See if the BIOS was redirecting. If so, pick up those settings
  608. // and use them.
  609. //
  610. BlRetrieveBIOSRedirectionInformation();
  611. if( LoaderRedirectionInformation.PortNumber ) {
  612. //
  613. // We don't need to even bother telling anyone else in the
  614. // loader that we're going to need to redirect because if
  615. // EFI is redirecting, then the loader will be redirecting (as
  616. // it's just an EFI app).
  617. //
  618. BlTerminalConnected = FALSE;
  619. //
  620. // We really need to make sure there's an address associated with
  621. // this port and not just a port number.
  622. //
  623. if( LoaderRedirectionInformation.PortAddress == NULL ) {
  624. switch( LoaderRedirectionInformation.PortNumber ) {
  625. case 4:
  626. LoaderRedirectionInformation.PortAddress = (PUCHAR)COM4_PORT;
  627. break;
  628. case 3:
  629. LoaderRedirectionInformation.PortAddress = (PUCHAR)COM3_PORT;
  630. break;
  631. case 2:
  632. LoaderRedirectionInformation.PortAddress = (PUCHAR)COM2_PORT;
  633. break;
  634. case 1:
  635. default:
  636. LoaderRedirectionInformation.PortAddress = (PUCHAR)COM1_PORT;
  637. break;
  638. }
  639. }
  640. //
  641. // Load in the machine's GUID
  642. //
  643. FlipToPhysical();
  644. reqd = sizeof(GUID);
  645. Status = EfiST->RuntimeServices->GetVariable( L"SystemGUID",
  646. &EfiGlobalVariable,
  647. NULL,
  648. &reqd,
  649. (VOID *)&LoaderRedirectionInformation.SystemGUID);
  650. FlipToVirtual();
  651. } else {
  652. BlTerminalConnected = FALSE;
  653. }
  654. }
  655. }
  656. LOGICAL
  657. BlTerminalAttached(
  658. IN ULONG DeviceId
  659. )
  660. /*++
  661. Routine Description:
  662. This routine will attempt to discover if a terminal is attached.
  663. Arguments:
  664. DeviceId - Value returned by BlPortInitialize()
  665. Return Value:
  666. TRUE - Port seems to have something attached.
  667. FALSE - Port doesn't seem to have anything attached.
  668. --*/
  669. {
  670. ULONG Control;
  671. ULONG Flags;
  672. EFI_STATUS Status;
  673. BOOLEAN ReturnValue;
  674. //
  675. // EFI requires all calls in physical mode.
  676. //
  677. FlipToPhysical();
  678. Status = SerialIoInterface->GetControl(SerialIoInterface,
  679. &Control
  680. );
  681. if (EFI_ERROR(Status)) {
  682. FlipToVirtual();
  683. return FALSE;
  684. }
  685. Flags = EFI_SERIAL_DATA_SET_READY |
  686. EFI_SERIAL_CLEAR_TO_SEND |
  687. EFI_SERIAL_CARRIER_DETECT;
  688. ReturnValue = ((Control & Flags) == Flags);
  689. //
  690. // Restore the processor to virtual mode.
  691. //
  692. FlipToVirtual();
  693. return ReturnValue;
  694. }
  695. VOID
  696. BlSetHeadlessRestartBlock(
  697. IN PTFTP_RESTART_BLOCK RestartBlock
  698. )
  699. /*++
  700. Routine Description:
  701. This routine will fill in the areas of the restart block that are appropriate
  702. for the headless server effort.
  703. Arguments:
  704. RestartBlock - The magic structure for holding restart information from oschoice
  705. to setupldr.
  706. Return Value:
  707. None.
  708. --*/
  709. {
  710. if( LoaderRedirectionInformation.PortNumber ) {
  711. RestartBlock->HeadlessUsedBiosSettings = (ULONG)LoaderRedirectionInformation.UsedBiosSettings;
  712. RestartBlock->HeadlessPortNumber = (ULONG)LoaderRedirectionInformation.PortNumber;
  713. RestartBlock->HeadlessPortAddress = (PUCHAR)LoaderRedirectionInformation.PortAddress;
  714. RestartBlock->HeadlessBaudRate = (ULONG)LoaderRedirectionInformation.BaudRate;
  715. RestartBlock->HeadlessParity = (ULONG)LoaderRedirectionInformation.Parity;
  716. RestartBlock->HeadlessStopBits = (ULONG)LoaderRedirectionInformation.StopBits;
  717. RestartBlock->HeadlessTerminalType = (ULONG)LoaderRedirectionInformation.TerminalType;
  718. RestartBlock->HeadlessPciDeviceId = LoaderRedirectionInformation.PciDeviceId;
  719. RestartBlock->HeadlessPciVendorId = LoaderRedirectionInformation.PciVendorId;
  720. RestartBlock->HeadlessPciBusNumber = LoaderRedirectionInformation.PciBusNumber;
  721. RestartBlock->HeadlessPciSlotNumber = LoaderRedirectionInformation.PciSlotNumber;
  722. RestartBlock->HeadlessPciFunctionNumber = LoaderRedirectionInformation.PciFunctionNumber;
  723. RestartBlock->HeadlessPciFlags = LoaderRedirectionInformation.PciFlags;
  724. }
  725. }
  726. VOID
  727. BlGetHeadlessRestartBlock(
  728. IN PTFTP_RESTART_BLOCK RestartBlock,
  729. IN BOOLEAN RestartBlockValid
  730. )
  731. /*++
  732. Routine Description:
  733. This routine will get all the information from a restart block
  734. for the headless server effort.
  735. Arguments:
  736. RestartBlock - The magic structure for holding restart information from oschoice
  737. to setupldr.
  738. RestartBlockValid - Is this block valid (full of good info)?
  739. Return Value:
  740. None.
  741. --*/
  742. {
  743. LoaderRedirectionInformation.UsedBiosSettings = (BOOLEAN)RestartBlock->HeadlessUsedBiosSettings;
  744. LoaderRedirectionInformation.DataBits = 0;
  745. LoaderRedirectionInformation.StopBits = (UCHAR)RestartBlock->HeadlessStopBits;
  746. LoaderRedirectionInformation.Parity = (BOOLEAN)RestartBlock->HeadlessParity;
  747. LoaderRedirectionInformation.BaudRate = (ULONG)RestartBlock->HeadlessBaudRate;;
  748. LoaderRedirectionInformation.PortNumber = (ULONG)RestartBlock->HeadlessPortNumber;
  749. LoaderRedirectionInformation.PortAddress = (PUCHAR)RestartBlock->HeadlessPortAddress;
  750. LoaderRedirectionInformation.TerminalType = (UCHAR)RestartBlock->HeadlessTerminalType;
  751. LoaderRedirectionInformation.PciDeviceId = (USHORT)RestartBlock->HeadlessPciDeviceId;
  752. LoaderRedirectionInformation.PciVendorId = (USHORT)RestartBlock->HeadlessPciVendorId;
  753. LoaderRedirectionInformation.PciBusNumber = (UCHAR)RestartBlock->HeadlessPciBusNumber;
  754. LoaderRedirectionInformation.PciSlotNumber = (UCHAR)RestartBlock->HeadlessPciSlotNumber;
  755. LoaderRedirectionInformation.PciFunctionNumber = (UCHAR)RestartBlock->HeadlessPciFunctionNumber;
  756. LoaderRedirectionInformation.PciFlags = (ULONG)RestartBlock->HeadlessPciFlags;
  757. }
  758. ULONG
  759. BlPortGetByte (
  760. IN ULONG BlFileId,
  761. OUT PUCHAR Input
  762. )
  763. /*++
  764. Routine Description:
  765. Fetch a byte from the port and return it.
  766. Arguments:
  767. BlFileId - The port to read from.
  768. Input - Returns the data byte.
  769. Return Value:
  770. CP_GET_SUCCESS is returned if a byte is successfully read from the
  771. kernel debugger line.
  772. CP_GET_ERROR is returned if error encountered during reading.
  773. CP_GET_NODATA is returned if timeout.
  774. --*/
  775. {
  776. ULONGLONG BufferSize = 1;
  777. EFI_STATUS Status;
  778. //
  779. // EFI requires all calls in physical mode.
  780. //
  781. FlipToPhysical();
  782. Status = SerialIoInterface->Read(SerialIoInterface,
  783. &BufferSize,
  784. Input
  785. );
  786. //
  787. // Restore the processor to virtual mode.
  788. //
  789. FlipToVirtual();
  790. switch (Status) {
  791. case EFI_SUCCESS:
  792. return CP_GET_SUCCESS;
  793. case EFI_TIMEOUT:
  794. return CP_GET_NODATA;
  795. default:
  796. return CP_GET_ERROR;
  797. }
  798. }
  799. VOID
  800. BlPortPutByte (
  801. IN ULONG BlFileId,
  802. IN UCHAR Output
  803. )
  804. /*++
  805. Routine Description:
  806. Write a byte to the port.
  807. Arguments:
  808. BlFileId - The port to write to.
  809. Output - Supplies the output data byte.
  810. Return Value:
  811. None.
  812. --*/
  813. {
  814. ULONGLONG BufferSize = 1;
  815. ULONG Control;
  816. EFI_STATUS Status;
  817. //
  818. // EFI requires all calls in physical mode.
  819. //
  820. FlipToPhysical();
  821. Status = SerialIoInterface->Write(SerialIoInterface,
  822. &BufferSize,
  823. &Output
  824. );
  825. //
  826. // Restore the processor to virtual mode.
  827. //
  828. FlipToVirtual();
  829. }
  830. ULONG
  831. BlPortPollByte (
  832. IN ULONG BlFileId,
  833. OUT PUCHAR Input
  834. )
  835. /*++
  836. Routine Description:
  837. Fetch a byte from the port and return it if one is available.
  838. Arguments:
  839. BlFileId - The port to poll.
  840. Input - Returns the data byte.
  841. Return Value:
  842. CP_GET_SUCCESS is returned if a byte is successfully read.
  843. CP_GET_ERROR is returned if error encountered during reading.
  844. CP_GET_NODATA is returned if timeout.
  845. --*/
  846. {
  847. ULONGLONG BufferSize = 1;
  848. ULONG Control;
  849. EFI_STATUS Status;
  850. //
  851. // EFI requires all calls in physical mode.
  852. //
  853. FlipToPhysical();
  854. Status = SerialIoInterface->GetControl(SerialIoInterface,
  855. &Control
  856. );
  857. if (EFI_ERROR(Status)) {
  858. FlipToVirtual();
  859. return CP_GET_ERROR;
  860. }
  861. if (Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) {
  862. FlipToVirtual();
  863. return CP_GET_NODATA;
  864. } else {
  865. Status = SerialIoInterface->Read(SerialIoInterface,
  866. &BufferSize,
  867. Input
  868. );
  869. FlipToVirtual();
  870. switch (Status) {
  871. case EFI_SUCCESS:
  872. return CP_GET_SUCCESS;
  873. case EFI_TIMEOUT:
  874. return CP_GET_NODATA;
  875. default:
  876. return CP_GET_ERROR;
  877. }
  878. }
  879. }
  880. ULONG
  881. BlPortPollOnly (
  882. IN ULONG BlFileId
  883. )
  884. /*++
  885. Routine Description:
  886. Check if a byte is available
  887. Arguments:
  888. BlFileId - The port to poll.
  889. Return Value:
  890. CP_GET_SUCCESS is returned if a byte is ready.
  891. CP_GET_ERROR is returned if error encountered.
  892. CP_GET_NODATA is returned if timeout.
  893. --*/
  894. {
  895. EFI_STATUS Status;
  896. ULONG Control;
  897. ULONG RetVal;
  898. //
  899. // EFI requires all calls in physical mode.
  900. //
  901. FlipToPhysical();
  902. Status = SerialIoInterface->GetControl(SerialIoInterface,
  903. &Control
  904. );
  905. //
  906. // Restore the processor to virtual mode.
  907. //
  908. FlipToVirtual();
  909. switch (Status) {
  910. case EFI_SUCCESS:
  911. if (Control & EFI_SERIAL_INPUT_BUFFER_EMPTY)
  912. return CP_GET_NODATA;
  913. else
  914. return CP_GET_SUCCESS;
  915. case EFI_TIMEOUT:
  916. return CP_GET_NODATA;
  917. default:
  918. return CP_GET_ERROR;
  919. }
  920. }