LegacyBios.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  1. /** @file
  2. Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include "LegacyBiosInterface.h"
  6. #define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))
  7. //
  8. // define maximum number of HDD system supports
  9. //
  10. #define MAX_HDD_ENTRIES 0x30
  11. //
  12. // Module Global:
  13. // Since this driver will only ever produce one instance of the Private Data
  14. // protocol you are not required to dynamically allocate the PrivateData.
  15. //
  16. LEGACY_BIOS_INSTANCE mPrivateData;
  17. //
  18. // The SMBIOS table in EfiRuntimeServicesData memory
  19. //
  20. VOID *mRuntimeSmbiosEntryPoint = NULL;
  21. //
  22. // The SMBIOS table in EfiReservedMemoryType memory
  23. //
  24. EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint = 0;
  25. EFI_PHYSICAL_ADDRESS mStructureTableAddress = 0;
  26. UINTN mStructureTablePages = 0;
  27. BOOLEAN mEndOfDxe = FALSE;
  28. /**
  29. Allocate memory for legacy usage. The memory is executable.
  30. @param AllocateType The type of allocation to perform.
  31. @param MemoryType The type of memory to allocate.
  32. @param StartPageAddress Start address of range
  33. @param Pages Number of pages to allocate
  34. @param Result Result of allocation
  35. @retval EFI_SUCCESS Legacy memory is allocated successfully.
  36. @retval Other Legacy memory is not allocated.
  37. **/
  38. EFI_STATUS
  39. AllocateLegacyMemory (
  40. IN EFI_ALLOCATE_TYPE AllocateType,
  41. IN EFI_MEMORY_TYPE MemoryType,
  42. IN EFI_PHYSICAL_ADDRESS StartPageAddress,
  43. IN UINTN Pages,
  44. OUT EFI_PHYSICAL_ADDRESS *Result
  45. )
  46. {
  47. EFI_STATUS Status;
  48. EFI_PHYSICAL_ADDRESS MemPage;
  49. EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;
  50. //
  51. // Allocate Pages of memory less <= StartPageAddress
  52. //
  53. MemPage = (EFI_PHYSICAL_ADDRESS)(UINTN)StartPageAddress;
  54. Status = gBS->AllocatePages (
  55. AllocateType,
  56. MemoryType,
  57. Pages,
  58. &MemPage
  59. );
  60. //
  61. // Do not ASSERT on Status error but let caller decide since some cases
  62. // memory is already taken but that is ok.
  63. //
  64. if (!EFI_ERROR (Status)) {
  65. if (MemoryType != EfiBootServicesCode) {
  66. //
  67. // Make sure that the buffer can be used to store code.
  68. //
  69. Status = gDS->GetMemorySpaceDescriptor (MemPage, &MemDesc);
  70. if (!EFI_ERROR (Status) && ((MemDesc.Attributes & EFI_MEMORY_XP) != 0)) {
  71. Status = gDS->SetMemorySpaceAttributes (
  72. MemPage,
  73. EFI_PAGES_TO_SIZE (Pages),
  74. MemDesc.Attributes & (~EFI_MEMORY_XP)
  75. );
  76. }
  77. if (EFI_ERROR (Status)) {
  78. gBS->FreePages (MemPage, Pages);
  79. }
  80. }
  81. }
  82. if (!EFI_ERROR (Status)) {
  83. *Result = (EFI_PHYSICAL_ADDRESS)(UINTN)MemPage;
  84. }
  85. return Status;
  86. }
  87. /**
  88. This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000
  89. 64 KB blocks.
  90. Note: inconsistency with the Framework CSM spec. Per the spec, this function may be
  91. invoked only once. This limitation is relaxed to allow multiple calls in this implementation.
  92. @param This Protocol instance pointer.
  93. @param LegacyMemorySize Size of required region
  94. @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
  95. block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
  96. block
  97. @param Alignment Address alignment. Bit mapped. First non-zero
  98. bit from right is alignment.
  99. @param LegacyMemoryAddress Region Assigned
  100. @retval EFI_SUCCESS Region assigned
  101. @retval EFI_ACCESS_DENIED Procedure previously invoked
  102. @retval Other Region not assigned
  103. **/
  104. EFI_STATUS
  105. EFIAPI
  106. LegacyBiosGetLegacyRegion (
  107. IN EFI_LEGACY_BIOS_PROTOCOL *This,
  108. IN UINTN LegacyMemorySize,
  109. IN UINTN Region,
  110. IN UINTN Alignment,
  111. OUT VOID **LegacyMemoryAddress
  112. )
  113. {
  114. LEGACY_BIOS_INSTANCE *Private;
  115. EFI_IA32_REGISTER_SET Regs;
  116. EFI_STATUS Status;
  117. UINT32 Granularity;
  118. Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
  119. Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
  120. ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
  121. Regs.X.AX = Legacy16GetTableAddress;
  122. Regs.X.BX = (UINT16)Region;
  123. Regs.X.CX = (UINT16)LegacyMemorySize;
  124. Regs.X.DX = (UINT16)Alignment;
  125. Private->LegacyBios.FarCall86 (
  126. &Private->LegacyBios,
  127. Private->Legacy16CallSegment,
  128. Private->Legacy16CallOffset,
  129. &Regs,
  130. NULL,
  131. 0
  132. );
  133. if (Regs.X.AX == 0) {
  134. *LegacyMemoryAddress = (VOID *)(((UINTN)Regs.X.DS << 4) + Regs.X.BX);
  135. Status = EFI_SUCCESS;
  136. } else {
  137. Status = EFI_OUT_OF_RESOURCES;
  138. }
  139. Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
  140. Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
  141. return Status;
  142. }
  143. /**
  144. This function is called when copying data to the region assigned by
  145. EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().
  146. @param This Protocol instance pointer.
  147. @param LegacyMemorySize Size of data to copy
  148. @param LegacyMemoryAddress Legacy Region destination address Note: must
  149. be in region assigned by
  150. LegacyBiosGetLegacyRegion
  151. @param LegacyMemorySourceAddress Source of data
  152. @retval EFI_SUCCESS The data was copied successfully.
  153. @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.
  154. **/
  155. EFI_STATUS
  156. EFIAPI
  157. LegacyBiosCopyLegacyRegion (
  158. IN EFI_LEGACY_BIOS_PROTOCOL *This,
  159. IN UINTN LegacyMemorySize,
  160. IN VOID *LegacyMemoryAddress,
  161. IN VOID *LegacyMemorySourceAddress
  162. )
  163. {
  164. LEGACY_BIOS_INSTANCE *Private;
  165. UINT32 Granularity;
  166. if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000) ||
  167. ((UINTN)LegacyMemoryAddress + LegacyMemorySize > (UINTN)0x100000)
  168. )
  169. {
  170. return EFI_ACCESS_DENIED;
  171. }
  172. //
  173. // There is no protection from writes over lapping if this function is
  174. // called multiple times.
  175. //
  176. Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
  177. Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
  178. CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);
  179. Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
  180. Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
  181. return EFI_SUCCESS;
  182. }
  183. /**
  184. Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
  185. the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
  186. been shadowed.
  187. @param Private Legacy BIOS context data
  188. @retval EFI_SUCCESS Legacy16 code loaded
  189. @retval Other No protocol installed, unload driver.
  190. **/
  191. EFI_STATUS
  192. ShadowAndStartLegacy16 (
  193. IN LEGACY_BIOS_INSTANCE *Private
  194. )
  195. {
  196. EFI_STATUS Status;
  197. UINT8 *Ptr;
  198. UINT8 *PtrEnd;
  199. BOOLEAN Done;
  200. EFI_COMPATIBILITY16_TABLE *Table;
  201. UINT8 CheckSum;
  202. EFI_IA32_REGISTER_SET Regs;
  203. EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
  204. EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
  205. VOID *LegacyBiosImage;
  206. UINTN LegacyBiosImageSize;
  207. UINTN E820Size;
  208. UINT32 *ClearPtr;
  209. BBS_TABLE *BbsTable;
  210. LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;
  211. UINTN Index;
  212. UINT32 TpmPointer;
  213. VOID *TpmBinaryImage;
  214. UINTN TpmBinaryImageSize;
  215. UINTN Location;
  216. UINTN Alignment;
  217. UINTN TempData;
  218. EFI_PHYSICAL_ADDRESS Address;
  219. UINT16 OldMask;
  220. UINT16 NewMask;
  221. UINT32 Granularity;
  222. EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
  223. Location = 0;
  224. Alignment = 0;
  225. //
  226. // we allocate the C/D/E/F segment as RT code so no one will use it any more.
  227. //
  228. Address = 0xC0000;
  229. gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
  230. if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
  231. //
  232. // If it is already reserved, we should be safe, or else we allocate it.
  233. //
  234. Status = gBS->AllocatePages (
  235. AllocateAddress,
  236. EfiRuntimeServicesCode,
  237. 0x40000/EFI_PAGE_SIZE,
  238. &Address
  239. );
  240. if (EFI_ERROR (Status)) {
  241. //
  242. // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.
  243. //
  244. DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));
  245. }
  246. }
  247. //
  248. // start testtest
  249. // GetTimerValue (&Ticker);
  250. //
  251. // gRT->SetVariable (L"StartLegacy",
  252. // &gEfiGlobalVariableGuid,
  253. // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
  254. // sizeof (UINT64),
  255. // (VOID *)&Ticker
  256. // );
  257. // end testtest
  258. //
  259. EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
  260. Status = Private->LegacyBiosPlatform->GetPlatformInfo (
  261. Private->LegacyBiosPlatform,
  262. EfiGetPlatformBinarySystemRom,
  263. &LegacyBiosImage,
  264. &LegacyBiosImageSize,
  265. &Location,
  266. &Alignment,
  267. 0,
  268. 0
  269. );
  270. if (EFI_ERROR (Status)) {
  271. return Status;
  272. }
  273. Private->BiosStart = (UINT32)(0x100000 - LegacyBiosImageSize);
  274. Private->OptionRom = 0xc0000;
  275. Private->LegacyBiosImageSize = (UINT32)LegacyBiosImageSize;
  276. //
  277. // Can only shadow into memory allocated for legacy usage.
  278. //
  279. ASSERT (Private->BiosStart > Private->OptionRom);
  280. //
  281. // Shadow Legacy BIOS. Turn on memory and copy image
  282. //
  283. Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
  284. ClearPtr = (VOID *)((UINTN)0xc0000);
  285. //
  286. // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused
  287. // regions to be used by EMM386 etc.
  288. //
  289. SetMem ((VOID *)ClearPtr, (UINTN)(0x40000 - LegacyBiosImageSize), 0xff);
  290. TempData = Private->BiosStart;
  291. CopyMem (
  292. (VOID *)TempData,
  293. LegacyBiosImage,
  294. (UINTN)LegacyBiosImageSize
  295. );
  296. Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);
  297. //
  298. // Search for Legacy16 table in Shadowed ROM
  299. //
  300. Done = FALSE;
  301. Table = NULL;
  302. for (Ptr = (UINT8 *)TempData; Ptr < (UINT8 *)((UINTN)0x100000) && !Done; Ptr += 0x10) {
  303. if (*(UINT32 *)Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {
  304. Table = (EFI_COMPATIBILITY16_TABLE *)Ptr;
  305. PtrEnd = Ptr + Table->TableLength;
  306. for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {
  307. CheckSum = (UINT8)(CheckSum +*Ptr);
  308. }
  309. Done = TRUE;
  310. }
  311. }
  312. if (Table == NULL) {
  313. DEBUG ((DEBUG_ERROR, "No Legacy16 table found\n"));
  314. return EFI_NOT_FOUND;
  315. }
  316. if (!Done) {
  317. //
  318. // Legacy16 table header checksum error.
  319. //
  320. DEBUG ((DEBUG_ERROR, "Legacy16 table found with bad talbe header checksum\n"));
  321. }
  322. //
  323. // Remember location of the Legacy16 table
  324. //
  325. Private->Legacy16Table = Table;
  326. Private->Legacy16CallSegment = Table->Compatibility16CallSegment;
  327. Private->Legacy16CallOffset = Table->Compatibility16CallOffset;
  328. EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;
  329. Private->Legacy16InitPtr = EfiToLegacy16InitTable;
  330. Private->Legacy16BootPtr = &Private->IntThunk->EfiToLegacy16BootTable;
  331. Private->InternalIrqRoutingTable = NULL;
  332. Private->NumberIrqRoutingEntries = 0;
  333. Private->BbsTablePtr = NULL;
  334. Private->LegacyEfiHddTable = NULL;
  335. Private->DiskEnd = 0;
  336. Private->Disk4075 = 0;
  337. Private->HddTablePtr = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;
  338. Private->NumberHddControllers = MAX_IDE_CONTROLLER;
  339. Private->Dump[0] = 'D';
  340. Private->Dump[1] = 'U';
  341. Private->Dump[2] = 'M';
  342. Private->Dump[3] = 'P';
  343. ZeroMem (
  344. Private->Legacy16BootPtr,
  345. sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)
  346. );
  347. //
  348. // Store away a copy of the EFI System Table
  349. //
  350. Table->EfiSystemTable = (UINT32)(UINTN)gST;
  351. //
  352. // IPF CSM integration -Bug
  353. //
  354. // Construct the Legacy16 boot memory map. This sets up number of
  355. // E820 entries.
  356. //
  357. LegacyBiosBuildE820 (Private, &E820Size);
  358. //
  359. // Initialize BDA and EBDA standard values needed to load Legacy16 code
  360. //
  361. LegacyBiosInitBda (Private);
  362. LegacyBiosInitCmos (Private);
  363. //
  364. // All legacy interrupt should be masked when do initialization work from legacy 16 code.
  365. //
  366. Private->Legacy8259->GetMask (Private->Legacy8259, &OldMask, NULL, NULL, NULL);
  367. NewMask = 0xFFFF;
  368. Private->Legacy8259->SetMask (Private->Legacy8259, &NewMask, NULL, NULL, NULL);
  369. //
  370. // Call into Legacy16 code to do an INIT
  371. //
  372. ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
  373. Regs.X.AX = Legacy16InitializeYourself;
  374. Regs.X.ES = EFI_SEGMENT (*((UINT32 *)&EfiToLegacy16InitTable));
  375. Regs.X.BX = EFI_OFFSET (*((UINT32 *)&EfiToLegacy16InitTable));
  376. Private->LegacyBios.FarCall86 (
  377. &Private->LegacyBios,
  378. Table->Compatibility16CallSegment,
  379. Table->Compatibility16CallOffset,
  380. &Regs,
  381. NULL,
  382. 0
  383. );
  384. //
  385. // Restore original legacy interrupt mask value
  386. //
  387. Private->Legacy8259->SetMask (Private->Legacy8259, &OldMask, NULL, NULL, NULL);
  388. if (Regs.X.AX != 0) {
  389. return EFI_DEVICE_ERROR;
  390. }
  391. //
  392. // start testtest
  393. // GetTimerValue (&Ticker);
  394. //
  395. // gRT->SetVariable (L"BackFromInitYourself",
  396. // &gEfiGlobalVariableGuid,
  397. // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
  398. // sizeof (UINT64),
  399. // (VOID *)&Ticker
  400. // );
  401. // end testtest
  402. //
  403. // Copy E820 table after InitializeYourself is completed
  404. //
  405. ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
  406. Regs.X.AX = Legacy16GetTableAddress;
  407. Regs.X.CX = (UINT16)E820Size;
  408. Regs.X.DX = 1;
  409. Private->LegacyBios.FarCall86 (
  410. &Private->LegacyBios,
  411. Table->Compatibility16CallSegment,
  412. Table->Compatibility16CallOffset,
  413. &Regs,
  414. NULL,
  415. 0
  416. );
  417. Table->E820Pointer = (UINT32)(Regs.X.DS * 16 + Regs.X.BX);
  418. Table->E820Length = (UINT32)E820Size;
  419. if (Regs.X.AX != 0) {
  420. DEBUG ((DEBUG_ERROR, "Legacy16 E820 length insufficient\n"));
  421. } else {
  422. TempData = Table->E820Pointer;
  423. CopyMem ((VOID *)TempData, Private->E820Table, E820Size);
  424. }
  425. //
  426. // Get PnPInstallationCheck Info.
  427. //
  428. Private->PnPInstallationCheckSegment = Table->PnPInstallationCheckSegment;
  429. Private->PnPInstallationCheckOffset = Table->PnPInstallationCheckOffset;
  430. //
  431. // Check if PCI Express is supported. If yes, Save base address.
  432. //
  433. Status = Private->LegacyBiosPlatform->GetPlatformInfo (
  434. Private->LegacyBiosPlatform,
  435. EfiGetPlatformPciExpressBase,
  436. NULL,
  437. NULL,
  438. &Location,
  439. &Alignment,
  440. 0,
  441. 0
  442. );
  443. if (!EFI_ERROR (Status)) {
  444. Private->Legacy16Table->PciExpressBase = (UINT32)Location;
  445. Location = 0;
  446. }
  447. //
  448. // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it
  449. // into, copy it and update pointer to binary image. This needs to be
  450. // done prior to any OPROM for security purposes.
  451. //
  452. Status = Private->LegacyBiosPlatform->GetPlatformInfo (
  453. Private->LegacyBiosPlatform,
  454. EfiGetPlatformBinaryTpmBinary,
  455. &TpmBinaryImage,
  456. &TpmBinaryImageSize,
  457. &Location,
  458. &Alignment,
  459. 0,
  460. 0
  461. );
  462. if (!EFI_ERROR (Status)) {
  463. ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
  464. Regs.X.AX = Legacy16GetTableAddress;
  465. Regs.X.CX = (UINT16)TpmBinaryImageSize;
  466. Regs.X.DX = 1;
  467. Private->LegacyBios.FarCall86 (
  468. &Private->LegacyBios,
  469. Table->Compatibility16CallSegment,
  470. Table->Compatibility16CallOffset,
  471. &Regs,
  472. NULL,
  473. 0
  474. );
  475. TpmPointer = (UINT32)(Regs.X.DS * 16 + Regs.X.BX);
  476. if (Regs.X.AX != 0) {
  477. DEBUG ((DEBUG_ERROR, "TPM cannot be loaded\n"));
  478. } else {
  479. CopyMem ((VOID *)(UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);
  480. Table->TpmSegment = Regs.X.DS;
  481. Table->TpmOffset = Regs.X.BX;
  482. }
  483. }
  484. //
  485. // Lock the Legacy BIOS region
  486. //
  487. Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32)LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);
  488. Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32)LegacyBiosImageSize, &Granularity);
  489. //
  490. // Get the BbsTable from LOW_MEMORY_THUNK
  491. //
  492. BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;
  493. ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));
  494. EfiToLegacy16BootTable->BbsTable = (UINT32)(UINTN)BbsTable;
  495. Private->BbsTablePtr = (VOID *)BbsTable;
  496. //
  497. // Populate entire table with BBS_IGNORE_ENTRY
  498. //
  499. EfiToLegacy16BootTable->NumberBbsEntries = MAX_BBS_ENTRIES;
  500. for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {
  501. BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;
  502. }
  503. //
  504. // Allocate space for Legacy HDD table
  505. //
  506. LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *)AllocateZeroPool ((UINTN)MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));
  507. ASSERT (LegacyEfiHddTable);
  508. Private->LegacyEfiHddTable = LegacyEfiHddTable;
  509. Private->LegacyEfiHddTableIndex = 0x00;
  510. //
  511. // start testtest
  512. // GetTimerValue (&Ticker);
  513. //
  514. // gRT->SetVariable (L"EndOfLoadFv",
  515. // &gEfiGlobalVariableGuid,
  516. // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
  517. // sizeof (UINT64),
  518. // (VOID *)&Ticker
  519. // );
  520. // end testtest
  521. //
  522. return EFI_SUCCESS;
  523. }
  524. /**
  525. Shadow all legacy16 OPROMs that haven't been shadowed.
  526. Warning: Use this with caution. This routine disconnects all EFI
  527. drivers. If used externally then caller must re-connect EFI
  528. drivers.
  529. @param This Protocol instance pointer.
  530. @retval EFI_SUCCESS OPROMs shadowed
  531. **/
  532. EFI_STATUS
  533. EFIAPI
  534. LegacyBiosShadowAllLegacyOproms (
  535. IN EFI_LEGACY_BIOS_PROTOCOL *This
  536. )
  537. {
  538. LEGACY_BIOS_INSTANCE *Private;
  539. //
  540. // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
  541. // EFI_LEGACY16_TABLE *Legacy16Table;
  542. //
  543. Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
  544. //
  545. // LegacyBiosPlatform = Private->LegacyBiosPlatform;
  546. // Legacy16Table = Private->Legacy16Table;
  547. //
  548. // Shadow PCI ROMs. We must do this near the end since this will kick
  549. // of Native EFI drivers that may be needed to collect info for Legacy16
  550. //
  551. // WARNING: PciIo is gone after this call.
  552. //
  553. PciProgramAllInterruptLineRegisters (Private);
  554. PciShadowRoms (Private);
  555. //
  556. // Shadow PXE base code, BIS etc.
  557. //
  558. // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,
  559. // &Private->OptionRom,
  560. // Legacy16Table);
  561. //
  562. return EFI_SUCCESS;
  563. }
  564. /**
  565. Get the PCI BIOS interface version.
  566. @param Private Driver private data.
  567. @return The PCI interface version number in Binary Coded Decimal (BCD) format.
  568. E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00
  569. **/
  570. UINT16
  571. GetPciInterfaceVersion (
  572. IN LEGACY_BIOS_INSTANCE *Private
  573. )
  574. {
  575. EFI_IA32_REGISTER_SET Reg;
  576. BOOLEAN ThunkFailed;
  577. UINT16 PciInterfaceVersion;
  578. PciInterfaceVersion = 0;
  579. Reg.X.AX = 0xB101;
  580. Reg.E.EDI = 0;
  581. ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);
  582. if (!ThunkFailed) {
  583. //
  584. // From PCI Firmware 3.0 Specification:
  585. // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the
  586. // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the
  587. // presence of the PCI function set. [BX] will further indicate the version level, with enough
  588. // granularity to allow for incremental changes in the code that don't affect the function interface.
  589. // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10
  590. // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.
  591. //
  592. if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {
  593. PciInterfaceVersion = Reg.X.BX;
  594. }
  595. }
  596. return PciInterfaceVersion;
  597. }
  598. /**
  599. Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table.
  600. SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path.
  601. @param Event Event whose notification function is being invoked.
  602. @param Context The pointer to the notification function's context,
  603. which is implementation-dependent.
  604. **/
  605. VOID
  606. EFIAPI
  607. InstallSmbiosEventCallback (
  608. IN EFI_EVENT Event,
  609. IN VOID *Context
  610. )
  611. {
  612. EFI_STATUS Status;
  613. SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure;
  614. //
  615. // Get SMBIOS table from EFI configuration table
  616. //
  617. Status = EfiGetSystemConfigurationTable (
  618. &gEfiSmbiosTableGuid,
  619. &mRuntimeSmbiosEntryPoint
  620. );
  621. if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) {
  622. return;
  623. }
  624. EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)mRuntimeSmbiosEntryPoint;
  625. //
  626. // Allocate memory for SMBIOS Entry Point Structure.
  627. // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE.
  628. //
  629. if (mReserveSmbiosEntryPoint == 0) {
  630. //
  631. // Entrypoint structure with fixed size is allocated only once.
  632. //
  633. mReserveSmbiosEntryPoint = SIZE_4GB - 1;
  634. Status = gBS->AllocatePages (
  635. AllocateMaxAddress,
  636. EfiReservedMemoryType,
  637. EFI_SIZE_TO_PAGES ((UINTN)(EntryPointStructure->EntryPointLength)),
  638. &mReserveSmbiosEntryPoint
  639. );
  640. if (EFI_ERROR (Status)) {
  641. mReserveSmbiosEntryPoint = 0;
  642. return;
  643. }
  644. DEBUG ((DEBUG_INFO, "Allocate memory for Smbios Entry Point Structure\n"));
  645. }
  646. if ((mStructureTableAddress != 0) &&
  647. (mStructureTablePages < EFI_SIZE_TO_PAGES ((UINT32)EntryPointStructure->TableLength)))
  648. {
  649. //
  650. // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate
  651. //
  652. gBS->FreePages (mStructureTableAddress, mStructureTablePages);
  653. mStructureTableAddress = 0;
  654. mStructureTablePages = 0;
  655. DEBUG ((DEBUG_INFO, "Original size is not enough. Re-allocate the memory.\n"));
  656. }
  657. if (mStructureTableAddress == 0) {
  658. //
  659. // Allocate reserved memory below 4GB.
  660. // Smbios spec requires the structure table is below 4GB.
  661. //
  662. mStructureTableAddress = SIZE_4GB - 1;
  663. mStructureTablePages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);
  664. Status = gBS->AllocatePages (
  665. AllocateMaxAddress,
  666. EfiReservedMemoryType,
  667. mStructureTablePages,
  668. &mStructureTableAddress
  669. );
  670. if (EFI_ERROR (Status)) {
  671. gBS->FreePages (
  672. mReserveSmbiosEntryPoint,
  673. EFI_SIZE_TO_PAGES ((UINTN)(EntryPointStructure->EntryPointLength))
  674. );
  675. mReserveSmbiosEntryPoint = 0;
  676. mStructureTableAddress = 0;
  677. mStructureTablePages = 0;
  678. return;
  679. }
  680. DEBUG ((DEBUG_INFO, "Allocate memory for Smbios Structure Table\n"));
  681. }
  682. }
  683. /**
  684. Callback function to toggle EndOfDxe status. NULL pointer detection needs
  685. this status to decide if it's necessary to change attributes of page 0.
  686. @param Event Event whose notification function is being invoked.
  687. @param Context The pointer to the notification function's context,
  688. which is implementation-dependent.
  689. **/
  690. VOID
  691. EFIAPI
  692. ToggleEndOfDxeStatus (
  693. IN EFI_EVENT Event,
  694. IN VOID *Context
  695. )
  696. {
  697. mEndOfDxe = TRUE;
  698. return;
  699. }
  700. /**
  701. Install Driver to produce Legacy BIOS protocol.
  702. @param ImageHandle Handle of driver image.
  703. @param SystemTable Pointer to system table.
  704. @retval EFI_SUCCESS Legacy BIOS protocol installed
  705. @retval No protocol installed, unload driver.
  706. **/
  707. EFI_STATUS
  708. EFIAPI
  709. LegacyBiosInstall (
  710. IN EFI_HANDLE ImageHandle,
  711. IN EFI_SYSTEM_TABLE *SystemTable
  712. )
  713. {
  714. EFI_STATUS Status;
  715. LEGACY_BIOS_INSTANCE *Private;
  716. EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
  717. EFI_PHYSICAL_ADDRESS MemoryAddress;
  718. EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress;
  719. VOID *MemoryPtr;
  720. EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB;
  721. UINTN Index;
  722. UINT32 *BaseVectorMaster;
  723. EFI_PHYSICAL_ADDRESS StartAddress;
  724. UINT32 *ClearPtr;
  725. EFI_PHYSICAL_ADDRESS MemStart;
  726. UINT32 IntRedirCode;
  727. UINT32 Granularity;
  728. BOOLEAN DecodeOn;
  729. UINT32 MemorySize;
  730. EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
  731. UINT64 Length;
  732. UINT8 *SecureBoot;
  733. EFI_EVENT InstallSmbiosEvent;
  734. EFI_EVENT EndOfDxeEvent;
  735. //
  736. // Load this driver's image to memory
  737. //
  738. Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);
  739. if (EFI_ERROR (Status)) {
  740. return Status;
  741. }
  742. //
  743. // When UEFI Secure Boot is enabled, CSM module will not start any more.
  744. //
  745. SecureBoot = NULL;
  746. GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID **)&SecureBoot, NULL);
  747. if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) {
  748. FreePool (SecureBoot);
  749. return EFI_SECURITY_VIOLATION;
  750. }
  751. if (SecureBoot != NULL) {
  752. FreePool (SecureBoot);
  753. }
  754. Private = &mPrivateData;
  755. ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));
  756. //
  757. // Grab a copy of all the protocols we depend on. Any error would
  758. // be a dispatcher bug!.
  759. //
  760. Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Private->Cpu);
  761. ASSERT_EFI_ERROR (Status);
  762. Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **)&Private->Timer);
  763. ASSERT_EFI_ERROR (Status);
  764. Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **)&Private->LegacyRegion);
  765. ASSERT_EFI_ERROR (Status);
  766. Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **)&Private->LegacyBiosPlatform);
  767. ASSERT_EFI_ERROR (Status);
  768. Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **)&Private->Legacy8259);
  769. ASSERT_EFI_ERROR (Status);
  770. Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **)&Private->LegacyInterrupt);
  771. ASSERT_EFI_ERROR (Status);
  772. //
  773. // Locate Memory Test Protocol if exists
  774. //
  775. Status = gBS->LocateProtocol (
  776. &gEfiGenericMemTestProtocolGuid,
  777. NULL,
  778. (VOID **)&Private->GenericMemoryTest
  779. );
  780. ASSERT_EFI_ERROR (Status);
  781. //
  782. // Make sure all memory from 0-640K is tested
  783. //
  784. for (StartAddress = 0; StartAddress < 0xa0000; ) {
  785. gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
  786. if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
  787. StartAddress = Descriptor.BaseAddress + Descriptor.Length;
  788. continue;
  789. }
  790. Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);
  791. Private->GenericMemoryTest->CompatibleRangeTest (
  792. Private->GenericMemoryTest,
  793. StartAddress,
  794. Length
  795. );
  796. StartAddress = StartAddress + Length;
  797. }
  798. //
  799. // Make sure all memory from 1MB to 16MB is tested and added to memory map
  800. //
  801. for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {
  802. gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
  803. if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
  804. StartAddress = Descriptor.BaseAddress + Descriptor.Length;
  805. continue;
  806. }
  807. Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);
  808. Private->GenericMemoryTest->CompatibleRangeTest (
  809. Private->GenericMemoryTest,
  810. StartAddress,
  811. Length
  812. );
  813. StartAddress = StartAddress + Length;
  814. }
  815. Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;
  816. Private->LegacyBios.Int86 = LegacyBiosInt86;
  817. Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;
  818. Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;
  819. Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;
  820. Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;
  821. Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;
  822. Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;
  823. Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;
  824. Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;
  825. Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;
  826. Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;
  827. Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;
  828. Private->ImageHandle = ImageHandle;
  829. //
  830. // Enable read attribute of legacy region.
  831. //
  832. DecodeOn = TRUE;
  833. Private->LegacyRegion->Decode (
  834. Private->LegacyRegion,
  835. 0xc0000,
  836. 0x40000,
  837. &Granularity,
  838. &DecodeOn
  839. );
  840. //
  841. // Set Cachebility for legacy region
  842. // BUGBUG: Comments about this legacy region cacheability setting
  843. // This setting will make D865GCHProduction CSM Unhappy
  844. //
  845. if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {
  846. gDS->SetMemorySpaceAttributes (
  847. 0x0,
  848. 0xA0000,
  849. EFI_MEMORY_WB
  850. );
  851. gDS->SetMemorySpaceAttributes (
  852. 0xc0000,
  853. 0x40000,
  854. EFI_MEMORY_WB
  855. );
  856. }
  857. gDS->SetMemorySpaceAttributes (
  858. 0xA0000,
  859. 0x20000,
  860. EFI_MEMORY_UC
  861. );
  862. //
  863. // Allocate 0 - 4K for real mode interrupt vectors and BDA.
  864. //
  865. AllocateLegacyMemory (
  866. AllocateAddress,
  867. EfiReservedMemoryType,
  868. 0,
  869. 1,
  870. &MemoryAddress
  871. );
  872. ASSERT (MemoryAddress == 0x000000000);
  873. ClearPtr = (VOID *)((UINTN)0x0000);
  874. //
  875. // Initialize region from 0x0000 to 4k. This initializes interrupt vector
  876. // range.
  877. //
  878. ACCESS_PAGE0_CODE (
  879. gBS->SetMem ((VOID *)ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);
  880. ZeroMem ((VOID *)((UINTN)ClearPtr + 0x400), 0xC00);
  881. );
  882. //
  883. // Allocate pages for OPROM usage
  884. //
  885. MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);
  886. ASSERT ((MemorySize & 0xFFF) == 0);
  887. Status = AllocateLegacyMemory (
  888. AllocateAddress,
  889. EfiReservedMemoryType,
  890. CONVENTIONAL_MEMORY_TOP - MemorySize,
  891. EFI_SIZE_TO_PAGES (MemorySize),
  892. &MemoryAddress
  893. );
  894. ASSERT_EFI_ERROR (Status);
  895. ZeroMem ((VOID *)((UINTN)MemoryAddress), MemorySize);
  896. //
  897. // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
  898. // don't use PMM but look for zeroed memory. Note that various non-BBS
  899. // OpROMs expect different areas to be free
  900. //
  901. EbdaReservedBaseAddress = MemoryAddress;
  902. MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase);
  903. MemorySize = PcdGet32 (PcdOpromReservedMemorySize);
  904. //
  905. // Check if base address and size for reserved memory are 4KB aligned.
  906. //
  907. ASSERT ((MemoryAddress & 0xFFF) == 0);
  908. ASSERT ((MemorySize & 0xFFF) == 0);
  909. //
  910. // Check if the reserved memory is below EBDA reserved range.
  911. //
  912. ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress));
  913. for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) {
  914. Status = AllocateLegacyMemory (
  915. AllocateAddress,
  916. EfiBootServicesCode,
  917. MemStart,
  918. 1,
  919. &StartAddress
  920. );
  921. if (!EFI_ERROR (Status)) {
  922. MemoryPtr = (VOID *)((UINTN)StartAddress);
  923. ZeroMem (MemoryPtr, 0x1000);
  924. } else {
  925. DEBUG ((DEBUG_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));
  926. }
  927. }
  928. //
  929. // Allocate low PMM memory and zero it out
  930. //
  931. MemorySize = PcdGet32 (PcdLowPmmMemorySize);
  932. ASSERT ((MemorySize & 0xFFF) == 0);
  933. Status = AllocateLegacyMemory (
  934. AllocateMaxAddress,
  935. EfiBootServicesCode,
  936. CONVENTIONAL_MEMORY_TOP,
  937. EFI_SIZE_TO_PAGES (MemorySize),
  938. &MemoryAddressUnder1MB
  939. );
  940. ASSERT_EFI_ERROR (Status);
  941. ZeroMem ((VOID *)((UINTN)MemoryAddressUnder1MB), MemorySize);
  942. //
  943. // Allocate space for thunker and Init Thunker
  944. //
  945. Status = AllocateLegacyMemory (
  946. AllocateMaxAddress,
  947. EfiReservedMemoryType,
  948. CONVENTIONAL_MEMORY_TOP,
  949. (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,
  950. &MemoryAddress
  951. );
  952. ASSERT_EFI_ERROR (Status);
  953. Private->IntThunk = (LOW_MEMORY_THUNK *)(UINTN)MemoryAddress;
  954. EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;
  955. EfiToLegacy16InitTable->ThunkStart = (UINT32)(EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
  956. EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32)(sizeof (LOW_MEMORY_THUNK));
  957. Status = LegacyBiosInitializeThunk (Private);
  958. ASSERT_EFI_ERROR (Status);
  959. //
  960. // Init the legacy memory map in memory < 1 MB.
  961. //
  962. EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32)MemoryAddressUnder1MB;
  963. EfiToLegacy16InitTable->LowPmmMemory = (UINT32)MemoryAddressUnder1MB;
  964. EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize;
  965. MemorySize = PcdGet32 (PcdHighPmmMemorySize);
  966. ASSERT ((MemorySize & 0xFFF) == 0);
  967. //
  968. // Allocate high PMM Memory under 16 MB
  969. //
  970. Status = AllocateLegacyMemory (
  971. AllocateMaxAddress,
  972. EfiBootServicesCode,
  973. 0x1000000,
  974. EFI_SIZE_TO_PAGES (MemorySize),
  975. &MemoryAddress
  976. );
  977. if (EFI_ERROR (Status)) {
  978. //
  979. // If it fails, allocate high PMM Memory under 4GB
  980. //
  981. Status = AllocateLegacyMemory (
  982. AllocateMaxAddress,
  983. EfiBootServicesCode,
  984. 0xFFFFFFFF,
  985. EFI_SIZE_TO_PAGES (MemorySize),
  986. &MemoryAddress
  987. );
  988. }
  989. if (!EFI_ERROR (Status)) {
  990. EfiToLegacy16InitTable->HiPmmMemory = (UINT32)(EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
  991. EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize;
  992. }
  993. //
  994. // ShutdownAPs();
  995. //
  996. // Start the Legacy BIOS;
  997. //
  998. Status = ShadowAndStartLegacy16 (Private);
  999. if (EFI_ERROR (Status)) {
  1000. return Status;
  1001. }
  1002. //
  1003. // Initialize interrupt redirection code and entries;
  1004. // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
  1005. //
  1006. CopyMem (
  1007. Private->IntThunk->InterruptRedirectionCode,
  1008. (VOID *)(UINTN)InterruptRedirectionTemplate,
  1009. sizeof (Private->IntThunk->InterruptRedirectionCode)
  1010. );
  1011. //
  1012. // Save Unexpected interrupt vector so can restore it just prior to boot
  1013. //
  1014. ACCESS_PAGE0_CODE (
  1015. BaseVectorMaster = (UINT32 *)(sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
  1016. Private->BiosUnexpectedInt = BaseVectorMaster[0];
  1017. IntRedirCode = (UINT32)(UINTN)Private->IntThunk->InterruptRedirectionCode;
  1018. for (Index = 0; Index < 8; Index++) {
  1019. BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);
  1020. }
  1021. );
  1022. //
  1023. // Save EFI value
  1024. //
  1025. Private->ThunkSeg = (UINT16)(EFI_SEGMENT (IntRedirCode));
  1026. //
  1027. // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists
  1028. //
  1029. InstallSmbiosEventCallback (NULL, NULL);
  1030. //
  1031. // Create callback function to update the size of reserved memory after LegacyBiosDxe starts
  1032. //
  1033. Status = gBS->CreateEventEx (
  1034. EVT_NOTIFY_SIGNAL,
  1035. TPL_NOTIFY,
  1036. InstallSmbiosEventCallback,
  1037. NULL,
  1038. &gEfiSmbiosTableGuid,
  1039. &InstallSmbiosEvent
  1040. );
  1041. ASSERT_EFI_ERROR (Status);
  1042. //
  1043. // Create callback to update status of EndOfDxe, which is needed by NULL
  1044. // pointer detection
  1045. //
  1046. Status = gBS->CreateEventEx (
  1047. EVT_NOTIFY_SIGNAL,
  1048. TPL_NOTIFY,
  1049. ToggleEndOfDxeStatus,
  1050. NULL,
  1051. &gEfiEndOfDxeEventGroupGuid,
  1052. &EndOfDxeEvent
  1053. );
  1054. ASSERT_EFI_ERROR (Status);
  1055. //
  1056. // Make a new handle and install the protocol
  1057. //
  1058. Private->Handle = NULL;
  1059. Status = gBS->InstallProtocolInterface (
  1060. &Private->Handle,
  1061. &gEfiLegacyBiosProtocolGuid,
  1062. EFI_NATIVE_INTERFACE,
  1063. &Private->LegacyBios
  1064. );
  1065. Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);
  1066. DEBUG ((
  1067. DEBUG_INFO,
  1068. "CSM16 PCI BIOS Interface Version: %02x.%02x\n",
  1069. (UINT8)(Private->Csm16PciInterfaceVersion >> 8),
  1070. (UINT8)Private->Csm16PciInterfaceVersion
  1071. ));
  1072. ASSERT (Private->Csm16PciInterfaceVersion != 0);
  1073. return Status;
  1074. }