Xen.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. /**@file
  2. Xen Platform PEI support
  3. Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
  4. Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
  5. Copyright (c) 2019, Citrix Systems, Inc.
  6. SPDX-License-Identifier: BSD-2-Clause-Patent
  7. **/
  8. //
  9. // The package level header files this module uses
  10. //
  11. #include <PiPei.h>
  12. //
  13. // The Library classes this module consumes
  14. //
  15. #include <Library/BaseMemoryLib.h>
  16. #include <Library/CpuLib.h>
  17. #include <Library/DebugLib.h>
  18. #include <Library/HobLib.h>
  19. #include <Library/LocalApicLib.h>
  20. #include <Library/MemoryAllocationLib.h>
  21. #include <Library/PcdLib.h>
  22. #include <Library/SafeIntLib.h>
  23. #include <Guid/XenInfo.h>
  24. #include <IndustryStandard/E820.h>
  25. #include <Library/ResourcePublicationLib.h>
  26. #include <Library/MtrrLib.h>
  27. #include <IndustryStandard/PageTable.h>
  28. #include <IndustryStandard/Xen/arch-x86/hvm/start_info.h>
  29. #include <Library/XenHypercallLib.h>
  30. #include <IndustryStandard/Xen/memory.h>
  31. #include "Platform.h"
  32. #include "Xen.h"
  33. STATIC UINT32 mXenLeaf = 0;
  34. EFI_XEN_INFO mXenInfo;
  35. //
  36. // Location of the firmware info struct setup by hvmloader.
  37. // Only the E820 table is used by OVMF.
  38. //
  39. EFI_XEN_OVMF_INFO *mXenHvmloaderInfo;
  40. STATIC EFI_E820_ENTRY64 mE820Entries[128];
  41. STATIC UINT32 mE820EntriesCount;
  42. /**
  43. Returns E820 map provided by Xen
  44. @param Entries Pointer to E820 map
  45. @param Count Number of entries
  46. @return EFI_STATUS
  47. **/
  48. EFI_STATUS
  49. XenGetE820Map (
  50. EFI_E820_ENTRY64 **Entries,
  51. UINT32 *Count
  52. )
  53. {
  54. INTN ReturnCode;
  55. xen_memory_map_t Parameters;
  56. UINTN LoopIndex;
  57. UINTN Index;
  58. EFI_E820_ENTRY64 TmpEntry;
  59. //
  60. // Get E820 produced by hvmloader
  61. //
  62. if (mXenHvmloaderInfo != NULL) {
  63. ASSERT (mXenHvmloaderInfo->E820 < MAX_ADDRESS);
  64. *Entries = (EFI_E820_ENTRY64 *)(UINTN)mXenHvmloaderInfo->E820;
  65. *Count = mXenHvmloaderInfo->E820EntriesCount;
  66. return EFI_SUCCESS;
  67. }
  68. //
  69. // Otherwise, get the E820 table from the Xen hypervisor
  70. //
  71. if (mE820EntriesCount > 0) {
  72. *Entries = mE820Entries;
  73. *Count = mE820EntriesCount;
  74. return EFI_SUCCESS;
  75. }
  76. Parameters.nr_entries = 128;
  77. set_xen_guest_handle (Parameters.buffer, mE820Entries);
  78. // Returns a errno
  79. ReturnCode = XenHypercallMemoryOp (XENMEM_memory_map, &Parameters);
  80. ASSERT (ReturnCode == 0);
  81. mE820EntriesCount = Parameters.nr_entries;
  82. //
  83. // Sort E820 entries
  84. //
  85. for (LoopIndex = 1; LoopIndex < mE820EntriesCount; LoopIndex++) {
  86. for (Index = LoopIndex; Index < mE820EntriesCount; Index++) {
  87. if (mE820Entries[Index - 1].BaseAddr > mE820Entries[Index].BaseAddr) {
  88. TmpEntry = mE820Entries[Index];
  89. mE820Entries[Index] = mE820Entries[Index - 1];
  90. mE820Entries[Index - 1] = TmpEntry;
  91. }
  92. }
  93. }
  94. *Count = mE820EntriesCount;
  95. *Entries = mE820Entries;
  96. return EFI_SUCCESS;
  97. }
  98. /**
  99. Connects to the Hypervisor.
  100. @return EFI_STATUS
  101. **/
  102. EFI_STATUS
  103. XenConnect (
  104. )
  105. {
  106. UINT32 Index;
  107. UINT32 TransferReg;
  108. UINT32 TransferPages;
  109. UINT32 XenVersion;
  110. EFI_XEN_OVMF_INFO *Info;
  111. CHAR8 Sig[sizeof (Info->Signature) + 1];
  112. UINT32 *PVHResetVectorData;
  113. RETURN_STATUS Status;
  114. ASSERT (mXenLeaf != 0);
  115. //
  116. // Prepare HyperPages to be able to make hypercalls
  117. //
  118. AsmCpuid (mXenLeaf + 2, &TransferPages, &TransferReg, NULL, NULL);
  119. mXenInfo.HyperPages = AllocatePages (TransferPages);
  120. if (!mXenInfo.HyperPages) {
  121. return EFI_OUT_OF_RESOURCES;
  122. }
  123. for (Index = 0; Index < TransferPages; Index++) {
  124. AsmWriteMsr64 (
  125. TransferReg,
  126. (UINTN)mXenInfo.HyperPages +
  127. (Index << EFI_PAGE_SHIFT) + Index
  128. );
  129. }
  130. //
  131. // Find out the Xen version
  132. //
  133. AsmCpuid (mXenLeaf + 1, &XenVersion, NULL, NULL, NULL);
  134. DEBUG ((
  135. DEBUG_ERROR,
  136. "Detected Xen version %d.%d\n",
  137. XenVersion >> 16,
  138. XenVersion & 0xFFFF
  139. ));
  140. mXenInfo.VersionMajor = (UINT16)(XenVersion >> 16);
  141. mXenInfo.VersionMinor = (UINT16)(XenVersion & 0xFFFF);
  142. //
  143. // Check if there are information left by hvmloader
  144. //
  145. Info = (EFI_XEN_OVMF_INFO *)(UINTN)OVMF_INFO_PHYSICAL_ADDRESS;
  146. //
  147. // Copy the signature, and make it null-terminated.
  148. //
  149. AsciiStrnCpyS (
  150. Sig,
  151. sizeof (Sig),
  152. (CHAR8 *)&Info->Signature,
  153. sizeof (Info->Signature)
  154. );
  155. if (AsciiStrCmp (Sig, "XenHVMOVMF") == 0) {
  156. mXenHvmloaderInfo = Info;
  157. } else {
  158. mXenHvmloaderInfo = NULL;
  159. }
  160. mXenInfo.RsdpPvh = NULL;
  161. //
  162. // Locate and use information from the start of day structure if we have
  163. // booted via the PVH entry point.
  164. //
  165. PVHResetVectorData = (VOID *)(UINTN)PcdGet32 (PcdXenPvhStartOfDayStructPtr);
  166. //
  167. // That magic value is written in XenResetVector/Ia32/XenPVHMain.asm
  168. //
  169. if (PVHResetVectorData[1] == SIGNATURE_32 ('X', 'P', 'V', 'H')) {
  170. struct hvm_start_info *HVMStartInfo;
  171. HVMStartInfo = (VOID *)(UINTN)PVHResetVectorData[0];
  172. if (HVMStartInfo->magic == XEN_HVM_START_MAGIC_VALUE) {
  173. ASSERT (HVMStartInfo->rsdp_paddr != 0);
  174. if (HVMStartInfo->rsdp_paddr != 0) {
  175. mXenInfo.RsdpPvh = (VOID *)(UINTN)HVMStartInfo->rsdp_paddr;
  176. }
  177. }
  178. }
  179. BuildGuidDataHob (
  180. &gEfiXenInfoGuid,
  181. &mXenInfo,
  182. sizeof (mXenInfo)
  183. );
  184. //
  185. // Initialize the XenHypercall library, now that the XenInfo HOB is
  186. // available
  187. //
  188. Status = XenHypercallLibInit ();
  189. ASSERT_RETURN_ERROR (Status);
  190. return EFI_SUCCESS;
  191. }
  192. /**
  193. Figures out if we are running inside Xen HVM.
  194. @retval TRUE Xen was detected
  195. @retval FALSE Xen was not detected
  196. **/
  197. BOOLEAN
  198. XenDetect (
  199. VOID
  200. )
  201. {
  202. UINT8 Signature[13];
  203. if (mXenLeaf != 0) {
  204. return TRUE;
  205. }
  206. Signature[12] = '\0';
  207. for (mXenLeaf = 0x40000000; mXenLeaf < 0x40010000; mXenLeaf += 0x100) {
  208. AsmCpuid (
  209. mXenLeaf,
  210. NULL,
  211. (UINT32 *)&Signature[0],
  212. (UINT32 *)&Signature[4],
  213. (UINT32 *)&Signature[8]
  214. );
  215. if (!AsciiStrCmp ((CHAR8 *)Signature, "XenVMMXenVMM")) {
  216. return TRUE;
  217. }
  218. }
  219. mXenLeaf = 0;
  220. return FALSE;
  221. }
  222. BOOLEAN
  223. XenHvmloaderDetected (
  224. VOID
  225. )
  226. {
  227. return (mXenHvmloaderInfo != NULL);
  228. }
  229. BOOLEAN
  230. XenPvhDetected (
  231. VOID
  232. )
  233. {
  234. //
  235. // This function should only be used after XenConnect
  236. //
  237. ASSERT (mXenInfo.HyperPages != NULL);
  238. return mXenHvmloaderInfo == NULL;
  239. }
  240. VOID
  241. XenPublishRamRegions (
  242. VOID
  243. )
  244. {
  245. EFI_E820_ENTRY64 *E820Map;
  246. UINT32 E820EntriesCount;
  247. EFI_STATUS Status;
  248. EFI_E820_ENTRY64 *Entry;
  249. UINTN Index;
  250. UINT64 LapicBase;
  251. UINT64 LapicEnd;
  252. DEBUG ((DEBUG_INFO, "Using memory map provided by Xen\n"));
  253. //
  254. // Parse RAM in E820 map
  255. //
  256. E820EntriesCount = 0;
  257. Status = XenGetE820Map (&E820Map, &E820EntriesCount);
  258. ASSERT_EFI_ERROR (Status);
  259. AddMemoryBaseSizeHob (0, 0xA0000);
  260. //
  261. // Video memory + Legacy BIOS region, to allow Linux to boot.
  262. //
  263. AddReservedMemoryBaseSizeHob (0xA0000, BASE_1MB - 0xA0000, TRUE);
  264. LapicBase = PcdGet32 (PcdCpuLocalApicBaseAddress);
  265. LapicEnd = LapicBase + SIZE_1MB;
  266. AddIoMemoryRangeHob (LapicBase, LapicEnd);
  267. for (Index = 0; Index < E820EntriesCount; Index++) {
  268. UINT64 Base;
  269. UINT64 End;
  270. UINT64 ReservedBase;
  271. UINT64 ReservedEnd;
  272. Entry = &E820Map[Index];
  273. //
  274. // Round up the start address, and round down the end address.
  275. //
  276. Base = ALIGN_VALUE (Entry->BaseAddr, (UINT64)EFI_PAGE_SIZE);
  277. End = (Entry->BaseAddr + Entry->Length) & ~(UINT64)EFI_PAGE_MASK;
  278. //
  279. // Ignore the first 1MB, this is handled before the loop.
  280. //
  281. if (Base < BASE_1MB) {
  282. Base = BASE_1MB;
  283. }
  284. if (Base >= End) {
  285. continue;
  286. }
  287. switch (Entry->Type) {
  288. case EfiAcpiAddressRangeMemory:
  289. AddMemoryRangeHob (Base, End);
  290. break;
  291. case EfiAcpiAddressRangeACPI:
  292. AddReservedMemoryRangeHob (Base, End, FALSE);
  293. break;
  294. case EfiAcpiAddressRangeReserved:
  295. //
  296. // hvmloader marks a range that overlaps with the local APIC memory
  297. // mapped region as reserved, but CpuDxe wants it as mapped IO. We
  298. // have already added it as mapped IO, so skip it here.
  299. //
  300. //
  301. // add LAPIC predecessor range, if any
  302. //
  303. ReservedBase = Base;
  304. ReservedEnd = MIN (End, LapicBase);
  305. if (ReservedBase < ReservedEnd) {
  306. AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE);
  307. }
  308. //
  309. // add LAPIC successor range, if any
  310. //
  311. ReservedBase = MAX (Base, LapicEnd);
  312. ReservedEnd = End;
  313. if (ReservedBase < ReservedEnd) {
  314. AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE);
  315. }
  316. break;
  317. default:
  318. break;
  319. }
  320. }
  321. }
  322. EFI_STATUS
  323. PhysicalAddressIdentityMapping (
  324. IN EFI_PHYSICAL_ADDRESS AddressToMap
  325. )
  326. {
  327. INTN Index;
  328. PAGE_MAP_AND_DIRECTORY_POINTER *L4, *L3;
  329. PAGE_TABLE_ENTRY *PageTable;
  330. DEBUG ((DEBUG_INFO, "Mapping 1:1 of address 0x%lx\n", (UINT64)AddressToMap));
  331. // L4 / Top level Page Directory Pointers
  332. L4 = (VOID *)(UINTN)PcdGet32 (PcdOvmfSecPageTablesBase);
  333. Index = PML4_OFFSET (AddressToMap);
  334. if (!L4[Index].Bits.Present) {
  335. L3 = AllocatePages (1);
  336. if (L3 == NULL) {
  337. return EFI_OUT_OF_RESOURCES;
  338. }
  339. ZeroMem (L3, EFI_PAGE_SIZE);
  340. L4[Index].Bits.ReadWrite = 1;
  341. L4[Index].Bits.Accessed = 1;
  342. L4[Index].Bits.PageTableBaseAddress = (EFI_PHYSICAL_ADDRESS)L3 >> 12;
  343. L4[Index].Bits.Present = 1;
  344. }
  345. // L3 / Next level Page Directory Pointers
  346. L3 = (VOID *)(EFI_PHYSICAL_ADDRESS)(L4[Index].Bits.PageTableBaseAddress << 12);
  347. Index = PDP_OFFSET (AddressToMap);
  348. if (!L3[Index].Bits.Present) {
  349. PageTable = AllocatePages (1);
  350. if (PageTable == NULL) {
  351. return EFI_OUT_OF_RESOURCES;
  352. }
  353. ZeroMem (PageTable, EFI_PAGE_SIZE);
  354. L3[Index].Bits.ReadWrite = 1;
  355. L3[Index].Bits.Accessed = 1;
  356. L3[Index].Bits.PageTableBaseAddress = (EFI_PHYSICAL_ADDRESS)PageTable >> 12;
  357. L3[Index].Bits.Present = 1;
  358. }
  359. // L2 / Page Table Entries
  360. PageTable = (VOID *)(EFI_PHYSICAL_ADDRESS)(L3[Index].Bits.PageTableBaseAddress << 12);
  361. Index = PDE_OFFSET (AddressToMap);
  362. if (!PageTable[Index].Bits.Present) {
  363. PageTable[Index].Bits.ReadWrite = 1;
  364. PageTable[Index].Bits.Accessed = 1;
  365. PageTable[Index].Bits.Dirty = 1;
  366. PageTable[Index].Bits.MustBe1 = 1;
  367. PageTable[Index].Bits.PageTableBaseAddress = AddressToMap >> 21;
  368. PageTable[Index].Bits.Present = 1;
  369. }
  370. CpuFlushTlb ();
  371. return EFI_SUCCESS;
  372. }
  373. STATIC
  374. EFI_STATUS
  375. MapSharedInfoPage (
  376. IN VOID *PagePtr
  377. )
  378. {
  379. xen_add_to_physmap_t Parameters;
  380. INTN ReturnCode;
  381. Parameters.domid = DOMID_SELF;
  382. Parameters.space = XENMAPSPACE_shared_info;
  383. Parameters.idx = 0;
  384. Parameters.gpfn = (UINTN)PagePtr >> EFI_PAGE_SHIFT;
  385. ReturnCode = XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameters);
  386. if (ReturnCode != 0) {
  387. return EFI_NO_MAPPING;
  388. }
  389. return EFI_SUCCESS;
  390. }
  391. STATIC
  392. VOID
  393. UnmapXenPage (
  394. IN VOID *PagePtr
  395. )
  396. {
  397. xen_remove_from_physmap_t Parameters;
  398. INTN ReturnCode;
  399. Parameters.domid = DOMID_SELF;
  400. Parameters.gpfn = (UINTN)PagePtr >> EFI_PAGE_SHIFT;
  401. ReturnCode = XenHypercallMemoryOp (XENMEM_remove_from_physmap, &Parameters);
  402. ASSERT (ReturnCode == 0);
  403. }
  404. STATIC
  405. UINT64
  406. GetCpuFreq (
  407. IN XEN_VCPU_TIME_INFO *VcpuTime
  408. )
  409. {
  410. UINT32 Version;
  411. UINT32 TscToSystemMultiplier;
  412. INT8 TscShift;
  413. UINT64 CpuFreq;
  414. do {
  415. Version = VcpuTime->Version;
  416. MemoryFence ();
  417. TscToSystemMultiplier = VcpuTime->TscToSystemMultiplier;
  418. TscShift = VcpuTime->TscShift;
  419. MemoryFence ();
  420. } while (((Version & 1) != 0) && (Version != VcpuTime->Version));
  421. CpuFreq = DivU64x32 (LShiftU64 (1000000000ULL, 32), TscToSystemMultiplier);
  422. if (TscShift >= 0) {
  423. CpuFreq = RShiftU64 (CpuFreq, TscShift);
  424. } else {
  425. CpuFreq = LShiftU64 (CpuFreq, -TscShift);
  426. }
  427. return CpuFreq;
  428. }
  429. STATIC
  430. VOID
  431. XenDelay (
  432. IN XEN_VCPU_TIME_INFO *VcpuTimeInfo,
  433. IN UINT64 DelayNs
  434. )
  435. {
  436. UINT64 Tick;
  437. UINT64 CpuFreq;
  438. UINT64 Delay;
  439. UINT64 DelayTick;
  440. UINT64 NewTick;
  441. RETURN_STATUS Status;
  442. Tick = AsmReadTsc ();
  443. CpuFreq = GetCpuFreq (VcpuTimeInfo);
  444. Status = SafeUint64Mult (DelayNs, CpuFreq, &Delay);
  445. if (EFI_ERROR (Status)) {
  446. DEBUG ((
  447. DEBUG_ERROR,
  448. "XenDelay (%lu ns): delay too big in relation to CPU freq %lu Hz\n",
  449. DelayNs,
  450. CpuFreq
  451. ));
  452. ASSERT_EFI_ERROR (Status);
  453. CpuDeadLoop ();
  454. }
  455. DelayTick = DivU64x32 (Delay, 1000000000);
  456. NewTick = Tick + DelayTick;
  457. //
  458. // Check for overflow
  459. //
  460. if (NewTick < Tick) {
  461. //
  462. // Overflow, wait for TSC to also overflow
  463. //
  464. while (AsmReadTsc () >= Tick) {
  465. CpuPause ();
  466. }
  467. }
  468. while (AsmReadTsc () <= NewTick) {
  469. CpuPause ();
  470. }
  471. }
  472. /**
  473. Calculate the frequency of the Local Apic Timer
  474. **/
  475. VOID
  476. CalibrateLapicTimer (
  477. VOID
  478. )
  479. {
  480. XEN_SHARED_INFO *SharedInfo;
  481. XEN_VCPU_TIME_INFO *VcpuTimeInfo;
  482. UINT32 TimerTick, TimerTick2, DiffTimer;
  483. UINT64 TscTick, TscTick2;
  484. UINT64 Freq;
  485. UINT64 Dividend;
  486. EFI_STATUS Status;
  487. SharedInfo = (VOID *)((UINTN)PcdGet32 (PcdCpuLocalApicBaseAddress) + SIZE_1MB);
  488. Status = PhysicalAddressIdentityMapping ((EFI_PHYSICAL_ADDRESS)SharedInfo);
  489. if (EFI_ERROR (Status)) {
  490. DEBUG ((
  491. DEBUG_ERROR,
  492. "Failed to add page table entry for Xen shared info page: %r\n",
  493. Status
  494. ));
  495. ASSERT_EFI_ERROR (Status);
  496. return;
  497. }
  498. Status = MapSharedInfoPage (SharedInfo);
  499. if (EFI_ERROR (Status)) {
  500. DEBUG ((
  501. DEBUG_ERROR,
  502. "Failed to map Xen's shared info page: %r\n",
  503. Status
  504. ));
  505. ASSERT_EFI_ERROR (Status);
  506. return;
  507. }
  508. VcpuTimeInfo = &SharedInfo->VcpuInfo[0].Time;
  509. InitializeApicTimer (1, MAX_UINT32, TRUE, 0);
  510. DisableApicTimerInterrupt ();
  511. TimerTick = GetApicTimerCurrentCount ();
  512. TscTick = AsmReadTsc ();
  513. XenDelay (VcpuTimeInfo, 1000000ULL);
  514. TimerTick2 = GetApicTimerCurrentCount ();
  515. TscTick2 = AsmReadTsc ();
  516. DiffTimer = TimerTick - TimerTick2;
  517. Status = SafeUint64Mult (GetCpuFreq (VcpuTimeInfo), DiffTimer, &Dividend);
  518. if (EFI_ERROR (Status)) {
  519. DEBUG ((DEBUG_ERROR, "overflow while calculating APIC frequency\n"));
  520. DEBUG ((
  521. DEBUG_ERROR,
  522. "CPU freq: %lu Hz; APIC timer tick count for 1 ms: %u\n",
  523. GetCpuFreq (VcpuTimeInfo),
  524. DiffTimer
  525. ));
  526. ASSERT_EFI_ERROR (Status);
  527. CpuDeadLoop ();
  528. }
  529. Freq = DivU64x64Remainder (Dividend, TscTick2 - TscTick, NULL);
  530. DEBUG ((DEBUG_INFO, "APIC Freq % 8lu Hz\n", Freq));
  531. ASSERT (Freq <= MAX_UINT32);
  532. Status = PcdSet32S (PcdFSBClock, (UINT32)Freq);
  533. ASSERT_EFI_ERROR (Status);
  534. UnmapXenPage (SharedInfo);
  535. }