Leaked source code of windows server 2003
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.

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