CpuDxe.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  1. /** @file
  2. CPU DXE Module to produce CPU ARCH Protocol.
  3. Copyright (c) 2008 - 2022, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "CpuDxe.h"
  7. #include "CpuMp.h"
  8. #include "CpuPageTable.h"
  9. #define CPU_INTERRUPT_NUM 256
  10. //
  11. // Global Variables
  12. //
  13. BOOLEAN InterruptState = FALSE;
  14. EFI_HANDLE mCpuHandle = NULL;
  15. BOOLEAN mIsFlushingGCD;
  16. BOOLEAN mIsAllocatingPageTable = FALSE;
  17. UINT64 mValidMtrrAddressMask;
  18. UINT64 mValidMtrrBitsMask;
  19. UINT64 mTimerPeriod = 0;
  20. FIXED_MTRR mFixedMtrrTable[] = {
  21. {
  22. MSR_IA32_MTRR_FIX64K_00000,
  23. 0,
  24. 0x10000
  25. },
  26. {
  27. MSR_IA32_MTRR_FIX16K_80000,
  28. 0x80000,
  29. 0x4000
  30. },
  31. {
  32. MSR_IA32_MTRR_FIX16K_A0000,
  33. 0xA0000,
  34. 0x4000
  35. },
  36. {
  37. MSR_IA32_MTRR_FIX4K_C0000,
  38. 0xC0000,
  39. 0x1000
  40. },
  41. {
  42. MSR_IA32_MTRR_FIX4K_C8000,
  43. 0xC8000,
  44. 0x1000
  45. },
  46. {
  47. MSR_IA32_MTRR_FIX4K_D0000,
  48. 0xD0000,
  49. 0x1000
  50. },
  51. {
  52. MSR_IA32_MTRR_FIX4K_D8000,
  53. 0xD8000,
  54. 0x1000
  55. },
  56. {
  57. MSR_IA32_MTRR_FIX4K_E0000,
  58. 0xE0000,
  59. 0x1000
  60. },
  61. {
  62. MSR_IA32_MTRR_FIX4K_E8000,
  63. 0xE8000,
  64. 0x1000
  65. },
  66. {
  67. MSR_IA32_MTRR_FIX4K_F0000,
  68. 0xF0000,
  69. 0x1000
  70. },
  71. {
  72. MSR_IA32_MTRR_FIX4K_F8000,
  73. 0xF8000,
  74. 0x1000
  75. },
  76. };
  77. EFI_CPU_ARCH_PROTOCOL gCpu = {
  78. CpuFlushCpuDataCache,
  79. CpuEnableInterrupt,
  80. CpuDisableInterrupt,
  81. CpuGetInterruptState,
  82. CpuInit,
  83. CpuRegisterInterruptHandler,
  84. CpuGetTimerValue,
  85. CpuSetMemoryAttributes,
  86. 1, // NumberOfTimers
  87. 4 // DmaBufferAlignment
  88. };
  89. //
  90. // CPU Arch Protocol Functions
  91. //
  92. /**
  93. Flush CPU data cache. If the instruction cache is fully coherent
  94. with all DMA operations then function can just return EFI_SUCCESS.
  95. @param This Protocol instance structure
  96. @param Start Physical address to start flushing from.
  97. @param Length Number of bytes to flush. Round up to chipset
  98. granularity.
  99. @param FlushType Specifies the type of flush operation to perform.
  100. @retval EFI_SUCCESS If cache was flushed
  101. @retval EFI_UNSUPPORTED If flush type is not supported.
  102. @retval EFI_DEVICE_ERROR If requested range could not be flushed.
  103. **/
  104. EFI_STATUS
  105. EFIAPI
  106. CpuFlushCpuDataCache (
  107. IN EFI_CPU_ARCH_PROTOCOL *This,
  108. IN EFI_PHYSICAL_ADDRESS Start,
  109. IN UINT64 Length,
  110. IN EFI_CPU_FLUSH_TYPE FlushType
  111. )
  112. {
  113. if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
  114. AsmWbinvd ();
  115. return EFI_SUCCESS;
  116. } else if (FlushType == EfiCpuFlushTypeInvalidate) {
  117. AsmInvd ();
  118. return EFI_SUCCESS;
  119. } else {
  120. return EFI_UNSUPPORTED;
  121. }
  122. }
  123. /**
  124. Enables CPU interrupts.
  125. @param This Protocol instance structure
  126. @retval EFI_SUCCESS If interrupts were enabled in the CPU
  127. @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.
  128. **/
  129. EFI_STATUS
  130. EFIAPI
  131. CpuEnableInterrupt (
  132. IN EFI_CPU_ARCH_PROTOCOL *This
  133. )
  134. {
  135. EnableInterrupts ();
  136. InterruptState = TRUE;
  137. return EFI_SUCCESS;
  138. }
  139. /**
  140. Disables CPU interrupts.
  141. @param This Protocol instance structure
  142. @retval EFI_SUCCESS If interrupts were disabled in the CPU.
  143. @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.
  144. **/
  145. EFI_STATUS
  146. EFIAPI
  147. CpuDisableInterrupt (
  148. IN EFI_CPU_ARCH_PROTOCOL *This
  149. )
  150. {
  151. DisableInterrupts ();
  152. InterruptState = FALSE;
  153. return EFI_SUCCESS;
  154. }
  155. /**
  156. Return the state of interrupts.
  157. @param This Protocol instance structure
  158. @param State Pointer to the CPU's current interrupt state
  159. @retval EFI_SUCCESS If interrupts were disabled in the CPU.
  160. @retval EFI_INVALID_PARAMETER State is NULL.
  161. **/
  162. EFI_STATUS
  163. EFIAPI
  164. CpuGetInterruptState (
  165. IN EFI_CPU_ARCH_PROTOCOL *This,
  166. OUT BOOLEAN *State
  167. )
  168. {
  169. if (State == NULL) {
  170. return EFI_INVALID_PARAMETER;
  171. }
  172. *State = InterruptState;
  173. return EFI_SUCCESS;
  174. }
  175. /**
  176. Generates an INIT to the CPU.
  177. @param This Protocol instance structure
  178. @param InitType Type of CPU INIT to perform
  179. @retval EFI_SUCCESS If CPU INIT occurred. This value should never be
  180. seen.
  181. @retval EFI_DEVICE_ERROR If CPU INIT failed.
  182. @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.
  183. **/
  184. EFI_STATUS
  185. EFIAPI
  186. CpuInit (
  187. IN EFI_CPU_ARCH_PROTOCOL *This,
  188. IN EFI_CPU_INIT_TYPE InitType
  189. )
  190. {
  191. return EFI_UNSUPPORTED;
  192. }
  193. /**
  194. Registers a function to be called from the CPU interrupt handler.
  195. @param This Protocol instance structure
  196. @param InterruptType Defines which interrupt to hook. IA-32
  197. valid range is 0x00 through 0xFF
  198. @param InterruptHandler A pointer to a function of type
  199. EFI_CPU_INTERRUPT_HANDLER that is called
  200. when a processor interrupt occurs. A null
  201. pointer is an error condition.
  202. @retval EFI_SUCCESS If handler installed or uninstalled.
  203. @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler
  204. for InterruptType was previously installed.
  205. @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
  206. InterruptType was not previously installed.
  207. @retval EFI_UNSUPPORTED The interrupt specified by InterruptType
  208. is not supported.
  209. **/
  210. EFI_STATUS
  211. EFIAPI
  212. CpuRegisterInterruptHandler (
  213. IN EFI_CPU_ARCH_PROTOCOL *This,
  214. IN EFI_EXCEPTION_TYPE InterruptType,
  215. IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
  216. )
  217. {
  218. return RegisterCpuInterruptHandler (InterruptType, InterruptHandler);
  219. }
  220. /**
  221. Returns a timer value from one of the CPU's internal timers. There is no
  222. inherent time interval between ticks but is a function of the CPU frequency.
  223. @param This - Protocol instance structure.
  224. @param TimerIndex - Specifies which CPU timer is requested.
  225. @param TimerValue - Pointer to the returned timer value.
  226. @param TimerPeriod - A pointer to the amount of time that passes
  227. in femtoseconds (10-15) for each increment
  228. of TimerValue. If TimerValue does not
  229. increment at a predictable rate, then 0 is
  230. returned. The amount of time that has
  231. passed between two calls to GetTimerValue()
  232. can be calculated with the formula
  233. (TimerValue2 - TimerValue1) * TimerPeriod.
  234. This parameter is optional and may be NULL.
  235. @retval EFI_SUCCESS - If the CPU timer count was returned.
  236. @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
  237. @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
  238. @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
  239. **/
  240. EFI_STATUS
  241. EFIAPI
  242. CpuGetTimerValue (
  243. IN EFI_CPU_ARCH_PROTOCOL *This,
  244. IN UINT32 TimerIndex,
  245. OUT UINT64 *TimerValue,
  246. OUT UINT64 *TimerPeriod OPTIONAL
  247. )
  248. {
  249. UINT64 BeginValue;
  250. UINT64 EndValue;
  251. if (TimerValue == NULL) {
  252. return EFI_INVALID_PARAMETER;
  253. }
  254. if (TimerIndex != 0) {
  255. return EFI_INVALID_PARAMETER;
  256. }
  257. *TimerValue = AsmReadTsc ();
  258. if (TimerPeriod != NULL) {
  259. if (mTimerPeriod == 0) {
  260. //
  261. // Read time stamp counter before and after delay of 100 microseconds
  262. //
  263. BeginValue = AsmReadTsc ();
  264. MicroSecondDelay (100);
  265. EndValue = AsmReadTsc ();
  266. //
  267. // Calculate the actual frequency
  268. //
  269. mTimerPeriod = DivU64x64Remainder (
  270. MultU64x32 (
  271. 1000 * 1000 * 1000,
  272. 100
  273. ),
  274. EndValue - BeginValue,
  275. NULL
  276. );
  277. }
  278. *TimerPeriod = mTimerPeriod;
  279. }
  280. return EFI_SUCCESS;
  281. }
  282. /**
  283. A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to
  284. EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure.
  285. @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed to
  286. MtrrSetAllMtrrs().
  287. **/
  288. VOID
  289. EFIAPI
  290. SetMtrrsFromBuffer (
  291. IN VOID *Buffer
  292. )
  293. {
  294. MtrrSetAllMtrrs (Buffer);
  295. }
  296. /**
  297. Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.
  298. This function modifies the attributes for the memory region specified by BaseAddress and
  299. Length from their current attributes to the attributes specified by Attributes.
  300. @param This The EFI_CPU_ARCH_PROTOCOL instance.
  301. @param BaseAddress The physical address that is the start address of a memory region.
  302. @param Length The size in bytes of the memory region.
  303. @param Attributes The bit mask of attributes to set for the memory region.
  304. @retval EFI_SUCCESS The attributes were set for the memory region.
  305. @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
  306. BaseAddress and Length cannot be modified.
  307. @retval EFI_INVALID_PARAMETER Length is zero.
  308. Attributes specified an illegal combination of attributes that
  309. cannot be set together.
  310. @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
  311. the memory resource range.
  312. @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
  313. resource range specified by BaseAddress and Length.
  314. The bit mask of attributes is not support for the memory resource
  315. range specified by BaseAddress and Length.
  316. **/
  317. EFI_STATUS
  318. EFIAPI
  319. CpuSetMemoryAttributes (
  320. IN EFI_CPU_ARCH_PROTOCOL *This,
  321. IN EFI_PHYSICAL_ADDRESS BaseAddress,
  322. IN UINT64 Length,
  323. IN UINT64 Attributes
  324. )
  325. {
  326. RETURN_STATUS Status;
  327. MTRR_MEMORY_CACHE_TYPE CacheType;
  328. EFI_STATUS MpStatus;
  329. EFI_MP_SERVICES_PROTOCOL *MpService;
  330. MTRR_SETTINGS MtrrSettings;
  331. UINT64 CacheAttributes;
  332. UINT64 MemoryAttributes;
  333. MTRR_MEMORY_CACHE_TYPE CurrentCacheType;
  334. //
  335. // If this function is called because GCD SetMemorySpaceAttributes () is called
  336. // by RefreshGcdMemoryAttributes (), then we are just synchronizing GCD memory
  337. // map with MTRR values. So there is no need to modify MTRRs, just return immediately
  338. // to avoid unnecessary computing.
  339. //
  340. if (mIsFlushingGCD) {
  341. DEBUG ((DEBUG_VERBOSE, " Flushing GCD\n"));
  342. return EFI_SUCCESS;
  343. }
  344. //
  345. // During memory attributes updating, new pages may be allocated to setup
  346. // smaller granularity of page table. Page allocation action might then cause
  347. // another calling of CpuSetMemoryAttributes() recursively, due to memory
  348. // protection policy configured (such as PcdDxeNxMemoryProtectionPolicy).
  349. // Since this driver will always protect memory used as page table by itself,
  350. // there's no need to apply protection policy requested from memory service.
  351. // So it's safe to just return EFI_SUCCESS if this time of calling is caused
  352. // by page table memory allocation.
  353. //
  354. if (mIsAllocatingPageTable) {
  355. DEBUG ((DEBUG_VERBOSE, " Allocating page table memory\n"));
  356. return EFI_SUCCESS;
  357. }
  358. CacheAttributes = Attributes & EFI_CACHE_ATTRIBUTE_MASK;
  359. MemoryAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
  360. if (Attributes != (CacheAttributes | MemoryAttributes)) {
  361. return EFI_INVALID_PARAMETER;
  362. }
  363. if (CacheAttributes != 0) {
  364. if (!IsMtrrSupported ()) {
  365. return EFI_UNSUPPORTED;
  366. }
  367. switch (CacheAttributes) {
  368. case EFI_MEMORY_UC:
  369. CacheType = CacheUncacheable;
  370. break;
  371. case EFI_MEMORY_WC:
  372. CacheType = CacheWriteCombining;
  373. break;
  374. case EFI_MEMORY_WT:
  375. CacheType = CacheWriteThrough;
  376. break;
  377. case EFI_MEMORY_WP:
  378. CacheType = CacheWriteProtected;
  379. break;
  380. case EFI_MEMORY_WB:
  381. CacheType = CacheWriteBack;
  382. break;
  383. default:
  384. return EFI_INVALID_PARAMETER;
  385. }
  386. CurrentCacheType = MtrrGetMemoryAttribute (BaseAddress);
  387. if (CurrentCacheType != CacheType) {
  388. //
  389. // call MTRR library function
  390. //
  391. Status = MtrrSetMemoryAttribute (
  392. BaseAddress,
  393. Length,
  394. CacheType
  395. );
  396. if (!RETURN_ERROR (Status)) {
  397. MpStatus = gBS->LocateProtocol (
  398. &gEfiMpServiceProtocolGuid,
  399. NULL,
  400. (VOID **)&MpService
  401. );
  402. //
  403. // Synchronize the update with all APs
  404. //
  405. if (!EFI_ERROR (MpStatus)) {
  406. MtrrGetAllMtrrs (&MtrrSettings);
  407. MpStatus = MpService->StartupAllAPs (
  408. MpService, // This
  409. SetMtrrsFromBuffer, // Procedure
  410. FALSE, // SingleThread
  411. NULL, // WaitEvent
  412. 0, // TimeoutInMicrosecsond
  413. &MtrrSettings, // ProcedureArgument
  414. NULL // FailedCpuList
  415. );
  416. ASSERT (MpStatus == EFI_SUCCESS || MpStatus == EFI_NOT_STARTED);
  417. }
  418. }
  419. if (EFI_ERROR (Status)) {
  420. return Status;
  421. }
  422. }
  423. }
  424. //
  425. // Set memory attribute by page table
  426. //
  427. return AssignMemoryPageAttributes (NULL, BaseAddress, Length, MemoryAttributes, NULL);
  428. }
  429. /**
  430. Initializes the valid bits mask and valid address mask for MTRRs.
  431. This function initializes the valid bits mask and valid address mask for MTRRs.
  432. **/
  433. VOID
  434. InitializeMtrrMask (
  435. VOID
  436. )
  437. {
  438. UINT32 RegEax;
  439. UINT8 PhysicalAddressBits;
  440. AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
  441. if (RegEax >= 0x80000008) {
  442. AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
  443. PhysicalAddressBits = (UINT8)RegEax;
  444. } else {
  445. PhysicalAddressBits = 36;
  446. }
  447. mValidMtrrBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;
  448. mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL;
  449. }
  450. /**
  451. Gets GCD Mem Space type from MTRR Type.
  452. This function gets GCD Mem Space type from MTRR Type.
  453. @param MtrrAttributes MTRR memory type
  454. @return GCD Mem Space type
  455. **/
  456. UINT64
  457. GetMemorySpaceAttributeFromMtrrType (
  458. IN UINT8 MtrrAttributes
  459. )
  460. {
  461. switch (MtrrAttributes) {
  462. case MTRR_CACHE_UNCACHEABLE:
  463. return EFI_MEMORY_UC;
  464. case MTRR_CACHE_WRITE_COMBINING:
  465. return EFI_MEMORY_WC;
  466. case MTRR_CACHE_WRITE_THROUGH:
  467. return EFI_MEMORY_WT;
  468. case MTRR_CACHE_WRITE_PROTECTED:
  469. return EFI_MEMORY_WP;
  470. case MTRR_CACHE_WRITE_BACK:
  471. return EFI_MEMORY_WB;
  472. default:
  473. return 0;
  474. }
  475. }
  476. /**
  477. Searches memory descriptors covered by given memory range.
  478. This function searches into the Gcd Memory Space for descriptors
  479. (from StartIndex to EndIndex) that contains the memory range
  480. specified by BaseAddress and Length.
  481. @param MemorySpaceMap Gcd Memory Space Map as array.
  482. @param NumberOfDescriptors Number of descriptors in map.
  483. @param BaseAddress BaseAddress for the requested range.
  484. @param Length Length for the requested range.
  485. @param StartIndex Start index into the Gcd Memory Space Map.
  486. @param EndIndex End index into the Gcd Memory Space Map.
  487. @retval EFI_SUCCESS Search successfully.
  488. @retval EFI_NOT_FOUND The requested descriptors does not exist.
  489. **/
  490. EFI_STATUS
  491. SearchGcdMemorySpaces (
  492. IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
  493. IN UINTN NumberOfDescriptors,
  494. IN EFI_PHYSICAL_ADDRESS BaseAddress,
  495. IN UINT64 Length,
  496. OUT UINTN *StartIndex,
  497. OUT UINTN *EndIndex
  498. )
  499. {
  500. UINTN Index;
  501. *StartIndex = 0;
  502. *EndIndex = 0;
  503. for (Index = 0; Index < NumberOfDescriptors; Index++) {
  504. if ((BaseAddress >= MemorySpaceMap[Index].BaseAddress) &&
  505. (BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))
  506. {
  507. *StartIndex = Index;
  508. }
  509. if ((BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress) &&
  510. (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))
  511. {
  512. *EndIndex = Index;
  513. return EFI_SUCCESS;
  514. }
  515. }
  516. return EFI_NOT_FOUND;
  517. }
  518. /**
  519. Sets the attributes for a specified range in Gcd Memory Space Map.
  520. This function sets the attributes for a specified range in
  521. Gcd Memory Space Map.
  522. @param MemorySpaceMap Gcd Memory Space Map as array
  523. @param NumberOfDescriptors Number of descriptors in map
  524. @param BaseAddress BaseAddress for the range
  525. @param Length Length for the range
  526. @param Attributes Attributes to set
  527. @retval EFI_SUCCESS Memory attributes set successfully
  528. @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
  529. **/
  530. EFI_STATUS
  531. SetGcdMemorySpaceAttributes (
  532. IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
  533. IN UINTN NumberOfDescriptors,
  534. IN EFI_PHYSICAL_ADDRESS BaseAddress,
  535. IN UINT64 Length,
  536. IN UINT64 Attributes
  537. )
  538. {
  539. EFI_STATUS Status;
  540. UINTN Index;
  541. UINTN StartIndex;
  542. UINTN EndIndex;
  543. EFI_PHYSICAL_ADDRESS RegionStart;
  544. UINT64 RegionLength;
  545. //
  546. // Get all memory descriptors covered by the memory range
  547. //
  548. Status = SearchGcdMemorySpaces (
  549. MemorySpaceMap,
  550. NumberOfDescriptors,
  551. BaseAddress,
  552. Length,
  553. &StartIndex,
  554. &EndIndex
  555. );
  556. if (EFI_ERROR (Status)) {
  557. return Status;
  558. }
  559. //
  560. // Go through all related descriptors and set attributes accordingly
  561. //
  562. for (Index = StartIndex; Index <= EndIndex; Index++) {
  563. if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
  564. continue;
  565. }
  566. //
  567. // Calculate the start and end address of the overlapping range
  568. //
  569. if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
  570. RegionStart = BaseAddress;
  571. } else {
  572. RegionStart = MemorySpaceMap[Index].BaseAddress;
  573. }
  574. if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
  575. RegionLength = BaseAddress + Length - RegionStart;
  576. } else {
  577. RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
  578. }
  579. //
  580. // Set memory attributes according to MTRR attribute and the original attribute of descriptor
  581. //
  582. gDS->SetMemorySpaceAttributes (
  583. RegionStart,
  584. RegionLength,
  585. (MemorySpaceMap[Index].Attributes & ~EFI_CACHE_ATTRIBUTE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
  586. );
  587. }
  588. return EFI_SUCCESS;
  589. }
  590. /**
  591. Refreshes the GCD Memory Space attributes according to MTRRs.
  592. This function refreshes the GCD Memory Space attributes according to MTRRs.
  593. **/
  594. VOID
  595. RefreshMemoryAttributesFromMtrr (
  596. VOID
  597. )
  598. {
  599. EFI_STATUS Status;
  600. UINTN Index;
  601. UINTN SubIndex;
  602. UINT64 RegValue;
  603. EFI_PHYSICAL_ADDRESS BaseAddress;
  604. UINT64 Length;
  605. UINT64 Attributes;
  606. UINT64 CurrentAttributes;
  607. UINT8 MtrrType;
  608. UINTN NumberOfDescriptors;
  609. EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
  610. UINT64 DefaultAttributes;
  611. VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
  612. MTRR_FIXED_SETTINGS MtrrFixedSettings;
  613. UINT32 FirmwareVariableMtrrCount;
  614. UINT8 DefaultMemoryType;
  615. FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
  616. ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
  617. MemorySpaceMap = NULL;
  618. //
  619. // Initialize the valid bits mask and valid address mask for MTRRs
  620. //
  621. InitializeMtrrMask ();
  622. //
  623. // Get the memory attribute of variable MTRRs
  624. //
  625. MtrrGetMemoryAttributeInVariableMtrr (
  626. mValidMtrrBitsMask,
  627. mValidMtrrAddressMask,
  628. VariableMtrr
  629. );
  630. //
  631. // Get the memory space map from GCD
  632. //
  633. Status = gDS->GetMemorySpaceMap (
  634. &NumberOfDescriptors,
  635. &MemorySpaceMap
  636. );
  637. ASSERT_EFI_ERROR (Status);
  638. DefaultMemoryType = (UINT8)MtrrGetDefaultMemoryType ();
  639. DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType);
  640. //
  641. // Set default attributes to all spaces.
  642. //
  643. for (Index = 0; Index < NumberOfDescriptors; Index++) {
  644. if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
  645. continue;
  646. }
  647. gDS->SetMemorySpaceAttributes (
  648. MemorySpaceMap[Index].BaseAddress,
  649. MemorySpaceMap[Index].Length,
  650. (MemorySpaceMap[Index].Attributes & ~EFI_CACHE_ATTRIBUTE_MASK) |
  651. (MemorySpaceMap[Index].Capabilities & DefaultAttributes)
  652. );
  653. }
  654. //
  655. // Go for variable MTRRs with WB attribute
  656. //
  657. for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
  658. if (VariableMtrr[Index].Valid &&
  659. (VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK))
  660. {
  661. SetGcdMemorySpaceAttributes (
  662. MemorySpaceMap,
  663. NumberOfDescriptors,
  664. VariableMtrr[Index].BaseAddress,
  665. VariableMtrr[Index].Length,
  666. EFI_MEMORY_WB
  667. );
  668. }
  669. }
  670. //
  671. // Go for variable MTRRs with the attribute except for WB and UC attributes
  672. //
  673. for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
  674. if (VariableMtrr[Index].Valid &&
  675. (VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK) &&
  676. (VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE))
  677. {
  678. Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8)VariableMtrr[Index].Type);
  679. SetGcdMemorySpaceAttributes (
  680. MemorySpaceMap,
  681. NumberOfDescriptors,
  682. VariableMtrr[Index].BaseAddress,
  683. VariableMtrr[Index].Length,
  684. Attributes
  685. );
  686. }
  687. }
  688. //
  689. // Go for variable MTRRs with UC attribute
  690. //
  691. for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
  692. if (VariableMtrr[Index].Valid &&
  693. (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE))
  694. {
  695. SetGcdMemorySpaceAttributes (
  696. MemorySpaceMap,
  697. NumberOfDescriptors,
  698. VariableMtrr[Index].BaseAddress,
  699. VariableMtrr[Index].Length,
  700. EFI_MEMORY_UC
  701. );
  702. }
  703. }
  704. //
  705. // Go for fixed MTRRs
  706. //
  707. Attributes = 0;
  708. BaseAddress = 0;
  709. Length = 0;
  710. MtrrGetFixedMtrr (&MtrrFixedSettings);
  711. for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
  712. RegValue = MtrrFixedSettings.Mtrr[Index];
  713. //
  714. // Check for continuous fixed MTRR sections
  715. //
  716. for (SubIndex = 0; SubIndex < 8; SubIndex++) {
  717. MtrrType = (UINT8)RShiftU64 (RegValue, SubIndex * 8);
  718. CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);
  719. if (Length == 0) {
  720. //
  721. // A new MTRR attribute begins
  722. //
  723. Attributes = CurrentAttributes;
  724. } else {
  725. //
  726. // If fixed MTRR attribute changed, then set memory attribute for previous attribute
  727. //
  728. if (CurrentAttributes != Attributes) {
  729. SetGcdMemorySpaceAttributes (
  730. MemorySpaceMap,
  731. NumberOfDescriptors,
  732. BaseAddress,
  733. Length,
  734. Attributes
  735. );
  736. BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;
  737. Length = 0;
  738. Attributes = CurrentAttributes;
  739. }
  740. }
  741. Length += mFixedMtrrTable[Index].Length;
  742. }
  743. }
  744. //
  745. // Handle the last fixed MTRR region
  746. //
  747. SetGcdMemorySpaceAttributes (
  748. MemorySpaceMap,
  749. NumberOfDescriptors,
  750. BaseAddress,
  751. Length,
  752. Attributes
  753. );
  754. //
  755. // Free memory space map allocated by GCD service GetMemorySpaceMap ()
  756. //
  757. if (MemorySpaceMap != NULL) {
  758. FreePool (MemorySpaceMap);
  759. }
  760. }
  761. /**
  762. Check if paging is enabled or not.
  763. **/
  764. BOOLEAN
  765. IsPagingAndPageAddressExtensionsEnabled (
  766. VOID
  767. )
  768. {
  769. IA32_CR0 Cr0;
  770. IA32_CR4 Cr4;
  771. Cr0.UintN = AsmReadCr0 ();
  772. Cr4.UintN = AsmReadCr4 ();
  773. return ((Cr0.Bits.PG != 0) && (Cr4.Bits.PAE != 0));
  774. }
  775. /**
  776. Refreshes the GCD Memory Space attributes according to MTRRs and Paging.
  777. This function refreshes the GCD Memory Space attributes according to MTRRs
  778. and page tables.
  779. **/
  780. VOID
  781. RefreshGcdMemoryAttributes (
  782. VOID
  783. )
  784. {
  785. mIsFlushingGCD = TRUE;
  786. if (IsMtrrSupported ()) {
  787. RefreshMemoryAttributesFromMtrr ();
  788. }
  789. if (IsPagingAndPageAddressExtensionsEnabled ()) {
  790. RefreshGcdMemoryAttributesFromPaging ();
  791. }
  792. mIsFlushingGCD = FALSE;
  793. }
  794. /**
  795. Initialize Interrupt Descriptor Table for interrupt handling.
  796. **/
  797. VOID
  798. InitInterruptDescriptorTable (
  799. VOID
  800. )
  801. {
  802. EFI_STATUS Status;
  803. EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
  804. EFI_VECTOR_HANDOFF_INFO *VectorInfo;
  805. IA32_IDT_GATE_DESCRIPTOR *IdtTable;
  806. IA32_DESCRIPTOR IdtDescriptor;
  807. UINTN IdtEntryCount;
  808. VectorInfo = NULL;
  809. Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
  810. if ((Status == EFI_SUCCESS) && (VectorInfoList != NULL)) {
  811. VectorInfo = VectorInfoList;
  812. }
  813. AsmReadIdtr (&IdtDescriptor);
  814. IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
  815. if (IdtEntryCount < CPU_INTERRUPT_NUM) {
  816. //
  817. // Increase Interrupt Descriptor Table and Copy the old IDT table in
  818. //
  819. IdtTable = AllocateZeroPool (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM);
  820. ASSERT (IdtTable != NULL);
  821. CopyMem (IdtTable, (VOID *)IdtDescriptor.Base, sizeof (IA32_IDT_GATE_DESCRIPTOR) * IdtEntryCount);
  822. //
  823. // Load Interrupt Descriptor Table
  824. //
  825. IdtDescriptor.Base = (UINTN)IdtTable;
  826. IdtDescriptor.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM - 1);
  827. AsmWriteIdtr (&IdtDescriptor);
  828. }
  829. Status = InitializeCpuExceptionHandlers (VectorInfo);
  830. ASSERT_EFI_ERROR (Status);
  831. }
  832. /**
  833. Callback function for idle events.
  834. @param Event Event whose notification function is being invoked.
  835. @param Context The pointer to the notification function's context,
  836. which is implementation-dependent.
  837. **/
  838. VOID
  839. EFIAPI
  840. IdleLoopEventCallback (
  841. IN EFI_EVENT Event,
  842. IN VOID *Context
  843. )
  844. {
  845. CpuSleep ();
  846. }
  847. /**
  848. Ensure the compatibility of a memory space descriptor with the MMIO aperture.
  849. The memory space descriptor can come from the GCD memory space map, or it can
  850. represent a gap between two neighboring memory space descriptors. In the
  851. latter case, the GcdMemoryType field is expected to be
  852. EfiGcdMemoryTypeNonExistent.
  853. If the memory space descriptor already has type
  854. EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the
  855. required capabilities, then no action is taken -- it is by definition
  856. compatible with the aperture.
  857. Otherwise, the intersection of the memory space descriptor is calculated with
  858. the aperture. If the intersection is the empty set (no overlap), no action is
  859. taken; the memory space descriptor is compatible with the aperture.
  860. Otherwise, the type of the descriptor is investigated again. If the type is
  861. EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with
  862. such a type), then an attempt is made to add the intersection as MMIO space
  863. to the GCD memory space map, with the specified capabilities. This ensures
  864. continuity for the aperture, and the descriptor is deemed compatible with the
  865. aperture.
  866. Otherwise, the memory space descriptor is incompatible with the MMIO
  867. aperture.
  868. @param[in] Base Base address of the aperture.
  869. @param[in] Length Length of the aperture.
  870. @param[in] Capabilities Capabilities required by the aperture.
  871. @param[in] Descriptor The descriptor to ensure compatibility with the
  872. aperture for.
  873. @retval EFI_SUCCESS The descriptor is compatible. The GCD memory
  874. space map may have been updated, for
  875. continuity within the aperture.
  876. @retval EFI_INVALID_PARAMETER The descriptor is incompatible.
  877. @return Error codes from gDS->AddMemorySpace().
  878. **/
  879. EFI_STATUS
  880. IntersectMemoryDescriptor (
  881. IN UINT64 Base,
  882. IN UINT64 Length,
  883. IN UINT64 Capabilities,
  884. IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
  885. )
  886. {
  887. UINT64 IntersectionBase;
  888. UINT64 IntersectionEnd;
  889. EFI_STATUS Status;
  890. if ((Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
  891. ((Descriptor->Capabilities & Capabilities) == Capabilities))
  892. {
  893. return EFI_SUCCESS;
  894. }
  895. IntersectionBase = MAX (Base, Descriptor->BaseAddress);
  896. IntersectionEnd = MIN (
  897. Base + Length,
  898. Descriptor->BaseAddress + Descriptor->Length
  899. );
  900. if (IntersectionBase >= IntersectionEnd) {
  901. //
  902. // The descriptor and the aperture don't overlap.
  903. //
  904. return EFI_SUCCESS;
  905. }
  906. if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
  907. Status = gDS->AddMemorySpace (
  908. EfiGcdMemoryTypeMemoryMappedIo,
  909. IntersectionBase,
  910. IntersectionEnd - IntersectionBase,
  911. Capabilities
  912. );
  913. DEBUG ((
  914. EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
  915. "%a: %a: add [%Lx, %Lx): %r\n",
  916. gEfiCallerBaseName,
  917. __FUNCTION__,
  918. IntersectionBase,
  919. IntersectionEnd,
  920. Status
  921. ));
  922. return Status;
  923. }
  924. DEBUG ((
  925. DEBUG_ERROR,
  926. "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "
  927. "with aperture [%Lx, %Lx) cap %Lx\n",
  928. gEfiCallerBaseName,
  929. __FUNCTION__,
  930. Descriptor->BaseAddress,
  931. Descriptor->BaseAddress + Descriptor->Length,
  932. (UINT32)Descriptor->GcdMemoryType,
  933. Descriptor->Capabilities,
  934. Base,
  935. Base + Length,
  936. Capabilities
  937. ));
  938. return EFI_INVALID_PARAMETER;
  939. }
  940. /**
  941. Add MMIO space to GCD.
  942. The routine checks the GCD database and only adds those which are
  943. not added in the specified range to GCD.
  944. @param Base Base address of the MMIO space.
  945. @param Length Length of the MMIO space.
  946. @param Capabilities Capabilities of the MMIO space.
  947. @retval EFI_SUCCESS The MMIO space was added successfully.
  948. **/
  949. EFI_STATUS
  950. AddMemoryMappedIoSpace (
  951. IN UINT64 Base,
  952. IN UINT64 Length,
  953. IN UINT64 Capabilities
  954. )
  955. {
  956. EFI_STATUS Status;
  957. UINTN Index;
  958. UINTN NumberOfDescriptors;
  959. EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
  960. Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
  961. if (EFI_ERROR (Status)) {
  962. DEBUG ((
  963. DEBUG_ERROR,
  964. "%a: %a: GetMemorySpaceMap(): %r\n",
  965. gEfiCallerBaseName,
  966. __FUNCTION__,
  967. Status
  968. ));
  969. return Status;
  970. }
  971. for (Index = 0; Index < NumberOfDescriptors; Index++) {
  972. Status = IntersectMemoryDescriptor (
  973. Base,
  974. Length,
  975. Capabilities,
  976. &MemorySpaceMap[Index]
  977. );
  978. if (EFI_ERROR (Status)) {
  979. goto FreeMemorySpaceMap;
  980. }
  981. }
  982. DEBUG_CODE_BEGIN ();
  983. //
  984. // Make sure there are adjacent descriptors covering [Base, Base + Length).
  985. // It is possible that they have not been merged; merging can be prevented
  986. // by allocation and different capabilities.
  987. //
  988. UINT64 CheckBase;
  989. EFI_STATUS CheckStatus;
  990. EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
  991. for (CheckBase = Base;
  992. CheckBase < Base + Length;
  993. CheckBase = Descriptor.BaseAddress + Descriptor.Length)
  994. {
  995. CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, &Descriptor);
  996. ASSERT_EFI_ERROR (CheckStatus);
  997. ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);
  998. ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);
  999. }
  1000. DEBUG_CODE_END ();
  1001. FreeMemorySpaceMap:
  1002. FreePool (MemorySpaceMap);
  1003. return Status;
  1004. }
  1005. /**
  1006. Add and allocate CPU local APIC memory mapped space.
  1007. @param[in]ImageHandle Image handle this driver.
  1008. **/
  1009. VOID
  1010. AddLocalApicMemorySpace (
  1011. IN EFI_HANDLE ImageHandle
  1012. )
  1013. {
  1014. EFI_STATUS Status;
  1015. EFI_PHYSICAL_ADDRESS BaseAddress;
  1016. BaseAddress = (EFI_PHYSICAL_ADDRESS)GetLocalApicBaseAddress ();
  1017. Status = AddMemoryMappedIoSpace (BaseAddress, SIZE_4KB, EFI_MEMORY_UC);
  1018. ASSERT_EFI_ERROR (Status);
  1019. //
  1020. // Try to allocate APIC memory mapped space, does not check return
  1021. // status because it may be allocated by other driver, or DXE Core if
  1022. // this range is built into Memory Allocation HOB.
  1023. //
  1024. Status = gDS->AllocateMemorySpace (
  1025. EfiGcdAllocateAddress,
  1026. EfiGcdMemoryTypeMemoryMappedIo,
  1027. 0,
  1028. SIZE_4KB,
  1029. &BaseAddress,
  1030. ImageHandle,
  1031. NULL
  1032. );
  1033. if (EFI_ERROR (Status)) {
  1034. DEBUG ((
  1035. DEBUG_INFO,
  1036. "%a: %a: AllocateMemorySpace() Status - %r\n",
  1037. gEfiCallerBaseName,
  1038. __FUNCTION__,
  1039. Status
  1040. ));
  1041. }
  1042. }
  1043. /**
  1044. Initialize the state information for the CPU Architectural Protocol.
  1045. @param ImageHandle Image handle this driver.
  1046. @param SystemTable Pointer to the System Table.
  1047. @retval EFI_SUCCESS Thread can be successfully created
  1048. @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
  1049. @retval EFI_DEVICE_ERROR Cannot create the thread
  1050. **/
  1051. EFI_STATUS
  1052. EFIAPI
  1053. InitializeCpu (
  1054. IN EFI_HANDLE ImageHandle,
  1055. IN EFI_SYSTEM_TABLE *SystemTable
  1056. )
  1057. {
  1058. EFI_STATUS Status;
  1059. EFI_EVENT IdleLoopEvent;
  1060. InitializePageTableLib ();
  1061. InitializeFloatingPointUnits ();
  1062. //
  1063. // Make sure interrupts are disabled
  1064. //
  1065. DisableInterrupts ();
  1066. //
  1067. // Init GDT for DXE
  1068. //
  1069. InitGlobalDescriptorTable ();
  1070. //
  1071. // Setup IDT pointer, IDT and interrupt entry points
  1072. //
  1073. InitInterruptDescriptorTable ();
  1074. //
  1075. // Install CPU Architectural Protocol
  1076. //
  1077. Status = gBS->InstallMultipleProtocolInterfaces (
  1078. &mCpuHandle,
  1079. &gEfiCpuArchProtocolGuid,
  1080. &gCpu,
  1081. NULL
  1082. );
  1083. ASSERT_EFI_ERROR (Status);
  1084. //
  1085. // Refresh GCD memory space map according to MTRR value.
  1086. //
  1087. RefreshGcdMemoryAttributes ();
  1088. //
  1089. // Add and allocate local APIC memory mapped space
  1090. //
  1091. AddLocalApicMemorySpace (ImageHandle);
  1092. //
  1093. // Setup a callback for idle events
  1094. //
  1095. Status = gBS->CreateEventEx (
  1096. EVT_NOTIFY_SIGNAL,
  1097. TPL_NOTIFY,
  1098. IdleLoopEventCallback,
  1099. NULL,
  1100. &gIdleLoopEventGuid,
  1101. &IdleLoopEvent
  1102. );
  1103. ASSERT_EFI_ERROR (Status);
  1104. InitializeMpSupport ();
  1105. return Status;
  1106. }