PiSmmCore.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  1. /** @file
  2. SMM Core Main Entry Point
  3. Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "PiSmmCore.h"
  7. //
  8. // Physical pointer to private structure shared between SMM IPL and the SMM Core
  9. //
  10. SMM_CORE_PRIVATE_DATA *gSmmCorePrivate;
  11. //
  12. // SMM Core global variable for SMM System Table. Only accessed as a physical structure in SMRAM.
  13. //
  14. EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst = {
  15. {
  16. SMM_SMST_SIGNATURE,
  17. EFI_SMM_SYSTEM_TABLE2_REVISION,
  18. sizeof (gSmmCoreSmst.Hdr)
  19. },
  20. NULL, // SmmFirmwareVendor
  21. 0, // SmmFirmwareRevision
  22. SmmInstallConfigurationTable,
  23. {
  24. {
  25. (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5, // SmmMemRead
  26. (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5 // SmmMemWrite
  27. },
  28. {
  29. (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5, // SmmIoRead
  30. (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5 // SmmIoWrite
  31. }
  32. },
  33. SmmAllocatePool,
  34. SmmFreePool,
  35. SmmAllocatePages,
  36. SmmFreePages,
  37. NULL, // SmmStartupThisAp
  38. 0, // CurrentlyExecutingCpu
  39. 0, // NumberOfCpus
  40. NULL, // CpuSaveStateSize
  41. NULL, // CpuSaveState
  42. 0, // NumberOfTableEntries
  43. NULL, // SmmConfigurationTable
  44. SmmInstallProtocolInterface,
  45. SmmUninstallProtocolInterface,
  46. SmmHandleProtocol,
  47. SmmRegisterProtocolNotify,
  48. SmmLocateHandle,
  49. SmmLocateProtocol,
  50. SmiManage,
  51. SmiHandlerRegister,
  52. SmiHandlerUnRegister
  53. };
  54. //
  55. // Flag to determine if the platform has performed a legacy boot.
  56. // If this flag is TRUE, then the runtime code and runtime data associated with the
  57. // SMM IPL are converted to free memory, so the SMM Core must guarantee that is
  58. // does not touch of the code/data associated with the SMM IPL if this flag is TRUE.
  59. //
  60. BOOLEAN mInLegacyBoot = FALSE;
  61. //
  62. // Flag to determine if it is during S3 resume.
  63. // It will be set in S3 entry callback and cleared at EndOfS3Resume.
  64. //
  65. BOOLEAN mDuringS3Resume = FALSE;
  66. //
  67. // Flag to determine if platform enabled S3.
  68. // Get the value from PcdAcpiS3Enable.
  69. //
  70. BOOLEAN mAcpiS3Enable = FALSE;
  71. //
  72. // Table of SMI Handlers that are registered by the SMM Core when it is initialized
  73. //
  74. SMM_CORE_SMI_HANDLERS mSmmCoreSmiHandlers[] = {
  75. { SmmDriverDispatchHandler, &gEfiEventDxeDispatchGuid, NULL, TRUE },
  76. { SmmReadyToLockHandler, &gEfiDxeSmmReadyToLockProtocolGuid, NULL, TRUE },
  77. { SmmLegacyBootHandler, &gEfiEventLegacyBootGuid, NULL, FALSE },
  78. { SmmExitBootServicesHandler, &gEfiEventExitBootServicesGuid, NULL, FALSE },
  79. { SmmReadyToBootHandler, &gEfiEventReadyToBootGuid, NULL, FALSE },
  80. { SmmEndOfDxeHandler, &gEfiEndOfDxeEventGroupGuid, NULL, TRUE },
  81. { NULL, NULL, NULL, FALSE }
  82. };
  83. //
  84. // Table of SMI Handlers that are registered by the SMM Core when it is initialized
  85. //
  86. SMM_CORE_SMI_HANDLERS mSmmCoreS3SmiHandlers[] = {
  87. { SmmS3SmmInitDoneHandler, &gEdkiiS3SmmInitDoneGuid, NULL, FALSE },
  88. { SmmEndOfS3ResumeHandler, &gEdkiiEndOfS3ResumeGuid, NULL, FALSE },
  89. { NULL, NULL, NULL, FALSE }
  90. };
  91. UINTN mFullSmramRangeCount;
  92. EFI_SMRAM_DESCRIPTOR *mFullSmramRanges;
  93. EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry;
  94. EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage;
  95. /**
  96. Place holder function until all the SMM System Table Service are available.
  97. Note: This function is only used by SMRAM invocation. It is never used by DXE invocation.
  98. @param Arg1 Undefined
  99. @param Arg2 Undefined
  100. @param Arg3 Undefined
  101. @param Arg4 Undefined
  102. @param Arg5 Undefined
  103. @return EFI_NOT_AVAILABLE_YET
  104. **/
  105. EFI_STATUS
  106. EFIAPI
  107. SmmEfiNotAvailableYetArg5 (
  108. UINTN Arg1,
  109. UINTN Arg2,
  110. UINTN Arg3,
  111. UINTN Arg4,
  112. UINTN Arg5
  113. )
  114. {
  115. //
  116. // This function should never be executed. If it does, then the architectural protocols
  117. // have not been designed correctly.
  118. //
  119. return EFI_NOT_AVAILABLE_YET;
  120. }
  121. /**
  122. Software SMI handler that is called when a Legacy Boot event is signalled. The SMM
  123. Core uses this signal to know that a Legacy Boot has been performed and that
  124. gSmmCorePrivate that is shared between the UEFI and SMM execution environments can
  125. not be accessed from SMM anymore since that structure is considered free memory by
  126. a legacy OS. Then the SMM Core also install SMM Legacy Boot protocol to notify SMM
  127. driver that system enter legacy boot.
  128. @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
  129. @param Context Points to an optional handler context which was specified when the handler was registered.
  130. @param CommBuffer A pointer to a collection of data in memory that will
  131. be conveyed from a non-SMM environment into an SMM environment.
  132. @param CommBufferSize The size of the CommBuffer.
  133. @return Status Code
  134. **/
  135. EFI_STATUS
  136. EFIAPI
  137. SmmLegacyBootHandler (
  138. IN EFI_HANDLE DispatchHandle,
  139. IN CONST VOID *Context OPTIONAL,
  140. IN OUT VOID *CommBuffer OPTIONAL,
  141. IN OUT UINTN *CommBufferSize OPTIONAL
  142. )
  143. {
  144. EFI_STATUS Status;
  145. EFI_HANDLE SmmHandle;
  146. UINTN Index;
  147. //
  148. // Install SMM Legacy Boot protocol.
  149. //
  150. SmmHandle = NULL;
  151. Status = SmmInstallProtocolInterface (
  152. &SmmHandle,
  153. &gEdkiiSmmLegacyBootProtocolGuid,
  154. EFI_NATIVE_INTERFACE,
  155. NULL
  156. );
  157. mInLegacyBoot = TRUE;
  158. SmiHandlerUnRegister (DispatchHandle);
  159. //
  160. // It is legacy boot, unregister ExitBootService SMI handler.
  161. //
  162. for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
  163. if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventExitBootServicesGuid)) {
  164. SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);
  165. break;
  166. }
  167. }
  168. return Status;
  169. }
  170. /**
  171. Software SMI handler that is called when an Exit Boot Services event is signalled.
  172. Then the SMM Core also install SMM Exit Boot Services protocol to notify SMM driver
  173. that system enter exit boot services.
  174. @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
  175. @param Context Points to an optional handler context which was specified when the handler was registered.
  176. @param CommBuffer A pointer to a collection of data in memory that will
  177. be conveyed from a non-SMM environment into an SMM environment.
  178. @param CommBufferSize The size of the CommBuffer.
  179. @return Status Code
  180. **/
  181. EFI_STATUS
  182. EFIAPI
  183. SmmExitBootServicesHandler (
  184. IN EFI_HANDLE DispatchHandle,
  185. IN CONST VOID *Context OPTIONAL,
  186. IN OUT VOID *CommBuffer OPTIONAL,
  187. IN OUT UINTN *CommBufferSize OPTIONAL
  188. )
  189. {
  190. EFI_STATUS Status;
  191. EFI_HANDLE SmmHandle;
  192. UINTN Index;
  193. //
  194. // Install SMM Exit Boot Services protocol.
  195. //
  196. SmmHandle = NULL;
  197. Status = SmmInstallProtocolInterface (
  198. &SmmHandle,
  199. &gEdkiiSmmExitBootServicesProtocolGuid,
  200. EFI_NATIVE_INTERFACE,
  201. NULL
  202. );
  203. SmiHandlerUnRegister (DispatchHandle);
  204. //
  205. // It is UEFI boot, unregister LegacyBoot SMI handler.
  206. //
  207. for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
  208. if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventLegacyBootGuid)) {
  209. SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);
  210. break;
  211. }
  212. }
  213. return Status;
  214. }
  215. /**
  216. Main entry point for an SMM handler dispatch or communicate-based callback.
  217. @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
  218. @param[in] Context Points to an optional handler context which was specified when the
  219. handler was registered.
  220. @param[in,out] CommBuffer A pointer to a collection of data in memory that will
  221. be conveyed from a non-SMM environment into an SMM environment.
  222. @param[in,out] CommBufferSize The size of the CommBuffer.
  223. @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
  224. should still be called.
  225. @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
  226. still be called.
  227. @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
  228. be called.
  229. @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
  230. **/
  231. EFI_STATUS
  232. EFIAPI
  233. SmmS3EntryCallBack (
  234. IN EFI_HANDLE DispatchHandle,
  235. IN CONST VOID *Context OPTIONAL,
  236. IN OUT VOID *CommBuffer OPTIONAL,
  237. IN OUT UINTN *CommBufferSize OPTIONAL
  238. )
  239. {
  240. mDuringS3Resume = TRUE;
  241. return EFI_SUCCESS;
  242. }
  243. /**
  244. Software SMI handler that is called when an Ready To Boot event is signalled.
  245. Then the SMM Core also install SMM Ready To Boot protocol to notify SMM driver
  246. that system enter ready to boot.
  247. @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
  248. @param Context Points to an optional handler context which was specified when the handler was registered.
  249. @param CommBuffer A pointer to a collection of data in memory that will
  250. be conveyed from a non-SMM environment into an SMM environment.
  251. @param CommBufferSize The size of the CommBuffer.
  252. @return Status Code
  253. **/
  254. EFI_STATUS
  255. EFIAPI
  256. SmmReadyToBootHandler (
  257. IN EFI_HANDLE DispatchHandle,
  258. IN CONST VOID *Context OPTIONAL,
  259. IN OUT VOID *CommBuffer OPTIONAL,
  260. IN OUT UINTN *CommBufferSize OPTIONAL
  261. )
  262. {
  263. EFI_STATUS Status;
  264. EFI_HANDLE SmmHandle;
  265. //
  266. // Install SMM Ready To Boot protocol.
  267. //
  268. SmmHandle = NULL;
  269. Status = SmmInstallProtocolInterface (
  270. &SmmHandle,
  271. &gEdkiiSmmReadyToBootProtocolGuid,
  272. EFI_NATIVE_INTERFACE,
  273. NULL
  274. );
  275. SmiHandlerUnRegister (DispatchHandle);
  276. return Status;
  277. }
  278. /**
  279. Software SMI handler that is called when the DxeSmmReadyToLock protocol is added
  280. or if gEfiEventReadyToBootGuid is signalled. This function unregisters the
  281. Software SMIs that are nor required after SMRAM is locked and installs the
  282. SMM Ready To Lock Protocol so SMM Drivers are informed that SMRAM is about
  283. to be locked. It also verifies the SMM CPU I/O 2 Protocol has been installed
  284. and NULLs gBS and gST because they can not longer be used after SMRAM is locked.
  285. @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
  286. @param Context Points to an optional handler context which was specified when the handler was registered.
  287. @param CommBuffer A pointer to a collection of data in memory that will
  288. be conveyed from a non-SMM environment into an SMM environment.
  289. @param CommBufferSize The size of the CommBuffer.
  290. @return Status Code
  291. **/
  292. EFI_STATUS
  293. EFIAPI
  294. SmmReadyToLockHandler (
  295. IN EFI_HANDLE DispatchHandle,
  296. IN CONST VOID *Context OPTIONAL,
  297. IN OUT VOID *CommBuffer OPTIONAL,
  298. IN OUT UINTN *CommBufferSize OPTIONAL
  299. )
  300. {
  301. EFI_STATUS Status;
  302. UINTN Index;
  303. EFI_HANDLE SmmHandle;
  304. VOID *Interface;
  305. //
  306. // Unregister SMI Handlers that are no required after the SMM driver dispatch is stopped
  307. //
  308. for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
  309. if (mSmmCoreSmiHandlers[Index].UnRegister) {
  310. SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);
  311. }
  312. }
  313. //
  314. // Install SMM Ready to lock protocol
  315. //
  316. SmmHandle = NULL;
  317. Status = SmmInstallProtocolInterface (
  318. &SmmHandle,
  319. &gEfiSmmReadyToLockProtocolGuid,
  320. EFI_NATIVE_INTERFACE,
  321. NULL
  322. );
  323. //
  324. // Make sure SMM CPU I/O 2 Protocol has been installed into the handle database
  325. //
  326. Status = SmmLocateProtocol (&gEfiSmmCpuIo2ProtocolGuid, NULL, &Interface);
  327. //
  328. // Print a message on a debug build if the SMM CPU I/O 2 Protocol is not installed
  329. //
  330. DEBUG_CODE_BEGIN ();
  331. if (EFI_ERROR (Status)) {
  332. DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
  333. }
  334. DEBUG_CODE_END ();
  335. //
  336. // Assert if the CPU I/O 2 Protocol is not installed
  337. //
  338. ASSERT_EFI_ERROR (Status);
  339. //
  340. // Display any drivers that were not dispatched because dependency expression
  341. // evaluated to false if this is a debug build
  342. //
  343. DEBUG_CODE_BEGIN ();
  344. SmmDisplayDiscoveredNotDispatched ();
  345. DEBUG_CODE_END ();
  346. //
  347. // Not allowed to use gST or gBS after lock
  348. //
  349. gST = NULL;
  350. gBS = NULL;
  351. SmramProfileReadyToLock ();
  352. return Status;
  353. }
  354. /**
  355. Software SMI handler that is called when the EndOfDxe event is signalled.
  356. This function installs the SMM EndOfDxe Protocol so SMM Drivers are informed that
  357. platform code will invoke 3rd part code.
  358. @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
  359. @param Context Points to an optional handler context which was specified when the handler was registered.
  360. @param CommBuffer A pointer to a collection of data in memory that will
  361. be conveyed from a non-SMM environment into an SMM environment.
  362. @param CommBufferSize The size of the CommBuffer.
  363. @return Status Code
  364. **/
  365. EFI_STATUS
  366. EFIAPI
  367. SmmEndOfDxeHandler (
  368. IN EFI_HANDLE DispatchHandle,
  369. IN CONST VOID *Context OPTIONAL,
  370. IN OUT VOID *CommBuffer OPTIONAL,
  371. IN OUT UINTN *CommBufferSize OPTIONAL
  372. )
  373. {
  374. EFI_STATUS Status;
  375. EFI_HANDLE SmmHandle;
  376. EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
  377. EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext;
  378. EFI_HANDLE S3EntryHandle;
  379. DEBUG ((DEBUG_INFO, "SmmEndOfDxeHandler\n"));
  380. //
  381. // Install SMM EndOfDxe protocol
  382. //
  383. SmmHandle = NULL;
  384. Status = SmmInstallProtocolInterface (
  385. &SmmHandle,
  386. &gEfiSmmEndOfDxeProtocolGuid,
  387. EFI_NATIVE_INTERFACE,
  388. NULL
  389. );
  390. if (mAcpiS3Enable) {
  391. //
  392. // Locate SmmSxDispatch2 protocol.
  393. //
  394. Status = SmmLocateProtocol (
  395. &gEfiSmmSxDispatch2ProtocolGuid,
  396. NULL,
  397. (VOID **)&SxDispatch
  398. );
  399. if (!EFI_ERROR (Status) && (SxDispatch != NULL)) {
  400. //
  401. // Register a S3 entry callback function to
  402. // determine if it will be during S3 resume.
  403. //
  404. EntryRegisterContext.Type = SxS3;
  405. EntryRegisterContext.Phase = SxEntry;
  406. Status = SxDispatch->Register (
  407. SxDispatch,
  408. SmmS3EntryCallBack,
  409. &EntryRegisterContext,
  410. &S3EntryHandle
  411. );
  412. ASSERT_EFI_ERROR (Status);
  413. }
  414. }
  415. return EFI_SUCCESS;
  416. }
  417. /**
  418. Software SMI handler that is called when the S3SmmInitDone signal is triggered.
  419. This function installs the SMM S3SmmInitDone Protocol so SMM Drivers are informed that
  420. S3 SMM initialization has been done.
  421. @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
  422. @param Context Points to an optional handler context which was specified when the handler was registered.
  423. @param CommBuffer A pointer to a collection of data in memory that will
  424. be conveyed from a non-SMM environment into an SMM environment.
  425. @param CommBufferSize The size of the CommBuffer.
  426. @return Status Code
  427. **/
  428. EFI_STATUS
  429. EFIAPI
  430. SmmS3SmmInitDoneHandler (
  431. IN EFI_HANDLE DispatchHandle,
  432. IN CONST VOID *Context OPTIONAL,
  433. IN OUT VOID *CommBuffer OPTIONAL,
  434. IN OUT UINTN *CommBufferSize OPTIONAL
  435. )
  436. {
  437. EFI_STATUS Status;
  438. EFI_HANDLE SmmHandle;
  439. DEBUG ((DEBUG_INFO, "SmmS3SmmInitDoneHandler\n"));
  440. if (!mDuringS3Resume) {
  441. DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n"));
  442. return EFI_SUCCESS;
  443. }
  444. //
  445. // Install SMM S3SmmInitDone protocol
  446. //
  447. SmmHandle = NULL;
  448. Status = SmmInstallProtocolInterface (
  449. &SmmHandle,
  450. &gEdkiiS3SmmInitDoneGuid,
  451. EFI_NATIVE_INTERFACE,
  452. NULL
  453. );
  454. ASSERT_EFI_ERROR (Status);
  455. //
  456. // Uninstall the protocol here because the comsumer just hook the
  457. // installation event.
  458. //
  459. Status = SmmUninstallProtocolInterface (
  460. SmmHandle,
  461. &gEdkiiS3SmmInitDoneGuid,
  462. NULL
  463. );
  464. ASSERT_EFI_ERROR (Status);
  465. return Status;
  466. }
  467. /**
  468. Software SMI handler that is called when the EndOfS3Resume signal is triggered.
  469. This function installs the SMM EndOfS3Resume Protocol so SMM Drivers are informed that
  470. S3 resume has finished.
  471. @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
  472. @param Context Points to an optional handler context which was specified when the handler was registered.
  473. @param CommBuffer A pointer to a collection of data in memory that will
  474. be conveyed from a non-SMM environment into an SMM environment.
  475. @param CommBufferSize The size of the CommBuffer.
  476. @return Status Code
  477. **/
  478. EFI_STATUS
  479. EFIAPI
  480. SmmEndOfS3ResumeHandler (
  481. IN EFI_HANDLE DispatchHandle,
  482. IN CONST VOID *Context OPTIONAL,
  483. IN OUT VOID *CommBuffer OPTIONAL,
  484. IN OUT UINTN *CommBufferSize OPTIONAL
  485. )
  486. {
  487. EFI_STATUS Status;
  488. EFI_HANDLE SmmHandle;
  489. DEBUG ((DEBUG_INFO, "SmmEndOfS3ResumeHandler\n"));
  490. if (!mDuringS3Resume) {
  491. DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n"));
  492. return EFI_SUCCESS;
  493. }
  494. //
  495. // Install SMM EndOfS3Resume protocol
  496. //
  497. SmmHandle = NULL;
  498. Status = SmmInstallProtocolInterface (
  499. &SmmHandle,
  500. &gEdkiiEndOfS3ResumeGuid,
  501. EFI_NATIVE_INTERFACE,
  502. NULL
  503. );
  504. ASSERT_EFI_ERROR (Status);
  505. //
  506. // Uninstall the protocol here because the consumer just hook the
  507. // installation event.
  508. //
  509. Status = SmmUninstallProtocolInterface (
  510. SmmHandle,
  511. &gEdkiiEndOfS3ResumeGuid,
  512. NULL
  513. );
  514. ASSERT_EFI_ERROR (Status);
  515. mDuringS3Resume = FALSE;
  516. return Status;
  517. }
  518. /**
  519. Determine if two buffers overlap in memory.
  520. @param[in] Buff1 Pointer to first buffer
  521. @param[in] Size1 Size of Buff1
  522. @param[in] Buff2 Pointer to second buffer
  523. @param[in] Size2 Size of Buff2
  524. @retval TRUE Buffers overlap in memory.
  525. @retval TRUE Math error. Prevents potential math over and underflows.
  526. @retval FALSE Buffer doesn't overlap.
  527. **/
  528. BOOLEAN
  529. InternalIsBufferOverlapped (
  530. IN UINT8 *Buff1,
  531. IN UINTN Size1,
  532. IN UINT8 *Buff2,
  533. IN UINTN Size2
  534. )
  535. {
  536. UINTN End1;
  537. UINTN End2;
  538. BOOLEAN IsOverUnderflow1;
  539. BOOLEAN IsOverUnderflow2;
  540. // Check for over or underflow
  541. IsOverUnderflow1 = EFI_ERROR (SafeUintnAdd ((UINTN)Buff1, Size1, &End1));
  542. IsOverUnderflow2 = EFI_ERROR (SafeUintnAdd ((UINTN)Buff2, Size2, &End2));
  543. if (IsOverUnderflow1 || IsOverUnderflow2) {
  544. return TRUE;
  545. }
  546. //
  547. // If buff1's end is less than the start of buff2, then it's ok.
  548. // Also, if buff1's start is beyond buff2's end, then it's ok.
  549. //
  550. if ((End1 <= (UINTN)Buff2) || ((UINTN)Buff1 >= End2)) {
  551. return FALSE;
  552. }
  553. return TRUE;
  554. }
  555. /**
  556. The main entry point to SMM Foundation.
  557. Note: This function is only used by SMRAM invocation. It is never used by DXE invocation.
  558. @param SmmEntryContext Processor information and functionality
  559. needed by SMM Foundation.
  560. **/
  561. VOID
  562. EFIAPI
  563. SmmEntryPoint (
  564. IN CONST EFI_SMM_ENTRY_CONTEXT *SmmEntryContext
  565. )
  566. {
  567. EFI_STATUS Status;
  568. EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;
  569. BOOLEAN InLegacyBoot;
  570. BOOLEAN IsOverlapped;
  571. BOOLEAN IsOverUnderflow;
  572. VOID *CommunicationBuffer;
  573. UINTN BufferSize;
  574. //
  575. // Update SMST with contents of the SmmEntryContext structure
  576. //
  577. gSmmCoreSmst.SmmStartupThisAp = SmmEntryContext->SmmStartupThisAp;
  578. gSmmCoreSmst.CurrentlyExecutingCpu = SmmEntryContext->CurrentlyExecutingCpu;
  579. gSmmCoreSmst.NumberOfCpus = SmmEntryContext->NumberOfCpus;
  580. gSmmCoreSmst.CpuSaveStateSize = SmmEntryContext->CpuSaveStateSize;
  581. gSmmCoreSmst.CpuSaveState = SmmEntryContext->CpuSaveState;
  582. //
  583. // Call platform hook before Smm Dispatch
  584. //
  585. PlatformHookBeforeSmmDispatch ();
  586. //
  587. // Call memory management hook function
  588. //
  589. SmmEntryPointMemoryManagementHook ();
  590. //
  591. // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed
  592. //
  593. InLegacyBoot = mInLegacyBoot;
  594. if (!InLegacyBoot) {
  595. //
  596. // Mark the InSmm flag as TRUE, it will be used by SmmBase2 protocol
  597. //
  598. gSmmCorePrivate->InSmm = TRUE;
  599. //
  600. // Check to see if this is a Synchronous SMI sent through the SMM Communication
  601. // Protocol or an Asynchronous SMI
  602. //
  603. CommunicationBuffer = gSmmCorePrivate->CommunicationBuffer;
  604. BufferSize = gSmmCorePrivate->BufferSize;
  605. if (CommunicationBuffer != NULL) {
  606. //
  607. // Synchronous SMI for SMM Core or request from Communicate protocol
  608. //
  609. IsOverlapped = InternalIsBufferOverlapped (
  610. (UINT8 *)CommunicationBuffer,
  611. BufferSize,
  612. (UINT8 *)gSmmCorePrivate,
  613. sizeof (*gSmmCorePrivate)
  614. );
  615. //
  616. // Check for over or underflows
  617. //
  618. IsOverUnderflow = EFI_ERROR (SafeUintnSub (BufferSize, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data), &BufferSize));
  619. if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicationBuffer, BufferSize) ||
  620. IsOverlapped || IsOverUnderflow)
  621. {
  622. //
  623. // If CommunicationBuffer is not in valid address scope,
  624. // or there is overlap between gSmmCorePrivate and CommunicationBuffer,
  625. // or there is over or underflow,
  626. // return EFI_INVALID_PARAMETER
  627. //
  628. gSmmCorePrivate->CommunicationBuffer = NULL;
  629. gSmmCorePrivate->ReturnStatus = EFI_ACCESS_DENIED;
  630. } else {
  631. CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommunicationBuffer;
  632. // BufferSize was updated by the SafeUintnSub() call above.
  633. Status = SmiManage (
  634. &CommunicateHeader->HeaderGuid,
  635. NULL,
  636. CommunicateHeader->Data,
  637. &BufferSize
  638. );
  639. //
  640. // Update CommunicationBuffer, BufferSize and ReturnStatus
  641. // Communicate service finished, reset the pointer to CommBuffer to NULL
  642. //
  643. gSmmCorePrivate->BufferSize = BufferSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
  644. gSmmCorePrivate->CommunicationBuffer = NULL;
  645. gSmmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
  646. }
  647. }
  648. }
  649. //
  650. // Process Asynchronous SMI sources
  651. //
  652. SmiManage (NULL, NULL, NULL, NULL);
  653. //
  654. // Call platform hook after Smm Dispatch
  655. //
  656. PlatformHookAfterSmmDispatch ();
  657. //
  658. // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed
  659. //
  660. if (!InLegacyBoot) {
  661. //
  662. // Clear the InSmm flag as we are going to leave SMM
  663. //
  664. gSmmCorePrivate->InSmm = FALSE;
  665. }
  666. }
  667. /**
  668. Install LoadedImage protocol for SMM Core.
  669. **/
  670. VOID
  671. SmmCoreInstallLoadedImage (
  672. VOID
  673. )
  674. {
  675. EFI_STATUS Status;
  676. EFI_HANDLE Handle;
  677. //
  678. // Allocate a Loaded Image Protocol in EfiBootServicesData
  679. //
  680. Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&mSmmCoreLoadedImage);
  681. ASSERT_EFI_ERROR (Status);
  682. ZeroMem (mSmmCoreLoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL));
  683. //
  684. // Fill in the remaining fields of the Loaded Image Protocol instance.
  685. // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
  686. //
  687. mSmmCoreLoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
  688. mSmmCoreLoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
  689. mSmmCoreLoadedImage->SystemTable = gST;
  690. mSmmCoreLoadedImage->ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase;
  691. mSmmCoreLoadedImage->ImageSize = gSmmCorePrivate->PiSmmCoreImageSize;
  692. mSmmCoreLoadedImage->ImageCodeType = EfiRuntimeServicesCode;
  693. mSmmCoreLoadedImage->ImageDataType = EfiRuntimeServicesData;
  694. //
  695. // Create a new image handle in the UEFI handle database for the SMM Driver
  696. //
  697. Handle = NULL;
  698. Status = gBS->InstallMultipleProtocolInterfaces (
  699. &Handle,
  700. &gEfiLoadedImageProtocolGuid,
  701. mSmmCoreLoadedImage,
  702. NULL
  703. );
  704. ASSERT_EFI_ERROR (Status);
  705. //
  706. // Allocate a Loaded Image Protocol in SMM
  707. //
  708. Status = SmmAllocatePool (EfiRuntimeServicesData, sizeof (EFI_SMM_DRIVER_ENTRY), (VOID **)&mSmmCoreDriverEntry);
  709. ASSERT_EFI_ERROR (Status);
  710. ZeroMem (mSmmCoreDriverEntry, sizeof (EFI_SMM_DRIVER_ENTRY));
  711. //
  712. // Fill in the remaining fields of the Loaded Image Protocol instance.
  713. //
  714. mSmmCoreDriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE;
  715. mSmmCoreDriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
  716. mSmmCoreDriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
  717. mSmmCoreDriverEntry->SmmLoadedImage.SystemTable = gST;
  718. mSmmCoreDriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase;
  719. mSmmCoreDriverEntry->SmmLoadedImage.ImageSize = gSmmCorePrivate->PiSmmCoreImageSize;
  720. mSmmCoreDriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode;
  721. mSmmCoreDriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData;
  722. mSmmCoreDriverEntry->ImageEntryPoint = gSmmCorePrivate->PiSmmCoreEntryPoint;
  723. mSmmCoreDriverEntry->ImageBuffer = gSmmCorePrivate->PiSmmCoreImageBase;
  724. mSmmCoreDriverEntry->NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)gSmmCorePrivate->PiSmmCoreImageSize);
  725. //
  726. // Create a new image handle in the SMM handle database for the SMM Driver
  727. //
  728. mSmmCoreDriverEntry->SmmImageHandle = NULL;
  729. Status = SmmInstallProtocolInterface (
  730. &mSmmCoreDriverEntry->SmmImageHandle,
  731. &gEfiLoadedImageProtocolGuid,
  732. EFI_NATIVE_INTERFACE,
  733. &mSmmCoreDriverEntry->SmmLoadedImage
  734. );
  735. ASSERT_EFI_ERROR (Status);
  736. return;
  737. }
  738. /**
  739. The Entry Point for SMM Core
  740. Install DXE Protocols and reload SMM Core into SMRAM and register SMM Core
  741. EntryPoint on the SMI vector.
  742. Note: This function is called for both DXE invocation and SMRAM invocation.
  743. @param ImageHandle The firmware allocated handle for the EFI image.
  744. @param SystemTable A pointer to the EFI System Table.
  745. @retval EFI_SUCCESS The entry point is executed successfully.
  746. @retval Other Some error occurred when executing this entry point.
  747. **/
  748. EFI_STATUS
  749. EFIAPI
  750. SmmMain (
  751. IN EFI_HANDLE ImageHandle,
  752. IN EFI_SYSTEM_TABLE *SystemTable
  753. )
  754. {
  755. EFI_STATUS Status;
  756. UINTN Index;
  757. //
  758. // Get SMM Core Private context passed in from SMM IPL in ImageHandle.
  759. //
  760. gSmmCorePrivate = (SMM_CORE_PRIVATE_DATA *)ImageHandle;
  761. //
  762. // Fill in SMRAM physical address for the SMM Services Table and the SMM Entry Point.
  763. //
  764. gSmmCorePrivate->Smst = &gSmmCoreSmst;
  765. gSmmCorePrivate->SmmEntryPoint = SmmEntryPoint;
  766. //
  767. // No need to initialize memory service.
  768. // It is done in constructor of PiSmmCoreMemoryAllocationLib(),
  769. // so that the library linked with PiSmmCore can use AllocatePool() in constructor.
  770. //
  771. SmramProfileInit ();
  772. //
  773. // Copy FullSmramRanges to SMRAM
  774. //
  775. mFullSmramRangeCount = gSmmCorePrivate->SmramRangeCount;
  776. mFullSmramRanges = AllocatePool (mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR));
  777. ASSERT (mFullSmramRanges != NULL);
  778. CopyMem (mFullSmramRanges, gSmmCorePrivate->SmramRanges, mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR));
  779. //
  780. // Register all SMI Handlers required by the SMM Core
  781. //
  782. for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
  783. Status = SmiHandlerRegister (
  784. mSmmCoreSmiHandlers[Index].Handler,
  785. mSmmCoreSmiHandlers[Index].HandlerType,
  786. &mSmmCoreSmiHandlers[Index].DispatchHandle
  787. );
  788. ASSERT_EFI_ERROR (Status);
  789. }
  790. mAcpiS3Enable = PcdGetBool (PcdAcpiS3Enable);
  791. if (mAcpiS3Enable) {
  792. //
  793. // Register all S3 related SMI Handlers required by the SMM Core
  794. //
  795. for (Index = 0; mSmmCoreS3SmiHandlers[Index].HandlerType != NULL; Index++) {
  796. Status = SmiHandlerRegister (
  797. mSmmCoreS3SmiHandlers[Index].Handler,
  798. mSmmCoreS3SmiHandlers[Index].HandlerType,
  799. &mSmmCoreS3SmiHandlers[Index].DispatchHandle
  800. );
  801. ASSERT_EFI_ERROR (Status);
  802. }
  803. }
  804. RegisterSmramProfileHandler ();
  805. SmramProfileInstallProtocol ();
  806. SmmCoreInstallLoadedImage ();
  807. SmmCoreInitializeMemoryAttributesTable ();
  808. SmmCoreInitializeSmiHandlerProfile ();
  809. return EFI_SUCCESS;
  810. }