1/**@file
2  Xen Platform PEI support
3
4  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
6
7  This program and the accompanying materials
8  are licensed and made available under the terms and conditions of the BSD License
9  which accompanies this distribution.  The full text of the license may be found at
10  http://opensource.org/licenses/bsd-license.php
11
12  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15**/
16
17//
18// The package level header files this module uses
19//
20#include <PiPei.h>
21
22//
23// The Library classes this module consumes
24//
25#include <Library/DebugLib.h>
26#include <Library/HobLib.h>
27#include <Library/MemoryAllocationLib.h>
28#include <Library/PcdLib.h>
29#include <Guid/XenInfo.h>
30#include <IndustryStandard/E820.h>
31#include <Library/ResourcePublicationLib.h>
32#include <Library/MtrrLib.h>
33
34#include "Platform.h"
35#include "Xen.h"
36
37BOOLEAN mXen = FALSE;
38
39STATIC UINT32 mXenLeaf = 0;
40
41EFI_XEN_INFO mXenInfo;
42
43/**
44  Returns E820 map provided by Xen
45
46  @param Entries      Pointer to E820 map
47  @param Count        Number of entries
48
49  @return EFI_STATUS
50**/
51EFI_STATUS
52XenGetE820Map (
53  EFI_E820_ENTRY64 **Entries,
54  UINT32 *Count
55  )
56{
57  EFI_XEN_OVMF_INFO *Info =
58    (EFI_XEN_OVMF_INFO *)(UINTN) OVMF_INFO_PHYSICAL_ADDRESS;
59
60  if (AsciiStrCmp ((CHAR8 *) Info->Signature, "XenHVMOVMF")) {
61    return EFI_NOT_FOUND;
62  }
63
64  ASSERT (Info->E820 < MAX_ADDRESS);
65  *Entries = (EFI_E820_ENTRY64 *)(UINTN) Info->E820;
66  *Count = Info->E820EntriesCount;
67
68  return EFI_SUCCESS;
69}
70
71/**
72  Connects to the Hypervisor.
73
74  @param  XenLeaf     CPUID index used to connect.
75
76  @return EFI_STATUS
77
78**/
79EFI_STATUS
80XenConnect (
81  UINT32 XenLeaf
82  )
83{
84  UINT32 Index;
85  UINT32 TransferReg;
86  UINT32 TransferPages;
87  UINT32 XenVersion;
88
89  AsmCpuid (XenLeaf + 2, &TransferPages, &TransferReg, NULL, NULL);
90  mXenInfo.HyperPages = AllocatePages (TransferPages);
91  if (!mXenInfo.HyperPages) {
92    return EFI_OUT_OF_RESOURCES;
93  }
94
95  for (Index = 0; Index < TransferPages; Index++) {
96    AsmWriteMsr64 (TransferReg,
97                   (UINTN) mXenInfo.HyperPages +
98                   (Index << EFI_PAGE_SHIFT) + Index);
99  }
100
101  AsmCpuid (XenLeaf + 1, &XenVersion, NULL, NULL, NULL);
102  DEBUG ((EFI_D_ERROR, "Detected Xen version %d.%d\n",
103          XenVersion >> 16, XenVersion & 0xFFFF));
104  mXenInfo.VersionMajor = (UINT16)(XenVersion >> 16);
105  mXenInfo.VersionMinor = (UINT16)(XenVersion & 0xFFFF);
106
107  /* TBD: Locate hvm_info and reserve it away. */
108  mXenInfo.HvmInfo = NULL;
109
110  BuildGuidDataHob (
111    &gEfiXenInfoGuid,
112    &mXenInfo,
113    sizeof(mXenInfo)
114    );
115
116  return EFI_SUCCESS;
117}
118
119/**
120  Figures out if we are running inside Xen HVM.
121
122  @retval TRUE   Xen was detected
123  @retval FALSE  Xen was not detected
124
125**/
126BOOLEAN
127XenDetect (
128  VOID
129  )
130{
131  UINT8 Signature[13];
132
133  if (mXenLeaf != 0) {
134    return TRUE;
135  }
136
137  Signature[12] = '\0';
138  for (mXenLeaf = 0x40000000; mXenLeaf < 0x40010000; mXenLeaf += 0x100) {
139    AsmCpuid (mXenLeaf,
140              NULL,
141              (UINT32 *) &Signature[0],
142              (UINT32 *) &Signature[4],
143              (UINT32 *) &Signature[8]);
144
145    if (!AsciiStrCmp ((CHAR8 *) Signature, "XenVMMXenVMM")) {
146      mXen = TRUE;
147      return TRUE;
148    }
149  }
150
151  mXenLeaf = 0;
152  return FALSE;
153}
154
155
156VOID
157XenPublishRamRegions (
158  VOID
159  )
160{
161  EFI_E820_ENTRY64  *E820Map;
162  UINT32            E820EntriesCount;
163  EFI_STATUS        Status;
164
165  if (!mXen) {
166    return;
167  }
168
169  DEBUG ((EFI_D_INFO, "Using memory map provided by Xen\n"));
170
171  //
172  // Parse RAM in E820 map
173  //
174  Status = XenGetE820Map (&E820Map, &E820EntriesCount);
175
176  ASSERT_EFI_ERROR (Status);
177
178  if (E820EntriesCount > 0) {
179    EFI_E820_ENTRY64 *Entry;
180    UINT32 Loop;
181
182    for (Loop = 0; Loop < E820EntriesCount; Loop++) {
183      Entry = E820Map + Loop;
184
185      //
186      // Only care about RAM
187      //
188      if (Entry->Type != EfiAcpiAddressRangeMemory) {
189        continue;
190      }
191
192      if (Entry->BaseAddr >= BASE_4GB) {
193        AddUntestedMemoryBaseSizeHob (Entry->BaseAddr, Entry->Length);
194      } else {
195        AddMemoryBaseSizeHob (Entry->BaseAddr, Entry->Length);
196      }
197
198      MtrrSetMemoryAttribute (Entry->BaseAddr, Entry->Length, CacheWriteBack);
199    }
200  }
201}
202
203
204/**
205  Perform Xen PEI initialization.
206
207  @return EFI_SUCCESS     Xen initialized successfully
208  @return EFI_NOT_FOUND   Not running under Xen
209
210**/
211EFI_STATUS
212InitializeXen (
213  VOID
214  )
215{
216  if (mXenLeaf == 0) {
217    return EFI_NOT_FOUND;
218  }
219
220  XenConnect (mXenLeaf);
221
222  //
223  // Reserve away HVMLOADER reserved memory [0xFC000000,0xFD000000).
224  // This needs to match HVMLOADER RESERVED_MEMBASE/RESERVED_MEMSIZE.
225  //
226  AddReservedMemoryBaseSizeHob (0xFC000000, 0x1000000, FALSE);
227
228  PcdSetBool (PcdPciDisableBusEnumeration, TRUE);
229
230  return EFI_SUCCESS;
231}
232