bdscon.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. bdscon.c
  9. Abstract:
  10. This module implements BDS console support functions.
  11. Author:
  12. Evan Green 17-Mar-2014
  13. Environment:
  14. Firmware
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "ueficore.h"
  20. #include "bds.h"
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // ------------------------------------------------------ Data Type Definitions
  26. //
  27. //
  28. // ----------------------------------------------- Internal Function Prototypes
  29. //
  30. EFI_STATUS
  31. EfipBdsConnectConsoleVariable (
  32. CHAR16 *ConsoleVariableName
  33. );
  34. EFI_STATUS
  35. EfipBdsUpdateConsoleVariable (
  36. CHAR16 *VariableName,
  37. EFI_DEVICE_PATH_PROTOCOL *CustomizedDevicePath,
  38. EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
  39. );
  40. BOOLEAN
  41. EfipBdsUpdateSystemTableConsole (
  42. CHAR16 *VariableName,
  43. EFI_GUID *ConsoleGuid,
  44. EFI_HANDLE *ConsoleHandle,
  45. VOID **ProtocolInterface
  46. );
  47. BOOLEAN
  48. EfipBdsIsConsoleVariableNonVolatile (
  49. CHAR16 *Name
  50. );
  51. //
  52. // -------------------------------------------------------------------- Globals
  53. //
  54. EFI_GUID EfiSimpleTextInputProtocolGuid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
  55. //
  56. // ------------------------------------------------------------------ Functions
  57. //
  58. EFI_STATUS
  59. EfipBdsConnectAllDefaultConsoles (
  60. VOID
  61. )
  62. /*++
  63. Routine Description:
  64. This routine connects the console device based on the console variables.
  65. Arguments:
  66. None.
  67. Return Value:
  68. None.
  69. --*/
  70. {
  71. EFI_STATUS Status;
  72. BOOLEAN SystemTableUpdated;
  73. BOOLEAN Updated;
  74. Status = EfipBdsConnectConsoleVariable(L"ConOut");
  75. if (EFI_ERROR(Status)) {
  76. return Status;
  77. }
  78. EfipBdsConnectConsoleVariable(L"ConIn");
  79. EfipBdsConnectConsoleVariable(L"ErrOut");
  80. SystemTableUpdated = FALSE;
  81. //
  82. // Fill console handles in the system table if no console device is
  83. // assigned.
  84. //
  85. Updated = EfipBdsUpdateSystemTableConsole(
  86. L"ConIn",
  87. &EfiSimpleTextInputProtocolGuid,
  88. &(EfiSystemTable->ConsoleInHandle),
  89. (VOID **)&(EfiSystemTable->ConIn));
  90. if (Updated != FALSE) {
  91. SystemTableUpdated = TRUE;
  92. }
  93. Updated = EfipBdsUpdateSystemTableConsole(
  94. L"ConOut",
  95. &EfiSimpleTextOutputProtocolGuid,
  96. &(EfiSystemTable->ConsoleOutHandle),
  97. (VOID **)&(EfiSystemTable->ConOut));
  98. if (Updated != FALSE) {
  99. SystemTableUpdated = TRUE;
  100. }
  101. Updated = EfipBdsUpdateSystemTableConsole(
  102. L"ErrOut",
  103. &EfiSimpleTextOutputProtocolGuid,
  104. &(EfiSystemTable->StandardErrorHandle),
  105. (VOID **)&(EfiSystemTable->StdErr));
  106. if (Updated != FALSE) {
  107. SystemTableUpdated = TRUE;
  108. }
  109. //
  110. // Recompute the CRC of the system table if it changed.
  111. //
  112. if (SystemTableUpdated != FALSE) {
  113. EfiSystemTable->Hdr.CRC32 = 0;
  114. EfiCalculateCrc32((UINT8 *)(&EfiSystemTable->Hdr),
  115. EfiSystemTable->Hdr.HeaderSize,
  116. &(EfiSystemTable->Hdr.CRC32));
  117. }
  118. return EFI_SUCCESS;
  119. }
  120. //
  121. // --------------------------------------------------------- Internal Functions
  122. //
  123. EFI_STATUS
  124. EfipBdsConnectConsoleVariable (
  125. CHAR16 *ConsoleVariableName
  126. )
  127. /*++
  128. Routine Description:
  129. This routine connects the console device named by the given variable name.
  130. If the device path is multi-instance any any instance is connected, this
  131. routine returns success.
  132. Arguments:
  133. ConsoleVariableName - Supplies a pointer to a string containing the name
  134. of the variable of the console. Valid values are ConIn, ConOut, and
  135. ErrOut.
  136. Return Value:
  137. EFI status code.
  138. --*/
  139. {
  140. BOOLEAN DeviceExists;
  141. EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;
  142. EFI_DEVICE_PATH_PROTOCOL *Instance;
  143. EFI_DEVICE_PATH_PROTOCOL *Next;
  144. UINTN Size;
  145. EFI_DEVICE_PATH_PROTOCOL *StartDevicePath;
  146. EFI_STATUS Status;
  147. UINTN VariableSize;
  148. Status = EFI_SUCCESS;
  149. DeviceExists = FALSE;
  150. StartDevicePath = EfipBdsGetVariable(ConsoleVariableName,
  151. &EfiGlobalVariableGuid,
  152. &VariableSize);
  153. if (StartDevicePath == NULL) {
  154. return EFI_UNSUPPORTED;
  155. }
  156. //
  157. // Loop across every instance in the variable.
  158. //
  159. DevicePathCopy = StartDevicePath;
  160. do {
  161. Instance = EfiCoreGetNextDevicePathInstance(&DevicePathCopy, &Size);
  162. if (Instance == NULL) {
  163. EfiCoreFreePool(StartDevicePath);
  164. return EFI_UNSUPPORTED;
  165. }
  166. Next = Instance;
  167. while (EfiCoreIsDevicePathEndType(Next) == FALSE) {
  168. Next = EfiCoreGetNextDevicePathNode(Next);
  169. }
  170. EfiCoreSetDevicePathEndNode(Next);
  171. //
  172. // This would be the place to check for a USB short form device path
  173. // and connect it directly.
  174. //
  175. Status = EfipBdsConnectDevicePath(Instance);
  176. if (EFI_ERROR(Status)) {
  177. EfipBdsUpdateConsoleVariable(ConsoleVariableName, NULL, Instance);
  178. } else {
  179. DeviceExists = TRUE;
  180. }
  181. EfiCoreFreePool(Instance);
  182. } while (DevicePathCopy != NULL);
  183. EfiCoreFreePool(StartDevicePath);
  184. if (DeviceExists == FALSE) {
  185. return EFI_NOT_FOUND;
  186. }
  187. return EFI_SUCCESS;
  188. }
  189. EFI_STATUS
  190. EfipBdsUpdateConsoleVariable (
  191. CHAR16 *VariableName,
  192. EFI_DEVICE_PATH_PROTOCOL *CustomizedDevicePath,
  193. EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
  194. )
  195. /*++
  196. Routine Description:
  197. This routine updates the console variable, adding or removing a device
  198. path from the variable.
  199. Arguments:
  200. VariableName - Supplies a pointer to a string containing the name of the
  201. variable of the console. Valid values are ConIn, ConOut, and ErrOut.
  202. CustomizedDevicePath - Supplies an optional pointer to the device path to
  203. be added to the variable. This parameter cannot be multi-instance.
  204. ExclusiveDevicePath - Supplies an optional pointer to the device path to
  205. remove from the variable. This cannot be multi-instance.
  206. Return Value:
  207. EFI status code.
  208. --*/
  209. {
  210. UINT32 Attributes;
  211. EFI_DEVICE_PATH_PROTOCOL *Console;
  212. UINTN DevicePathSize;
  213. EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
  214. EFI_DEVICE_PATH_PROTOCOL *OldNewDevicePath;
  215. EFI_STATUS Status;
  216. Console = NULL;
  217. DevicePathSize = 0;
  218. if (CustomizedDevicePath == ExclusiveDevicePath) {
  219. return EFI_UNSUPPORTED;
  220. }
  221. Console = EfipBdsGetVariable(VariableName,
  222. &EfiGlobalVariableGuid,
  223. &DevicePathSize);
  224. NewDevicePath = Console;
  225. //
  226. // If the exclusive device path is part of the variable, delete it.
  227. //
  228. if ((ExclusiveDevicePath != NULL) && (Console != NULL)) {
  229. NewDevicePath = EfipBdsDeletePartialMatchInstance(Console,
  230. ExclusiveDevicePath);
  231. }
  232. //
  233. // Try to append the customized device path.
  234. //
  235. if (CustomizedDevicePath != NULL) {
  236. if (EfipBdsMatchDevicePaths(NewDevicePath, CustomizedDevicePath) ==
  237. FALSE) {
  238. //
  239. // If there is a part of the customized path in the new device
  240. // path, delete it.
  241. //
  242. NewDevicePath = EfipBdsDeletePartialMatchInstance(
  243. NewDevicePath,
  244. CustomizedDevicePath);
  245. OldNewDevicePath = NewDevicePath;
  246. NewDevicePath = EfiCoreAppendDevicePathInstance(
  247. NewDevicePath,
  248. CustomizedDevicePath);
  249. if (OldNewDevicePath != NULL) {
  250. EfiCoreFreePool(OldNewDevicePath);
  251. }
  252. }
  253. }
  254. //
  255. // The attributes for ConInDev, ConOutDev, and ErrOutDev is not
  256. // non-volatile.
  257. //
  258. Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
  259. EFI_VARIABLE_RUNTIME_ACCESS;
  260. if (EfipBdsIsConsoleVariableNonVolatile(VariableName) != FALSE) {
  261. Attributes |= EFI_VARIABLE_NON_VOLATILE;
  262. }
  263. //
  264. // Finally, update the variable of the default console.
  265. //
  266. DevicePathSize = EfiCoreGetDevicePathSize(NewDevicePath);
  267. Status = EfiSetVariable(VariableName,
  268. &EfiGlobalVariableGuid,
  269. Attributes,
  270. DevicePathSize,
  271. NewDevicePath);
  272. if ((DevicePathSize == 0) || (Status == EFI_NOT_FOUND)) {
  273. Status = EFI_SUCCESS;
  274. }
  275. ASSERT(!EFI_ERROR(Status));
  276. if (Console != NULL) {
  277. EfiCoreFreePool(Console);
  278. }
  279. if ((Console != NewDevicePath) && (NewDevicePath != NULL)) {
  280. EfiCoreFreePool(NewDevicePath);
  281. }
  282. return Status;
  283. }
  284. BOOLEAN
  285. EfipBdsUpdateSystemTableConsole (
  286. CHAR16 *VariableName,
  287. EFI_GUID *ConsoleGuid,
  288. EFI_HANDLE *ConsoleHandle,
  289. VOID **ProtocolInterface
  290. )
  291. /*++
  292. Routine Description:
  293. This routine fills in the console handle in the system table if there are
  294. no valid console handles.
  295. Arguments:
  296. VariableName - Supplies a pointer to the string containing the standard
  297. console variable name.
  298. ConsoleGuid - Supplies a pointer to the console protocol GUID.
  299. ConsoleHandle - Supplies a pointer that on input points to the console
  300. handle in the system table to be checked. On output, this value may be
  301. updated.
  302. ProtocolInterface - Supplies a pointer that on input points to the console
  303. handle interface in the system table to be checked. On output, this
  304. value may be updated.
  305. Return Value:
  306. TRUE if the system tablw as updated.
  307. FALSE if the table did not change.
  308. --*/
  309. {
  310. EFI_DEVICE_PATH_PROTOCOL *Console;
  311. UINTN DevicePathSize;
  312. EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
  313. EFI_DEVICE_PATH_PROTOCOL *Instance;
  314. VOID *Interface;
  315. BOOLEAN IsTextOut;
  316. EFI_HANDLE NewHandle;
  317. EFI_STATUS Status;
  318. EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
  319. ASSERT((VariableName != NULL) && (ConsoleHandle != NULL) &&
  320. (ConsoleGuid != NULL) && (ProtocolInterface != NULL));
  321. if (*ConsoleHandle != NULL) {
  322. Status = EfiHandleProtocol(*ConsoleHandle,
  323. ConsoleGuid,
  324. &Interface);
  325. if ((Status == EFI_SUCCESS) && (Interface == *ProtocolInterface)) {
  326. return FALSE;
  327. }
  328. }
  329. //
  330. // Get all possible device paths from the variable.
  331. //
  332. Console = EfipBdsGetVariable(VariableName,
  333. &EfiGlobalVariableGuid,
  334. &DevicePathSize);
  335. if (Console == NULL) {
  336. return FALSE;
  337. }
  338. //
  339. // Loop over every instance path in the device path.
  340. //
  341. FullDevicePath = Console;
  342. do {
  343. Instance = EfiCoreGetNextDevicePathInstance(&Console, &DevicePathSize);
  344. if (Instance == NULL) {
  345. EfiCoreFreePool(FullDevicePath);
  346. ASSERT(FALSE);
  347. }
  348. //
  349. // Find the console device handle with the instance.
  350. //
  351. Status = EfiLocateDevicePath(ConsoleGuid, &Instance, &NewHandle);
  352. if (!EFI_ERROR(Status)) {
  353. //
  354. // Get the console protocol on this handle.
  355. //
  356. Status = EfiHandleProtocol(NewHandle, ConsoleGuid, &Interface);
  357. if (!EFI_ERROR(Status)) {
  358. *ConsoleHandle = NewHandle;
  359. *ProtocolInterface = Interface;
  360. //
  361. // If it's a console out device, set the mode if the mode is
  362. // not valid.
  363. //
  364. IsTextOut = EfiCoreCompareGuids(
  365. ConsoleGuid,
  366. &EfiSimpleTextOutputProtocolGuid);
  367. if (IsTextOut != FALSE) {
  368. TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Interface;
  369. if (TextOut->Mode->Mode == -1) {
  370. TextOut->SetMode(TextOut, 0);
  371. }
  372. }
  373. return TRUE;
  374. }
  375. }
  376. } while (Instance != NULL);
  377. //
  378. // No available console device was found.
  379. //
  380. return FALSE;
  381. }
  382. BOOLEAN
  383. EfipBdsIsConsoleVariableNonVolatile (
  384. CHAR16 *Name
  385. )
  386. /*++
  387. Routine Description:
  388. This routine returns whether or not a given console variable name should be
  389. set with the non-volatile flag. If the device ends in Dev, then it returns
  390. FALSE, otherwise it returns TRUE.
  391. Arguments:
  392. Name - Supplies a pointer to the string containing the standard console
  393. variable name.
  394. Return Value:
  395. TRUE if the variable is non-volatile.
  396. FALSE if the variable is volatile.
  397. --*/
  398. {
  399. CHAR16 *Character;
  400. Character = Name;
  401. while (*Character != L'\0') {
  402. Character += 1;
  403. }
  404. if (((INTN)((UINTN)Character - (UINTN)Name) / sizeof(CHAR16)) <= 3) {
  405. return TRUE;
  406. }
  407. if ((*(Character - 3) == L'D') && (*(Character - 2) == L'e') &&
  408. (*(Character - 1) == L'v')) {
  409. return FALSE;
  410. }
  411. return TRUE;
  412. }