Browse Source

SimicsOpenBoardPkg: Add SimicsOpenBoardPkg and its modules

Add modules Include, Library, SimicsDxe, SimicsPei, Policy,
SmbiosPlatformDxe and SecCore for Simics Quick Start Platform support.

Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Ankit Sinha <ankit.sinha@intel.com>
Cc: Agyeman Prince <prince.agyeman@intel.com>
Cc: Kubacki Michael A <michael.a.kubacki@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>

Signed-off-by: David Wei <david.y.wei@intel.com>
Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
Reviewed-by: Michael Kubacki <michael.a.kubacki@intel.com>
Wei, David Y 4 years ago
parent
commit
ff753bc187
57 changed files with 11289 additions and 0 deletions
  1. 18 0
      Platform/Intel/SimicsOpenBoardPkg/Include/Guid/SimicsBoardConfig.h
  2. 50 0
      Platform/Intel/SimicsOpenBoardPkg/Include/IndustryStandard/I440FxPiix4.h
  3. 159 0
      Platform/Intel/SimicsOpenBoardPkg/Include/IndustryStandard/LinuxBzImage.h
  4. 205 0
      Platform/Intel/SimicsOpenBoardPkg/Include/Library/LoadLinuxLib.h
  5. 224 0
      Platform/Intel/SimicsOpenBoardPkg/Include/Library/SerializeVariablesLib.h
  6. 55 0
      Platform/Intel/SimicsOpenBoardPkg/Include/SimicsPlatforms.h
  7. 55 0
      Platform/Intel/SimicsOpenBoardPkg/Library/DxeLogoLib/DxeLogoLib.inf
  8. 647 0
      Platform/Intel/SimicsOpenBoardPkg/Library/DxeLogoLib/Logo.c
  9. 83 0
      Platform/Intel/SimicsOpenBoardPkg/Library/DxeLogoLib/OemBadging.h
  10. 42 0
      Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/DxeLoadLinuxLib.inf
  11. 41 0
      Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.nasm
  12. 662 0
      Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/Linux.c
  13. 175 0
      Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/LinuxGdt.c
  14. 52 0
      Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/LoadLinuxLib.h
  15. 85 0
      Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/X64/JumpToKernel.nasm
  16. 507 0
      Platform/Intel/SimicsOpenBoardPkg/Library/NvVarsFileLib/FsAccess.c
  17. 77 0
      Platform/Intel/SimicsOpenBoardPkg/Library/NvVarsFileLib/NvVarsFileLib.c
  18. 55 0
      Platform/Intel/SimicsOpenBoardPkg/Library/NvVarsFileLib/NvVarsFileLib.h
  19. 53 0
      Platform/Intel/SimicsOpenBoardPkg/Library/NvVarsFileLib/NvVarsFileLib.inf
  20. 68 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PciHostBridgeLib/PciHostBridge.h
  21. 419 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
  22. 51 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
  23. 100 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PeiReportFvLib/Fv.c
  24. 119 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PeiReportFvLib/PeiReportFvLib.c
  25. 56 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PeiReportFvLib/PeiReportFvLib.inf
  26. 1553 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PlatformBootManagerLib/BdsPlatform.c
  27. 172 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PlatformBootManagerLib/BdsPlatform.h
  28. 72 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
  29. 35 0
      Platform/Intel/SimicsOpenBoardPkg/Library/PlatformBootManagerLib/PlatformData.c
  30. 869 0
      Platform/Intel/SimicsOpenBoardPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c
  31. 33 0
      Platform/Intel/SimicsOpenBoardPkg/Library/SerializeVariablesLib/SerializeVariablesLib.h
  32. 36 0
      Platform/Intel/SimicsOpenBoardPkg/Library/SerializeVariablesLib/SerializeVariablesLib.inf
  33. 108 0
      Platform/Intel/SimicsOpenBoardPkg/Policy/Library/SiliconPolicyInitLib/SiliconPolicyInitLib.c
  34. 38 0
      Platform/Intel/SimicsOpenBoardPkg/Policy/Library/SiliconPolicyInitLib/SiliconPolicyInitLib.inf
  35. 70 0
      Platform/Intel/SimicsOpenBoardPkg/Policy/Library/SiliconPolicyUpdateLib/SiliconPolicyUpdateLib.c
  36. 35 0
      Platform/Intel/SimicsOpenBoardPkg/Policy/Library/SiliconPolicyUpdateLib/SiliconPolicyUpdateLib.inf
  37. 45 0
      Platform/Intel/SimicsOpenBoardPkg/SecCore/Ia32/SecEntry.nasm
  38. 956 0
      Platform/Intel/SimicsOpenBoardPkg/SecCore/SecMain.c
  39. 73 0
      Platform/Intel/SimicsOpenBoardPkg/SecCore/SecMain.inf
  40. 45 0
      Platform/Intel/SimicsOpenBoardPkg/SecCore/X64/SecEntry.nasm
  41. 865 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/Platform.c
  42. 38 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/Platform.h
  43. 31 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/Platform.uni
  44. 124 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/PlatformConfig.c
  45. 52 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/PlatformConfig.h
  46. 67 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/PlatformForms.vfr
  47. 65 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/SimicsDxe.inf
  48. 57 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsPei/Cmos.c
  49. 50 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsPei/Cmos.h
  50. 115 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsPei/FeatureControl.c
  51. 568 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsPei/MemDetect.c
  52. 630 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsPei/Platform.c
  53. 88 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsPei/Platform.h
  54. 104 0
      Platform/Intel/SimicsOpenBoardPkg/SimicsPei/SimicsPei.inf
  55. 148 0
      Platform/Intel/SimicsOpenBoardPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.c
  56. 38 0
      Platform/Intel/SimicsOpenBoardPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.h
  57. 51 0
      Platform/Intel/SimicsOpenBoardPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf

+ 18 - 0
Platform/Intel/SimicsOpenBoardPkg/Include/Guid/SimicsBoardConfig.h

@@ -0,0 +1,18 @@
+/** @file
+  GUID for UEFI variables that are specific to Simics Board configuration.
+
+  Copyright (C) 2014, Red Hat, Inc.
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __SIMICS_BOARD_CONFIG_H__
+#define __SIMICS_BOARD_CONFIG_H__
+
+#define SIMICS_BOARD_CONFIG_GUID \
+{0x8a318e00, 0xfaf5, 0x499f, { 0x91,0x75, 0xce, 0x4d, 0x8d, 0xa6, 0x70, 0xae}}
+
+extern EFI_GUID gSimicsBoardConfigGuid;
+
+#endif

+ 50 - 0
Platform/Intel/SimicsOpenBoardPkg/Include/IndustryStandard/I440FxPiix4.h

@@ -0,0 +1,50 @@
+/** @file
+  Various register numbers and value bits based on the following publications:
+  - Intel(R) datasheet 290549-001
+  - Intel(R) datasheet 290562-001
+  - Intel(R) datasheet 297654-006
+  - Intel(R) datasheet 297738-017
+
+  Copyright (C) 2015, Red Hat, Inc.
+  Copyright (c) 2014, Gabriel L. Somlo <somlo@cmu.edu>
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __I440FX_PIIX4_H__
+#define __I440FX_PIIX4_H__
+
+#include <Library/PciLib.h>
+
+//
+// Host Bridge Device ID (DID) value for I440FX
+//
+#define INTEL_82441_DEVICE_ID 0x1237
+
+//
+// B/D/F/Type: 0/0/0/PCI
+//
+#define PMC_REGISTER_PIIX4(Offset) PCI_LIB_ADDRESS (0, 0, 0, (Offset))
+
+#define PIIX4_PAM0              0x59
+#define PIIX4_PAM1              0x5A
+#define PIIX4_PAM2              0x5B
+#define PIIX4_PAM3              0x5C
+#define PIIX4_PAM4              0x5D
+#define PIIX4_PAM5              0x5E
+#define PIIX4_PAM6              0x5F
+
+//
+// B/D/F/Type: 0/1/3/PCI
+//
+#define POWER_MGMT_REGISTER_PIIX4(Offset) PCI_LIB_ADDRESS (0, 1, 3, (Offset))
+
+#define PIIX4_PMBA             0x40
+#define PIIX4_PMBA_MASK          (BIT15 | BIT14 | BIT13 | BIT12 | BIT11 | \
+                                  BIT10 | BIT9  | BIT8  | BIT7  | BIT6)
+
+#define PIIX4_PMREGMISC        0x80
+#define PIIX4_PMREGMISC_PMIOSE   BIT0
+
+#endif

+ 159 - 0
Platform/Intel/SimicsOpenBoardPkg/Include/IndustryStandard/LinuxBzImage.h

@@ -0,0 +1,159 @@
+/** @file
+
+  Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __LINUX_BZIMAGE_H__
+#define __LINUX_BZIMAGE_H__
+
+#define BOOTSIG         0x1FE
+#define SETUP_HDR       0x53726448  /* 0x53726448 == "HdrS" */
+
+#define E820_RAM        1
+#define E820_RESERVED   2
+#define E820_ACPI       3
+#define E820_NVS        4
+#define E820_UNUSABLE   5
+
+#pragma pack(1)
+
+struct setup_header {
+  UINT8 setup_secs;  /* Sectors for setup code */
+  UINT16 root_flags;
+  UINT32 sys_size;
+  UINT16 ram_size;
+  UINT16 video_mode;
+  UINT16 root_dev;
+  UINT16 signature;  /* Boot signature */
+  UINT16 jump;
+  UINT32 header;
+  UINT16 version;
+  UINT16 su_switch;
+  UINT16 setup_seg;
+  UINT16 start_sys;
+  UINT16 kernel_ver;
+  UINT8 loader_id;
+  UINT8 load_flags;
+  UINT16 movesize;
+  UINT32 code32_start;  /* Start of code loaded high */
+  UINT32 ramdisk_start;  /* Start of initial ramdisk */
+  UINT32 ramdisk_len;  /* Length of initial ramdisk */
+  UINT32 bootsect_kludge;
+  UINT16 heap_end;
+  UINT8 ext_loader_ver;  /* Extended boot loader version */
+  UINT8 ext_loader_type; /* Extended boot loader ID */
+  UINT32 cmd_line_ptr;   /* 32-bit pointer to the kernel command line */
+  UINT32 ramdisk_max;    /* Highest legal initrd address */
+  UINT32 kernel_alignment;  /* Physical addr alignment required for kernel */
+  UINT8 relocatable_kernel;  /* Whether kernel is relocatable or not */
+  UINT8 min_alignment;
+  UINT16 xloadflags;
+  UINT32 cmdline_size;
+  UINT32 hardware_subarch;
+  UINT64 hardware_subarch_data;
+  UINT32 payload_offset;
+  UINT32 payload_length;
+  UINT64 setup_data;
+  UINT64 pref_address;
+  UINT32 init_size;
+  UINT32 handover_offset;
+};
+
+struct efi_info {
+  UINT32 efi_loader_signature;
+  UINT32 efi_systab;
+  UINT32 efi_memdesc_size;
+  UINT32 efi_memdesc_version;
+  UINT32 efi_memmap;
+  UINT32 efi_memmap_size;
+  UINT32 efi_systab_hi;
+  UINT32 efi_memmap_hi;
+};
+
+struct e820_entry {
+  UINT64 addr;  /* start of memory segment */
+  UINT64 size;  /* size of memory segment */
+  UINT32 type;  /* type of memory segment */
+};
+
+struct screen_info {
+        UINT8  orig_x;           /* 0x00 */
+        UINT8  orig_y;           /* 0x01 */
+        UINT16 ext_mem_k;        /* 0x02 */
+        UINT16 orig_video_page;  /* 0x04 */
+        UINT8  orig_video_mode;  /* 0x06 */
+        UINT8  orig_video_cols;  /* 0x07 */
+        UINT8  flags;            /* 0x08 */
+        UINT8  unused2;          /* 0x09 */
+        UINT16 orig_video_ega_bx;/* 0x0a */
+        UINT16 unused3;          /* 0x0c */
+        UINT8  orig_video_lines; /* 0x0e */
+        UINT8  orig_video_isVGA; /* 0x0f */
+        UINT16 orig_video_points;/* 0x10 */
+
+  /* VESA graphic mode -- linear frame buffer */
+        UINT16 lfb_width;        /* 0x12 */
+        UINT16 lfb_height;       /* 0x14 */
+        UINT16 lfb_depth;        /* 0x16 */
+        UINT32 lfb_base;         /* 0x18 */
+        UINT32 lfb_size;         /* 0x1c */
+        UINT16 cl_magic, cl_offset; /* 0x20 */
+        UINT16 lfb_linelength;   /* 0x24 */
+        UINT8  red_size;         /* 0x26 */
+        UINT8  red_pos;          /* 0x27 */
+        UINT8  green_size;       /* 0x28 */
+        UINT8  green_pos;        /* 0x29 */
+        UINT8  blue_size;        /* 0x2a */
+        UINT8  blue_pos;         /* 0x2b */
+        UINT8  rsvd_size;        /* 0x2c */
+        UINT8  rsvd_pos;         /* 0x2d */
+        UINT16 vesapm_seg;       /* 0x2e */
+        UINT16 vesapm_off;       /* 0x30 */
+        UINT16 pages;            /* 0x32 */
+        UINT16 vesa_attributes;  /* 0x34 */
+        UINT32 capabilities;     /* 0x36 */
+        UINT8  _reserved[6];     /* 0x3a */
+};
+
+struct boot_params {
+struct screen_info screen_info;
+  UINT8 apm_bios_info[0x14];
+  UINT8 _pad2[4];
+  UINT64 tboot_addr;
+  UINT8 ist_info[0x10];
+  UINT8 _pad3[16];
+  UINT8 hd0_info[16];
+  UINT8 hd1_info[16];
+  UINT8 sys_desc_table[0x10];
+  UINT8 olpc_ofw_header[0x10];
+  UINT8 _pad4[128];
+  UINT8 edid_info[0x80];
+  struct efi_info efi_info;
+  UINT32 alt_mem_k;
+  UINT32 scratch;
+  UINT8 e820_entries;
+  UINT8 eddbuf_entries;
+  UINT8 edd_mbr_sig_buf_entries;
+  UINT8 _pad6[6];
+  struct setup_header hdr;
+  UINT8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
+  UINT32 edd_mbr_sig_buffer[16];
+  struct e820_entry e820_map[128];
+  UINT8 _pad8[48];
+  UINT8 eddbuf[0x1ec];
+  UINT8 _pad9[276];
+};
+
+typedef struct {
+  UINT16 limit;
+  UINT64 *base;
+} dt_addr_t;
+
+#pragma pack()
+
+extern EFI_STATUS setup_graphics(struct boot_params *buf);
+
+#endif /* __LINUX_BZIMAGE_H__ */

+ 205 - 0
Platform/Intel/SimicsOpenBoardPkg/Include/Library/LoadLinuxLib.h

@@ -0,0 +1,205 @@
+/** @file
+  Load/boot UEFI Linux.
+
+  Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __LOAD_LINUX_LIB__
+#define __LOAD_LINUX_LIB__
+
+
+/**
+  Verifies that the kernel setup image is valid and supported.
+  The kernel setup image should be checked before using other library
+  routines which take the kernel setup as an input.
+
+  @param[in]     KernelSetup - The kernel setup image
+  @param[in]     KernelSetupSize - The kernel setup size
+
+  @retval    EFI_SUCCESS - The Linux kernel setup is valid and supported
+  @retval    EFI_INVALID_PARAMETER - KernelSetup was NULL
+  @retval    EFI_UNSUPPORTED - The Linux kernel is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+LoadLinuxCheckKernelSetup (
+  IN VOID        *KernelSetup,
+  IN UINTN       KernelSetupSize
+  );
+
+
+/**
+  Gets the initial runtime size of the Linux kernel image by examining
+  the kernel setup image.
+
+  @param[in]     KernelSetup - The kernel setup image
+  @param[in]     KernelSize - The kernel size on disk.
+
+  @retval    0                An error occurred
+  @retval    !0               The initial size required by the kernel to
+                              begin execution.
+
+**/
+UINTN
+EFIAPI
+LoadLinuxGetKernelSize (
+  IN VOID        *KernelSetup,
+  IN UINTN       KernelSize
+  );
+
+
+/**
+  Loads and boots UEFI Linux.
+
+  Note: If successful, then this routine will not return
+
+  @param[in]     Kernel - The main kernel image
+  @param[in,out] KernelSetup - The kernel setup image
+
+  @retval    EFI_NOT_FOUND - The Linux kernel was not found
+  @retval    EFI_INVALID_PARAMETER - Kernel or KernelSetup was NULL
+  @retval    EFI_UNSUPPORTED - The Linux kernel version is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+LoadLinux (
+  IN VOID      *Kernel,
+  IN OUT VOID  *KernelSetup
+  );
+
+
+/**
+  Allocates pages for the kernel setup image.
+
+  @param[in]     Pages - The number of pages
+
+  @retval    NULL - Unable to allocate pages
+  @retval    !NULL - The address of the pages allocated
+
+**/
+VOID*
+EFIAPI
+LoadLinuxAllocateKernelSetupPages (
+  IN UINTN                  Pages
+  );
+
+
+/**
+  Clears the uninitialised space before and after the struct setup_header
+  in the kernel setup image. The kernel requires that these be zeroed
+  unless explicitly initialised, so this function should be called after
+  the setup_header has been copied in from a bzImage, before setting up
+  anything else.
+
+  @param[in]     KernelSetup - The kernel setup image
+
+  @retval    EFI_SUCCESS - The Linux kernel setup was successfully initialized
+  @retval    EFI_INVALID_PARAMETER - KernelSetup was NULL
+  @retval    EFI_UNSUPPORTED - The Linux kernel is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+LoadLinuxInitializeKernelSetup (
+  IN VOID        *KernelSetup
+  );
+
+/**
+  Allocates pages for the kernel.
+
+  @param[in]     KernelSetup - The kernel setup image
+  @param[in]     Pages - The number of pages. (It is recommended to use the
+                         size returned from LoadLinuxGetKernelSize.)
+
+  @retval    NULL - Unable to allocate pages
+  @retval    !NULL - The address of the pages allocated
+
+**/
+VOID*
+EFIAPI
+LoadLinuxAllocateKernelPages (
+  IN VOID                   *KernelSetup,
+  IN UINTN                  Pages
+  );
+
+
+/**
+  Allocates pages for the kernel command line.
+
+  @param[in]     Pages - The number of pages.
+
+  @retval    NULL - Unable to allocate pages
+  @retval    !NULL - The address of the pages allocated
+
+**/
+VOID*
+EFIAPI
+LoadLinuxAllocateCommandLinePages (
+  IN UINTN                  Pages
+  );
+
+
+/**
+  Allocates pages for the initrd image.
+
+  @param[in,out] KernelSetup - The kernel setup image
+  @param[in]     Pages - The number of pages.
+
+  @retval    NULL - Unable to allocate pages
+  @retval    !NULL - The address of the pages allocated
+
+**/
+VOID*
+EFIAPI
+LoadLinuxAllocateInitrdPages (
+  IN VOID                   *KernelSetup,
+  IN UINTN                  Pages
+  );
+
+
+/**
+  Sets the kernel command line parameter within the setup image.
+
+  @param[in,out] KernelSetup - The kernel setup image
+  @param[in]     CommandLine - The kernel command line
+
+  @retval    EFI_SUCCESS - The Linux kernel setup is valid and supported
+  @retval    EFI_INVALID_PARAMETER - KernelSetup was NULL
+  @retval    EFI_UNSUPPORTED - The Linux kernel is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+LoadLinuxSetCommandLine (
+  IN OUT VOID    *KernelSetup,
+  IN CHAR8       *CommandLine
+  );
+
+
+/**
+  Sets the kernel initial ram disk pointer within the setup image.
+
+  @param[in,out] KernelSetup - The kernel setup image
+  @param[in]     Initrd - Pointer to the initial ram disk
+  @param[in]     InitrdSize - The initial ram disk image size
+
+  @retval    EFI_SUCCESS - The Linux kernel setup is valid and supported
+  @retval    EFI_INVALID_PARAMETER - KernelSetup was NULL
+  @retval    EFI_UNSUPPORTED - The Linux kernel is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+LoadLinuxSetInitrd (
+  IN OUT VOID    *KernelSetup,
+  IN VOID        *Initrd,
+  IN UINTN       InitrdSize
+  );
+
+
+#endif
+

+ 224 - 0
Platform/Intel/SimicsOpenBoardPkg/Include/Library/SerializeVariablesLib.h

@@ -0,0 +1,224 @@
+/** @file
+  Serialize & Deserialize UEFI Variables
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __SERIALIZE_VARIABLES_LIB__
+#define __SERIALIZE_VARIABLES_LIB__
+
+
+/**
+  Callback function for each variable
+
+  @param[in] Context - Context as sent to the iteration function
+  @param[in] VariableName - Refer to RuntimeServices GetNextVariableName
+  @param[in] VendorGuid - Refer to RuntimeServices GetNextVariableName
+  @param[in] Attributes - Refer to RuntimeServices GetVariable
+  @param[in] DataSize - Refer to RuntimeServices GetVariable
+  @param[in] Data - Refer to RuntimeServices GetVariable
+
+  @retval RETURN_SUCCESS         Continue iterating through the variables
+  @return Any RETURN_ERROR       Stop iterating through the variables
+
+**/
+typedef
+RETURN_STATUS
+(EFIAPI *VARIABLE_SERIALIZATION_ITERATION_CALLBACK)(
+  IN  VOID                         *Context,
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid,
+  IN  UINT32                       Attributes,
+  IN  UINTN                        DataSize,
+  IN  VOID                         *Data
+  );
+
+
+/**
+  Creates a new variable serialization instance
+
+  @param[out]  Handle - Handle for a variable serialization instance
+
+  @retval      RETURN_SUCCESS - The variable serialization instance was
+                 successfully created.
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 create the variable serialization instance.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesNewInstance (
+  OUT EFI_HANDLE                      *Handle
+  );
+
+
+/**
+  Free memory associated with a variable serialization instance
+
+  @param[in]  Handle - Handle for a variable serialization instance
+
+  @retval      RETURN_SUCCESS - The variable serialization instance was
+                 successfully freed.
+  @retval      RETURN_INVALID_PARAMETER - Handle was not a valid
+                 variable serialization instance.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesFreeInstance (
+  IN EFI_HANDLE Handle
+  );
+
+
+/**
+  Creates a new variable serialization instance using the given
+  binary representation of the variables to fill the new instance
+
+  @param[out] Handle - Handle for a variable serialization instance
+  @param[in]  Buffer - A buffer with the serialized representation
+                of the variables.  Must be the same format as produced
+                by SerializeVariablesToBuffer.
+  @param[in]  Size - This is the size of the binary representation
+                of the variables.
+
+  @retval      RETURN_SUCCESS - The binary representation was successfully
+                 imported into a new variable serialization instance
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 create the new variable serialization instance
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesNewInstanceFromBuffer (
+  OUT EFI_HANDLE                          *Handle,
+  IN  VOID                                *Buffer,
+  IN  UINTN                               Size
+  );
+
+
+/**
+  Iterates all variables found with RuntimeServices GetNextVariableName
+
+  @param[in]   CallbackFunction - Function called for each variable instance
+  @param[in]   Context - Passed to each call of CallbackFunction
+
+  @retval      RETURN_SUCCESS - All variables were iterated without the
+                 CallbackFunction returning an error
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 iterate through the variables
+  @return      Any of RETURN_ERROR indicates an error reading the variable
+                 or an error was returned from CallbackFunction
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesIterateSystemVariables (
+  IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction,
+  IN VOID                                      *Context
+  );
+
+
+/**
+  Iterates all variables found in the variable serialization instance
+
+  @param[in]   Handle - Handle for a variable serialization instance
+  @param[in]   CallbackFunction - Function called for each variable instance
+  @param[in]   Context - Passed to each call of CallbackFunction
+
+  @retval      RETURN_SUCCESS - All variables were iterated without the
+                 CallbackFunction returning an error
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 iterate through the variables
+  @return      Any of RETURN_ERROR indicates an error reading the variable
+                 or an error was returned from CallbackFunction
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesIterateInstanceVariables (
+  IN EFI_HANDLE                                Handle,
+  IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction,
+  IN VOID                                      *Context
+  );
+
+
+/**
+  Sets all variables found in the variable serialization instance
+
+  @param[in]   Handle - Handle for a variable serialization instance
+
+  @retval      RETURN_SUCCESS - All variables were set successfully
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 set all the variables
+  @return      Any of RETURN_ERROR indicates an error reading the variables
+                 or in attempting to set a variable
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesSetSerializedVariables (
+  IN EFI_HANDLE                       Handle
+  );
+
+
+/**
+  Adds a variable to the variable serialization instance
+
+  @param[in] Handle - Handle for a variable serialization instance
+  @param[in] VariableName - Refer to RuntimeServices GetVariable
+  @param[in] VendorGuid - Refer to RuntimeServices GetVariable
+  @param[in] Attributes - Refer to RuntimeServices GetVariable
+  @param[in] DataSize - Refer to RuntimeServices GetVariable
+  @param[in] Data - Refer to RuntimeServices GetVariable
+
+  @retval      RETURN_SUCCESS - All variables were set successfully
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 add the variable
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesAddVariable (
+  IN EFI_HANDLE                   Handle,
+  IN CHAR16                       *VariableName,
+  IN EFI_GUID                     *VendorGuid,
+  IN UINT32                       Attributes,
+  IN UINTN                        DataSize,
+  IN VOID                         *Data
+  );
+
+
+/**
+  Serializes the variables known to this instance into the
+  provided buffer.
+
+  @param[in]     Handle - Handle for a variable serialization instance
+  @param[out]    Buffer - A buffer to store the binary representation
+                   of the variables.
+  @param[in,out] Size - On input this is the size of the buffer.
+                   On output this is the size of the binary representation
+                   of the variables.
+
+  @retval      RETURN_SUCCESS - The binary representation was successfully
+                 completed and returned in the buffer.
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 save the variables to the buffer.
+  @retval      RETURN_INVALID_PARAMETER - Handle was not a valid
+                 variable serialization instance or
+                 Size or Buffer were NULL.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesToBuffer (
+  IN     EFI_HANDLE                       Handle,
+  OUT    VOID                             *Buffer,
+  IN OUT UINTN                            *Size
+  );
+
+
+#endif
+

+ 55 - 0
Platform/Intel/SimicsOpenBoardPkg/Include/SimicsPlatforms.h

@@ -0,0 +1,55 @@
+/** @file
+  Simics Platform definitions
+
+  Copyright (C) 2015, Red Hat, Inc.
+  Copyright (c) 2014, Gabriel L. Somlo <somlo@cmu.edu>
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __SIMICS_PLATFORMS_H__
+#define __SIMICS_PLATFORMS_H__
+
+#include <Library/PciLib.h>
+#include <IndustryStandard/Pci22.h>
+#include <Register/X58Ich10.h>
+#include <IndustryStandard/I440FxPiix4.h>
+
+//
+// Simics Host Bridge DID Address
+//
+#define SIMICS_HOSTBRIDGE_DID \
+  PCI_LIB_ADDRESS (0, 0, 0, PCI_DEVICE_ID_OFFSET)
+
+//
+// Simics SideBand PCI device registers
+//
+#define SIMICS_SIDEBANDPCI_DEV  0
+#define SIMICS_SIDEBANDPCI_FUNC 7
+#define SIMICS_SIDEBANDPCI_SVID \
+  PCI_LIB_ADDRESS (0, 0, 7, PCI_SVID_OFFSET)
+#define SIMICS_SIDEBANDPCI_SDID \
+  PCI_LIB_ADDRESS (0, 0, 7, PCI_SID_OFFSET)
+#define SIMICS_SIDEBANDPCI_CAP \
+  PCI_LIB_ADDRESS (0, 0, 7, PCI_CAPBILITY_POINTER_OFFSET)
+#define SIMICS_SIDEBANDPCI_CAP_Offset 0x40
+#define SIMICS_SIDEBANDPCI_CAP_ID     0xFF
+
+//
+// Values we program into the PM base address registers
+//
+#define PIIX4_PMBA_VALUE  0xB000
+#define ICH10_PMBASE_VALUE 0x0400
+
+//
+// Common bits in same-purpose registers
+//
+#define PMBA_RTE BIT0
+
+//
+// Common IO ports relative to the Power Management Base Address
+//
+#define ACPI_TIMER_OFFSET 0x8
+
+#endif

+ 55 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/DxeLogoLib/DxeLogoLib.inf

@@ -0,0 +1,55 @@
+### @file
+# Module that show progress bar and title above it.
+#
+# General BDS defines and produce general interfaces for platform BDS driver including:
+# 1) BDS boot policy interface;
+# 2) BDS boot device connect interface;
+# 3) BDS Misc interfaces for mainting boot variable, ouput string, etc.
+#
+# Copyright (c) 2007 - 2019 Intel Corporation. All rights reserved. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+[Defines]
+  INF_VERSION                    = 0x00010017
+  BASE_NAME                      = DxeLogoLib
+  FILE_GUID                      = F5AE5B5C-42E8-4A9B-829D-5B631CD5367A
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = DXE_DRIVER
+  LIBRARY_CLASS                  = LogoLib|DXE_DRIVER UEFI_APPLICATION
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[LibraryClasses]
+  BaseLib
+  UefiBootServicesTableLib
+  MemoryAllocationLib
+  UefiLib
+  BaseMemoryLib
+  DebugLib
+  PrintLib
+  PcdLib
+  DxeServicesLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+
+[FeaturePcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport
+
+[Sources]
+  Logo.c
+
+[Protocols]
+  gEfiGraphicsOutputProtocolGuid                ## SOMETIMES_CONSUMES
+  gEfiUgaDrawProtocolGuid                       ## SOMETIMES_CONSUMES
+  gEfiBootLogoProtocolGuid                      ## SOMETIMES_CONSUMES
+  gEfiUserManagerProtocolGuid                   ## CONSUMES
+  gEfiOemBadgingProtocolGuid                    ## CONSUMES

+ 647 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/DxeLogoLib/Logo.c

@@ -0,0 +1,647 @@
+/** @file
+  BDS Lib functions which contain all the code to connect console device
+
+  Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+#include <Protocol/SimpleTextOut.h>
+#include <OemBadging.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UgaDraw.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+
+#include <IndustryStandard/Bmp.h>
+#include <Protocol/BootLogo.h>
+
+/**
+  Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
+  is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
+  buffer is passed in it will be used if it is big enough.
+
+  @param  BmpImage      Pointer to BMP file
+  @param  BmpImageSize  Number of bytes in BmpImage
+  @param  GopBlt        Buffer containing GOP version of BmpImage.
+  @param  GopBltSize    Size of GopBlt in bytes.
+  @param  PixelHeight   Height of GopBlt/BmpImage in pixels
+  @param  PixelWidth    Width of GopBlt/BmpImage in pixels
+
+  @retval EFI_SUCCESS           GopBlt and GopBltSize are returned.
+  @retval EFI_UNSUPPORTED       BmpImage is not a valid *.BMP image
+  @retval EFI_BUFFER_TOO_SMALL  The passed in GopBlt buffer is not big enough.
+                                GopBltSize will contain the required size.
+  @retval EFI_OUT_OF_RESOURCES  No enough buffer to allocate.
+
+**/
+EFI_STATUS
+ConvertBmpToGopBlt (
+  IN     VOID      *BmpImage,
+  IN     UINTN     BmpImageSize,
+  IN OUT VOID      **GopBlt,
+  IN OUT UINTN     *GopBltSize,
+     OUT UINTN     *PixelHeight,
+     OUT UINTN     *PixelWidth
+  )
+{
+  UINT8                         *Image;
+  UINT8                         *ImageHeader;
+  BMP_IMAGE_HEADER              *BmpHeader;
+  BMP_COLOR_MAP                 *BmpColorMap;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+  UINT64                        BltBufferSize;
+  UINTN                         Index;
+  UINTN                         Height;
+  UINTN                         Width;
+  UINTN                         ImageIndex;
+  UINT32                        DataSizePerLine;
+  BOOLEAN                       IsAllocated;
+  UINT32                        ColorMapNum;
+
+  if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
+
+  if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Doesn't support compress.
+  //
+  if (BmpHeader->CompressionType != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Only support BITMAPINFOHEADER format.
+  // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
+  //
+  if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // The data size in each line must be 4 byte alignment.
+  //
+  DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
+  BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
+  if (BltBufferSize > (UINT32) ~0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((BmpHeader->Size != BmpImageSize) ||
+      (BmpHeader->Size < BmpHeader->ImageOffset) ||
+      (BmpHeader->Size - BmpHeader->ImageOffset !=  BmpHeader->PixelHeight * DataSizePerLine)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Calculate Color Map offset in the image.
+  //
+  Image       = BmpImage;
+  BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
+  if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
+    switch (BmpHeader->BitPerPixel) {
+      case 1:
+        ColorMapNum = 2;
+        break;
+      case 4:
+        ColorMapNum = 16;
+        break;
+      case 8:
+        ColorMapNum = 256;
+        break;
+      default:
+        ColorMapNum = 0;
+        break;
+      }
+    //
+    // BMP file may has padding data between the bmp header section and the bmp data section.
+    //
+    if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Calculate graphics image data address in the image
+  //
+  Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
+  ImageHeader   = Image;
+
+  //
+  // Calculate the BltBuffer needed size.
+  //
+  BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
+  //
+  // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+  //
+  if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
+    return EFI_UNSUPPORTED;
+  }
+  BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+  IsAllocated   = FALSE;
+  if (*GopBlt == NULL) {
+    //
+    // GopBlt is not allocated by caller.
+    //
+    *GopBltSize = (UINTN) BltBufferSize;
+    *GopBlt     = AllocatePool (*GopBltSize);
+    IsAllocated = TRUE;
+    if (*GopBlt == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    //
+    // GopBlt has been allocated by caller.
+    //
+    if (*GopBltSize < (UINTN) BltBufferSize) {
+      *GopBltSize = (UINTN) BltBufferSize;
+      return EFI_BUFFER_TOO_SMALL;
+    }
+  }
+
+  *PixelWidth   = BmpHeader->PixelWidth;
+  *PixelHeight  = BmpHeader->PixelHeight;
+
+  //
+  // Convert image from BMP to Blt buffer format
+  //
+  BltBuffer = *GopBlt;
+  for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
+    Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
+    for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
+      switch (BmpHeader->BitPerPixel) {
+      case 1:
+        //
+        // Convert 1-bit (2 colors) BMP to 24-bit color
+        //
+        for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
+          Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
+          Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
+          Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
+          Blt++;
+          Width++;
+        }
+
+        Blt--;
+        Width--;
+        break;
+
+      case 4:
+        //
+        // Convert 4-bit (16 colors) BMP Palette to 24-bit color
+        //
+        Index       = (*Image) >> 4;
+        Blt->Red    = BmpColorMap[Index].Red;
+        Blt->Green  = BmpColorMap[Index].Green;
+        Blt->Blue   = BmpColorMap[Index].Blue;
+        if (Width < (BmpHeader->PixelWidth - 1)) {
+          Blt++;
+          Width++;
+          Index       = (*Image) & 0x0f;
+          Blt->Red    = BmpColorMap[Index].Red;
+          Blt->Green  = BmpColorMap[Index].Green;
+          Blt->Blue   = BmpColorMap[Index].Blue;
+        }
+        break;
+
+      case 8:
+        //
+        // Convert 8-bit (256 colors) BMP Palette to 24-bit color
+        //
+        Blt->Red    = BmpColorMap[*Image].Red;
+        Blt->Green  = BmpColorMap[*Image].Green;
+        Blt->Blue   = BmpColorMap[*Image].Blue;
+        break;
+
+      case 24:
+        //
+        // It is 24-bit BMP.
+        //
+        Blt->Blue   = *Image++;
+        Blt->Green  = *Image++;
+        Blt->Red    = *Image;
+        break;
+
+      default:
+        //
+        // Other bit format BMP is not supported.
+        //
+        if (IsAllocated) {
+          FreePool (*GopBlt);
+          *GopBlt = NULL;
+        }
+        return EFI_UNSUPPORTED;
+        break;
+      };
+
+    }
+
+    ImageIndex = (UINTN) (Image - ImageHeader);
+    if ((ImageIndex % 4) != 0) {
+      //
+      // Bmp Image starts each row on a 32-bit boundary!
+      //
+      Image = Image + (4 - (ImageIndex % 4));
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Use SystemTable Conout to stop video based Simple Text Out consoles from going
+  to the video device. Put up LogoFile on every video device that is a console.
+
+  @param[in]  LogoFile   File name of logo to display on the center of the screen.
+
+  @retval EFI_SUCCESS     ConsoleControl has been flipped to graphics and logo displayed.
+  @retval EFI_UNSUPPORTED Logo not found
+
+**/
+EFI_STATUS
+EFIAPI
+EnableBootLogo (
+  IN  EFI_GUID  *LogoFile
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_OEM_BADGING_PROTOCOL      *Badging;
+  UINT32                        SizeOfX;
+  UINT32                        SizeOfY;
+  INTN                          DestX;
+  INTN                          DestY;
+  UINT8                         *ImageData;
+  UINTN                         ImageSize;
+  UINTN                         BltSize;
+  UINT32                        Instance;
+  EFI_BADGING_FORMAT            Format;
+  EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
+  UINTN                         CoordinateX;
+  UINTN                         CoordinateY;
+  UINTN                         Height;
+  UINTN                         Width;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+  EFI_UGA_DRAW_PROTOCOL         *UgaDraw;
+  UINT32                        ColorDepth;
+  UINT32                        RefreshRate;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
+  EFI_BOOT_LOGO_PROTOCOL        *BootLogo;
+  UINTN                         NumberOfLogos;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
+  UINTN                         LogoDestX;
+  UINTN                         LogoDestY;
+  UINTN                         LogoHeight;
+  UINTN                         LogoWidth;
+  UINTN                         NewDestX;
+  UINTN                         NewDestY;
+  UINTN                         NewHeight;
+  UINTN                         NewWidth;
+  UINT64                        BufferSize;
+
+  UgaDraw = NULL;
+  //
+  // Try to open GOP first
+  //
+  Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
+  if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
+    GraphicsOutput = NULL;
+    //
+    // Open GOP failed, try to open UGA
+    //
+    Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
+  }
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Try to open Boot Logo Protocol.
+  //
+  BootLogo = NULL;
+  gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+
+  //
+  // Erase Cursor from screen
+  //
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+  Badging = NULL;
+  Status  = gBS->LocateProtocol (&gEfiOemBadgingProtocolGuid, NULL, (VOID **) &Badging);
+
+  if (GraphicsOutput != NULL) {
+    SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
+    SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
+
+  } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+    Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
+    if (EFI_ERROR (Status)) {
+      return EFI_UNSUPPORTED;
+    }
+  } else {
+    return EFI_UNSUPPORTED;
+  }
+
+  Blt = NULL;
+  NumberOfLogos = 0;
+  LogoDestX = 0;
+  LogoDestY = 0;
+  LogoHeight = 0;
+  LogoWidth = 0;
+  NewDestX = 0;
+  NewDestY = 0;
+  NewHeight = 0;
+  NewWidth = 0;
+  Instance = 0;
+  while (1) {
+    ImageData = NULL;
+    ImageSize = 0;
+
+    if (Badging != NULL) {
+      //
+      // Get image from OEMBadging protocol.
+      //
+      Status = Badging->GetImage (
+                          Badging,
+                          &Instance,
+                          &Format,
+                          &ImageData,
+                          &ImageSize,
+                          &Attribute,
+                          &CoordinateX,
+                          &CoordinateY
+                          );
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+
+    } else {
+      //
+      // Get the specified image from FV.
+      //
+      Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
+      if (EFI_ERROR (Status)) {
+        return EFI_UNSUPPORTED;
+      }
+
+      CoordinateX = 0;
+      CoordinateY = 0;
+      Attribute   = EfiBadgingDisplayAttributeCenter;
+    }
+
+    if (Blt != NULL) {
+      FreePool (Blt);
+    }
+
+    //
+    // Try BMP decoder
+    //
+    Blt = NULL;
+    Status = ConvertBmpToGopBlt (
+              ImageData,
+              ImageSize,
+              (VOID **) &Blt,
+              &BltSize,
+              &Height,
+              &Width
+              );
+
+    if (EFI_ERROR (Status)) {
+      FreePool (ImageData);
+
+      if (Badging == NULL) {
+        return Status;
+      } else {
+        continue;
+      }
+    }
+
+    //
+    // Calculate the display position according to Attribute.
+    //
+    switch (Attribute) {
+    case EfiBadgingDisplayAttributeLeftTop:
+      DestX = CoordinateX;
+      DestY = CoordinateY;
+      break;
+
+    case EfiBadgingDisplayAttributeCenterTop:
+      DestX = (SizeOfX - Width) / 2;
+      DestY = CoordinateY;
+      break;
+
+    case EfiBadgingDisplayAttributeRightTop:
+      DestX = (SizeOfX - Width - CoordinateX);
+      DestY = CoordinateY;;
+      break;
+
+    case EfiBadgingDisplayAttributeCenterRight:
+      DestX = (SizeOfX - Width - CoordinateX);
+      DestY = (SizeOfY - Height) / 2;
+      break;
+
+    case EfiBadgingDisplayAttributeRightBottom:
+      DestX = (SizeOfX - Width - CoordinateX);
+      DestY = (SizeOfY - Height - CoordinateY);
+      break;
+
+    case EfiBadgingDisplayAttributeCenterBottom:
+      DestX = (SizeOfX - Width) / 2;
+      DestY = (SizeOfY - Height - CoordinateY);
+      break;
+
+    case EfiBadgingDisplayAttributeLeftBottom:
+      DestX = CoordinateX;
+      DestY = (SizeOfY - Height - CoordinateY);
+      break;
+
+    case EfiBadgingDisplayAttributeCenterLeft:
+      DestX = CoordinateX;
+      DestY = (SizeOfY - Height) / 2;
+      break;
+
+    case EfiBadgingDisplayAttributeCenter:
+      DestX = (SizeOfX - Width) / 2;
+      DestY = (SizeOfY - Height) / 2;
+      break;
+
+    default:
+      DestX = CoordinateX;
+      DestY = CoordinateY;
+      break;
+    }
+
+    if ((DestX >= 0) && (DestY >= 0)) {
+      if (GraphicsOutput != NULL) {
+        Status = GraphicsOutput->Blt (
+                            GraphicsOutput,
+                            Blt,
+                            EfiBltBufferToVideo,
+                            0,
+                            0,
+                            (UINTN) DestX,
+                            (UINTN) DestY,
+                            Width,
+                            Height,
+                            Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                            );
+      } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+        Status = UgaDraw->Blt (
+                            UgaDraw,
+                            (EFI_UGA_PIXEL *) Blt,
+                            EfiUgaBltBufferToVideo,
+                            0,
+                            0,
+                            (UINTN) DestX,
+                            (UINTN) DestY,
+                            Width,
+                            Height,
+                            Width * sizeof (EFI_UGA_PIXEL)
+                            );
+      } else {
+        Status = EFI_UNSUPPORTED;
+      }
+
+      //
+      // Report displayed Logo information.
+      //
+      if (!EFI_ERROR (Status)) {
+        NumberOfLogos++;
+
+        if (LogoWidth == 0) {
+          //
+          // The first Logo.
+          //
+          LogoDestX = (UINTN) DestX;
+          LogoDestY = (UINTN) DestY;
+          LogoWidth = Width;
+          LogoHeight = Height;
+        } else {
+          //
+          // Merge new logo with old one.
+          //
+          NewDestX = MIN ((UINTN) DestX, LogoDestX);
+          NewDestY = MIN ((UINTN) DestY, LogoDestY);
+          NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
+          NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
+
+          LogoDestX = NewDestX;
+          LogoDestY = NewDestY;
+          LogoWidth = NewWidth;
+          LogoHeight = NewHeight;
+        }
+      }
+    }
+
+    FreePool (ImageData);
+
+    if (Badging == NULL) {
+      break;
+    }
+  }
+
+Done:
+  if (BootLogo == NULL || NumberOfLogos == 0) {
+    //
+    // No logo displayed.
+    //
+    if (Blt != NULL) {
+      FreePool (Blt);
+    }
+
+    return Status;
+  }
+
+  //
+  // Advertise displayed Logo information.
+  //
+  if (NumberOfLogos == 1) {
+    //
+    // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
+    //
+    LogoBlt = Blt;
+    Status = EFI_SUCCESS;
+  } else {
+    //
+    // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
+    //
+    if (Blt != NULL) {
+      FreePool (Blt);
+    }
+
+    //
+    // Ensure the LogoHeight * LogoWidth doesn't overflow
+    //
+    if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) {
+      return EFI_UNSUPPORTED;
+    }
+    BufferSize = MultU64x64 (LogoWidth, LogoHeight);
+
+    //
+    // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+    //
+    if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
+      return EFI_UNSUPPORTED;
+    }
+
+    LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+    if (LogoBlt == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    if (GraphicsOutput != NULL) {
+      Status = GraphicsOutput->Blt (
+                          GraphicsOutput,
+                          LogoBlt,
+                          EfiBltVideoToBltBuffer,
+                          LogoDestX,
+                          LogoDestY,
+                          0,
+                          0,
+                          LogoWidth,
+                          LogoHeight,
+                          LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                          );
+    } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+      Status = UgaDraw->Blt (
+                          UgaDraw,
+                          (EFI_UGA_PIXEL *) LogoBlt,
+                          EfiUgaVideoToBltBuffer,
+                          LogoDestX,
+                          LogoDestY,
+                          0,
+                          0,
+                          LogoWidth,
+                          LogoHeight,
+                          LogoWidth * sizeof (EFI_UGA_PIXEL)
+                          );
+    } else {
+      Status = EFI_UNSUPPORTED;
+    }
+  }
+
+  if (!EFI_ERROR (Status)) {
+    BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
+  }
+  FreePool (LogoBlt);
+
+  return Status;
+}

+ 83 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/DxeLogoLib/OemBadging.h

@@ -0,0 +1,83 @@
+/** @file
+  The OEM Badging Protocol defines the interface to get the OEM badging
+  image with the display attribute. This protocol can be produced based on OEM badging images.
+
+  Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EFI_OEM_BADGING_H__
+#define __EFI_OEM_BADGING_H__
+
+//
+// GUID for EFI OEM Badging Protocol
+//
+#define EFI_OEM_BADGING_PROTOCOL_GUID \
+  { 0x170e13c0, 0xbf1b, 0x4218, {0x87, 0x1d, 0x2a, 0xbd, 0xc6, 0xf8, 0x87, 0xbc } }
+
+
+typedef struct _EFI_OEM_BADGING_PROTOCOL EFI_OEM_BADGING_PROTOCOL;
+
+typedef enum {
+  EfiBadgingFormatBMP,
+  EfiBadgingFormatJPEG,
+  EfiBadgingFormatTIFF,
+  EfiBadgingFormatGIF,
+  EfiBadgingFormatUnknown
+} EFI_BADGING_FORMAT;
+
+typedef enum {
+  EfiBadgingDisplayAttributeLeftTop,
+  EfiBadgingDisplayAttributeCenterTop,
+  EfiBadgingDisplayAttributeRightTop,
+  EfiBadgingDisplayAttributeCenterRight,
+  EfiBadgingDisplayAttributeRightBottom,
+  EfiBadgingDisplayAttributeCenterBottom,
+  EfiBadgingDisplayAttributeLeftBottom,
+  EfiBadgingDisplayAttributeCenterLeft,
+  EfiBadgingDisplayAttributeCenter,
+  EfiBadgingDisplayAttributeCustomized
+} EFI_BADGING_DISPLAY_ATTRIBUTE;
+
+/**
+
+  Load an OEM badge image and return its data and attributes.
+
+  @param This              The pointer to this protocol instance.
+  @param Instance          The visible image instance is found.
+  @param Format            The format of the image. Examples: BMP, JPEG.
+  @param ImageData         The image data for the badge file. Currently only
+                           supports the .bmp file format.
+  @param ImageSize         The size of the image returned.
+  @param Attribute         The display attributes of the image returned.
+  @param CoordinateX       The X coordinate of the image.
+  @param CoordinateY       The Y coordinate of the image.
+
+  @retval EFI_SUCCESS      The image was fetched successfully.
+  @retval EFI_NOT_FOUND    The specified image could not be found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BADGING_GET_IMAGE)(
+  IN     EFI_OEM_BADGING_PROTOCOL          *This,
+  IN OUT UINT32                            *Instance,
+     OUT EFI_BADGING_FORMAT                *Format,
+     OUT UINT8                             **ImageData,
+     OUT UINTN                             *ImageSize,
+     OUT EFI_BADGING_DISPLAY_ATTRIBUTE     *Attribute,
+     OUT UINTN                             *CoordinateX,
+     OUT UINTN                             *CoordinateY
+);
+
+
+struct _EFI_OEM_BADGING_PROTOCOL {
+  EFI_BADGING_GET_IMAGE       GetImage;
+};
+
+
+extern EFI_GUID gEfiOemBadgingProtocolGuid;
+
+#endif

+ 42 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/DxeLoadLinuxLib.inf

@@ -0,0 +1,42 @@
+## @file
+#
+# Copyright (c) 2008 - 2019 Intel Corporation. All rights reserved. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = DxeLoadLinuxLib
+  FILE_GUID                      = 63CC8497-C9D0-46A8-AC08-49DF92A2FF62
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = DxeLoadLinuxLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources.common]
+  Linux.c
+  LinuxGdt.c
+
+[Sources.IA32]
+  Ia32/JumpToKernel.nasm
+
+[Sources.X64]
+  X64/JumpToKernel.nasm
+
+[Packages]
+  MdePkg/MdePkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  MemoryAllocationLib
+  BaseMemoryLib
+

+ 41 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.nasm

@@ -0,0 +1,41 @@
+; @file
+; Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+
+  SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; JumpToKernel (
+;   VOID *KernelStart,
+;   VOID *KernelBootParams
+;   );
+;------------------------------------------------------------------------------
+global ASM_PFX(JumpToKernel)
+ASM_PFX(JumpToKernel):
+
+    mov     esi, [esp + 8]
+    call    DWORD [esp + 4]
+    ret
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; JumpToUefiKernel (
+;   EFI_HANDLE ImageHandle,
+;   EFI_SYSTEM_TABLE *SystemTable,
+;   VOID *KernelBootParams,
+;   VOID *KernelStart
+;   );
+;------------------------------------------------------------------------------
+global ASM_PFX(JumpToUefiKernel)
+ASM_PFX(JumpToUefiKernel):
+
+    mov     eax, [esp + 12]
+    mov     eax, [eax + 0x264]
+    add     eax, [esp + 16]
+    jmp     eax
+

+ 662 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/Linux.c

@@ -0,0 +1,662 @@
+/** @file
+  Copyright (c) 2011 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "LoadLinuxLib.h"
+
+
+/**
+  A simple check of the kernel setup image
+
+  An assumption is made that the size of the data is at least the
+  size of struct boot_params.
+
+  @param[in]    KernelSetup - The kernel setup image
+
+  @retval    EFI_SUCCESS - The kernel setup looks valid and supported
+  @retval    EFI_INVALID_PARAMETER - KernelSetup was NULL
+  @retval    EFI_UNSUPPORTED - The kernel setup is not valid or supported
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BasicKernelSetupCheck (
+  IN VOID        *KernelSetup
+  )
+{
+  return LoadLinuxCheckKernelSetup(KernelSetup, sizeof (struct boot_params));
+}
+
+
+EFI_STATUS
+EFIAPI
+LoadLinuxCheckKernelSetup (
+  IN VOID        *KernelSetup,
+  IN UINTN       KernelSetupSize
+  )
+{
+  struct boot_params        *Bp;
+
+  if (KernelSetup == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (KernelSetupSize < sizeof (*Bp)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Bp = (struct boot_params*) KernelSetup;
+
+  if ((Bp->hdr.signature != 0xAA55) || // Check boot sector signature
+      (Bp->hdr.header != SETUP_HDR) ||
+      (Bp->hdr.version < 0x205) || // We only support relocatable kernels
+      (!Bp->hdr.relocatable_kernel)
+     ) {
+    return EFI_UNSUPPORTED;
+  } else {
+    return EFI_SUCCESS;
+  }
+}
+
+
+UINTN
+EFIAPI
+LoadLinuxGetKernelSize (
+  IN VOID        *KernelSetup,
+  IN UINTN       KernelSize
+  )
+{
+  struct boot_params        *Bp;
+
+  if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
+    return 0;
+  }
+
+  Bp = (struct boot_params*) KernelSetup;
+
+  if (Bp->hdr.version > 0x20a) {
+    return Bp->hdr.init_size;
+  } else {
+    //
+    // Add extra size for kernel decompression
+    //
+    return 3 * KernelSize;
+  }
+}
+
+
+VOID*
+EFIAPI
+LoadLinuxAllocateKernelSetupPages (
+  IN UINTN                  Pages
+  )
+{
+  EFI_STATUS                Status;
+  EFI_PHYSICAL_ADDRESS      Address;
+
+  Address = BASE_1GB;
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiLoaderData,
+                  Pages,
+                  &Address
+                  );
+  if (!EFI_ERROR (Status)) {
+    return (VOID*)(UINTN) Address;
+  } else {
+    return NULL;
+  }
+}
+
+EFI_STATUS
+EFIAPI
+LoadLinuxInitializeKernelSetup (
+  IN VOID        *KernelSetup
+  )
+{
+  EFI_STATUS                Status;
+  UINTN                     SetupEnd;
+  struct boot_params        *Bp;
+
+  Status = BasicKernelSetupCheck (KernelSetup);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Bp = (struct boot_params*) KernelSetup;
+
+  SetupEnd = 0x202 + (Bp->hdr.jump & 0xff);
+
+  //
+  // Clear all but the setup_header
+  //
+  ZeroMem (KernelSetup, 0x1f1);
+  ZeroMem (((UINT8 *)KernelSetup) + SetupEnd, 4096 - SetupEnd);
+  DEBUG ((EFI_D_INFO, "Cleared kernel setup 0-0x1f1, 0x%Lx-0x1000\n",
+    (UINT64)SetupEnd));
+
+  return EFI_SUCCESS;
+}
+
+VOID*
+EFIAPI
+LoadLinuxAllocateKernelPages (
+  IN VOID                   *KernelSetup,
+  IN UINTN                  Pages
+  )
+{
+  EFI_STATUS                Status;
+  EFI_PHYSICAL_ADDRESS      KernelAddress;
+  UINT32                    Loop;
+  struct boot_params        *Bp;
+
+  if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
+    return NULL;
+  }
+
+  Bp = (struct boot_params*) KernelSetup;
+
+  for (Loop = 1; Loop < 512; Loop++) {
+    KernelAddress = MultU64x32 (
+                      2 * Bp->hdr.kernel_alignment,
+                      Loop
+                      );
+    Status = gBS->AllocatePages (
+                    AllocateAddress,
+                    EfiLoaderData,
+                    Pages,
+                    &KernelAddress
+                    );
+    if (!EFI_ERROR (Status)) {
+      return (VOID*)(UINTN) KernelAddress;
+    }
+  }
+
+  return NULL;
+}
+
+
+VOID*
+EFIAPI
+LoadLinuxAllocateCommandLinePages (
+  IN UINTN                  Pages
+  )
+{
+  EFI_STATUS                Status;
+  EFI_PHYSICAL_ADDRESS      Address;
+
+  Address = 0xa0000;
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiLoaderData,
+                  Pages,
+                  &Address
+                  );
+  if (!EFI_ERROR (Status)) {
+    return (VOID*)(UINTN) Address;
+  } else {
+    return NULL;
+  }
+}
+
+
+VOID*
+EFIAPI
+LoadLinuxAllocateInitrdPages (
+  IN VOID                   *KernelSetup,
+  IN UINTN                  Pages
+  )
+{
+  EFI_STATUS                Status;
+  EFI_PHYSICAL_ADDRESS      Address;
+
+  struct boot_params        *Bp;
+
+  if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
+    return NULL;
+  }
+
+  Bp = (struct boot_params*) KernelSetup;
+
+  Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Bp->hdr.ramdisk_max;
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiLoaderData,
+                  Pages,
+                  &Address
+                  );
+  if (!EFI_ERROR (Status)) {
+    return (VOID*)(UINTN) Address;
+  } else {
+    return NULL;
+  }
+}
+
+
+STATIC
+VOID
+SetupLinuxMemmap (
+  IN OUT struct boot_params        *Bp
+  )
+{
+  EFI_STATUS                           Status;
+  UINT8                                TmpMemoryMap[1];
+  UINTN                                MapKey;
+  UINTN                                DescriptorSize;
+  UINT32                               DescriptorVersion;
+  UINTN                                MemoryMapSize;
+  EFI_MEMORY_DESCRIPTOR                *MemoryMap;
+  EFI_MEMORY_DESCRIPTOR                *MemoryMapPtr;
+  UINTN                                Index;
+  struct efi_info                      *Efi;
+  struct e820_entry                    *LastE820;
+  struct e820_entry                    *E820;
+  UINTN                                E820EntryCount;
+  EFI_PHYSICAL_ADDRESS                 LastEndAddr;
+
+  //
+  // Get System MemoryMapSize
+  //
+  MemoryMapSize = sizeof (TmpMemoryMap);
+  Status = gBS->GetMemoryMap (
+                  &MemoryMapSize,
+                  (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap,
+                  &MapKey,
+                  &DescriptorSize,
+                  &DescriptorVersion
+                  );
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+  //
+  // Enlarge space here, because we will allocate pool now.
+  //
+  MemoryMapSize += EFI_PAGE_SIZE;
+  Status = gBS->AllocatePool (
+                  EfiLoaderData,
+                  MemoryMapSize,
+                  (VOID **) &MemoryMap
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Get System MemoryMap
+  //
+  Status = gBS->GetMemoryMap (
+                  &MemoryMapSize,
+                  MemoryMap,
+                  &MapKey,
+                  &DescriptorSize,
+                  &DescriptorVersion
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  LastE820 = NULL;
+  E820 = &Bp->e820_map[0];
+  E820EntryCount = 0;
+  LastEndAddr = 0;
+  MemoryMapPtr = MemoryMap;
+  for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
+    UINTN E820Type = 0;
+
+    if (MemoryMap->NumberOfPages == 0) {
+      continue;
+    }
+
+    switch(MemoryMap->Type) {
+    case EfiReservedMemoryType:
+    case EfiRuntimeServicesCode:
+    case EfiRuntimeServicesData:
+    case EfiMemoryMappedIO:
+    case EfiMemoryMappedIOPortSpace:
+    case EfiPalCode:
+      E820Type = E820_RESERVED;
+      break;
+
+    case EfiUnusableMemory:
+      E820Type = E820_UNUSABLE;
+      break;
+
+    case EfiACPIReclaimMemory:
+      E820Type = E820_ACPI;
+      break;
+
+    case EfiLoaderCode:
+    case EfiLoaderData:
+    case EfiBootServicesCode:
+    case EfiBootServicesData:
+    case EfiConventionalMemory:
+      E820Type = E820_RAM;
+      break;
+
+    case EfiACPIMemoryNVS:
+      E820Type = E820_NVS;
+      break;
+
+    default:
+      DEBUG ((
+        EFI_D_ERROR,
+        "Invalid EFI memory descriptor type (0x%x)!\n",
+        MemoryMap->Type
+        ));
+      continue;
+    }
+
+    if ((LastE820 != NULL) &&
+        (LastE820->type == (UINT32) E820Type) &&
+        (MemoryMap->PhysicalStart == LastEndAddr)) {
+      LastE820->size += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
+      LastEndAddr += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
+    } else {
+      if (E820EntryCount >= (sizeof (Bp->e820_map) / sizeof (Bp->e820_map[0]))) {
+        break;
+      }
+      E820->type = (UINT32) E820Type;
+      E820->addr = MemoryMap->PhysicalStart;
+      E820->size = EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
+      LastE820 = E820;
+      LastEndAddr = E820->addr + E820->size;
+      E820++;
+      E820EntryCount++;
+    }
+
+    //
+    // Get next item
+    //
+    MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize);
+  }
+  Bp->e820_entries = (UINT8) E820EntryCount;
+
+  Efi = &Bp->efi_info;
+  Efi->efi_systab = (UINT32)(UINTN) gST;
+  Efi->efi_memdesc_size = (UINT32) DescriptorSize;
+  Efi->efi_memdesc_version = DescriptorVersion;
+  Efi->efi_memmap = (UINT32)(UINTN) MemoryMapPtr;
+  Efi->efi_memmap_size = (UINT32) MemoryMapSize;
+#ifdef MDE_CPU_IA32
+  Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '3', '2');
+#else
+  Efi->efi_systab_hi = (UINT32) (((UINT64)(UINTN) gST) >> 32);
+  Efi->efi_memmap_hi = (UINT32) (((UINT64)(UINTN) MemoryMapPtr) >> 32);
+  Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '6', '4');
+#endif
+
+  gBS->ExitBootServices (gImageHandle, MapKey);
+}
+
+
+EFI_STATUS
+EFIAPI
+LoadLinuxSetCommandLine (
+  IN OUT VOID    *KernelSetup,
+  IN CHAR8       *CommandLine
+  )
+{
+  EFI_STATUS             Status;
+  struct boot_params     *Bp;
+
+  Status = BasicKernelSetupCheck (KernelSetup);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Bp = (struct boot_params*) KernelSetup;
+
+  Bp->hdr.cmd_line_ptr = (UINT32)(UINTN) CommandLine;
+
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+LoadLinuxSetInitrd (
+  IN OUT VOID    *KernelSetup,
+  IN VOID        *Initrd,
+  IN UINTN       InitrdSize
+  )
+{
+  EFI_STATUS             Status;
+  struct boot_params     *Bp;
+
+  Status = BasicKernelSetupCheck (KernelSetup);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Bp = (struct boot_params*) KernelSetup;
+
+  Bp->hdr.ramdisk_start = (UINT32)(UINTN) Initrd;
+  Bp->hdr.ramdisk_len = (UINT32) InitrdSize;
+
+  return EFI_SUCCESS;
+}
+
+
+STATIC VOID
+FindBits (
+  unsigned long Mask,
+  UINT8 *Pos,
+  UINT8 *Size
+  )
+{
+  UINT8 First, Len;
+
+  First = 0;
+  Len = 0;
+
+  if (Mask) {
+    while (!(Mask & 0x1)) {
+      Mask = Mask >> 1;
+      First++;
+    }
+
+    while (Mask & 0x1) {
+      Mask = Mask >> 1;
+      Len++;
+    }
+  }
+  *Pos = First;
+  *Size = Len;
+}
+
+
+STATIC
+EFI_STATUS
+SetupGraphicsFromGop (
+  struct screen_info           *Si,
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
+  )
+{
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+  EFI_STATUS                           Status;
+  UINTN                                Size;
+
+  Status = Gop->QueryMode(Gop, Gop->Mode->Mode, &Size, &Info);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  /* We found a GOP */
+
+  /* EFI framebuffer */
+  Si->orig_video_isVGA = 0x70;
+
+  Si->orig_x = 0;
+  Si->orig_y = 0;
+  Si->orig_video_page = 0;
+  Si->orig_video_mode = 0;
+  Si->orig_video_cols = 0;
+  Si->orig_video_lines = 0;
+  Si->orig_video_ega_bx = 0;
+  Si->orig_video_points = 0;
+
+  Si->lfb_base = (UINT32) Gop->Mode->FrameBufferBase;
+  Si->lfb_size = (UINT32) Gop->Mode->FrameBufferSize;
+  Si->lfb_width = (UINT16) Info->HorizontalResolution;
+  Si->lfb_height = (UINT16) Info->VerticalResolution;
+  Si->pages = 1;
+  Si->vesapm_seg = 0;
+  Si->vesapm_off = 0;
+
+  if (Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
+    Si->lfb_depth = 32;
+    Si->red_size = 8;
+    Si->red_pos = 0;
+    Si->green_size = 8;
+    Si->green_pos = 8;
+    Si->blue_size = 8;
+    Si->blue_pos = 16;
+    Si->rsvd_size = 8;
+    Si->rsvd_pos = 24;
+    Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
+
+  } else if (Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
+    Si->lfb_depth = 32;
+    Si->red_size = 8;
+    Si->red_pos = 16;
+    Si->green_size = 8;
+    Si->green_pos = 8;
+    Si->blue_size = 8;
+    Si->blue_pos = 0;
+    Si->rsvd_size = 8;
+    Si->rsvd_pos = 24;
+    Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
+  } else if (Info->PixelFormat == PixelBitMask) {
+    FindBits(Info->PixelInformation.RedMask,
+        &Si->red_pos, &Si->red_size);
+    FindBits(Info->PixelInformation.GreenMask,
+        &Si->green_pos, &Si->green_size);
+    FindBits(Info->PixelInformation.BlueMask,
+        &Si->blue_pos, &Si->blue_size);
+    FindBits(Info->PixelInformation.ReservedMask,
+        &Si->rsvd_pos, &Si->rsvd_size);
+    Si->lfb_depth = Si->red_size + Si->green_size +
+      Si->blue_size + Si->rsvd_size;
+    Si->lfb_linelength = (UINT16) ((Info->PixelsPerScanLine * Si->lfb_depth) / 8);
+  } else {
+    Si->lfb_depth = 4;
+    Si->red_size = 0;
+    Si->red_pos = 0;
+    Si->green_size = 0;
+    Si->green_pos = 0;
+    Si->blue_size = 0;
+    Si->blue_pos = 0;
+    Si->rsvd_size = 0;
+    Si->rsvd_pos = 0;
+    Si->lfb_linelength = Si->lfb_width / 2;
+  }
+
+  return Status;
+}
+
+
+STATIC
+EFI_STATUS
+SetupGraphics (
+  IN OUT struct boot_params *Bp
+  )
+{
+  EFI_STATUS                      Status;
+  EFI_HANDLE                      *HandleBuffer;
+  UINTN                           HandleCount;
+  UINTN                           Index;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL    *Gop;
+
+  ZeroMem ((VOID*)&Bp->screen_info, sizeof(Bp->screen_info));
+
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiGraphicsOutputProtocolGuid,
+                  NULL,
+                  &HandleCount,
+                  &HandleBuffer
+                  );
+  if (!EFI_ERROR (Status)) {
+    for (Index = 0; Index < HandleCount; Index++) {
+      Status = gBS->HandleProtocol (
+                      HandleBuffer[Index],
+                      &gEfiGraphicsOutputProtocolGuid,
+                      (VOID*) &Gop
+                      );
+      if (EFI_ERROR (Status)) {
+        continue;
+      }
+
+      Status = SetupGraphicsFromGop (&Bp->screen_info, Gop);
+      if (!EFI_ERROR (Status)) {
+        FreePool (HandleBuffer);
+        return EFI_SUCCESS;
+      }
+    }
+
+    FreePool (HandleBuffer);
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+
+STATIC
+EFI_STATUS
+SetupLinuxBootParams (
+  IN OUT struct boot_params *Bp
+  )
+{
+  SetupGraphics (Bp);
+
+  SetupLinuxMemmap (Bp);
+
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+LoadLinux (
+  IN VOID      *Kernel,
+  IN OUT VOID  *KernelSetup
+  )
+{
+  EFI_STATUS             Status;
+  struct boot_params  *Bp;
+
+  Status = BasicKernelSetupCheck (KernelSetup);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Bp = (struct boot_params *) KernelSetup;
+
+  if (Bp->hdr.version < 0x205 || !Bp->hdr.relocatable_kernel) {
+    //
+    // We only support relocatable kernels
+    //
+    return EFI_UNSUPPORTED;
+  }
+
+  InitLinuxDescriptorTables ();
+
+  Bp->hdr.code32_start = (UINT32)(UINTN) Kernel;
+  if (Bp->hdr.version >= 0x20c && Bp->hdr.handover_offset &&
+      (Bp->hdr.xloadflags & (sizeof (UINTN) == 4 ? BIT2 : BIT3))) {
+    DEBUG ((EFI_D_INFO, "Jumping to kernel EFI handover point at ofs %x\n", Bp->hdr.handover_offset));
+
+    DisableInterrupts ();
+    JumpToUefiKernel ((VOID*) gImageHandle, (VOID*) gST, KernelSetup, Kernel);
+  }
+
+  //
+  // Old kernels without EFI handover protocol
+  //
+  SetupLinuxBootParams (KernelSetup);
+
+  DEBUG ((EFI_D_INFO, "Jumping to kernel\n"));
+  DisableInterrupts ();
+  SetLinuxDescriptorTables ();
+  JumpToKernel (Kernel, (VOID*) KernelSetup);
+
+  return EFI_SUCCESS;
+}
+

+ 175 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/LinuxGdt.c

@@ -0,0 +1,175 @@
+/** @file
+  Initialize GDT for Linux.
+
+  Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "LoadLinuxLib.h"
+
+
+//
+// Local structure definitions
+//
+
+#pragma pack (1)
+
+//
+// Global Descriptor Entry structures
+//
+
+typedef struct _GDT_ENTRY {
+  UINT16 Limit15_0;
+  UINT16 Base15_0;
+  UINT8  Base23_16;
+  UINT8  Type;
+  UINT8  Limit19_16_and_flags;
+  UINT8  Base31_24;
+} GDT_ENTRY;
+
+typedef
+struct _GDT_ENTRIES {
+  GDT_ENTRY Null;
+  GDT_ENTRY Null2;
+  GDT_ENTRY Linear;
+  GDT_ENTRY LinearCode;
+  GDT_ENTRY TaskSegment;
+  GDT_ENTRY Spare4;
+  GDT_ENTRY Spare5;
+} GDT_ENTRIES;
+
+#pragma pack ()
+
+STATIC GDT_ENTRIES *mGdt = NULL;
+
+//
+// Global descriptor table (GDT) Template
+//
+STATIC GDT_ENTRIES GdtTemplate = {
+  //
+  // Null
+  //
+  {
+    0x0,            // limit 15:0
+    0x0,            // base 15:0
+    0x0,            // base 23:16
+    0x0,            // type
+    0x0,            // limit 19:16, flags
+    0x0,            // base 31:24
+  },
+  //
+  // Null2
+  //
+  {
+    0x0,            // limit 15:0
+    0x0,            // base 15:0
+    0x0,            // base 23:16
+    0x0,            // type
+    0x0,            // limit 19:16, flags
+    0x0,            // base 31:24
+  },
+  //
+  // Linear
+  //
+  {
+    0x0FFFF,        // limit 0xFFFFF
+    0x0,            // base 0
+    0x0,
+    0x09A,          // present, ring 0, data, expand-up, writable
+    0x0CF,          // page-granular, 32-bit
+    0x0,
+  },
+  //
+  // LinearCode
+  //
+  {
+    0x0FFFF,        // limit 0xFFFFF
+    0x0,            // base 0
+    0x0,
+    0x092,          // present, ring 0, data, expand-up, writable
+    0x0CF,          // page-granular, 32-bit
+    0x0,
+  },
+  //
+  // TaskSegment
+  //
+  {
+    0x0,            // limit 0
+    0x0,            // base 0
+    0x0,
+    0x089,          // ?
+    0x080,          // ?
+    0x0,
+  },
+  //
+  // Spare4
+  //
+  {
+    0x0,            // limit 0
+    0x0,            // base 0
+    0x0,
+    0x0,            // present, ring 0, data, expand-up, writable
+    0x0,            // page-granular, 32-bit
+    0x0,
+  },
+  //
+  // Spare5
+  //
+  {
+    0x0,            // limit 0
+    0x0,            // base 0
+    0x0,
+    0x0,            // present, ring 0, data, expand-up, writable
+    0x0,            // page-granular, 32-bit
+    0x0,
+  },
+};
+
+/**
+  Initialize Global Descriptor Table.
+
+**/
+VOID
+InitLinuxDescriptorTables (
+  VOID
+  )
+{
+  //
+  // Allocate Runtime Data for the GDT
+  //
+  mGdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8);
+  ASSERT (mGdt != NULL);
+  mGdt = ALIGN_POINTER (mGdt, 8);
+
+  //
+  // Initialize all GDT entries
+  //
+  CopyMem (mGdt, &GdtTemplate, sizeof (GdtTemplate));
+
+}
+
+/**
+  Initialize Global Descriptor Table.
+
+**/
+VOID
+SetLinuxDescriptorTables (
+  VOID
+  )
+{
+  IA32_DESCRIPTOR GdtPtr;
+  IA32_DESCRIPTOR IdtPtr;
+
+  //
+  // Write GDT register
+  //
+  GdtPtr.Base = (UINT32)(UINTN)(VOID*) mGdt;
+  GdtPtr.Limit = (UINT16) (sizeof (GdtTemplate) - 1);
+  AsmWriteGdtr (&GdtPtr);
+
+  IdtPtr.Base = (UINT32) 0;
+  IdtPtr.Limit = (UINT16) 0;
+  AsmWriteIdtr (&IdtPtr);
+}
+

+ 52 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/LoadLinuxLib.h

@@ -0,0 +1,52 @@
+/** @file
+  Boot UEFI Linux.
+
+  Copyright (c) 2008 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _LOAD_LINUX_LIB_INCLUDED_
+#define _LOAD_LINUX_LIB_INCLUDED_
+
+#include <Uefi.h>
+#include <Library/LoadLinuxLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <IndustryStandard/LinuxBzImage.h>
+
+#include <Protocol/GraphicsOutput.h>
+
+VOID
+EFIAPI
+JumpToKernel (
+  VOID *KernelStart,
+  VOID *KernelBootParams
+  );
+
+VOID
+EFIAPI
+JumpToUefiKernel (
+  EFI_HANDLE ImageHandle,
+  EFI_SYSTEM_TABLE *SystemTable,
+  VOID *KernelBootParams,
+  VOID *KernelStart
+  );
+
+VOID
+InitLinuxDescriptorTables (
+  VOID
+  );
+
+VOID
+SetLinuxDescriptorTables (
+  VOID
+  );
+
+#endif
+

+ 85 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/LoadLinuxLib/X64/JumpToKernel.nasm

@@ -0,0 +1,85 @@
+; @file
+; Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+
+  DEFAULT REL
+  SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; JumpToKernel (
+;   VOID *KernelStart,         // rcx
+;   VOID *KernelBootParams     // rdx
+;   );
+;------------------------------------------------------------------------------
+global ASM_PFX(JumpToKernel)
+ASM_PFX(JumpToKernel):
+
+    ; Set up for executing kernel. BP in %esi, entry point on the stack
+    ; (64-bit when the 'ret' will use it as 32-bit, but we're little-endian)
+    mov    rsi, rdx
+    push   rcx
+
+    ; Jump into the compatibility mode CS
+    push    0x10
+    lea     rax, [.0]
+    push    rax
+    DB 0x48, 0xcb                      ; retfq
+
+.0:
+    ; Now in compatibility mode.
+
+    DB 0xb8, 0x18, 0x0, 0x0, 0x0    ; movl    $0x18, %eax
+    DB 0x8e, 0xd8                      ; movl    %eax, %ds
+    DB 0x8e, 0xc0                      ; movl    %eax, %es
+    DB 0x8e, 0xe0                      ; movl    %eax, %fs
+    DB 0x8e, 0xe8                      ; movl    %eax, %gs
+    DB 0x8e, 0xd0                      ; movl    %eax, %ss
+
+    ; Disable paging
+    DB 0xf, 0x20, 0xc0                ; movl    %cr0, %eax
+    DB 0xf, 0xba, 0xf8, 0x1f          ; btcl    $31, %eax
+    DB 0xf, 0x22, 0xc0                ; movl    %eax, %cr0
+
+    ; Disable long mode in EFER
+    DB 0xb9, 0x80, 0x0, 0x0, 0xc0    ; movl    $0x0c0000080, %ecx
+    DB 0xf, 0x32                      ; rdmsr
+    DB 0xf, 0xba, 0xf8, 0x8          ; btcl    $8, %eax
+    DB 0xf, 0x30                      ; wrmsr
+
+    ; Disable PAE
+    DB 0xf, 0x20, 0xe0                ; movl    %cr4, %eax
+    DB 0xf, 0xba, 0xf8, 0x5          ; btcl    $5, %eax
+    DB 0xf, 0x22, 0xe0                ; movl    %eax, %cr4
+
+    DB 0x31, 0xed                      ; xor     %ebp, %ebp
+    DB 0x31, 0xff                      ; xor     %edi, %edi
+    DB 0x31, 0xdb                      ; xor     %ebx, %ebx
+    DB 0xc3                            ; ret
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; JumpToUefiKernel (
+;   EFI_HANDLE ImageHandle,        // rcx
+;   EFI_SYSTEM_TABLE *SystemTable, // rdx
+;   VOID *KernelBootParams         // r8
+;   VOID *KernelStart,             // r9
+;   );
+;------------------------------------------------------------------------------
+global ASM_PFX(JumpToUefiKernel)
+ASM_PFX(JumpToUefiKernel):
+
+    mov     rdi, rcx
+    mov     rsi, rdx
+    mov     rdx, r8
+    xor     rax, rax
+    mov     eax, [r8 + 0x264]
+    add     r9, rax
+    add     r9, 0x200
+    call    r9
+    ret
+

+ 507 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/NvVarsFileLib/FsAccess.c

@@ -0,0 +1,507 @@
+/** @file
+  File System Access for NvVarsFileLib
+
+  Copyright (c) 2004 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "NvVarsFileLib.h"
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+
+/**
+  Open the NvVars file for reading or writing
+
+  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
+  @param[in]  ReadingFile - TRUE: open the file for reading.  FALSE: writing
+  @param[out] NvVarsFile - If EFI_SUCCESS is returned, then this is updated
+                           with the opened NvVars file.
+
+  @return     EFI_SUCCESS if the file was opened
+
+**/
+EFI_STATUS
+GetNvVarsFile (
+  IN  EFI_HANDLE            FsHandle,
+  IN  BOOLEAN               ReadingFile,
+  OUT EFI_FILE_HANDLE       *NvVarsFile
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL       *Fs;
+  EFI_FILE_HANDLE                       Root;
+
+  //
+  // Get the FileSystem protocol on that handle
+  //
+  Status = gBS->HandleProtocol (
+                  FsHandle,
+                  &gEfiSimpleFileSystemProtocolGuid,
+                  (VOID **)&Fs
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the volume (the root directory)
+  //
+  Status = Fs->OpenVolume (Fs, &Root);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Attempt to open the NvVars file in the root directory
+  //
+  Status = Root->Open (
+                   Root,
+                   NvVarsFile,
+                   L"NvVars",
+                   ReadingFile ?
+                     EFI_FILE_MODE_READ :
+                     (
+                       EFI_FILE_MODE_CREATE |
+                       EFI_FILE_MODE_READ |
+                       EFI_FILE_MODE_WRITE
+                     ),
+                   0
+                   );
+
+  return Status;
+}
+
+
+/**
+  Open the NvVars file for reading or writing
+
+  @param[in]  File - The file to inspect
+  @param[out] Exists - Returns whether the file exists
+  @param[out] Size - Returns the size of the file
+                     (0 if the file does not exist)
+
+**/
+VOID
+NvVarsFileReadCheckup (
+  IN  EFI_FILE_HANDLE        File,
+  OUT BOOLEAN                *Exists,
+  OUT UINTN                  *Size
+  )
+{
+  EFI_FILE_INFO               *FileInfo;
+
+  *Exists = FALSE;
+  *Size = 0;
+
+  FileInfo = FileHandleGetInfo (File);
+  if (FileInfo == NULL) {
+    return;
+  }
+
+  if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
+    FreePool (FileInfo);
+    return;
+  }
+
+  *Exists = TRUE;
+  *Size = (UINTN) FileInfo->FileSize;
+
+  FreePool (FileInfo);
+}
+
+
+/**
+  Open the NvVars file for reading or writing
+
+  @param[in]  File - The file to inspect
+  @param[out] Exists - Returns whether the file exists
+  @param[out] Size - Returns the size of the file
+                     (0 if the file does not exist)
+
+**/
+EFI_STATUS
+FileHandleEmpty (
+  IN  EFI_FILE_HANDLE        File
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_FILE_INFO               *FileInfo;
+
+  //
+  // Retrieve the FileInfo structure
+  //
+  FileInfo = FileHandleGetInfo (File);
+  if (FileInfo == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // If the path is a directory, then return an error
+  //
+  if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
+    FreePool (FileInfo);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // If the file size is already 0, then it is empty, so
+  // we can return success.
+  //
+  if (FileInfo->FileSize == 0) {
+    FreePool (FileInfo);
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Set the file size to 0.
+  //
+  FileInfo->FileSize = 0;
+  Status = FileHandleSetInfo (File, FileInfo);
+
+  FreePool (FileInfo);
+
+  return Status;
+}
+
+
+/**
+  Reads a file to a newly allocated buffer
+
+  @param[in]  File - The file to read
+  @param[in]  ReadSize - The size of data to read from the file
+
+  @return     Pointer to buffer allocated to hold the file
+              contents.  NULL if an error occurred.
+
+**/
+VOID*
+FileHandleReadToNewBuffer (
+  IN EFI_FILE_HANDLE            FileHandle,
+  IN UINTN                      ReadSize
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       ActualReadSize;
+  VOID                        *FileContents;
+
+  ActualReadSize = ReadSize;
+  FileContents = AllocatePool (ReadSize);
+  if (FileContents != NULL) {
+    Status = FileHandleRead (
+               FileHandle,
+               &ReadSize,
+               FileContents
+               );
+    if (EFI_ERROR (Status) || (ActualReadSize != ReadSize)) {
+      FreePool (FileContents);
+      return NULL;
+    }
+  }
+
+  return FileContents;
+}
+
+
+/**
+  Reads the contents of the NvVars file on the file system
+
+  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
+
+  @return     EFI_STATUS based on the success or failure of the file read
+
+**/
+EFI_STATUS
+ReadNvVarsFile (
+  IN  EFI_HANDLE            FsHandle
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_FILE_HANDLE             File;
+  UINTN                       FileSize;
+  BOOLEAN                     FileExists;
+  VOID                        *FileContents;
+  EFI_HANDLE                  SerializedVariables;
+
+  Status = GetNvVarsFile (FsHandle, TRUE, &File);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "FsAccess.c: Could not open NV Variables file on this file system\n"));
+    return Status;
+  }
+
+  NvVarsFileReadCheckup (File, &FileExists, &FileSize);
+  if (FileSize == 0) {
+    FileHandleClose (File);
+    return EFI_UNSUPPORTED;
+  }
+
+  FileContents = FileHandleReadToNewBuffer (File, FileSize);
+  if (FileContents == NULL) {
+    FileHandleClose (File);
+    return EFI_UNSUPPORTED;
+  }
+
+  DEBUG ((
+    EFI_D_INFO,
+    "FsAccess.c: Read %Lu bytes from NV Variables file\n",
+    (UINT64)FileSize
+    ));
+
+  Status = SerializeVariablesNewInstanceFromBuffer (
+             &SerializedVariables,
+             FileContents,
+             FileSize
+             );
+  if (!RETURN_ERROR (Status)) {
+    Status = SerializeVariablesSetSerializedVariables (SerializedVariables);
+  }
+
+  FreePool (FileContents);
+  FileHandleClose (File);
+
+  return Status;
+}
+
+
+/**
+  Writes a variable to indicate that the NV variables
+  have been loaded from the file system.
+
+**/
+STATIC
+VOID
+SetNvVarsVariable (
+  VOID
+  )
+{
+  BOOLEAN                        VarData;
+  UINTN                          Size;
+
+  //
+  // Write a variable to indicate we've already loaded the
+  // variable data.  If it is found, we skip the loading on
+  // subsequent attempts.
+  //
+  Size = sizeof (VarData);
+  VarData = TRUE;
+  gRT->SetVariable (
+         L"NvVars",
+         &gEfiSimpleFileSystemProtocolGuid,
+         EFI_VARIABLE_NON_VOLATILE |
+           EFI_VARIABLE_BOOTSERVICE_ACCESS |
+           EFI_VARIABLE_RUNTIME_ACCESS,
+         Size,
+         (VOID*) &VarData
+         );
+}
+
+
+/**
+  Loads the non-volatile variables from the NvVars file on the
+  given file system.
+
+  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
+
+  @return     EFI_STATUS based on the success or failure of load operation
+
+**/
+EFI_STATUS
+LoadNvVarsFromFs (
+  EFI_HANDLE                            FsHandle
+  )
+{
+  EFI_STATUS                     Status;
+  BOOLEAN                        VarData;
+  UINTN                          Size;
+
+  DEBUG ((EFI_D_INFO, "FsAccess.c: LoadNvVarsFromFs\n"));
+
+  //
+  // We write a variable to indicate we've already loaded the
+  // variable data.  If it is found, we skip the loading.
+  //
+  // This is relevant if the non-volatile variable have been
+  // able to survive a reboot operation.  In that case, we don't
+  // want to re-load the file as it would overwrite newer changes
+  // made to the variables.
+  //
+  Size = sizeof (VarData);
+  VarData = TRUE;
+  Status = gRT->GetVariable (
+                  L"NvVars",
+                  &gEfiSimpleFileSystemProtocolGuid,
+                  NULL,
+                  &Size,
+                  (VOID*) &VarData
+                  );
+  if (Status == EFI_SUCCESS) {
+    DEBUG ((EFI_D_INFO, "NV Variables were already loaded\n"));
+    return EFI_ALREADY_STARTED;
+  }
+
+  //
+  // Attempt to restore the variables from the NvVars file.
+  //
+  Status = ReadNvVarsFile (FsHandle);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "Error while restoring NV variable data\n"));
+    return Status;
+  }
+
+  //
+  // Write a variable to indicate we've already loaded the
+  // variable data.  If it is found, we skip the loading on
+  // subsequent attempts.
+  //
+  SetNvVarsVariable();
+
+  DEBUG ((
+    EFI_D_INFO,
+    "FsAccess.c: Read NV Variables file (size=%Lu)\n",
+    (UINT64)Size
+    ));
+
+  return Status;
+}
+
+
+STATIC
+RETURN_STATUS
+EFIAPI
+IterateVariablesCallbackAddAllNvVariables (
+  IN  VOID                         *Context,
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid,
+  IN  UINT32                       Attributes,
+  IN  UINTN                        DataSize,
+  IN  VOID                         *Data
+  )
+{
+  EFI_HANDLE  Instance;
+
+  Instance = (EFI_HANDLE) Context;
+
+  //
+  // Only save non-volatile variables
+  //
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+    return RETURN_SUCCESS;
+  }
+
+  return SerializeVariablesAddVariable (
+           Instance,
+           VariableName,
+           VendorGuid,
+           Attributes,
+           DataSize,
+           Data
+           );
+}
+
+
+/**
+  Saves the non-volatile variables into the NvVars file on the
+  given file system.
+
+  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
+
+  @return     EFI_STATUS based on the success or failure of load operation
+
+**/
+EFI_STATUS
+SaveNvVarsToFs (
+  EFI_HANDLE                            FsHandle
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_FILE_HANDLE             File;
+  UINTN                       WriteSize;
+  UINTN                       VariableDataSize;
+  VOID                        *VariableData;
+  EFI_HANDLE                  SerializedVariables;
+
+  SerializedVariables = NULL;
+
+  Status = SerializeVariablesNewInstance (&SerializedVariables);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = SerializeVariablesIterateSystemVariables (
+             IterateVariablesCallbackAddAllNvVariables,
+             (VOID*) SerializedVariables
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  VariableData = NULL;
+  VariableDataSize = 0;
+  Status = SerializeVariablesToBuffer (
+             SerializedVariables,
+             NULL,
+             &VariableDataSize
+             );
+  if (Status == RETURN_BUFFER_TOO_SMALL) {
+    VariableData = AllocatePool (VariableDataSize);
+    if (VariableData == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+    } else {
+      Status = SerializeVariablesToBuffer (
+                 SerializedVariables,
+                 VariableData,
+                 &VariableDataSize
+                 );
+    }
+  }
+
+  SerializeVariablesFreeInstance (SerializedVariables);
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Open the NvVars file for writing.
+  //
+  Status = GetNvVarsFile (FsHandle, FALSE, &File);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));
+    return Status;
+  }
+
+  //
+  // Empty the starting file contents.
+  //
+  Status = FileHandleEmpty (File);
+  if (EFI_ERROR (Status)) {
+    FileHandleClose (File);
+    return Status;
+  }
+
+  WriteSize = VariableDataSize;
+  Status = FileHandleWrite (File, &WriteSize, VariableData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  FileHandleClose (File);
+
+  if (!EFI_ERROR (Status)) {
+    //
+    // Write a variable to indicate we've already loaded the
+    // variable data.  If it is found, we skip the loading on
+    // subsequent attempts.
+    //
+    SetNvVarsVariable();
+
+	DEBUG ((EFI_D_INFO, "Saved NV Variables to NvVars file\n"));
+  }
+
+  return Status;
+}
+
+

+ 77 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/NvVarsFileLib/NvVarsFileLib.c

@@ -0,0 +1,77 @@
+/** @file
+  Save Non-Volatile Variables to a file system.
+
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "NvVarsFileLib.h"
+#include <Library/DebugLib.h>
+#include <Library/NvVarsFileLib.h>
+
+EFI_HANDLE    mNvVarsFileLibFsHandle = NULL;
+
+
+/**
+  Attempts to connect the NvVarsFileLib to the specified file system.
+
+  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
+
+  @return     The EFI_STATUS while attempting to connect the NvVarsFileLib
+              to the file system instance.
+  @retval     EFI_SUCCESS - The given file system was connected successfully
+
+**/
+EFI_STATUS
+EFIAPI
+ConnectNvVarsToFileSystem (
+  IN EFI_HANDLE    FsHandle
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // We might fail to load the variable, since the file system initially
+  // will not have the NvVars file.
+  //
+  LoadNvVarsFromFs (FsHandle);
+
+  //
+  // We must be able to save the variables successfully to the file system
+  // to have connected successfully.
+  //
+  Status = SaveNvVarsToFs (FsHandle);
+  if (!EFI_ERROR (Status)) {
+    mNvVarsFileLibFsHandle = FsHandle;
+  }
+
+  return Status;
+}
+
+
+/**
+  Update non-volatile variables stored on the file system.
+
+  @return     The EFI_STATUS while attempting to update the variable on
+              the connected file system.
+  @retval     EFI_SUCCESS - The non-volatile variables were saved to the disk
+  @retval     EFI_NOT_STARTED - A file system has not been connected
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateNvVarsOnFileSystem (
+  )
+{
+  if (mNvVarsFileLibFsHandle == NULL) {
+    //
+    // A file system had not been connected to the library.
+    //
+    return EFI_NOT_STARTED;
+  } else {
+    return SaveNvVarsToFs (mNvVarsFileLibFsHandle);
+  }
+}
+
+

+ 55 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/NvVarsFileLib/NvVarsFileLib.h

@@ -0,0 +1,55 @@
+/** @file
+  Save Non-Volatile Variables to a file system.
+
+  Copyright (c) 2009 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __NV_VARS_FILE_LIB_INSTANCE__
+#define __NV_VARS_FILE_LIB_INSTANCE__
+
+#include <Uefi.h>
+
+#include <Guid/FileInfo.h>
+
+#include <Protocol/SimpleFileSystem.h>
+
+#include <Library/BaseLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/SerializeVariablesLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+/**
+  Loads the non-volatile variables from the NvVars file on the
+  given file system.
+
+  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
+
+  @return     EFI_STATUS based on the success or failure of load operation
+
+**/
+EFI_STATUS
+LoadNvVarsFromFs (
+  EFI_HANDLE                            FsHandle
+  );
+
+
+/**
+  Saves the non-volatile variables into the NvVars file on the
+  given file system.
+
+  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
+
+  @return     EFI_STATUS based on the success or failure of load operation
+
+**/
+EFI_STATUS
+SaveNvVarsToFs (
+  EFI_HANDLE                            FsHandle
+  );
+
+#endif
+

+ 53 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/NvVarsFileLib/NvVarsFileLib.inf

@@ -0,0 +1,53 @@
+## @file
+#  NvVarsFileLib
+#
+#  This library saves and restores non-volatile variables in a
+#  file within a file system.
+#
+# Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = NvVarsFileLib
+  FILE_GUID                      = 8ECD4CC0-1772-4583-8A74-83633A15FAA0
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = NvVarsFileLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  FsAccess.c
+  NvVarsFileLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ShellPkg/ShellPkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  FileHandleLib
+  MemoryAllocationLib
+  SerializeVariablesLib
+
+[Protocols]
+  gEfiSimpleFileSystemProtocolGuid              ## CONSUMES
+
+[Guids]
+  gEfiFileInfoGuid
+
+[Depex]
+  gEfiVariableWriteArchProtocolGuid
+

+ 68 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PciHostBridgeLib/PciHostBridge.h

@@ -0,0 +1,68 @@
+/** @file
+  Header file of OVMF instance of PciHostBridgeLib.
+
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+PCI_ROOT_BRIDGE *
+ScanForRootBridges (
+  UINTN      *NumberOfRootBridges
+);
+
+/**
+  Initialize a PCI_ROOT_BRIDGE structure.
+
+  @param[in]  Supports         Supported attributes.
+
+  @param[in]  Attributes       Initial attributes.
+
+  @param[in]  AllocAttributes  Allocation attributes.
+
+  @param[in]  RootBusNumber    The bus number to store in RootBus.
+
+  @param[in]  MaxSubBusNumber  The inclusive maximum bus number that can be
+                               assigned to any subordinate bus found behind any
+                               PCI bridge hanging off this root bus.
+
+                               The caller is repsonsible for ensuring that
+                               RootBusNumber <= MaxSubBusNumber. If
+                               RootBusNumber equals MaxSubBusNumber, then the
+                               root bus has no room for subordinate buses.
+
+  @param[in]  Io               IO aperture.
+
+  @param[in]  Mem              MMIO aperture.
+
+  @param[in]  MemAbove4G       MMIO aperture above 4G.
+
+  @param[in]  PMem             Prefetchable MMIO aperture.
+
+  @param[in]  PMemAbove4G      Prefetchable MMIO aperture above 4G.
+
+  @param[out] RootBus          The PCI_ROOT_BRIDGE structure (allocated by the
+                               caller) that should be filled in by this
+                               function.
+
+  @retval EFI_SUCCESS           Initialization successful. A device path
+                                consisting of an ACPI device path node, with
+                                UID = RootBusNumber, has been allocated and
+                                linked into RootBus.
+
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
+**/
+EFI_STATUS
+InitRootBridge (
+  IN  UINT64                   Supports,
+  IN  UINT64                   Attributes,
+  IN  UINT64                   AllocAttributes,
+  IN  UINT8                    RootBusNumber,
+  IN  UINT8                    MaxSubBusNumber,
+  IN  PCI_ROOT_BRIDGE_APERTURE *Io,
+  IN  PCI_ROOT_BRIDGE_APERTURE *Mem,
+  IN  PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
+  IN  PCI_ROOT_BRIDGE_APERTURE *PMem,
+  IN  PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G,
+  OUT PCI_ROOT_BRIDGE          *RootBus
+  );

+ 419 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c

@@ -0,0 +1,419 @@
+/** @file
+  SIMICS QSP's instance of the PCI Host Bridge Library.
+
+  Copyright (C) 2016, Red Hat, Inc.
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Pci.h>
+#include <Register/X58Ich10.h>
+
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/PciRootBridgeIo.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/PciLib.h>
+#include "PciHostBridge.h"
+
+
+#pragma pack(1)
+typedef struct {
+  ACPI_HID_DEVICE_PATH     AcpiDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH;
+#pragma pack ()
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
+  L"Mem", L"I/O", L"Bus"
+};
+
+
+STATIC
+CONST
+OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = {
+  {
+    {
+      ACPI_DEVICE_PATH,
+      ACPI_DP,
+      {
+        (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)),
+        (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8)
+      }
+    },
+    EISA_PNP_ID(0x0A03), // HID
+    0                    // UID
+  },
+
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      END_DEVICE_PATH_LENGTH,
+      0
+    }
+  }
+};
+
+STATIC PCI_ROOT_BRIDGE_APERTURE mNonExistAperture = { MAX_UINT64, 0 };
+
+/**
+  Initialize a PCI_ROOT_BRIDGE structure.
+
+  @param[in]  Supports         Supported attributes.
+
+  @param[in]  Attributes       Initial attributes.
+
+  @param[in]  AllocAttributes  Allocation attributes.
+
+  @param[in]  RootBusNumber    The bus number to store in RootBus.
+
+  @param[in]  MaxSubBusNumber  The inclusive maximum bus number that can be
+                               assigned to any subordinate bus found behind any
+                               PCI bridge hanging off this root bus.
+
+                               The caller is repsonsible for ensuring that
+                               RootBusNumber <= MaxSubBusNumber. If
+                               RootBusNumber equals MaxSubBusNumber, then the
+                               root bus has no room for subordinate buses.
+
+  @param[in]  Io               IO aperture.
+
+  @param[in]  Mem              MMIO aperture.
+
+  @param[in]  MemAbove4G       MMIO aperture above 4G.
+
+  @param[in]  PMem             Prefetchable MMIO aperture.
+
+  @param[in]  PMemAbove4G      Prefetchable MMIO aperture above 4G.
+
+  @param[out] RootBus          The PCI_ROOT_BRIDGE structure (allocated by the
+                               caller) that should be filled in by this
+                               function.
+
+  @retval EFI_SUCCESS           Initialization successful. A device path
+                                consisting of an ACPI device path node, with
+                                UID = RootBusNumber, has been allocated and
+                                linked into RootBus.
+
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
+**/
+EFI_STATUS
+InitRootBridge (
+  IN  UINT64                   Supports,
+  IN  UINT64                   Attributes,
+  IN  UINT64                   AllocAttributes,
+  IN  UINT8                    RootBusNumber,
+  IN  UINT8                    MaxSubBusNumber,
+  IN  PCI_ROOT_BRIDGE_APERTURE *Io,
+  IN  PCI_ROOT_BRIDGE_APERTURE *Mem,
+  IN  PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
+  IN  PCI_ROOT_BRIDGE_APERTURE *PMem,
+  IN  PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G,
+  OUT PCI_ROOT_BRIDGE          *RootBus
+  )
+{
+  OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;
+
+  //
+  // Be safe if other fields are added to PCI_ROOT_BRIDGE later.
+  //
+  ZeroMem (RootBus, sizeof *RootBus);
+
+  RootBus->Segment = 0;
+
+  RootBus->Supports   = Supports;
+  RootBus->Attributes = Attributes;
+
+  RootBus->DmaAbove4G = FALSE;
+
+  RootBus->AllocationAttributes = AllocAttributes;
+  RootBus->Bus.Base  = RootBusNumber;
+  RootBus->Bus.Limit = MaxSubBusNumber;
+  CopyMem (&RootBus->Io, Io, sizeof (*Io));
+  CopyMem (&RootBus->Mem, Mem, sizeof (*Mem));
+  CopyMem (&RootBus->MemAbove4G, MemAbove4G, sizeof (*MemAbove4G));
+  CopyMem (&RootBus->PMem, PMem, sizeof (*PMem));
+  CopyMem (&RootBus->PMemAbove4G, PMemAbove4G, sizeof (*PMemAbove4G));
+
+  RootBus->NoExtendedConfigSpace = (PcdGet16 (PcdSimicsX58HostBridgePciDevId) !=
+                                    INTEL_ICH10_DEVICE_ID);
+
+  DevicePath = AllocateCopyPool (sizeof mRootBridgeDevicePathTemplate,
+                 &mRootBridgeDevicePathTemplate);
+  if (DevicePath == NULL) {
+    DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  DevicePath->AcpiDevicePath.UID = RootBusNumber;
+  RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
+
+  DEBUG ((EFI_D_INFO,
+    "%a: populated root bus %d, with room for %d subordinate bus(es)\n",
+    __FUNCTION__, RootBusNumber, MaxSubBusNumber - RootBusNumber));
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Uninitialize a PCI_ROOT_BRIDGE structure set up with InitRootBridge().
+
+  param[in] RootBus  The PCI_ROOT_BRIDGE structure, allocated by the caller and
+                     initialized with InitRootBridge(), that should be
+                     uninitialized. This function doesn't free RootBus.
+**/
+STATIC
+VOID
+UninitRootBridge (
+  IN PCI_ROOT_BRIDGE *RootBus
+  )
+{
+  FreePool (RootBus->DevicePath);
+}
+
+
+/**
+  Return all the root bridge instances in an array.
+
+  @param Count  Return the count of root bridge instances.
+
+  @return All the root bridge instances in an array.
+          The array should be passed into PciHostBridgeFreeRootBridges()
+          when it's not used.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+  UINTN *Count
+  )
+{
+  EFI_STATUS           Status;
+  UINT64               ExtraRootBridges;
+  PCI_ROOT_BRIDGE      *Bridges;
+  UINTN                Initialized;
+  UINTN                LastRootBridgeNumber;
+  UINTN                RootBridgeNumber;
+  UINT64               Attributes;
+  UINT64               AllocationAttributes;
+  PCI_ROOT_BRIDGE_APERTURE Io;
+  PCI_ROOT_BRIDGE_APERTURE Mem;
+  PCI_ROOT_BRIDGE_APERTURE MemAbove4G;
+
+  ZeroMem (&Io, sizeof (Io));
+  ZeroMem (&Mem, sizeof (Mem));
+  ZeroMem (&MemAbove4G, sizeof (MemAbove4G));
+
+  Attributes = EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO |
+    EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |
+    EFI_PCI_ATTRIBUTE_ISA_IO_16 |
+    EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO |
+    EFI_PCI_ATTRIBUTE_VGA_MEMORY |
+    EFI_PCI_ATTRIBUTE_VGA_IO_16 |
+    EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
+
+  AllocationAttributes = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;
+  if (PcdGet64 (PcdPciMmio64Size) > 0) {
+    AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;
+    MemAbove4G.Base = PcdGet64 (PcdPciMmio64Base);
+    MemAbove4G.Limit = PcdGet64 (PcdPciMmio64Base) +
+                       PcdGet64 (PcdPciMmio64Size) - 1;
+  } else {
+    CopyMem (&MemAbove4G, &mNonExistAperture, sizeof (mNonExistAperture));
+  }
+
+  Io.Base = PcdGet64 (PcdPciIoBase);
+  Io.Limit = PcdGet64 (PcdPciIoBase) + (PcdGet64 (PcdPciIoSize) - 1);
+  Mem.Base = PcdGet64 (PcdPciMmio32Base);
+  Mem.Limit = PcdGet64 (PcdPciMmio32Base) + (PcdGet64 (PcdPciMmio32Size) - 1);
+
+  *Count = 0;
+  ExtraRootBridges = 0;
+
+  //
+  // Allocate the "main" root bridge, and any extra root bridges.
+  //
+  Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);
+  if (Bridges == NULL) {
+    DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));
+    return NULL;
+  }
+  Initialized = 0;
+
+  //
+  // The "main" root bus is always there.
+  //
+  LastRootBridgeNumber = 0;
+
+  //
+  // Scan all other root buses. If function 0 of any device on a bus returns a
+  // VendorId register value different from all-bits-one, then that bus is
+  // alive.
+  //
+  for (RootBridgeNumber = 1;
+       RootBridgeNumber <= PCI_MAX_BUS && Initialized < ExtraRootBridges;
+       ++RootBridgeNumber) {
+    UINTN Device;
+
+    for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {
+      if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0,
+                       PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) {
+        break;
+      }
+    }
+    if (Device <= PCI_MAX_DEVICE) {
+      //
+      // Found the next root bus. We can now install the *previous* one,
+      // because now we know how big a bus number range *that* one has, for any
+      // subordinate buses that might exist behind PCI bridges hanging off it.
+      //
+      Status = InitRootBridge (
+        Attributes,
+        Attributes,
+        AllocationAttributes,
+        (UINT8) LastRootBridgeNumber,
+        (UINT8) (RootBridgeNumber - 1),
+        &Io,
+        &Mem,
+        &MemAbove4G,
+        &mNonExistAperture,
+        &mNonExistAperture,
+        &Bridges[Initialized]
+        );
+      if (EFI_ERROR (Status)) {
+        goto FreeBridges;
+      }
+      ++Initialized;
+      LastRootBridgeNumber = RootBridgeNumber;
+    }
+  }
+
+  //
+  // Install the last root bus (which might be the only, ie. main, root bus, if
+  // we've found no extra root buses).
+  //
+  Status = InitRootBridge (
+    Attributes,
+    Attributes,
+    AllocationAttributes,
+    (UINT8) LastRootBridgeNumber,
+    PCI_MAX_BUS,
+    &Io,
+    &Mem,
+    &MemAbove4G,
+    &mNonExistAperture,
+    &mNonExistAperture,
+    &Bridges[Initialized]
+    );
+  if (EFI_ERROR (Status)) {
+    goto FreeBridges;
+  }
+  ++Initialized;
+
+  *Count = Initialized;
+  return Bridges;
+
+FreeBridges:
+  while (Initialized > 0) {
+    --Initialized;
+    UninitRootBridge (&Bridges[Initialized]);
+  }
+
+  FreePool (Bridges);
+  return NULL;
+}
+
+
+/**
+  Free the root bridge instances array returned from
+  PciHostBridgeGetRootBridges().
+
+  @param  The root bridge instances array.
+  @param  The count of the array.
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+  PCI_ROOT_BRIDGE *Bridges,
+  UINTN           Count
+  )
+{
+  if (Bridges == NULL && Count == 0) {
+    return;
+  }
+  ASSERT (Bridges != NULL && Count > 0);
+
+  do {
+    --Count;
+    UninitRootBridge (&Bridges[Count]);
+  } while (Count > 0);
+
+  FreePool (Bridges);
+}
+
+
+/**
+  Inform the platform that the resource conflict happens.
+
+  @param HostBridgeHandle Handle of the Host Bridge.
+  @param Configuration    Pointer to PCI I/O and PCI memory resource
+                          descriptors. The Configuration contains the resources
+                          for all the root bridges. The resource for each root
+                          bridge is terminated with END descriptor and an
+                          additional END is appended indicating the end of the
+                          entire resources. The resource descriptor field
+                          values follow the description in
+                          EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+                          .SubmitResources().
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+  EFI_HANDLE                        HostBridgeHandle,
+  VOID                              *Configuration
+  )
+{
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+  UINTN                             RootBridgeIndex;
+  DEBUG ((EFI_D_ERROR, "PciHostBridge: Resource conflict happens!\n"));
+
+  RootBridgeIndex = 0;
+  Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+  while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+    DEBUG ((EFI_D_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+    for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+      ASSERT (Descriptor->ResType <
+              (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) /
+               sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0])
+               )
+              );
+      DEBUG ((EFI_D_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
+              mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
+              Descriptor->AddrLen, Descriptor->AddrRangeMax
+              ));
+      if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+        DEBUG ((EFI_D_ERROR, "     Granularity/SpecificFlag = %ld / %02x%s\n",
+                Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+                ((Descriptor->SpecificFlag &
+                  EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
+                  ) != 0) ? L" (Prefetchable)" : L""
+                ));
+      }
+    }
+    //
+    // Skip the END descriptor for root bridge
+    //
+    ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
+    Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+                   (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
+                   );
+  }
+}

+ 51 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf

@@ -0,0 +1,51 @@
+## @file
+#  Simics's instance of the PCI Host Bridge Library.
+#
+#  Copyright (C) 2016, Red Hat, Inc.
+#  Copyright (c) 2016 - 2019 Intel Corporation. All rights reserved. <BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PciHostBridgeLib
+  FILE_GUID                      = 2F04EC41-C3A0-43EB-AC6A-409F973F4439
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PciHostBridgeLib
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  PciHostBridgeLib.c
+  PciHostBridge.h
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+  SimicsIch10Pkg/Ich10Pkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  PciLib
+
+[Pcd]
+  gBoardModuleTokenSpaceGuid.PcdPciIoBase
+  gBoardModuleTokenSpaceGuid.PcdPciIoSize
+  gBoardModuleTokenSpaceGuid.PcdPciMmio32Base
+  gBoardModuleTokenSpaceGuid.PcdPciMmio32Size
+  gBoardModuleTokenSpaceGuid.PcdPciMmio64Base
+  gBoardModuleTokenSpaceGuid.PcdPciMmio64Size
+  gBoardModuleTokenSpaceGuid.PcdSimicsX58HostBridgePciDevId
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration

+ 100 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PeiReportFvLib/Fv.c

@@ -0,0 +1,100 @@
+/** @file
+  Build FV related hobs for platform.
+
+  Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "PiPei.h"
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+
+BOOLEAN mS3Supported = TRUE;
+
+/**
+  Publish PEI & DXE (Decompressed) Memory based FVs to let PEI
+  and DXE know about them.
+
+  @retval EFI_SUCCESS   Platform PEI FVs were initialized successfully.
+
+**/
+EFI_STATUS
+PeiFvInitialization (
+  VOID
+  )
+{
+  BOOLEAN SecureS3Needed;
+
+  DEBUG ((EFI_D_INFO, "Platform PEI Firmware Volume Initialization\n"));
+
+  DEBUG (
+    (EFI_D_ERROR, "Firmware Volume HOB: 0x%x 0x%x\n",
+      PcdGet32 (PcdSimicsPeiMemFvBase),
+      PcdGet32 (PcdSimicsPeiMemFvSize)
+      )
+    );
+  //
+  // Create a memory allocation HOB for the PEI FV.
+  //
+  // Allocate as ACPI NVS is S3 is supported
+  //
+  BuildMemoryAllocationHob (
+    PcdGet32 (PcdSimicsPeiMemFvBase),
+    PcdGet32 (PcdSimicsPeiMemFvSize),
+    mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+    );
+
+  //
+  // Let DXE know about the DXE FV
+  //
+  BuildFvHob (PcdGet32 (PcdSimicsDxeMemFvBase), PcdGet32 (PcdSimicsDxeMemFvSize));
+
+  SecureS3Needed = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire);
+
+  //
+  // Create a memory allocation HOB for the DXE FV.
+  //
+  // If "secure" S3 is needed, then SEC will decompress both PEI and DXE
+  // firmware volumes at S3 resume too, hence we need to keep away the OS from
+  // DXEFV as well. Otherwise we only need to keep away DXE itself from the
+  // DXEFV area.
+  //
+  BuildMemoryAllocationHob (
+    PcdGet32 (PcdSimicsDxeMemFvBase),
+    PcdGet32 (PcdSimicsDxeMemFvSize),
+    SecureS3Needed ? EfiACPIMemoryNVS : EfiBootServicesData
+    );
+
+  //
+  // Additionally, said decompression will use temporary memory above the end
+  // of DXEFV, so let's keep away the OS from there too.
+  //
+  if (SecureS3Needed) {
+    UINT32 DxeMemFvEnd;
+
+    DxeMemFvEnd = PcdGet32 (PcdSimicsDxeMemFvBase) +
+                  PcdGet32 (PcdSimicsDxeMemFvSize);
+    BuildMemoryAllocationHob (
+      DxeMemFvEnd,
+      PcdGet32 (PcdSimicsDecompressionScratchEnd) - DxeMemFvEnd,
+      EfiACPIMemoryNVS
+      );
+  }
+
+  //
+  // Let PEI know about the DXE FV so it can find the DXE Core
+  //
+  PeiServicesInstallFvInfoPpi (
+    NULL,
+    (VOID *)(UINTN) PcdGet32 (PcdSimicsDxeMemFvBase),
+    PcdGet32 (PcdSimicsDxeMemFvSize),
+    NULL,
+    NULL
+    );
+
+  return EFI_SUCCESS;
+}
+

+ 119 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PeiReportFvLib/PeiReportFvLib.c

@@ -0,0 +1,119 @@
+/** @file
+  Source code file for Report Firmware Volume (FV) library
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/ReportFvLib.h>
+#include <Guid/FirmwareFileSystem2.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Library/IoLib.h>
+#include <Register/X58Ich10.h>
+
+EFI_STATUS
+PeiFvInitialization(
+  VOID
+);
+
+VOID
+ReportPreMemFv (
+  VOID
+  )
+{
+  if (IoBitFieldRead16(ICH10_PMBASE_IO + 4, 10, 12) != 0x5) { // not S3 resume
+    PeiFvInitialization();
+  }
+
+  DEBUG ((DEBUG_INFO, "Install FlashFvSecurity - 0x%x, 0x%x\n", PcdGet32 (PcdFlashFvSecurityBase), PcdGet32 (PcdFlashFvSecuritySize)));
+  PeiServicesInstallFvInfo2Ppi (
+    &(((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) PcdGet32 (PcdFlashFvSecurityBase))->FileSystemGuid),
+    (VOID *) (UINTN) PcdGet32 (PcdFlashFvSecurityBase),
+    PcdGet32 (PcdFlashFvSecuritySize),
+    NULL,
+    NULL,
+    0
+    );
+  DEBUG ((DEBUG_INFO, "Install FlashFvAdvanced - 0x%x, 0x%x\n", PcdGet32 (PcdFlashFvAdvancedBase), PcdGet32 (PcdFlashFvAdvancedSize)));
+  PeiServicesInstallFvInfo2Ppi (
+    &(((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) PcdGet32 (PcdFlashFvAdvancedBase))->FileSystemGuid),
+    (VOID *) (UINTN) PcdGet32 (PcdFlashFvAdvancedBase),
+    PcdGet32 (PcdFlashFvAdvancedSize),
+    NULL,
+    NULL,
+    0
+    );
+}
+
+VOID
+ReportPostMemFv (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_BOOT_MODE                 BootMode;
+
+  Status = PeiServicesGetBootMode (&BootMode);
+  ASSERT_EFI_ERROR (Status);
+
+  ///
+  /// Build HOB for DXE
+  ///
+  if (BootMode == BOOT_IN_RECOVERY_MODE) {
+    ///
+    /// Prepare the recovery service
+    ///
+  } else {
+    DEBUG ((DEBUG_INFO, "Install FlashFvPostMemory - 0x%x, 0x%x\n", PcdGet32 (PcdFlashFvPostMemoryBase), PcdGet32 (PcdFlashFvPostMemorySize)));
+    PeiServicesInstallFvInfo2Ppi (
+      &(((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) PcdGet32 (PcdFlashFvPostMemoryBase))->FileSystemGuid),
+      (VOID *) (UINTN) PcdGet32 (PcdFlashFvPostMemoryBase),
+      PcdGet32 (PcdFlashFvPostMemorySize),
+      NULL,
+      NULL,
+      0
+      );
+    DEBUG ((DEBUG_INFO, "Install FlashFvUefiBoot - 0x%x, 0x%x\n", PcdGet32 (PcdFlashFvUefiBootBase), PcdGet32 (PcdFlashFvUefiBootSize)));
+    PeiServicesInstallFvInfo2Ppi (
+      &(((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) PcdGet32 (PcdFlashFvUefiBootBase))->FileSystemGuid),
+      (VOID *) (UINTN) PcdGet32 (PcdFlashFvUefiBootBase),
+      PcdGet32 (PcdFlashFvUefiBootSize),
+      NULL,
+      NULL,
+      0
+      );
+    DEBUG ((DEBUG_INFO, "Install FlashFvOsBoot - 0x%x, 0x%x\n", PcdGet32 (PcdFlashFvOsBootBase), PcdGet32 (PcdFlashFvOsBootSize)));
+    PeiServicesInstallFvInfo2Ppi (
+      &(((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) PcdGet32 (PcdFlashFvOsBootBase))->FileSystemGuid),
+      (VOID *) (UINTN) PcdGet32 (PcdFlashFvOsBootBase),
+      PcdGet32 (PcdFlashFvOsBootSize),
+      NULL,
+      NULL,
+      0
+      );
+  }
+
+  //
+  // Report resource HOB for flash FV
+  //
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_MEMORY_MAPPED_IO,
+    (EFI_RESOURCE_ATTRIBUTE_PRESENT    |
+    EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+    EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
+    (UINTN) PcdGet32 (PcdFlashAreaBaseAddress),
+    (UINTN) PcdGet32 (PcdFlashAreaSize)
+    );
+  BuildMemoryAllocationHob (
+    (UINTN) PcdGet32 (PcdFlashAreaBaseAddress),
+    (UINTN) PcdGet32 (PcdFlashAreaSize),
+    EfiMemoryMappedIO
+    );
+}

+ 56 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PeiReportFvLib/PeiReportFvLib.inf

@@ -0,0 +1,56 @@
+### @file
+# Component information file for the Report Firmware Volume (FV) library.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+[Defines]
+  INF_VERSION                    = 0x00010017
+  BASE_NAME                      = PeiReportFvLib
+  FILE_GUID                      = 44328FA5-E4DD-4A15-ABDF-C6584AC363D9
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = PEIM
+  LIBRARY_CLASS                  = ReportFvLib
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  HobLib
+  PeiServicesLib
+  PcdLib
+  IoLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MinPlatformPkg/MinPlatformPkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+  SimicsX58SktPkg/SktPkg.dec
+  SimicsIch10Pkg/Ich10Pkg.dec
+
+[Sources]
+  PeiReportFvLib.c
+  Fv.c
+
+[Pcd]
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashAreaBaseAddress     ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashAreaSize            ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvPostMemoryBase    ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvPostMemorySize    ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvUefiBootBase      ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvUefiBootSize      ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvOsBootBase        ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvOsBootSize        ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvSecurityBase      ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvSecuritySize      ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvAdvancedBase      ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashFvAdvancedSize      ## CONSUMES
+  gBoardModuleTokenSpaceGuid.PcdSimicsPeiMemFvBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsPeiMemFvSize
+  gBoardModuleTokenSpaceGuid.PcdSimicsDxeMemFvBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsDxeMemFvSize
+  gBoardModuleTokenSpaceGuid.PcdSimicsDecompressionScratchEnd
+  gSimicsX58PkgTokenSpaceGuid.PcdSmmSmramRequire

+ 1553 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PlatformBootManagerLib/BdsPlatform.c

@@ -0,0 +1,1553 @@
+/** @file
+  Platform BDS customizations.
+
+  Copyright (c) 2004 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "BdsPlatform.h"
+#include <Guid/RootBridgesConnectedEventGroup.h>
+#include <Protocol/FirmwareVolume2.h>
+
+#define LEGACY_8259_MASK_REGISTER_MASTER                  0x21
+#define LEGACY_8259_MASK_REGISTER_SLAVE                   0xA1
+#define LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER  0x4D0
+#define LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE   0x4D1
+
+//
+// Global data
+//
+
+VOID          *mEfiDevPathNotifyReg;
+EFI_EVENT     mEfiDevPathEvent;
+VOID          *mEmuVariableEventReg;
+EFI_EVENT     mEmuVariableEvent;
+BOOLEAN       mDetectVgaOnly;
+UINT16        mHostBridgeDevId;
+
+//
+// Table of host IRQs matching PCI IRQs A-D
+// (for configuring PCI Interrupt Line register)
+//
+CONST UINT8 PciHostIrqs[] = {
+  0x0a, 0x0a, 0x0b, 0x0b
+};
+
+//
+// Type definitions
+//
+
+typedef
+EFI_STATUS
+(EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
+  IN EFI_HANDLE           Handle,
+  IN VOID                 *Instance,
+  IN VOID                 *Context
+  );
+
+/**
+  @param[in]  Handle - Handle of PCI device instance
+  @param[in]  PciIo - PCI IO protocol instance
+  @param[in]  Pci - PCI Header register block
+**/
+typedef
+EFI_STATUS
+(EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
+  IN EFI_HANDLE           Handle,
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN PCI_TYPE00           *Pci
+  );
+
+
+//
+// Function prototypes
+//
+
+EFI_STATUS
+VisitAllInstancesOfProtocol (
+  IN EFI_GUID                    *Id,
+  IN PROTOCOL_INSTANCE_CALLBACK  CallBackFunction,
+  IN VOID                        *Context
+  );
+
+EFI_STATUS
+VisitAllPciInstancesOfProtocol (
+  IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
+  );
+
+VOID
+InstallDevicePathCallback (
+  VOID
+  );
+
+VOID
+PlatformRegisterFvBootOption (
+  EFI_GUID                         *FileGuid,
+  CHAR16                           *Description,
+  UINT32                           Attributes
+  )
+{
+  EFI_STATUS                        Status;
+  INTN                              OptionIndex;
+  EFI_BOOT_MANAGER_LOAD_OPTION      NewOption;
+  EFI_BOOT_MANAGER_LOAD_OPTION      *BootOptions;
+  UINTN                             BootOptionCount;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+  EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;
+  EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
+
+  Status = gBS->HandleProtocol (
+                  gImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID **) &LoadedImage
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+  DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
+  ASSERT (DevicePath != NULL);
+  DevicePath = AppendDevicePathNode (
+                 DevicePath,
+                 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+                 );
+  ASSERT (DevicePath != NULL);
+
+  Status = EfiBootManagerInitializeLoadOption (
+             &NewOption,
+             LoadOptionNumberUnassigned,
+             LoadOptionTypeBoot,
+             Attributes,
+             Description,
+             DevicePath,
+             NULL,
+             0
+             );
+  ASSERT_EFI_ERROR (Status);
+  FreePool (DevicePath);
+
+  BootOptions = EfiBootManagerGetLoadOptions (
+                  &BootOptionCount, LoadOptionTypeBoot
+                  );
+
+  OptionIndex = EfiBootManagerFindLoadOption (
+                  &NewOption, BootOptions, BootOptionCount
+                  );
+
+  if (OptionIndex == -1) {
+    Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
+    ASSERT_EFI_ERROR (Status);
+  }
+  EfiBootManagerFreeLoadOption (&NewOption);
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+/**
+  Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
+  whose device paths do not resolve exactly to an FvFile in the system.
+
+  This removes any boot options that point to binaries built into the firmware
+  and have become stale due to any of the following:
+  - DXEFV's base address or size changed (historical),
+  - DXEFV's FvNameGuid changed,
+  - the FILE_GUID of the pointed-to binary changed,
+  - the referenced binary is no longer built into the firmware.
+
+  EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
+  avoids exact duplicates.
+**/
+VOID
+RemoveStaleFvFileOptions (
+  VOID
+  )
+{
+  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+  UINTN                        BootOptionCount;
+  UINTN                        Index;
+
+  BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
+                  LoadOptionTypeBoot);
+
+  for (Index = 0; Index < BootOptionCount; ++Index) {
+    EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
+    EFI_STATUS               Status;
+    EFI_HANDLE               FvHandle;
+
+    //
+    // If the device path starts with neither MemoryMapped(...) nor Fv(...),
+    // then keep the boot option.
+    //
+    Node1 = BootOptions[Index].FilePath;
+    if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&
+          DevicePathSubType (Node1) == HW_MEMMAP_DP) &&
+        !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&
+          DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {
+      continue;
+    }
+
+    //
+    // If the second device path node is not FvFile(...), then keep the boot
+    // option.
+    //
+    Node2 = NextDevicePathNode (Node1);
+    if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||
+        DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {
+      continue;
+    }
+
+    //
+    // Locate the Firmware Volume2 protocol instance that is denoted by the
+    // boot option. If this lookup fails (i.e., the boot option references a
+    // firmware volume that doesn't exist), then we'll proceed to delete the
+    // boot option.
+    //
+    SearchNode = Node1;
+    Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
+                    &SearchNode, &FvHandle);
+
+    if (!EFI_ERROR (Status)) {
+      //
+      // The firmware volume was found; now let's see if it contains the FvFile
+      // identified by GUID.
+      //
+      EFI_FIRMWARE_VOLUME2_PROTOCOL     *FvProtocol;
+      MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
+      UINTN                             BufferSize;
+      EFI_FV_FILETYPE                   FoundType;
+      EFI_FV_FILE_ATTRIBUTES            FileAttributes;
+      UINT32                            AuthenticationStatus;
+
+      Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
+                      (VOID **)&FvProtocol);
+      ASSERT_EFI_ERROR (Status);
+
+      FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
+      //
+      // Buffer==NULL means we request metadata only: BufferSize, FoundType,
+      // FileAttributes.
+      //
+      Status = FvProtocol->ReadFile (
+                             FvProtocol,
+                             &FvFileNode->FvFileName, // NameGuid
+                             NULL,                    // Buffer
+                             &BufferSize,
+                             &FoundType,
+                             &FileAttributes,
+                             &AuthenticationStatus
+                             );
+      if (!EFI_ERROR (Status)) {
+        //
+        // The FvFile was found. Keep the boot option.
+        //
+        continue;
+      }
+    }
+
+    //
+    // Delete the boot option.
+    //
+    Status = EfiBootManagerDeleteLoadOptionVariable (
+               BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+    DEBUG_CODE (
+      CHAR16 *DevicePathString;
+
+      DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,
+                           FALSE, FALSE);
+      DEBUG ((
+        EFI_ERROR (Status) ? EFI_D_WARN : EFI_D_VERBOSE,
+        "%a: removing stale Boot#%04x %s: %r\n",
+        __FUNCTION__,
+        (UINT32)BootOptions[Index].OptionNumber,
+        DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
+        Status
+        ));
+      if (DevicePathString != NULL) {
+        FreePool (DevicePathString);
+      }
+      );
+  }
+
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+VOID
+PlatformRegisterOptionsAndKeys (
+  VOID
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_INPUT_KEY                Enter;
+  EFI_INPUT_KEY                F2;
+  EFI_INPUT_KEY                Esc;
+  EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+
+  //
+  // Register ENTER as CONTINUE key
+  //
+  Enter.ScanCode    = SCAN_NULL;
+  Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
+  Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Map F2 to Boot Manager Menu
+  //
+  F2.ScanCode     = SCAN_F2;
+  F2.UnicodeChar  = CHAR_NULL;
+  Esc.ScanCode    = SCAN_ESC;
+  Esc.UnicodeChar = CHAR_NULL;
+  Status = EfiBootManagerGetBootManagerMenu (&BootOption);
+  ASSERT_EFI_ERROR (Status);
+  Status = EfiBootManagerAddKeyOptionVariable (
+             NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
+             );
+  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+  Status = EfiBootManagerAddKeyOptionVariable (
+             NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
+             );
+  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+}
+
+EFI_STATUS
+EFIAPI
+ConnectRootBridge (
+  IN EFI_HANDLE  RootBridgeHandle,
+  IN VOID        *Instance,
+  IN VOID        *Context
+  );
+
+STATIC
+VOID
+SaveS3BootScript (
+  VOID
+  );
+
+//
+// BDS Platform Functions
+//
+/**
+  Do the platform init, can be customized by OEM/IBV
+
+  Possible things that can be done in PlatformBootManagerBeforeConsole:
+
+  > Update console variable: 1. include hot-plug devices;
+  >                          2. Clear ConIn and add SOL for AMT
+  > Register new Driver#### or Boot####
+  > Register new Key####: e.g.: F12
+  > Signal ReadyToLock event
+  > Authentication action: 1. connect Auth devices;
+  >                        2. Identify auto logon user.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+  VOID
+  )
+{
+//  EFI_HANDLE    Handle;
+//  EFI_STATUS    Status;
+
+  DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole\n"));
+  InstallDevicePathCallback ();
+
+  VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,
+    ConnectRootBridge, NULL);
+  //
+  // Enable LPC
+  //
+  PciOr16(POWER_MGMT_REGISTER_ICH10(0x04),
+           BIT0 | BIT1 | BIT2);
+  //
+  // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
+  // the preparation of S3 system information. That logic has a hard dependency
+  // on the presence of the FACS ACPI table. Since our ACPI tables are only
+  // installed after PCI enumeration completes, we must not trigger the S3 save
+  // earlier, hence we can't signal End-of-Dxe earlier.
+  //
+  EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
+
+  PlatformInitializeConsole (gPlatformConsole);
+
+  PlatformRegisterOptionsAndKeys ();
+}
+
+
+EFI_STATUS
+EFIAPI
+ConnectRootBridge (
+  IN EFI_HANDLE  RootBridgeHandle,
+  IN VOID        *Instance,
+  IN VOID        *Context
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Make the PCI bus driver connect the root bridge, non-recursively. This
+  // will produce a number of child handles with PciIo on them.
+  //
+  Status = gBS->ConnectController (
+                  RootBridgeHandle, // ControllerHandle
+                  NULL,             // DriverImageHandle
+                  NULL,             // RemainingDevicePath -- produce all
+                                    //   children
+                  FALSE             // Recursive
+                  );
+  return Status;
+}
+
+
+/**
+  Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
+
+  @param[in] DeviceHandle  Handle of the LPC Bridge device.
+
+  @retval EFI_SUCCESS  Console devices on the LPC bridge have been added to
+                       ConOut, ConIn, and ErrOut.
+
+  @return              Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
+                       from DeviceHandle.
+**/
+EFI_STATUS
+PrepareLpcBridgeDevicePath (
+  IN EFI_HANDLE                DeviceHandle
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
+  CHAR16                    *DevPathStr;
+
+  DevicePath = NULL;
+  Status = gBS->HandleProtocol (
+                  DeviceHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID*)&DevicePath
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  TempDevicePath = DevicePath;
+
+  //
+  // Register Keyboard
+  //
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
+
+  EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+
+  //
+  // Register COM1
+  //
+  DevicePath = TempDevicePath;
+  gPnp16550ComPortDeviceNode.UID = 0;
+
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
+
+  //
+  // Print Device Path
+  //
+  DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+  if (DevPathStr != NULL) {
+    DEBUG((
+      EFI_D_INFO,
+      "BdsPlatform.c+%d: COM%d DevPath: %s\n",
+      __LINE__,
+      gPnp16550ComPortDeviceNode.UID + 1,
+      DevPathStr
+      ));
+    FreePool(DevPathStr);
+  }
+
+  EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+  EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+  EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+
+  //
+  // Register COM2
+  //
+  DevicePath = TempDevicePath;
+  gPnp16550ComPortDeviceNode.UID = 1;
+
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
+
+  //
+  // Print Device Path
+  //
+  DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+  if (DevPathStr != NULL) {
+    DEBUG((
+      EFI_D_INFO,
+      "BdsPlatform.c+%d: COM%d DevPath: %s\n",
+      __LINE__,
+      gPnp16550ComPortDeviceNode.UID + 1,
+      DevPathStr
+      ));
+    FreePool(DevPathStr);
+  }
+
+  EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+  EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+  EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetGopDevicePath (
+   IN  EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
+   OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
+   )
+{
+  UINTN                           Index;
+  EFI_STATUS                      Status;
+  EFI_HANDLE                      PciDeviceHandle;
+  EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL        *TempPciDevicePath;
+  UINTN                           GopHandleCount;
+  EFI_HANDLE                      *GopHandleBuffer;
+
+  if (PciDevicePath == NULL || GopDevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Initialize the GopDevicePath to be PciDevicePath
+  //
+  *GopDevicePath    = PciDevicePath;
+  TempPciDevicePath = PciDevicePath;
+
+  Status = gBS->LocateDevicePath (
+                  &gEfiDevicePathProtocolGuid,
+                  &TempPciDevicePath,
+                  &PciDeviceHandle
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Try to connect this handle, so that GOP driver could start on this
+  // device and create child handles with GraphicsOutput Protocol installed
+  // on them, then we get device paths of these child handles and select
+  // them as possible console device.
+  //
+  gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
+
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiGraphicsOutputProtocolGuid,
+                  NULL,
+                  &GopHandleCount,
+                  &GopHandleBuffer
+                  );
+  if (!EFI_ERROR (Status)) {
+    //
+    // Add all the child handles as possible Console Device
+    //
+    for (Index = 0; Index < GopHandleCount; Index++) {
+      Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
+      if (EFI_ERROR (Status)) {
+        continue;
+      }
+      if (CompareMem (
+            PciDevicePath,
+            TempDevicePath,
+            GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
+            ) == 0) {
+        //
+        // In current implementation, we only enable one of the child handles
+        // as console device, i.e. sotre one of the child handle's device
+        // path to variable "ConOut"
+        // In future, we could select all child handles to be console device
+        //
+
+        *GopDevicePath = TempDevicePath;
+
+        //
+        // Delete the PCI device's path that added by
+        // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
+        //
+        EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
+        EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
+      }
+    }
+    gBS->FreePool (GopHandleBuffer);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Add PCI display to ConOut.
+
+  @param[in] DeviceHandle  Handle of the PCI display device.
+
+  @retval EFI_SUCCESS  The PCI display device has been added to ConOut.
+
+  @return              Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
+                       from DeviceHandle.
+**/
+EFI_STATUS
+PreparePciDisplayDevicePath (
+  IN EFI_HANDLE                DeviceHandle
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *GopDevicePath;
+
+  DevicePath    = NULL;
+  GopDevicePath = NULL;
+  Status = gBS->HandleProtocol (
+                  DeviceHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID*)&DevicePath
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  GetGopDevicePath (DevicePath, &GopDevicePath);
+  DevicePath = GopDevicePath;
+
+  EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Add PCI Serial to ConOut, ConIn, ErrOut.
+
+  @param[in] DeviceHandle  Handle of the PCI serial device.
+
+  @retval EFI_SUCCESS  The PCI serial device has been added to ConOut, ConIn,
+                       ErrOut.
+
+  @return              Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
+                       from DeviceHandle.
+**/
+EFI_STATUS
+PreparePciSerialDevicePath (
+  IN EFI_HANDLE                DeviceHandle
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+
+  DevicePath = NULL;
+  Status = gBS->HandleProtocol (
+                  DeviceHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID*)&DevicePath
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
+  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
+
+  EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+  EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+  EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+VisitAllInstancesOfProtocol (
+  IN EFI_GUID                    *Id,
+  IN PROTOCOL_INSTANCE_CALLBACK  CallBackFunction,
+  IN VOID                        *Context
+  )
+{
+  EFI_STATUS                Status;
+  UINTN                     HandleCount;
+  EFI_HANDLE                *HandleBuffer;
+  UINTN                     Index;
+  VOID                      *Instance;
+
+  //
+  // Start to check all the PciIo to find all possible device
+  //
+  HandleCount = 0;
+  HandleBuffer = NULL;
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  Id,
+                  NULL,
+                  &HandleCount,
+                  &HandleBuffer
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  for (Index = 0; Index < HandleCount; Index++) {
+    Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    Status = (*CallBackFunction) (
+               HandleBuffer[Index],
+               Instance,
+               Context
+               );
+  }
+
+  gBS->FreePool (HandleBuffer);
+
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+VisitingAPciInstance (
+  IN EFI_HANDLE  Handle,
+  IN VOID        *Instance,
+  IN VOID        *Context
+  )
+{
+  EFI_STATUS                Status;
+  EFI_PCI_IO_PROTOCOL       *PciIo;
+  PCI_TYPE00                Pci;
+
+  PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
+
+  //
+  // Check for all PCI device
+  //
+  Status = PciIo->Pci.Read (
+                    PciIo,
+                    EfiPciIoWidthUint32,
+                    0,
+                    sizeof (Pci) / sizeof (UINT32),
+                    &Pci
+                    );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
+           Handle,
+           PciIo,
+           &Pci
+           );
+
+}
+
+
+
+EFI_STATUS
+VisitAllPciInstances (
+  IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
+  )
+{
+  return VisitAllInstancesOfProtocol (
+           &gEfiPciIoProtocolGuid,
+           VisitingAPciInstance,
+           (VOID*)(UINTN) CallBackFunction
+           );
+}
+
+
+/**
+  Do platform specific PCI Device check and add them to
+  ConOut, ConIn, ErrOut.
+
+  @param[in]  Handle - Handle of PCI device instance
+  @param[in]  PciIo - PCI IO protocol instance
+  @param[in]  Pci - PCI Header register block
+
+  @retval EFI_SUCCESS - PCI Device check and Console variable update
+                        successfully.
+  @retval EFI_STATUS - PCI Device check or Console variable update fail.
+
+**/
+EFI_STATUS
+EFIAPI
+DetectAndPreparePlatformPciDevicePath (
+  IN EFI_HANDLE           Handle,
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN PCI_TYPE00           *Pci
+  )
+{
+  EFI_STATUS                Status;
+
+  Status = PciIo->Attributes (
+    PciIo,
+    EfiPciIoAttributeOperationEnable,
+    EFI_PCI_DEVICE_ENABLE,
+    NULL
+    );
+  ASSERT_EFI_ERROR (Status);
+
+  if (!mDetectVgaOnly) {
+    //
+    // Here we decide whether it is LPC Bridge
+    //
+    if ((IS_PCI_LPC (Pci)) ||
+        ((IS_PCI_ISA_PDECODE (Pci)) &&
+         (Pci->Hdr.VendorId == 0x8086) &&
+         (Pci->Hdr.DeviceId == 0x7000)
+        )
+       ) {
+      //
+      // Add IsaKeyboard to ConIn,
+      // add IsaSerial to ConOut, ConIn, ErrOut
+      //
+      DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));
+      PrepareLpcBridgeDevicePath (Handle);
+      return EFI_SUCCESS;
+    }
+    //
+    // Here we decide which Serial device to enable in PCI bus
+    //
+    if (IS_PCI_16550SERIAL (Pci)) {
+      //
+      // Add them to ConOut, ConIn, ErrOut.
+      //
+      DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));
+      PreparePciSerialDevicePath (Handle);
+      return EFI_SUCCESS;
+    }
+  }
+
+  //
+  // Here we decide which display device to enable in PCI bus
+  //
+  if (IS_PCI_DISPLAY (Pci)) {
+    //
+    // Add them to ConOut.
+    //
+    DEBUG ((EFI_D_INFO, "Found PCI display device\n"));
+    PreparePciDisplayDevicePath (Handle);
+    return EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+
+/**
+  Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
+
+  @param[in]  DetectVgaOnly - Only detect VGA device if it's TRUE.
+
+  @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
+  @retval EFI_STATUS - PCI Device check or Console variable update fail.
+
+**/
+EFI_STATUS
+DetectAndPreparePlatformPciDevicePaths (
+  BOOLEAN DetectVgaOnly
+  )
+{
+  mDetectVgaOnly = DetectVgaOnly;
+  return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
+}
+
+/**
+  Connect the predefined platform default console device.
+
+  Always try to find and enable PCI display devices.
+
+  @param[in] PlatformConsole  Predefined platform default console device array.
+**/
+VOID
+PlatformInitializeConsole (
+  IN PLATFORM_CONSOLE_CONNECT_ENTRY   *PlatformConsole
+  )
+{
+  UINTN                              Index;
+  EFI_DEVICE_PATH_PROTOCOL           *VarConout;
+  EFI_DEVICE_PATH_PROTOCOL           *VarConin;
+
+  //
+  // Connect RootBridge
+  //
+  GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout, NULL);
+  GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);
+
+  if (VarConout == NULL || VarConin == NULL) {
+    //
+    // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
+    //
+    DetectAndPreparePlatformPciDevicePaths (FALSE);
+    DetectAndPreparePlatformPciDevicePaths(TRUE);
+    //
+    // Have chance to connect the platform default console,
+    // the platform default console is the minimue device group
+    // the platform should support
+    //
+    for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
+      //
+      // Update the console variable with the connect type
+      //
+      if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
+        EfiBootManagerUpdateConsoleVariable (ConIn, PlatformConsole[Index].DevicePath, NULL);
+      }
+      if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
+        EfiBootManagerUpdateConsoleVariable (ConOut, PlatformConsole[Index].DevicePath, NULL);
+      }
+      if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
+        EfiBootManagerUpdateConsoleVariable (ErrOut, PlatformConsole[Index].DevicePath, NULL);
+      }
+    }
+  } else {
+    //
+    // Only detect VGA device and add them to ConOut
+    //
+    DetectAndPreparePlatformPciDevicePaths (TRUE);
+  }
+}
+
+
+/**
+  Configure PCI Interrupt Line register for applicable devices
+  Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
+
+  @param[in]  Handle - Handle of PCI device instance
+  @param[in]  PciIo - PCI IO protocol instance
+  @param[in]  PciHdr - PCI Header register block
+
+  @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SetPciIntLine (
+  IN EFI_HANDLE           Handle,
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN PCI_TYPE00           *PciHdr
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *DevPathNode;
+  EFI_DEVICE_PATH_PROTOCOL  *DevPath;
+  UINTN                     RootSlot;
+  UINTN                     Idx;
+  UINT8                     IrqLine;
+  EFI_STATUS                Status;
+  UINT32                    RootBusNumber;
+
+  Status = EFI_SUCCESS;
+
+  if (PciHdr->Device.InterruptPin != 0) {
+
+    DevPathNode = DevicePathFromHandle (Handle);
+    ASSERT (DevPathNode != NULL);
+    DevPath = DevPathNode;
+
+    RootBusNumber = 0;
+    if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&
+        DevicePathSubType (DevPathNode) == ACPI_DP &&
+        ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {
+      RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
+    }
+
+    //
+    // Compute index into PciHostIrqs[] table by walking
+    // the device path and adding up all device numbers
+    //
+    Status = EFI_NOT_FOUND;
+    RootSlot = 0;
+    Idx = PciHdr->Device.InterruptPin - 1;
+    while (!IsDevicePathEnd (DevPathNode)) {
+      if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
+          DevicePathSubType (DevPathNode) == HW_PCI_DP) {
+
+        Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
+
+        //
+        // Unlike SeaBIOS, which starts climbing from the leaf device
+        // up toward the root, we traverse the device path starting at
+        // the root moving toward the leaf node.
+        // The slot number of the top-level parent bridge is needed
+        // with more than 24 slots on the root bus.
+        //
+        if (Status != EFI_SUCCESS) {
+          Status = EFI_SUCCESS;
+          RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
+        }
+      }
+
+      DevPathNode = NextDevicePathNode (DevPathNode);
+    }
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    if (RootBusNumber == 0 && RootSlot == 0) {
+      return Status; //bugbug: workaround; need SIMICS change B0/D0/F0 PCI_IntPin reg(0x3D) = 0X0
+//      DEBUG((
+//        EFI_D_ERROR,
+//       "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
+//        __FUNCTION__
+//        ));
+//      ASSERT (FALSE);
+    }
+
+    //
+    // Final PciHostIrqs[] index calculation depends on the platform
+    // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
+    //
+    switch (mHostBridgeDevId) {
+      case INTEL_82441_DEVICE_ID:
+        Idx -= 1;
+        break;
+      case INTEL_ICH10_DEVICE_ID:
+        //
+        // SeaBIOS contains the following comment:
+        // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
+        //  with a different starting index.
+        //
+        //  Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
+        //
+        if (RootSlot > 24) {
+          //
+          // in this case, subtract back out RootSlot from Idx
+          // (SeaBIOS never adds it to begin with, but that would make our
+          //  device path traversal loop above too awkward)
+          //
+          Idx -= RootSlot;
+        }
+        break;
+      default:
+        ASSERT (FALSE); // should never get here
+    }
+    Idx %= ARRAY_SIZE (PciHostIrqs);
+    IrqLine = PciHostIrqs[Idx];
+
+    DEBUG_CODE_BEGIN ();
+    {
+      CHAR16        *DevPathString;
+      STATIC CHAR16 Fallback[] = L"<failed to convert>";
+      UINTN         Segment, Bus, Device, Function;
+
+      DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
+      if (DevPathString == NULL) {
+        DevPathString = Fallback;
+      }
+      Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
+      ASSERT_EFI_ERROR (Status);
+
+      DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
+        (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
+        IrqLine));
+
+      if (DevPathString != Fallback) {
+        FreePool (DevPathString);
+      }
+    }
+    DEBUG_CODE_END ();
+
+    //
+    // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
+    //
+    Status = PciIo->Pci.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               PCI_INT_LINE_OFFSET,
+               1,
+               &IrqLine
+               );
+  }
+
+  return Status;
+}
+
+/**
+Write to mask and edge/level triggered registers of master and slave 8259 PICs.
+
+@param[in]  Mask       low byte for master PIC mask register,
+high byte for slave PIC mask register.
+@param[in]  EdgeLevel  low byte for master PIC edge/level triggered register,
+high byte for slave PIC edge/level triggered register.
+
+**/
+VOID
+Interrupt8259WriteMask(
+  IN UINT16  Mask,
+  IN UINT16  EdgeLevel
+)
+{
+  IoWrite8(LEGACY_8259_MASK_REGISTER_MASTER, (UINT8)Mask);
+  IoWrite8(LEGACY_8259_MASK_REGISTER_SLAVE, (UINT8)(Mask >> 8));
+  IoWrite8(LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER, (UINT8)EdgeLevel);
+  IoWrite8(LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE, (UINT8)(EdgeLevel >> 8));
+}
+
+VOID
+PciAcpiInitialization (
+  )
+{
+  UINTN  Pmba;
+
+  //
+  // Query Host Bridge DID to determine platform type
+  //
+  mHostBridgeDevId = PcdGet16 (PcdSimicsX58HostBridgePciDevId);
+  switch (mHostBridgeDevId) {
+    case INTEL_82441_DEVICE_ID:
+      Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
+      //
+      // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
+      //
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
+      break;
+    case INTEL_ICH10_DEVICE_ID:
+      Pmba = POWER_MGMT_REGISTER_ICH10 (ICH10_PMBASE);
+      //
+      // 00:1f.0 LPC Bridge LNK routing targets
+      //
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
+      break;
+    default:
+      DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
+        __FUNCTION__, mHostBridgeDevId));
+      ASSERT (FALSE);
+      return;
+  }
+
+  //
+  // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
+  //
+  VisitAllPciInstances (SetPciIntLine);
+
+  //
+  // Set ACPI SCI_EN bit in PMCNTRL
+  //
+  IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
+  //
+  // Set all 8259 interrupts to edge triggered and disabled
+  //
+  Interrupt8259WriteMask(0xFFFF, 0x0000);
+}
+
+EFI_STATUS
+EFIAPI
+ConnectRecursivelyIfPciMassStorage (
+  IN EFI_HANDLE           Handle,
+  IN EFI_PCI_IO_PROTOCOL  *Instance,
+  IN PCI_TYPE00           *PciHeader
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  CHAR16                    *DevPathStr;
+
+  //
+  // Recognize PCI Mass Storage
+  //
+  if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {
+    DevicePath = NULL;
+    Status = gBS->HandleProtocol (
+                    Handle,
+                    &gEfiDevicePathProtocolGuid,
+                    (VOID*)&DevicePath
+                    );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // Print Device Path
+    //
+    DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+    if (DevPathStr != NULL) {
+      DEBUG((
+        EFI_D_INFO,
+        "Found Mass Storage device: %s\n",
+        DevPathStr
+        ));
+      FreePool(DevPathStr);
+    }
+
+    Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  This notification function is invoked when the
+  EMU Variable FVB has been changed.
+
+  @param  Event                 The event that occurred
+  @param  Context               For EFI compatibility.  Not used.
+
+**/
+VOID
+EFIAPI
+EmuVariablesUpdatedCallback (
+  IN  EFI_EVENT Event,
+  IN  VOID      *Context
+  )
+{
+  DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));
+  UpdateNvVarsOnFileSystem ();
+}
+
+
+EFI_STATUS
+EFIAPI
+VisitingFileSystemInstance (
+  IN EFI_HANDLE  Handle,
+  IN VOID        *Instance,
+  IN VOID        *Context
+  )
+{
+  EFI_STATUS      Status;
+  STATIC BOOLEAN  ConnectedToFileSystem = FALSE;
+
+  if (ConnectedToFileSystem) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  Status = ConnectNvVarsToFileSystem (Handle);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ConnectedToFileSystem = TRUE;
+  mEmuVariableEvent =
+    EfiCreateProtocolNotifyEvent (
+      &gEfiDevicePathProtocolGuid,
+      TPL_CALLBACK,
+      EmuVariablesUpdatedCallback,
+      NULL,
+      &mEmuVariableEventReg
+      );
+  PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent);
+
+  return EFI_SUCCESS;
+}
+
+
+VOID
+PlatformBdsRestoreNvVarsFromHardDisk (
+  )
+{
+  VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
+  VisitAllInstancesOfProtocol (
+    &gEfiSimpleFileSystemProtocolGuid,
+    VisitingFileSystemInstance,
+    NULL
+    );
+
+}
+
+/**
+  Connect with predefined platform connect sequence.
+
+  The OEM/IBV can customize with their own connect sequence.
+**/
+VOID
+PlatformBdsConnectSequence (
+  VOID
+  )
+{
+  UINTN Index;
+
+  DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
+
+  Index = 0;
+
+  //
+  // Here we can get the customized platform connect sequence
+  // Notes: we can connect with new variable which record the
+  // last time boots connect device path sequence
+  //
+  while (gPlatformConnectSequence[Index] != NULL) {
+    //
+    // Build the platform boot option
+    //
+    EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
+    Index++;
+  }
+
+  //
+  // Just use the simple policy to connect all devices
+  //
+  DEBUG ((EFI_D_INFO, "EfiBootManagerConnectAll\n"));
+  EfiBootManagerConnectAll ();
+
+  PciAcpiInitialization ();
+}
+
+/**
+  Save the S3 boot script.
+
+  Note that DxeSmmReadyToLock must be signaled after this function returns;
+  otherwise the script wouldn't be saved actually.
+**/
+STATIC
+VOID
+SaveS3BootScript (
+  VOID
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
+  STATIC CONST UINT8         Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
+
+  Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
+                  (VOID **) &BootScript);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Despite the opcode documentation in the PI spec, the protocol
+  // implementation embeds a deep copy of the info in the boot script, rather
+  // than storing just a pointer to runtime or NVS storage.
+  //
+  Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
+                         (UINT32) sizeof Info,
+                         (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
+  ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+  Do the platform specific action after the console is ready
+
+  Possible things that can be done in PlatformBootManagerAfterConsole:
+
+  > Console post action:
+    > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
+    > Signal console ready platform customized event
+  > Run diagnostics like memory testing
+  > Connect certain devices
+  > Dispatch aditional option roms
+  > Special boot: e.g.: USB boot, enter UI
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+  VOID
+  )
+{
+  EFI_BOOT_MODE                      BootMode;
+  EFI_HANDLE                         Handle;
+  EFI_STATUS                         Status;
+
+  DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));
+
+  //
+  // Prevent further changes to LockBoxes or SMRAM.
+  //
+  Handle = NULL;
+  Status = gBS->InstallProtocolInterface(&Handle,
+    &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
+      NULL);
+  ASSERT_EFI_ERROR(Status);
+
+  if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
+    DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
+      "from disk since flash variables appear to be supported.\n"));
+  } else {
+    //
+    // Try to restore variables from the hard disk early so
+    // they can be used for the other BDS connect operations.
+    //
+    PlatformBdsRestoreNvVarsFromHardDisk ();
+  }
+
+  //
+  // Get current Boot Mode
+  //
+  BootMode = GetBootModeHob ();
+  DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
+
+  //
+  // Go the different platform policy with different boot mode
+  // Notes: this part code can be change with the table policy
+  //
+  ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
+
+  // Perform some platform specific connect sequence
+  //
+  PlatformBdsConnectSequence ();
+  //
+  // Logo show
+  //
+  EnableBootLogo(PcdGetPtr(PcdLogoFile));
+
+  EfiBootManagerRefreshAllBootOption ();
+
+  //
+  // Register UEFI Shell
+  //
+  PlatformRegisterFvBootOption (
+    PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+    );
+
+  RemoveStaleFvFileOptions ();
+}
+
+/**
+  This notification function is invoked when an instance of the
+  EFI_DEVICE_PATH_PROTOCOL is produced.
+
+  @param  Event                 The event that occurred
+  @param  Context               For EFI compatibility.  Not used.
+
+**/
+VOID
+EFIAPI
+NotifyDevPath (
+  IN  EFI_EVENT Event,
+  IN  VOID      *Context
+  )
+{
+  EFI_HANDLE                            Handle;
+  EFI_STATUS                            Status;
+  UINTN                                 BufferSize;
+  EFI_DEVICE_PATH_PROTOCOL             *DevPathNode;
+  ATAPI_DEVICE_PATH                    *Atapi;
+
+  //
+  // Examine all new handles
+  //
+  for (;;) {
+    //
+    // Get the next handle
+    //
+    BufferSize = sizeof (Handle);
+    Status = gBS->LocateHandle (
+              ByRegisterNotify,
+              NULL,
+              mEfiDevPathNotifyReg,
+              &BufferSize,
+              &Handle
+              );
+
+    //
+    // If not found, we're done
+    //
+    if (EFI_NOT_FOUND == Status) {
+      break;
+    }
+
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    //
+    // Get the DevicePath protocol on that handle
+    //
+    Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
+    ASSERT_EFI_ERROR (Status);
+
+    while (!IsDevicePathEnd (DevPathNode)) {
+      //
+      // Find the handler to dump this device path node
+      //
+      if (
+           (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
+           (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
+         ) {
+        Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
+        PciOr16 (
+          PCI_LIB_ADDRESS (
+            0,
+            1,
+            1,
+            (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
+            ),
+          BIT15
+          );
+      }
+
+      //
+      // Next device path node
+      //
+      DevPathNode = NextDevicePathNode (DevPathNode);
+    }
+  }
+
+  return;
+}
+
+
+VOID
+InstallDevicePathCallback (
+  VOID
+  )
+{
+  DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
+  mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
+                          &gEfiDevicePathProtocolGuid,
+                          TPL_CALLBACK,
+                          NotifyDevPath,
+                          NULL,
+                          &mEfiDevPathNotifyReg
+                          );
+}
+
+/**
+  This function is called each second during the boot manager waits the
+  timeout.
+
+  @param TimeoutRemain  The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+  UINT16          TimeoutRemain
+  )
+{
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
+  UINT16                              Timeout;
+
+  Timeout = PcdGet16 (PcdPlatformBootTimeOut);
+
+  Black.Raw = 0x00000000;
+  White.Raw = 0x00FFFFFF;
+
+  BootLogoUpdateProgress (
+    White.Pixel,
+    Black.Pixel,
+    L"Start boot option",
+    White.Pixel,
+    (Timeout - TimeoutRemain) * 100 / Timeout,
+    0
+    );
+}
+
+/**
+  The function is called when no boot option could be launched,
+  including platform recovery options and options pointing to applications
+  built into firmware volumes.
+
+  If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot (
+  VOID
+  )
+{
+  // BUGBUG- will do it if need
+}

+ 172 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PlatformBootManagerLib/BdsPlatform.h

@@ -0,0 +1,172 @@
+/** @file
+  Platform BDS customizations include file.
+
+  Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PLATFORM_SPECIFIC_BDS_PLATFORM_H_
+#define _PLATFORM_SPECIFIC_BDS_PLATFORM_H_
+
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/SmBios.h>
+#include <IndustryStandard/PeImage.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/BootLogoLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/NvVarsFileLib.h>
+
+#include <Protocol/Decompress.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/S3SaveState.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/LoadedImage.h>
+
+#include <Guid/Acpi.h>
+#include <Guid/SmBios.h>
+#include <Guid/Mps.h>
+#include <Guid/HobList.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/EventGroup.h>
+
+#include <SimicsPlatforms.h>
+
+extern EFI_DEVICE_PATH_PROTOCOL   *gPlatformConnectSequence[];
+extern ACPI_HID_DEVICE_PATH       gPnpPs2KeyboardDeviceNode;
+extern ACPI_HID_DEVICE_PATH       gPnp16550ComPortDeviceNode;
+extern UART_DEVICE_PATH           gUartDeviceNode;
+extern VENDOR_DEVICE_PATH         gTerminalTypeDeviceNode;
+
+#define PCI_DEVICE_PATH_NODE(Func, Dev) \
+  { \
+    { \
+      HARDWARE_DEVICE_PATH, \
+      HW_PCI_DP, \
+      { \
+        (UINT8) (sizeof (PCI_DEVICE_PATH)), \
+        (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
+      } \
+    }, \
+    (Func), \
+    (Dev) \
+  }
+
+#define PNPID_DEVICE_PATH_NODE(PnpId) \
+  { \
+    { \
+      ACPI_DEVICE_PATH, \
+      ACPI_DP, \
+      { \
+        (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
+        (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
+      }, \
+    }, \
+    EISA_PNP_ID((PnpId)), \
+    0 \
+  }
+
+#define gPciIsaBridge \
+  PCI_DEVICE_PATH_NODE(0, 0x1f)
+
+#define gP2PBridge \
+  PCI_DEVICE_PATH_NODE(0, 0x1e)
+
+#define gPnpPs2Keyboard \
+  PNPID_DEVICE_PATH_NODE(0x0303)
+
+#define gPnp16550ComPort \
+  PNPID_DEVICE_PATH_NODE(0x0501)
+
+#define gUart \
+  { \
+    { \
+      MESSAGING_DEVICE_PATH, \
+      MSG_UART_DP, \
+      { \
+        (UINT8) (sizeof (UART_DEVICE_PATH)), \
+        (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8) \
+      } \
+    }, \
+    0, \
+    115200, \
+    8, \
+    1, \
+    1 \
+  }
+
+#define gPcAnsiTerminal \
+  { \
+    { \
+      MESSAGING_DEVICE_PATH, \
+      MSG_VENDOR_DP, \
+      { \
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)), \
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) \
+      } \
+    }, \
+    DEVICE_PATH_MESSAGING_PC_ANSI \
+  }
+
+#define PCI_CLASS_SCC          0x07
+#define PCI_SUBCLASS_SERIAL    0x00
+#define PCI_IF_16550           0x02
+#define IS_PCI_16550SERIAL(_p)           IS_CLASS3 (_p, PCI_CLASS_SCC, PCI_SUBCLASS_SERIAL, PCI_IF_16550)
+#define IS_PCI_ISA_PDECODE(_p)        IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA_PDECODE, 0)
+
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  UINTN                     ConnectType;
+} PLATFORM_CONSOLE_CONNECT_ENTRY;
+
+#define CONSOLE_OUT BIT0
+#define CONSOLE_IN  BIT1
+#define STD_ERROR   BIT2
+extern PLATFORM_CONSOLE_CONNECT_ENTRY  gPlatformConsole[];
+
+//
+// Platform BDS Functions
+//
+
+VOID
+PlatformInitializeConsole (
+  IN PLATFORM_CONSOLE_CONNECT_ENTRY   *PlatformConsole
+  );
+
+/**
+  Use SystemTable ConOut to stop video based Simple Text Out consoles from going
+  to the video device. Put up LogoFile on every video device that is a console.
+
+  @param[in]  LogoFile   The file name of logo to display on the center of the screen.
+
+  @retval EFI_SUCCESS     ConsoleControl has been flipped to graphics and logo displayed.
+  @retval EFI_UNSUPPORTED Logo not found.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableBootLogo(
+  IN  EFI_GUID  *LogoFile
+);
+
+#endif // _PLATFORM_SPECIFIC_BDS_PLATFORM_H_

+ 72 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf

@@ -0,0 +1,72 @@
+## @file
+#  Platform BDS customizations library.
+#
+# Copyright (c) 2007 - 2019 Intel Corporation. All rights reserved. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PlatformBootManagerLib
+  FILE_GUID                      = 8AE4756F-0C71-4C06-84D4-4C71F204D514
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PlatformBootManagerLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  BdsPlatform.c
+  PlatformData.c
+  BdsPlatform.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+  OvmfPkg/OvmfPkg.dec
+  SimicsIch10Pkg/Ich10Pkg.dec
+
+[LibraryClasses]
+  BaseLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+  UefiBootManagerLib
+  BootLogoLib
+  DevicePathLib
+  PciLib
+  NvVarsFileLib
+  DxeLoadLinuxLib
+  UefiLib
+  LogoLib
+
+[Pcd]
+  gBoardModuleTokenSpaceGuid.PcdEmuVariableEvent
+  gBoardModuleTokenSpaceGuid.PcdOvmfFlashVariablesEnable
+  gBoardModuleTokenSpaceGuid.PcdSimicsX58HostBridgePciDevId
+  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
+  gBoardModuleTokenSpaceGuid.PcdShellFile
+  gBoardModuleTokenSpaceGuid.PcdLogoFile
+
+[Pcd.IA32, Pcd.X64]
+  gEfiMdePkgTokenSpaceGuid.PcdFSBClock
+
+[Protocols]
+  gEfiDecompressProtocolGuid
+  gEfiPciRootBridgeIoProtocolGuid
+  gEfiS3SaveStateProtocolGuid                   # PROTOCOL SOMETIMES_CONSUMED
+  gEfiDxeSmmReadyToLockProtocolGuid             # PROTOCOL SOMETIMES_PRODUCED
+  gEfiLoadedImageProtocolGuid                   # PROTOCOL SOMETIMES_PRODUCED
+  gEfiFirmwareVolume2ProtocolGuid               # PROTOCOL SOMETIMES_CONSUMED
+
+[Guids]
+  gEfiEndOfDxeEventGroupGuid

+ 35 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/PlatformBootManagerLib/PlatformData.c

@@ -0,0 +1,35 @@
+/** @file
+  Defined the platform specific device path which will be used by
+  platform Bbd to perform the platform policy connect.
+
+  Copyright (c) 2004 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "BdsPlatform.h"
+
+ACPI_HID_DEVICE_PATH       gPnpPs2KeyboardDeviceNode  = gPnpPs2Keyboard;
+ACPI_HID_DEVICE_PATH       gPnp16550ComPortDeviceNode = gPnp16550ComPort;
+UART_DEVICE_PATH           gUartDeviceNode            = gUart;
+VENDOR_DEVICE_PATH         gTerminalTypeDeviceNode    = gPcAnsiTerminal;
+
+//
+// Platform specific keyboard device path
+//
+
+//
+// Predefined platform default console device path
+//
+PLATFORM_CONSOLE_CONNECT_ENTRY   gPlatformConsole[] = {
+  {
+    NULL,
+    0
+  }
+};
+
+//
+// Predefined platform connect sequence
+//
+EFI_DEVICE_PATH_PROTOCOL    *gPlatformConnectSequence[] = { NULL };
+

+ 869 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/SerializeVariablesLib/SerializeVariablesLib.c

@@ -0,0 +1,869 @@
+/** @file
+  Serialize Variables Library implementation
+
+  Copyright (c) 2004 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "SerializeVariablesLib.h"
+
+/**
+  Serialization format:
+
+  The SerializeVariablesLib interface does not specify a format
+  for the serialization of the variable data.  This library uses
+  a packed array of a non-uniformly sized data structure elements.
+
+  Each variable is stored (packed) as:
+    UINT32   VendorNameSize;  // Name size in bytes
+    CHAR16   VendorName[?];   // The variable unicode name including the
+                              // null terminating character.
+    EFI_GUID VendorGuid;      // The variable GUID
+    UINT32   DataSize;        // The size of variable data in bytes
+    UINT8    Data[?];         // The variable data
+
+**/
+
+
+/**
+  Unpacks the next variable from the buffer
+
+  @param[in]  Buffer - Buffer pointing to the next variable instance
+                On subsequent calls, the pointer should be incremented
+                by the returned SizeUsed value.
+  @param[in]  MaxSize - Max allowable size for the variable data
+                On subsequent calls, this should be decremented
+                by the returned SizeUsed value.
+  @param[out] Name - Variable name string (address in Buffer)
+  @param[out] NameSize - Size of Name in bytes
+  @param[out] Guid - GUID of variable (address in Buffer)
+  @param[out] Attributes - Attributes of variable
+  @param[out] Data - Buffer containing Data for variable (address in Buffer)
+  @param[out] DataSize - Size of Data in bytes
+  @param[out] SizeUsed - Total size used for this variable instance in Buffer
+
+  @return     EFI_STATUS based on the success or failure of the operation
+
+**/
+STATIC
+EFI_STATUS
+UnpackVariableFromBuffer (
+  IN  VOID     *Buffer,
+  IN  UINTN    MaxSize,
+  OUT CHAR16   **Name,
+  OUT UINT32   *NameSize,
+  OUT EFI_GUID **Guid,
+  OUT UINT32   *Attributes,
+  OUT UINT32   *DataSize,
+  OUT VOID     **Data,
+  OUT UINTN    *SizeUsed
+  )
+{
+  UINT8  *BytePtr;
+  UINTN  Offset;
+
+  BytePtr = (UINT8*)Buffer;
+  Offset = 0;
+
+  *NameSize = *(UINT32*) (BytePtr + Offset);
+  Offset = Offset + sizeof (UINT32);
+
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Name = (CHAR16*) (BytePtr + Offset);
+  Offset = Offset + *(UINT32*)BytePtr;
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Guid = (EFI_GUID*) (BytePtr + Offset);
+  Offset = Offset + sizeof (EFI_GUID);
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Attributes = *(UINT32*) (BytePtr + Offset);
+  Offset = Offset + sizeof (UINT32);
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DataSize = *(UINT32*) (BytePtr + Offset);
+  Offset = Offset + sizeof (UINT32);
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Data = (VOID*) (BytePtr + Offset);
+  Offset = Offset + *DataSize;
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *SizeUsed = Offset;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Iterates through the variables in the buffer, and calls a callback
+  function for each variable found.
+
+  @param[in]  CallbackFunction - Function called for each variable instance
+  @param[in]  Context - Passed to each call of CallbackFunction
+  @param[in]  Buffer - Buffer containing serialized variables
+  @param[in]  MaxSize - Size of Buffer in bytes
+
+  @return     EFI_STATUS based on the success or failure of the operation
+
+**/
+STATIC
+EFI_STATUS
+IterateVariablesInBuffer (
+  IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK  CallbackFunction,
+  IN VOID                                       *CallbackContext,
+  IN VOID                                       *Buffer,
+  IN UINTN                                      MaxSize
+  )
+{
+  RETURN_STATUS Status;
+  UINTN         TotalSizeUsed;
+  UINTN         SizeUsed;
+
+  CHAR16        *Name;
+  UINT32        NameSize;
+  CHAR16        *AlignedName;
+  UINT32        AlignedNameMaxSize;
+  EFI_GUID      *Guid;
+  UINT32        Attributes;
+  UINT32        DataSize;
+  VOID          *Data;
+
+  SizeUsed = 0;
+  AlignedName = NULL;
+  AlignedNameMaxSize = 0;
+  Name = NULL;
+  Guid = NULL;
+  Attributes = 0;
+  DataSize = 0;
+  Data = NULL;
+
+  for (
+    Status = EFI_SUCCESS, TotalSizeUsed = 0;
+    !EFI_ERROR (Status) && (TotalSizeUsed < MaxSize);
+    ) {
+    Status = UnpackVariableFromBuffer (
+               (VOID*) ((UINT8*) Buffer + TotalSizeUsed),
+               (MaxSize - TotalSizeUsed),
+               &Name,
+               &NameSize,
+               &Guid,
+               &Attributes,
+               &DataSize,
+               &Data,
+               &SizeUsed
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // We copy the name to a separately allocated buffer,
+    // to be sure it is 16-bit aligned.
+    //
+    if (NameSize > AlignedNameMaxSize) {
+      if (AlignedName != NULL) {
+        FreePool (AlignedName);
+      }
+      AlignedName = AllocatePool (NameSize);
+    }
+    if (AlignedName == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    CopyMem (AlignedName, Name, NameSize);
+
+    TotalSizeUsed = TotalSizeUsed + SizeUsed;
+
+    //
+    // Run the callback function
+    //
+    Status = (*CallbackFunction) (
+               CallbackContext,
+               AlignedName,
+               Guid,
+               Attributes,
+               DataSize,
+               Data
+               );
+
+  }
+
+  if (AlignedName != NULL) {
+    FreePool (AlignedName);
+  }
+
+  //
+  // Make sure the entire buffer was used, or else return an error
+  //
+  if (TotalSizeUsed != MaxSize) {
+    DEBUG ((
+      EFI_D_ERROR,
+      "Deserialize variables error: TotalSizeUsed(%Lu) != MaxSize(%Lu)\n",
+      (UINT64)TotalSizeUsed,
+      (UINT64)MaxSize
+      ));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+STATIC
+RETURN_STATUS
+EFIAPI
+IterateVariablesCallbackNop (
+  IN  VOID                         *Context,
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid,
+  IN  UINT32                       Attributes,
+  IN  UINTN                        DataSize,
+  IN  VOID                         *Data
+  )
+{
+  return RETURN_SUCCESS;
+}
+
+
+STATIC
+RETURN_STATUS
+EFIAPI
+IterateVariablesCallbackSetInInstance (
+  IN  VOID                         *Context,
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid,
+  IN  UINT32                       Attributes,
+  IN  UINTN                        DataSize,
+  IN  VOID                         *Data
+  )
+{
+  EFI_HANDLE  Instance;
+
+  Instance = (EFI_HANDLE) Context;
+
+  return SerializeVariablesAddVariable (
+           Instance,
+           VariableName,
+           VendorGuid,
+           Attributes,
+           DataSize,
+           Data
+           );
+}
+
+
+STATIC
+RETURN_STATUS
+EFIAPI
+IterateVariablesCallbackSetSystemVariable (
+  IN  VOID                         *Context,
+  IN  CHAR16                       *VariableName,
+  IN  EFI_GUID                     *VendorGuid,
+  IN  UINT32                       Attributes,
+  IN  UINTN                        DataSize,
+  IN  VOID                         *Data
+  )
+{
+  EFI_STATUS          Status;
+  STATIC CONST UINT32 AuthMask =
+                        EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
+                        EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+
+  Status = gRT->SetVariable (
+             VariableName,
+             VendorGuid,
+             Attributes,
+             DataSize,
+             Data
+             );
+
+  if (Status == EFI_SECURITY_VIOLATION && (Attributes & AuthMask) != 0) {
+    DEBUG ((DEBUG_WARN, "%a: setting authenticated variable \"%s\" "
+            "failed with EFI_SECURITY_VIOLATION, ignoring\n", __FUNCTION__,
+            VariableName));
+    Status = EFI_SUCCESS;
+  } else if (Status == EFI_WRITE_PROTECTED) {
+    DEBUG ((DEBUG_WARN, "%a: setting ReadOnly variable \"%s\" "
+            "failed with EFI_WRITE_PROTECTED, ignoring\n", __FUNCTION__,
+            VariableName));
+    Status = EFI_SUCCESS;
+  }
+  return Status;
+}
+
+
+STATIC
+RETURN_STATUS
+EnsureExtraBufferSpace (
+  IN  SV_INSTANCE  *Instance,
+  IN  UINTN        Size
+  )
+{
+  VOID *NewBuffer;
+  UINTN NewSize;
+
+  NewSize = Instance->DataSize + Size;
+  if (NewSize <= Instance->BufferSize) {
+    return RETURN_SUCCESS;
+  }
+
+  //
+  // Double the required size to lessen the need to re-allocate in the future
+  //
+  NewSize = 2 * NewSize;
+
+  NewBuffer = AllocatePool (NewSize);
+  if (NewBuffer == NULL) {
+    return RETURN_OUT_OF_RESOURCES;
+  }
+
+  if (Instance->BufferPtr != NULL) {
+    CopyMem (NewBuffer, Instance->BufferPtr, Instance->DataSize);
+    FreePool (Instance->BufferPtr);
+  }
+
+  Instance->BufferPtr = NewBuffer;
+  Instance->BufferSize = NewSize;
+
+  return RETURN_SUCCESS;
+}
+
+
+STATIC
+VOID
+AppendToBuffer (
+  IN  SV_INSTANCE  *Instance,
+  IN  VOID         *Data,
+  IN  UINTN        Size
+  )
+{
+  UINTN NewSize;
+
+  ASSERT (Instance != NULL);
+  ASSERT (Data != NULL);
+
+  NewSize = Instance->DataSize + Size;
+  ASSERT ((Instance->DataSize + Size) <= Instance->BufferSize);
+
+  CopyMem (
+    (VOID*) (((UINT8*) (Instance->BufferPtr)) + Instance->DataSize),
+    Data,
+    Size
+    );
+
+  Instance->DataSize = NewSize;
+}
+
+
+/**
+  Creates a new variable serialization instance
+
+  @param[out]  Handle - Handle for a variable serialization instance
+
+  @retval      RETURN_SUCCESS - The variable serialization instance was
+                 successfully created.
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 create the variable serialization instance.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesNewInstance (
+  OUT EFI_HANDLE                      *Handle
+  )
+{
+  SV_INSTANCE  *New;
+
+  New = AllocateZeroPool (sizeof (*New));
+  if (New == NULL) {
+    return RETURN_OUT_OF_RESOURCES;
+  }
+
+  New->Signature = SV_SIGNATURE;
+
+  *Handle = (EFI_HANDLE) New;
+  return RETURN_SUCCESS;
+}
+
+
+/**
+  Free memory associated with a variable serialization instance
+
+  @param[in]  Handle - Handle for a variable serialization instance
+
+  @retval      RETURN_SUCCESS - The variable serialization instance was
+                 successfully freed.
+  @retval      RETURN_INVALID_PARAMETER - Handle was not a valid
+                 variable serialization instance.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesFreeInstance (
+  IN EFI_HANDLE Handle
+  )
+{
+  SV_INSTANCE    *Instance;
+
+  Instance = SV_FROM_HANDLE (Handle);
+
+  if (Instance->Signature != SV_SIGNATURE) {
+    return RETURN_INVALID_PARAMETER;
+  }
+
+  Instance->Signature = 0;
+
+  if (Instance->BufferPtr != NULL) {
+    FreePool (Instance->BufferPtr);
+  }
+
+  FreePool (Instance);
+
+  return RETURN_SUCCESS;
+}
+
+
+/**
+  Creates a new variable serialization instance using the given
+  binary representation of the variables to fill the new instance
+
+  @param[out] Handle - Handle for a variable serialization instance
+  @param[in]  Buffer - A buffer with the serialized representation
+                of the variables.  Must be the same format as produced
+                by SerializeVariablesToBuffer.
+  @param[in]  Size - This is the size of the binary representation
+                of the variables.
+
+  @retval      RETURN_SUCCESS - The binary representation was successfully
+                 imported into a new variable serialization instance
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 create the new variable serialization instance
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesNewInstanceFromBuffer (
+  OUT EFI_HANDLE                          *Handle,
+  IN  VOID                                *Buffer,
+  IN  UINTN                               Size
+  )
+{
+  RETURN_STATUS Status;
+
+  Status = SerializeVariablesNewInstance (Handle);
+  if (RETURN_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = IterateVariablesInBuffer (
+             IterateVariablesCallbackNop,
+             NULL,
+             Buffer,
+             Size
+             );
+  if (RETURN_ERROR (Status)) {
+    SerializeVariablesFreeInstance (*Handle);
+    return Status;
+  }
+
+  Status = IterateVariablesInBuffer (
+             IterateVariablesCallbackSetInInstance,
+             (VOID*) *Handle,
+             Buffer,
+             Size
+             );
+  if (RETURN_ERROR (Status)) {
+    SerializeVariablesFreeInstance (*Handle);
+    return Status;
+  }
+
+  return Status;
+}
+
+
+/**
+  Iterates all variables found with RuntimeServices GetNextVariableName
+
+  @param[in]   CallbackFunction - Function called for each variable instance
+  @param[in]   Context - Passed to each call of CallbackFunction
+
+  @retval      RETURN_SUCCESS - All variables were iterated without the
+                 CallbackFunction returning an error
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 iterate through the variables
+  @return      Any of RETURN_ERROR indicates an error reading the variable
+                 or an error was returned from CallbackFunction
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesIterateSystemVariables (
+  IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction,
+  IN VOID                                      *Context
+  )
+{
+  RETURN_STATUS               Status;
+  UINTN                       VariableNameBufferSize;
+  UINTN                       VariableNameSize;
+  CHAR16                      *VariableName;
+  EFI_GUID                    VendorGuid;
+  UINTN                       VariableDataBufferSize;
+  UINTN                       VariableDataSize;
+  VOID                        *VariableData;
+  UINT32                      VariableAttributes;
+  VOID                        *NewBuffer;
+
+  //
+  // Initialize the variable name and data buffer variables.
+  //
+  VariableNameBufferSize = sizeof (CHAR16);
+  VariableName = AllocateZeroPool (VariableNameBufferSize);
+
+  VariableDataBufferSize = 0;
+  VariableData = NULL;
+
+  for (;;) {
+    //
+    // Get the next variable name and guid
+    //
+    VariableNameSize = VariableNameBufferSize;
+    Status = gRT->GetNextVariableName (
+                    &VariableNameSize,
+                    VariableName,
+                    &VendorGuid
+                    );
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+      //
+      // The currently allocated VariableName buffer is too small,
+      // so we allocate a larger buffer, and copy the old buffer
+      // to it.
+      //
+      NewBuffer = AllocatePool (VariableNameSize);
+      if (NewBuffer == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        break;
+      }
+      CopyMem (NewBuffer, VariableName, VariableNameBufferSize);
+      if (VariableName != NULL) {
+        FreePool (VariableName);
+      }
+      VariableName = NewBuffer;
+      VariableNameBufferSize = VariableNameSize;
+
+      //
+      // Try to get the next variable name again with the larger buffer.
+      //
+      Status = gRT->GetNextVariableName (
+                      &VariableNameSize,
+                      VariableName,
+                      &VendorGuid
+                      );
+    }
+
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_NOT_FOUND) {
+        Status = EFI_SUCCESS;
+      }
+      break;
+    }
+
+    //
+    // Get the variable data and attributes
+    //
+    VariableDataSize = VariableDataBufferSize;
+    Status = gRT->GetVariable (
+                    VariableName,
+                    &VendorGuid,
+                    &VariableAttributes,
+                    &VariableDataSize,
+                    VariableData
+                    );
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+      //
+      // The currently allocated VariableData buffer is too small,
+      // so we allocate a larger buffer.
+      //
+      if (VariableDataBufferSize != 0) {
+        FreePool (VariableData);
+        VariableData = NULL;
+        VariableDataBufferSize = 0;
+      }
+      VariableData = AllocatePool (VariableDataSize);
+      if (VariableData == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        break;
+      }
+      VariableDataBufferSize = VariableDataSize;
+
+      //
+      // Try to read the variable again with the larger buffer.
+      //
+      Status = gRT->GetVariable (
+                      VariableName,
+                      &VendorGuid,
+                      &VariableAttributes,
+                      &VariableDataSize,
+                      VariableData
+                      );
+    }
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    //
+    // Run the callback function
+    //
+    Status = (*CallbackFunction) (
+               Context,
+               VariableName,
+               &VendorGuid,
+               VariableAttributes,
+               VariableDataSize,
+               VariableData
+               );
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+  }
+
+  if (VariableName != NULL) {
+    FreePool (VariableName);
+  }
+
+  if (VariableData != NULL) {
+    FreePool (VariableData);
+  }
+
+  return Status;
+}
+
+
+/**
+  Iterates all variables found in the variable serialization instance
+
+  @param[in]   Handle - Handle for a variable serialization instance
+  @param[in]   CallbackFunction - Function called for each variable instance
+  @param[in]   Context - Passed to each call of CallbackFunction
+
+  @retval      RETURN_SUCCESS - All variables were iterated without the
+                 CallbackFunction returning an error
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 iterate through the variables
+  @return      Any of RETURN_ERROR indicates an error reading the variable
+                 or an error was returned from CallbackFunction
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesIterateInstanceVariables (
+  IN EFI_HANDLE                                Handle,
+  IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction,
+  IN VOID                                      *Context
+  )
+{
+  SV_INSTANCE    *Instance;
+
+  Instance = SV_FROM_HANDLE (Handle);
+
+  if ((Instance->BufferPtr != NULL) && (Instance->DataSize != 0)) {
+    return IterateVariablesInBuffer (
+             CallbackFunction,
+             Context,
+             Instance->BufferPtr,
+             Instance->DataSize
+             );
+  } else {
+    return RETURN_SUCCESS;
+  }
+}
+
+
+/**
+  Sets all variables found in the variable serialization instance
+
+  @param[in]   Handle - Handle for a variable serialization instance
+
+  @retval      RETURN_SUCCESS - All variables were set successfully
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 set all the variables
+  @return      Any of RETURN_ERROR indicates an error reading the variables
+                 or in attempting to set a variable
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesSetSerializedVariables (
+  IN EFI_HANDLE                       Handle
+  )
+{
+  return SerializeVariablesIterateInstanceVariables (
+           Handle,
+           IterateVariablesCallbackSetSystemVariable,
+           NULL
+           );
+}
+
+
+/**
+  Adds a variable to the variable serialization instance
+
+  @param[in] Handle - Handle for a variable serialization instance
+  @param[in] VariableName - Refer to RuntimeServices GetVariable
+  @param[in] VendorGuid - Refer to RuntimeServices GetVariable
+  @param[in] Attributes - Refer to RuntimeServices GetVariable
+  @param[in] DataSize - Refer to RuntimeServices GetVariable
+  @param[in] Data - Refer to RuntimeServices GetVariable
+
+  @retval      RETURN_SUCCESS - All variables were set successfully
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 add the variable
+  @retval      RETURN_INVALID_PARAMETER - Handle was not a valid
+                 variable serialization instance or
+                 VariableName, VariableGuid or Data are NULL.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesAddVariable (
+  IN EFI_HANDLE                   Handle,
+  IN CHAR16                       *VariableName,
+  IN EFI_GUID                     *VendorGuid,
+  IN UINT32                       Attributes,
+  IN UINTN                        DataSize,
+  IN VOID                         *Data
+  )
+{
+  RETURN_STATUS  Status;
+  SV_INSTANCE    *Instance;
+  UINT32         SerializedNameSize;
+  UINT32         SerializedDataSize;
+  UINTN          SerializedSize;
+
+  Instance = SV_FROM_HANDLE (Handle);
+
+  if ((Instance->Signature != SV_SIGNATURE) ||
+      (VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
+  }
+
+  SerializedNameSize = (UINT32) StrSize (VariableName);
+
+  SerializedSize =
+    sizeof (SerializedNameSize) +
+    SerializedNameSize +
+    sizeof (*VendorGuid) +
+    sizeof (Attributes) +
+    sizeof (SerializedDataSize) +
+    DataSize;
+
+  Status = EnsureExtraBufferSpace (
+             Instance,
+             SerializedSize
+             );
+  if (RETURN_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Add name size (UINT32)
+  //
+  AppendToBuffer (Instance, (VOID*) &SerializedNameSize, sizeof (SerializedNameSize));
+
+  //
+  // Add variable unicode name string
+  //
+  AppendToBuffer (Instance, (VOID*) VariableName, SerializedNameSize);
+
+  //
+  // Add variable GUID
+  //
+  AppendToBuffer (Instance, (VOID*) VendorGuid, sizeof (*VendorGuid));
+
+  //
+  // Add variable attributes
+  //
+  AppendToBuffer (Instance, (VOID*) &Attributes, sizeof (Attributes));
+
+  //
+  // Add variable data size (UINT32)
+  //
+  SerializedDataSize = (UINT32) DataSize;
+  AppendToBuffer (Instance, (VOID*) &SerializedDataSize, sizeof (SerializedDataSize));
+
+  //
+  // Add variable data
+  //
+  AppendToBuffer (Instance, Data, DataSize);
+
+  return RETURN_SUCCESS;
+}
+
+
+/**
+  Serializes the variables known to this instance into the
+  provided buffer.
+
+  @param[in]     Handle - Handle for a variable serialization instance
+  @param[out]    Buffer - A buffer to store the binary representation
+                   of the variables.
+  @param[in,out] Size - On input this is the size of the buffer.
+                   On output this is the size of the binary representation
+                   of the variables.
+
+  @retval      RETURN_SUCCESS - The binary representation was successfully
+                 completed and returned in the buffer.
+  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
+                 save the variables to the buffer.
+  @retval      RETURN_INVALID_PARAMETER - Handle was not a valid
+                 variable serialization instance or
+                 Size or Buffer were NULL.
+  @retval      RETURN_BUFFER_TOO_SMALL - The Buffer size as indicated by
+                 the Size parameter was too small for the serialized
+                 variable data.  Size is returned with the required size.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerializeVariablesToBuffer (
+  IN     EFI_HANDLE                       Handle,
+  OUT    VOID                             *Buffer,
+  IN OUT UINTN                            *Size
+  )
+{
+  SV_INSTANCE    *Instance;
+
+  Instance = SV_FROM_HANDLE (Handle);
+
+  if (Size == NULL) {
+    return RETURN_INVALID_PARAMETER;
+  }
+
+  if (*Size < Instance->DataSize) {
+    *Size = Instance->DataSize;
+    return RETURN_BUFFER_TOO_SMALL;
+  }
+
+  if (Buffer == NULL) {
+    return RETURN_INVALID_PARAMETER;
+  }
+
+  *Size = Instance->DataSize;
+  CopyMem (Buffer, Instance->BufferPtr, Instance->DataSize);
+
+  return RETURN_SUCCESS;
+}
+

+ 33 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/SerializeVariablesLib/SerializeVariablesLib.h

@@ -0,0 +1,33 @@
+/** @file
+  Serialize Variables Library implementation
+
+  Copyright (c) 2009 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __SERIALIZE_VARIABLES_LIB_INSTANCE__
+#define __SERIALIZE_VARIABLES_LIB_INSTANCE__
+
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SerializeVariablesLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#define SV_FROM_HANDLE(a)       CR (a, SV_INSTANCE, Signature, SV_SIGNATURE)
+#define SV_SIGNATURE            SIGNATURE_32 ('S', 'V', 'A', 'R')
+
+typedef struct {
+  UINT32                              Signature;
+  VOID                                *BufferPtr;
+  UINTN                               BufferSize;
+  UINTN                               DataSize;
+} SV_INSTANCE;
+
+#endif
+

+ 36 - 0
Platform/Intel/SimicsOpenBoardPkg/Library/SerializeVariablesLib/SerializeVariablesLib.inf

@@ -0,0 +1,36 @@
+## @file
+#  Serialize Variables Library implementation
+#
+#  This library serializes and deserializes UEFI variables
+#
+# Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = DxeSerializeVariablesLib
+  FILE_GUID                      = 266A1434-6B22-441F-A8D2-D54AA8FDF95C
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = SerializeVariablesLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER
+
+[Sources]
+  SerializeVariablesLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ShellPkg/ShellPkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+

+ 108 - 0
Platform/Intel/SimicsOpenBoardPkg/Policy/Library/SiliconPolicyInitLib/SiliconPolicyInitLib.c

@@ -0,0 +1,108 @@
+/** @file
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+/**
+  Performs silicon pre-mem policy initialization.
+
+  The meaning of Policy is defined by silicon code.
+  It could be the raw data, a handle, a PPI, etc.
+
+  The returned data must be used as input data for SiliconPolicyDonePreMem(),
+  and SiliconPolicyUpdateLib.SiliconPolicyUpdatePreMem().
+
+  1) In FSP path, the input Policy should be FspmUpd.
+  Value of FspmUpd has been initialized by FSP binary default value.
+  Only a subset of FspmUpd needs to be updated for different silicon sku.
+  The return data is same FspmUpd.
+
+  2) In non-FSP path, the input policy could be NULL.
+  The return data is the initialized policy.
+
+  @param[in, out] Policy       Pointer to policy.
+
+  @return the initialized policy.
+**/
+VOID *
+EFIAPI
+SiliconPolicyInitPreMem (
+  IN OUT VOID *Policy OPTIONAL
+  )
+{
+  return Policy;
+}
+
+/*
+  The silicon pre-mem policy is finalized.
+  Silicon code can do initialization based upon the policy data.
+
+  The input Policy must be returned by SiliconPolicyInitPreMem().
+
+  @param[in] Policy       Pointer to policy.
+
+  @retval RETURN_SUCCESS The policy is handled consumed by silicon code.
+*/
+RETURN_STATUS
+EFIAPI
+SiliconPolicyDonePreMem (
+  IN VOID *Policy
+  )
+{
+  return RETURN_SUCCESS;
+}
+
+/**
+  Performs silicon post-mem policy initialization.
+
+  The meaning of Policy is defined by silicon code.
+  It could be the raw data, a handle, a PPI, etc.
+
+  The returned data must be used as input data for SiliconPolicyDonePostMem(),
+  and SiliconPolicyUpdateLib.SiliconPolicyUpdatePostMem().
+
+  1) In FSP path, the input Policy should be FspsUpd.
+  Value of FspsUpd has been initialized by FSP binary default value.
+  Only a subset of FspsUpd needs to be updated for different silicon sku.
+  The return data is same FspsUpd.
+
+  2) In non-FSP path, the input policy could be NULL.
+  The return data is the initialized policy.
+
+  @param[in, out] Policy       Pointer to policy.
+
+  @return the initialized policy.
+**/
+VOID *
+EFIAPI
+SiliconPolicyInitPostMem (
+  IN OUT VOID *Policy OPTIONAL
+  )
+{
+  return Policy;
+}
+
+/*
+  The silicon post-mem policy is finalized.
+  Silicon code can do initialization based upon the policy data.
+
+  The input Policy must be returned by SiliconPolicyInitPostMem().
+
+  @param[in] Policy       Pointer to policy.
+
+  @retval RETURN_SUCCESS The policy is handled consumed by silicon code.
+*/
+RETURN_STATUS
+EFIAPI
+SiliconPolicyDonePostMem (
+  IN VOID *Policy
+  )
+{
+  return RETURN_SUCCESS;
+}

+ 38 - 0
Platform/Intel/SimicsOpenBoardPkg/Policy/Library/SiliconPolicyInitLib/SiliconPolicyInitLib.inf

@@ -0,0 +1,38 @@
+## @file
+#
+# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION          = 0x00010005
+  BASE_NAME            = SiliconPolicyInitLib
+  FILE_GUID            = B494DF39-A5F8-48A1-B2D0-EF523AD91C55
+  MODULE_TYPE          = PEIM
+  VERSION_STRING       = 1.0
+  LIBRARY_CLASS        = SiliconPolicyInitLib
+
+[Sources]
+  SiliconPolicyInitLib.c
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+#                              this module.
+#
+################################################################################
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  BaseLib
+  DebugLib
+  DebugPrintErrorLevelLib
+  HobLib
+  IoLib
+  MemoryAllocationLib
+  PeiServicesLib
+

+ 70 - 0
Platform/Intel/SimicsOpenBoardPkg/Policy/Library/SiliconPolicyUpdateLib/SiliconPolicyUpdateLib.c

@@ -0,0 +1,70 @@
+/** @file
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiPei.h>
+
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Library/PeiServicesLib.h>
+
+/**
+  Performs silicon pre-mem policy update.
+
+  The meaning of Policy is defined by silicon code.
+  It could be the raw data, a handle, a PPI, etc.
+
+  The input Policy must be returned by SiliconPolicyDonePreMem().
+
+  1) In FSP path, the input Policy should be FspmUpd.
+  A platform may use this API to update the FSPM UPD policy initialized
+  by the silicon module or the default UPD data.
+  The output of FSPM UPD data from this API is the final UPD data.
+
+  2) In non-FSP path, the board may use additional way to get
+  the silicon policy data field based upon the input Policy.
+
+  @param[in, out] Policy       Pointer to policy.
+
+  @return the updated policy.
+**/
+VOID *
+EFIAPI
+SiliconPolicyUpdatePreMem (
+  IN OUT VOID *Policy
+  )
+{
+  return Policy;
+}
+
+/**
+  Performs silicon post-mem policy update.
+
+  The meaning of Policy is defined by silicon code.
+  It could be the raw data, a handle, a PPI, etc.
+
+  The input Policy must be returned by SiliconPolicyDonePostMem().
+
+  1) In FSP path, the input Policy should be FspsUpd.
+  A platform may use this API to update the FSPS UPD policy initialized
+  by the silicon module or the default UPD data.
+  The output of FSPS UPD data from this API is the final UPD data.
+
+  2) In non-FSP path, the board may use additional way to get
+  the silicon policy data field based upon the input Policy.
+
+  @param[in, out] Policy       Pointer to policy.
+
+  @return the updated policy.
+**/
+VOID *
+EFIAPI
+SiliconPolicyUpdatePostMem (
+  IN OUT VOID *Policy
+  )
+{
+  return Policy;
+}

+ 35 - 0
Platform/Intel/SimicsOpenBoardPkg/Policy/Library/SiliconPolicyUpdateLib/SiliconPolicyUpdateLib.inf

@@ -0,0 +1,35 @@
+## @file
+#
+# Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SiliconPolicyUpdateLib
+  FILE_GUID                      = 6EA9585C-3C15-47da-9FFC-25E9E4EA4D0C
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = SiliconPolicyUpdateLib
+
+[Sources]
+  SiliconPolicyUpdateLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  HobLib
+  IoLib
+  PcdLib
+
+[Pcd]
+
+[FixedPcd]
+
+[Ppis]
+
+[Guids]

+ 45 - 0
Platform/Intel/SimicsOpenBoardPkg/SecCore/Ia32/SecEntry.nasm

@@ -0,0 +1,45 @@
+; @file
+; Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+
+#include <Base.h>
+
+    SECTION .text
+
+extern ASM_PFX(SecCoreStartupWithStack)
+
+;
+; SecCore Entry Point
+;
+; Processor is in flat protected mode
+;
+; @param[in]  EAX   Initial value of the EAX register (BIST: Built-in Self Test)
+; @param[in]  DI    'BP': boot-strap processor, or 'AP': application processor
+; @param[in]  EBP   Pointer to the start of the Boot Firmware Volume
+;
+; @return     None  This routine does not return
+;
+global ASM_PFX(_ModuleEntryPoint)
+ASM_PFX(_ModuleEntryPoint):
+
+    ;
+    ; Load temporary RAM stack based on PCDs
+    ;
+    %define SEC_TOP_OF_STACK (FixedPcdGet32 (PcdSimicsSecPeiTempRamBase) + \
+                          FixedPcdGet32 (PcdSimicsSecPeiTempRamSize))
+    mov     eax, SEC_TOP_OF_STACK
+    mov     esp, eax
+    nop
+
+    ;
+    ; Setup parameters and call SecCoreStartupWithStack
+    ;   [esp]   return address for call
+    ;   [esp+4] BootFirmwareVolumePtr
+    ;   [esp+8] TopOfCurrentStack
+    ;
+    push    eax
+    push    ebp
+    call    ASM_PFX(SecCoreStartupWithStack)
+

+ 956 - 0
Platform/Intel/SimicsOpenBoardPkg/SecCore/SecMain.c

@@ -0,0 +1,956 @@
+/** @file
+  Main SEC phase code.  Transitions to PEI.
+
+  Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
+  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiPei.h>
+
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiCpuLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/IoLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/PciCf8Lib.h>
+
+#include <Ppi/TemporaryRamSupport.h>
+#include <Register/X58Ich10.h>
+
+#define SEC_IDT_ENTRY_COUNT  34
+
+typedef struct _SEC_IDT_TABLE {
+  EFI_PEI_SERVICES          *PeiService;
+  IA32_IDT_GATE_DESCRIPTOR  IdtTable[SEC_IDT_ENTRY_COUNT];
+} SEC_IDT_TABLE;
+
+VOID
+EFIAPI
+SecStartupPhase2 (
+  IN VOID                     *Context
+  );
+
+EFI_STATUS
+EFIAPI
+TemporaryRamMigration (
+  IN CONST EFI_PEI_SERVICES   **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
+  IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
+  IN UINTN                    CopySize
+  );
+
+EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {
+  TemporaryRamMigration
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {
+  {
+    (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+    &gEfiTemporaryRamSupportPpiGuid,
+    &mTemporaryRamSupportPpi
+  },
+};
+
+//
+// Template of an IDT entry pointing to 10:FFFFFFE4h.
+//
+IA32_IDT_GATE_DESCRIPTOR  mIdtEntryTemplate = {
+  {                                      // Bits
+    0xffe4,                              // OffsetLow
+    0x10,                                // Selector
+    0x0,                                 // Reserved_0
+    IA32_IDT_GATE_TYPE_INTERRUPT_32,     // GateType
+    0xffff                               // OffsetHigh
+  }
+};
+
+/**
+  Locates the main boot firmware volume.
+
+  @param[in,out]  BootFv  On input, the base of the BootFv
+                          On output, the decompressed main firmware volume
+
+  @retval EFI_SUCCESS    The main firmware volume was located and decompressed
+  @retval EFI_NOT_FOUND  The main firmware volume was not found
+
+**/
+EFI_STATUS
+FindMainFv (
+  IN OUT  EFI_FIRMWARE_VOLUME_HEADER   **BootFv
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER  *Fv;
+  UINTN                       Distance;
+
+  ASSERT (((UINTN) *BootFv & EFI_PAGE_MASK) == 0);
+
+  Fv = *BootFv;
+  Distance = (UINTN) (*BootFv)->FvLength;
+  do {
+    Fv = (EFI_FIRMWARE_VOLUME_HEADER*) ((UINT8*) Fv - EFI_PAGE_SIZE);
+    Distance += EFI_PAGE_SIZE;
+    if (Distance > SIZE_32MB) {
+      return EFI_NOT_FOUND;
+    }
+
+    if (Fv->Signature != EFI_FVH_SIGNATURE) {
+      continue;
+    }
+
+    if ((UINTN) Fv->FvLength > Distance) {
+      continue;
+    }
+
+    *BootFv = Fv;
+    return EFI_SUCCESS;
+
+  } while (TRUE);
+}
+
+/**
+  Locates a section within a series of sections
+  with the specified section type.
+
+  The Instance parameter indicates which instance of the section
+  type to return. (0 is first instance, 1 is second...)
+
+  @param[in]   Sections        The sections to search
+  @param[in]   SizeOfSections  Total size of all sections
+  @param[in]   SectionType     The section type to locate
+  @param[in]   Instance        The section instance number
+  @param[out]  FoundSection    The FFS section if found
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+
+**/
+EFI_STATUS
+FindFfsSectionInstance (
+  IN  VOID                             *Sections,
+  IN  UINTN                            SizeOfSections,
+  IN  EFI_SECTION_TYPE                 SectionType,
+  IN  UINTN                            Instance,
+  OUT EFI_COMMON_SECTION_HEADER        **FoundSection
+  )
+{
+  EFI_PHYSICAL_ADDRESS        CurrentAddress;
+  UINT32                      Size;
+  EFI_PHYSICAL_ADDRESS        EndOfSections;
+  EFI_COMMON_SECTION_HEADER   *Section;
+  EFI_PHYSICAL_ADDRESS        EndOfSection;
+
+  //
+  // Loop through the FFS file sections within the PEI Core FFS file
+  //
+  EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections;
+  EndOfSections = EndOfSection + SizeOfSections;
+  for (;;) {
+    if (EndOfSection == EndOfSections) {
+      break;
+    }
+    CurrentAddress = (EndOfSection + 3) & ~(3ULL);
+    if (CurrentAddress >= EndOfSections) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
+    DEBUG ((EFI_D_VERBOSE, "Section->Type: 0x%x\n", Section->Type));
+
+    Size = SECTION_SIZE (Section);
+    if (Size < sizeof (*Section)) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    EndOfSection = CurrentAddress + Size;
+    if (EndOfSection > EndOfSections) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    //
+    // Look for the requested section type
+    //
+    if (Section->Type == SectionType) {
+      if (Instance == 0) {
+        *FoundSection = Section;
+        return EFI_SUCCESS;
+      } else {
+        Instance--;
+      }
+    }
+    DEBUG ((EFI_D_VERBOSE, "Section->Type (0x%x) != SectionType (0x%x)\n", Section->Type, SectionType));
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Locates a section within a series of sections
+  with the specified section type.
+
+  @param[in]   Sections        The sections to search
+  @param[in]   SizeOfSections  Total size of all sections
+  @param[in]   SectionType     The section type to locate
+  @param[out]  FoundSection    The FFS section if found
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+
+**/
+EFI_STATUS
+FindFfsSectionInSections (
+  IN  VOID                             *Sections,
+  IN  UINTN                            SizeOfSections,
+  IN  EFI_SECTION_TYPE                 SectionType,
+  OUT EFI_COMMON_SECTION_HEADER        **FoundSection
+  )
+{
+  return FindFfsSectionInstance (
+           Sections,
+           SizeOfSections,
+           SectionType,
+           0,
+           FoundSection
+           );
+}
+
+/**
+  Locates a FFS file with the specified file type and a section
+  within that file with the specified section type.
+
+  @param[in]   Fv            The firmware volume to search
+  @param[in]   FileType      The file type to locate
+  @param[in]   SectionType   The section type to locate
+  @param[out]  FoundSection  The FFS section if found
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+
+**/
+EFI_STATUS
+FindFfsFileAndSection (
+  IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
+  IN  EFI_FV_FILETYPE                  FileType,
+  IN  EFI_SECTION_TYPE                 SectionType,
+  OUT EFI_COMMON_SECTION_HEADER        **FoundSection
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_PHYSICAL_ADDRESS        CurrentAddress;
+  EFI_PHYSICAL_ADDRESS        EndOfFirmwareVolume;
+  EFI_FFS_FILE_HEADER         *File;
+  UINT32                      Size;
+  EFI_PHYSICAL_ADDRESS        EndOfFile;
+
+  if (Fv->Signature != EFI_FVH_SIGNATURE) {
+    DEBUG ((EFI_D_ERROR, "FV at %p does not have FV header signature\n", Fv));
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Fv;
+  EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
+
+  //
+  // Loop through the FFS files in the Boot Firmware Volume
+  //
+  for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
+
+    CurrentAddress = (EndOfFile + 7) & ~(7ULL);
+    if (CurrentAddress > EndOfFirmwareVolume) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
+    Size = *(UINT32*) File->Size & 0xffffff;
+    if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+    DEBUG ((EFI_D_VERBOSE, "File->Type: 0x%x\n", File->Type));
+
+    EndOfFile = CurrentAddress + Size;
+    if (EndOfFile > EndOfFirmwareVolume) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    //
+    // Look for the request file type
+    //
+    if (File->Type != FileType) {
+      DEBUG ((EFI_D_VERBOSE, "File->Type (0x%x) != FileType (0x%x)\n", File->Type, FileType));
+      continue;
+    }
+
+    Status = FindFfsSectionInSections (
+               (VOID*) (File + 1),
+               (UINTN) EndOfFile - (UINTN) (File + 1),
+               SectionType,
+               FoundSection
+               );
+    if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) {
+      return Status;
+    }
+  }
+}
+
+/**
+  Locates the compressed main firmware volume and decompresses it.
+
+  @param[in,out]  Fv            On input, the firmware volume to search
+                                On output, the decompressed BOOT/PEI FV
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+
+**/
+EFI_STATUS
+DecompressMemFvs (
+  IN OUT EFI_FIRMWARE_VOLUME_HEADER       **Fv
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_GUID_DEFINED_SECTION          *Section;
+  UINT32                            OutputBufferSize;
+  UINT32                            ScratchBufferSize;
+  UINT16                            SectionAttribute;
+  UINT32                            AuthenticationStatus;
+  VOID                              *OutputBuffer;
+  VOID                              *ScratchBuffer;
+  EFI_COMMON_SECTION_HEADER         *FvSection;
+  EFI_FIRMWARE_VOLUME_HEADER        *PeiMemFv;
+  EFI_FIRMWARE_VOLUME_HEADER        *DxeMemFv;
+  UINT32                            FvHeaderSize;
+  UINT32                            FvSectionSize;
+
+  FvSection = (EFI_COMMON_SECTION_HEADER*) NULL;
+
+  DEBUG ((EFI_D_VERBOSE, "Find and decompress FV image.\n"));
+  Status = FindFfsFileAndSection (
+             *Fv,
+             EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
+             EFI_SECTION_GUID_DEFINED,
+             (EFI_COMMON_SECTION_HEADER**) &Section
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Unable to find GUID defined section\n"));
+    return Status;
+  }
+
+  Status = ExtractGuidedSectionGetInfo (
+             Section,
+             &OutputBufferSize,
+             &ScratchBufferSize,
+             &SectionAttribute
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Unable to GetInfo for GUIDed section\n"));
+    return Status;
+  }
+
+  OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdSimicsDxeMemFvBase) + SIZE_1MB);
+  ScratchBuffer = ALIGN_POINTER ((UINT8*) OutputBuffer + OutputBufferSize, SIZE_1MB);
+
+  DEBUG ((EFI_D_VERBOSE, "PcdSimicsDxeMemFvBase: 0x%x\n", PcdGet32 (PcdSimicsDxeMemFvBase)));
+  DEBUG ((EFI_D_VERBOSE, "OutputBuffer: 0x%x\n", OutputBuffer));
+  DEBUG ((EFI_D_VERBOSE, "OutputBufferSize: 0x%x\n", OutputBufferSize));
+  DEBUG ((EFI_D_VERBOSE, "ScratchBuffer: 0x%x\n", ScratchBuffer));
+  DEBUG ((EFI_D_VERBOSE, "ScratchBufferSize: 0x%x\n", ScratchBufferSize));
+  DEBUG ((EFI_D_VERBOSE, "PcdSimicsDecompressionScratchEnd: 0x%x\n", PcdGet32 (PcdSimicsDecompressionScratchEnd)));
+
+  DEBUG ((EFI_D_VERBOSE, "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x "
+    "PcdSimicsDecompressionScratchEnd=0x%x\n", __FUNCTION__, OutputBuffer,
+    OutputBufferSize, ScratchBuffer, ScratchBufferSize,
+    PcdGet32 (PcdSimicsDecompressionScratchEnd)));
+  ASSERT ((UINTN)ScratchBuffer + ScratchBufferSize ==
+    PcdGet32 (PcdSimicsDecompressionScratchEnd));
+
+  Status = ExtractGuidedSectionDecode (
+             Section,
+             &OutputBuffer,
+             ScratchBuffer,
+             &AuthenticationStatus
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Error during GUID section decode\n"));
+    return Status;
+  }
+
+  Status = FindFfsSectionInstance (
+             OutputBuffer,
+             OutputBufferSize,
+             EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
+             0,
+             &FvSection
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Unable to find PEI FV section\n"));
+    return Status;
+  }
+
+  ASSERT (SECTION_SIZE (FvSection) ==
+          (PcdGet32 (PcdSimicsPeiMemFvSize) + sizeof (*FvSection)));
+  ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
+
+  PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdSimicsPeiMemFvBase);
+  CopyMem (PeiMemFv, (VOID*) (FvSection + 1), PcdGet32 (PcdSimicsPeiMemFvSize));
+
+  if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) {
+    DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv));
+    CpuDeadLoop ();
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  Status = FindFfsSectionInstance (
+             OutputBuffer,
+             OutputBufferSize,
+             EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
+             1,
+             &FvSection
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Unable to find DXE FV section\n"));
+    return Status;
+  }
+
+  ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
+
+  if (IS_SECTION2 (FvSection)) {
+    FvSectionSize = SECTION2_SIZE (FvSection);
+    FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
+  } else {
+    FvSectionSize = SECTION_SIZE (FvSection);
+    FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
+  }
+
+  ASSERT (FvSectionSize == (PcdGet32 (PcdSimicsDxeMemFvSize) + FvHeaderSize));
+
+  DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdSimicsDxeMemFvBase);
+  CopyMem (DxeMemFv, (VOID*) ((UINTN)FvSection + FvHeaderSize), PcdGet32 (PcdSimicsDxeMemFvSize));
+
+  if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) {
+    DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv));
+    CpuDeadLoop ();
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  *Fv = PeiMemFv;
+  return EFI_SUCCESS;
+}
+
+/**
+  Locates the PEI Core entry point address
+
+  @param[in]  Fv                 The firmware volume to search
+  @param[out] PeiCoreEntryPoint  The entry point of the PEI Core image
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+
+**/
+EFI_STATUS
+FindPeiCoreImageBaseInFv (
+  IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
+  OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_COMMON_SECTION_HEADER   *Section;
+
+  DEBUG ((EFI_D_VERBOSE, "Find PEI Core image.\n"));
+  Status = FindFfsFileAndSection (
+             Fv,
+             EFI_FV_FILETYPE_PEI_CORE,
+             EFI_SECTION_PE32,
+             &Section
+             );
+  if (EFI_ERROR (Status)) {
+    Status = FindFfsFileAndSection (
+               Fv,
+               EFI_FV_FILETYPE_PEI_CORE,
+               EFI_SECTION_TE,
+               &Section
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Unable to find PEI Core image\n"));
+      return Status;
+    }
+  }
+
+  *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
+  DEBUG ((EFI_D_VERBOSE, "PEI core image base 0x%016LX.\n", *PeiCoreImageBase));
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Reads 8-bits of CMOS data.
+
+  Reads the 8-bits of CMOS data at the location specified by Index.
+  The 8-bit read value is returned.
+
+  @param  Index  The CMOS location to read.
+
+  @return The value read.
+
+**/
+STATIC
+UINT8
+CmosRead8 (
+  IN UINTN        Index
+  )
+{
+  IoWrite8 (0x70, (UINT8) Index);
+  return IoRead8 (0x71);
+}
+
+
+STATIC
+BOOLEAN
+IsS3Resume (
+  VOID
+  )
+{
+  DEBUG((EFI_D_VERBOSE, "modeValue = %x\n", IoBitFieldRead16(ICH10_PMBASE_IO + 4, 10, 12)));
+  return (IoBitFieldRead16(ICH10_PMBASE_IO + 4, 10, 12) == 0x5);
+}
+
+
+STATIC
+EFI_STATUS
+GetS3ResumePeiFv (
+  IN OUT EFI_FIRMWARE_VOLUME_HEADER       **PeiFv
+  )
+{
+  *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdSimicsPeiMemFvBase);
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Locates the PEI Core entry point address
+
+  @param[in,out]  Fv                 The firmware volume to search
+  @param[out]     PeiCoreEntryPoint  The entry point of the PEI Core image
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+
+**/
+VOID
+FindPeiCoreImageBase (
+  IN OUT  EFI_FIRMWARE_VOLUME_HEADER       **BootFv,
+     OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
+  )
+{
+  BOOLEAN S3Resume;
+
+  *PeiCoreImageBase = 0;
+
+  S3Resume = IsS3Resume ();
+  if (S3Resume && !FeaturePcdGet (PcdSmmSmramRequire)) {
+    //
+    // A malicious runtime OS may have injected something into our previously
+    // decoded PEI FV, but we don't care about that unless SMM/SMRAM is required.
+    //
+    DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume\n"));
+    GetS3ResumePeiFv (BootFv);
+  } else {
+    //
+    // We're either not resuming, or resuming "securely" -- we'll decompress
+    // both PEI FV and DXE FV from pristine flash.
+    //
+    DEBUG ((EFI_D_VERBOSE, "SEC: %a\n",
+      S3Resume ? "S3 resume (with PEI decompression)" : "Normal boot"));
+    FindMainFv (BootFv);
+
+    DecompressMemFvs (BootFv);
+  }
+
+  FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);
+}
+
+/**
+  Find core image base.
+
+**/
+EFI_STATUS
+FindImageBase (
+  IN  EFI_FIRMWARE_VOLUME_HEADER       *BootFirmwareVolumePtr,
+  OUT EFI_PHYSICAL_ADDRESS             *SecCoreImageBase
+  )
+{
+  EFI_PHYSICAL_ADDRESS        CurrentAddress;
+  EFI_PHYSICAL_ADDRESS        EndOfFirmwareVolume;
+  EFI_FFS_FILE_HEADER         *File;
+  UINT32                      Size;
+  EFI_PHYSICAL_ADDRESS        EndOfFile;
+  EFI_COMMON_SECTION_HEADER   *Section;
+  EFI_PHYSICAL_ADDRESS        EndOfSection;
+
+  *SecCoreImageBase = 0;
+
+  CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr;
+  EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;
+
+  //
+  // Loop through the FFS files in the Boot Firmware Volume
+  //
+  for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
+
+    CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
+    if (CurrentAddress > EndOfFirmwareVolume) {
+      return EFI_NOT_FOUND;
+    }
+
+    File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
+    Size = *(UINT32*) File->Size & 0xffffff;
+    if (Size < sizeof (*File)) {
+      return EFI_NOT_FOUND;
+    }
+
+    EndOfFile = CurrentAddress + Size;
+    if (EndOfFile > EndOfFirmwareVolume) {
+      return EFI_NOT_FOUND;
+    }
+
+    //
+    // Look for SEC Core
+    //
+    if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE) {
+      continue;
+    }
+
+    //
+    // Loop through the FFS file sections within the FFS file
+    //
+    EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);
+    for (;;) {
+      CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
+      Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
+
+      Size = *(UINT32*) Section->Size & 0xffffff;
+      if (Size < sizeof (*Section)) {
+        return EFI_NOT_FOUND;
+      }
+
+      EndOfSection = CurrentAddress + Size;
+      if (EndOfSection > EndOfFile) {
+        return EFI_NOT_FOUND;
+      }
+
+      //
+      // Look for executable sections
+      //
+      if (Section->Type == EFI_SECTION_PE32 || Section->Type == EFI_SECTION_TE) {
+        if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {
+          *SecCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) (Section + 1);
+        }
+        break;
+      }
+    }
+
+    //
+    // SEC Core image found
+    //
+    if (*SecCoreImageBase != 0) {
+      return EFI_SUCCESS;
+    }
+  }
+}
+
+/*
+  Find and return Pei Core entry point.
+
+  It also find SEC and PEI Core file debug information. It will report them if
+  remote debug is enabled.
+
+**/
+VOID
+FindAndReportEntryPoints (
+  IN  EFI_FIRMWARE_VOLUME_HEADER       **BootFirmwareVolumePtr,
+  OUT EFI_PEI_CORE_ENTRY_POINT         *PeiCoreEntryPoint
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_PHYSICAL_ADDRESS             SecCoreImageBase;
+  EFI_PHYSICAL_ADDRESS             PeiCoreImageBase;
+  PE_COFF_LOADER_IMAGE_CONTEXT     ImageContext;
+
+  //
+  // Find SEC Core and PEI Core image base
+   //
+  Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);
+  ASSERT_EFI_ERROR (Status);
+
+  FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);
+
+  ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
+  //
+  // Report SEC Core debug information when remote debug is enabled
+  //
+  ImageContext.ImageAddress = SecCoreImageBase;
+  ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
+  PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+
+  //
+  // Report PEI Core debug information when remote debug is enabled
+  //
+  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
+  ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
+  PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+
+  //
+  // Find PEI Core entry point
+  //
+  Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);
+  if (EFI_ERROR (Status)) {
+    *PeiCoreEntryPoint = 0;
+  }
+
+  return;
+}
+
+VOID
+EFIAPI
+SecCoreStartupWithStack (
+  IN EFI_FIRMWARE_VOLUME_HEADER       *BootFv,
+  IN VOID                             *TopOfCurrentStack
+  )
+{
+  EFI_SEC_PEI_HAND_OFF        SecCoreData;
+  SEC_IDT_TABLE               IdtTableInStack;
+  IA32_DESCRIPTOR             IdtDescriptor;
+  UINT32                      Index;
+  volatile UINT8              *Table;
+
+  //
+  // Initialize floating point operating environment
+  // to be compliant with UEFI spec.
+  //
+  InitializeFloatingPointUnits ();
+
+  //
+  // Initialize the PCIe Configuration base register.
+  //
+  PciCf8Write32 (PCI_CF8_LIB_ADDRESS (0xFF, 0, 1, 0x50), 0xE0000001);
+
+  //
+  // To ensure SMM can't be compromised on S3 resume, we must force re-init of
+  // the BaseExtractGuidedSectionLib. Since this is before library contructors
+  // are called, we must use a loop rather than SetMem.
+  //
+  Table = (UINT8*)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);
+  for (Index = 0;
+       Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);
+       ++Index) {
+    Table[Index] = 0;
+  }
+
+  ProcessLibraryConstructorList (NULL, NULL);
+
+  DEBUG ((EFI_D_INFO,
+    "SecCoreStartupWithStack(0x%x, 0x%x)\n",
+    (UINT32)(UINTN)BootFv,
+    (UINT32)(UINTN)TopOfCurrentStack
+    ));
+
+  //
+  // Initialize IDT
+  //
+  IdtTableInStack.PeiService = NULL;
+  for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
+    CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));
+  }
+
+  IdtDescriptor.Base  = (UINTN)&IdtTableInStack.IdtTable;
+  IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
+
+  AsmWriteIdtr (&IdtDescriptor);
+
+#if defined (MDE_CPU_X64)
+  //
+  // ASSERT that the Page Tables were set by the reset vector code to
+  // the address we expect.
+  //
+  ASSERT (AsmReadCr3 () == (UINTN) PcdGet32 (PcdSimicsSecPageTablesBase));
+#endif
+
+  //
+  // |-------------|       <-- TopOfCurrentStack
+  // |   Stack     | 32k
+  // |-------------|
+  // |    Heap     | 32k
+  // |-------------|       <-- SecCoreData.TemporaryRamBase
+  //
+
+  ASSERT ((UINTN) (PcdGet32 (PcdSimicsSecPeiTempRamBase) +
+                   PcdGet32 (PcdSimicsSecPeiTempRamSize)) ==
+          (UINTN) TopOfCurrentStack);
+
+  //
+  // Initialize SEC hand-off state
+  //
+  SecCoreData.DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
+
+  SecCoreData.TemporaryRamSize       = (UINTN) PcdGet32 (PcdSimicsSecPeiTempRamSize);
+  SecCoreData.TemporaryRamBase       = (VOID*)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);
+
+  SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;
+  SecCoreData.PeiTemporaryRamSize    = SecCoreData.TemporaryRamSize >> 1;
+
+  SecCoreData.StackBase              = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
+  SecCoreData.StackSize              = SecCoreData.TemporaryRamSize >> 1;
+
+  SecCoreData.BootFirmwareVolumeBase = BootFv;
+  SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
+
+  //
+  // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
+  //
+  IoWrite8 (0x21, 0xff);
+  IoWrite8 (0xA1, 0xff);
+
+  //
+  // Initialize Local APIC Timer hardware and disable Local APIC Timer
+  // interrupts before initializing the Debug Agent and the debug timer is
+  // enabled.
+  //
+  InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
+  DisableApicTimerInterrupt ();
+
+  //
+  // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
+  //
+  InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
+}
+
+/**
+  Caller provided function to be invoked at the end of InitializeDebugAgent().
+
+  Entry point to the C language phase of SEC. After the SEC assembly
+  code has initialized some temporary memory and set up the stack,
+  the control is transferred to this function.
+
+  @param[in] Context    The first input parameter of InitializeDebugAgent().
+
+**/
+VOID
+EFIAPI
+SecStartupPhase2(
+  IN VOID                     *Context
+  )
+{
+  EFI_SEC_PEI_HAND_OFF        *SecCoreData;
+  EFI_FIRMWARE_VOLUME_HEADER  *BootFv;
+  EFI_PEI_CORE_ENTRY_POINT    PeiCoreEntryPoint;
+
+  SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;
+
+  //
+  // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
+  // is enabled.
+  //
+  BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
+  FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
+  SecCoreData->BootFirmwareVolumeBase = BootFv;
+  SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
+
+  //
+  // Transfer the control to the PEI core
+  //
+  (*PeiCoreEntryPoint) (SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
+
+  //
+  // If we get here then the PEI Core returned, which is not recoverable.
+  //
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+}
+
+EFI_STATUS
+EFIAPI
+TemporaryRamMigration (
+  IN CONST EFI_PEI_SERVICES   **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
+  IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
+  IN UINTN                    CopySize
+  )
+{
+  IA32_DESCRIPTOR                  IdtDescriptor;
+  VOID                             *OldHeap;
+  VOID                             *NewHeap;
+  VOID                             *OldStack;
+  VOID                             *NewStack;
+  DEBUG_AGENT_CONTEXT_POSTMEM_SEC  DebugAgentContext;
+  BOOLEAN                          OldStatus;
+  BASE_LIBRARY_JUMP_BUFFER         JumpBuffer;
+
+  DEBUG ((EFI_D_INFO,
+    "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
+    TemporaryMemoryBase,
+    PermanentMemoryBase,
+    (UINT64)CopySize
+    ));
+
+  OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
+  NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1));
+
+  OldStack = (VOID*)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
+  NewStack = (VOID*)(UINTN)PermanentMemoryBase;
+
+  DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;
+  DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;
+
+  OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);
+  InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *) &DebugAgentContext, NULL);
+
+  //
+  // Migrate Heap
+  //
+  CopyMem (NewHeap, OldHeap, CopySize >> 1);
+
+  //
+  // Migrate Stack
+  //
+  CopyMem (NewStack, OldStack, CopySize >> 1);
+
+  //
+  // Rebase IDT table in permanent memory
+  //
+  AsmReadIdtr (&IdtDescriptor);
+  IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;
+
+  AsmWriteIdtr (&IdtDescriptor);
+
+  //
+  // Use SetJump()/LongJump() to switch to a new stack.
+  //
+  if (SetJump (&JumpBuffer) == 0) {
+#if defined (MDE_CPU_IA32)
+    JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;
+#endif
+#if defined (MDE_CPU_X64)
+    JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;
+#endif
+    LongJump (&JumpBuffer, (UINTN)-1);
+  }
+
+  SaveAndSetDebugTimerInterrupt (OldStatus);
+
+  return EFI_SUCCESS;
+}

+ 73 - 0
Platform/Intel/SimicsOpenBoardPkg/SecCore/SecMain.inf

@@ -0,0 +1,73 @@
+## @file
+#  SEC Driver
+#
+# Copyright (c) 2008 - 2019 Intel Corporation. All rights reserved. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SecMain
+  FILE_GUID                      = e67f156f-54c5-47f3-a35d-07c045881e14
+  MODULE_TYPE                    = SEC
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = SecMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  SecMain.c
+
+[Sources.IA32]
+  Ia32/SecEntry.nasm
+
+[Sources.X64]
+  X64/SecEntry.nasm
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  SimicsX58SktPkg/SktPkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+  SimicsIch10Pkg/Ich10Pkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  BaseMemoryLib
+  PeiServicesLib
+  PcdLib
+  UefiCpuLib
+  DebugAgentLib
+  IoLib
+  PeCoffLib
+  PeCoffGetEntryPointLib
+  PeCoffExtraActionLib
+  ExtractGuidedSectionLib
+  LocalApicLib
+  PciCf8Lib
+
+[Ppis]
+  gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
+
+[Pcd]
+  gBoardModuleTokenSpaceGuid.PcdSimicsPeiMemFvBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsPeiMemFvSize
+  gBoardModuleTokenSpaceGuid.PcdSimicsDxeMemFvBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsDxeMemFvSize
+  gBoardModuleTokenSpaceGuid.PcdSimicsSecPageTablesBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsSecPeiTempRamBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsSecPeiTempRamSize
+  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
+  gBoardModuleTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
+  gBoardModuleTokenSpaceGuid.PcdSimicsDecompressionScratchEnd
+
+[FeaturePcd]
+  gSimicsX58PkgTokenSpaceGuid.PcdSmmSmramRequire

+ 45 - 0
Platform/Intel/SimicsOpenBoardPkg/SecCore/X64/SecEntry.nasm

@@ -0,0 +1,45 @@
+; @file
+; Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+
+#include <Base.h>
+
+DEFAULT REL
+SECTION .text
+
+extern ASM_PFX(SecCoreStartupWithStack)
+
+;
+; SecCore Entry Point
+;
+; Processor is in flat protected mode
+;
+; @param[in]  RAX   Initial value of the EAX register (BIST: Built-in Self Test)
+; @param[in]  DI    'BP': boot-strap processor, or 'AP': application processor
+; @param[in]  RBP   Pointer to the start of the Boot Firmware Volume
+;
+; @return     None  This routine does not return
+;
+global ASM_PFX(_ModuleEntryPoint)
+ASM_PFX(_ModuleEntryPoint):
+
+    ;
+    ; Load temporary RAM stack based on PCDs
+    ;
+    %define SEC_TOP_OF_STACK (FixedPcdGet32 (PcdSimicsSecPeiTempRamBase) + \
+                          FixedPcdGet32 (PcdSimicsSecPeiTempRamSize))
+    mov     rsp, SEC_TOP_OF_STACK
+    nop
+
+    ;
+    ; Setup parameters and call SecCoreStartupWithStack
+    ;   rcx: BootFirmwareVolumePtr
+    ;   rdx: TopOfCurrentStack
+    ;
+    mov     rcx, rbp
+    mov     rdx, rsp
+    sub     rsp, 0x20
+    call    ASM_PFX(SecCoreStartupWithStack)
+

+ 865 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/Platform.c

@@ -0,0 +1,865 @@
+/** @file
+  This driver effectuates QSP platform configuration settings and exposes
+  them via HII.
+
+  Copyright (C) 2014, Red Hat, Inc.
+  Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/SimicsBoardConfig.h>
+
+#include "Platform.h"
+#include "PlatformConfig.h"
+#include <Library/DxeServicesTableLib.h>
+//
+// The HiiAddPackages() library function requires that any controller (or
+// image) handle, to be associated with the HII packages under installation, be
+// "decorated" with a device path. The tradition seems to be a vendor device
+// path.
+//
+// We'd like to associate our HII packages with the driver's image handle. The
+// first idea is to use the driver image's device path. Unfortunately, loaded
+// images only come with an EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL (not the
+// usual EFI_DEVICE_PATH_PROTOCOL), ie. a different GUID. In addition, even the
+// EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL interface may be NULL, if the image
+// has been loaded from an "unnamed" memory source buffer.
+//
+// Hence let's just stick with the tradition -- use a dedicated vendor device
+// path, with the driver's FILE_GUID.
+//
+#pragma pack(1)
+typedef struct {
+  VENDOR_DEVICE_PATH       VendorDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL End;
+} PKG_DEVICE_PATH;
+#pragma pack()
+
+STATIC PKG_DEVICE_PATH mPkgDevicePath = {
+  {
+    {
+      HARDWARE_DEVICE_PATH,
+      HW_VENDOR_DP,
+      {
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)     ),
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH) >> 8)
+      }
+    },
+    EFI_CALLER_ID_GUID
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      (UINT8) (END_DEVICE_PATH_LENGTH     ),
+      (UINT8) (END_DEVICE_PATH_LENGTH >> 8)
+    }
+  }
+};
+
+//
+// The configuration interface between the HII engine (form display etc) and
+// this driver.
+//
+STATIC EFI_HII_CONFIG_ACCESS_PROTOCOL mConfigAccess;
+
+//
+// The handle representing our list of packages after installation.
+//
+STATIC EFI_HII_HANDLE mInstalledPackages;
+
+//
+// The arrays below constitute our HII package list. They are auto-generated by
+// the VFR compiler and linked into the driver image during the build.
+//
+// - The strings package receives its C identifier from the driver's BASE_NAME,
+//   plus "Strings".
+//
+// - The forms package receives its C identifier from the VFR file's basename,
+//   plus "Bin".
+//
+//
+extern UINT8 SimicsDxeStrings[];
+extern UINT8 PlatformFormsBin[];
+
+//
+// We want to be notified about GOP installations until we find one GOP
+// interface that lets us populate the form.
+//
+STATIC EFI_EVENT mGopEvent;
+
+//
+// The registration record underneath this pointer allows us to iterate through
+// the GOP instances one by one.
+//
+STATIC VOID *mGopTracker;
+
+//
+// Cache the resolutions we get from the GOP.
+//
+typedef struct {
+  UINT32 X;
+  UINT32 Y;
+} GOP_MODE;
+
+STATIC UINTN    mNumGopModes;
+STATIC GOP_MODE *mGopModes;
+
+
+/**
+  Load the persistent platform configuration and translate it to binary form
+  state.
+
+  If the platform configuration is missing, then the function fills in a
+  default state.
+
+  @param[out] MainFormState  Binary form/widget state after translation.
+
+  @retval EFI_SUCCESS  Form/widget state ready.
+  @return              Error codes from underlying functions.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PlatformConfigToFormState (
+  OUT MAIN_FORM_STATE *MainFormState
+  )
+{
+  EFI_STATUS      Status;
+  PLATFORM_CONFIG PlatformConfig;
+  UINT64          OptionalElements;
+  UINTN           ModeNumber;
+
+  ZeroMem (MainFormState, sizeof *MainFormState);
+
+  Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
+  switch (Status) {
+  case EFI_SUCCESS:
+    if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
+      //
+      // Format the preferred resolution as text.
+      //
+      UnicodeSPrintAsciiFormat (
+        (CHAR16 *) MainFormState->CurrentPreferredResolution,
+        sizeof MainFormState->CurrentPreferredResolution,
+        "%Ldx%Ld",
+        (INT64) PlatformConfig.HorizontalResolution,
+        (INT64) PlatformConfig.VerticalResolution);
+
+      //
+      // Try to locate it in the drop-down list too. This may not succeed, but
+      // that's fine.
+      //
+      for (ModeNumber = 0; ModeNumber < mNumGopModes; ++ModeNumber) {
+        if (mGopModes[ModeNumber].X == PlatformConfig.HorizontalResolution &&
+            mGopModes[ModeNumber].Y == PlatformConfig.VerticalResolution) {
+          MainFormState->NextPreferredResolution = (UINT32) ModeNumber;
+          break;
+        }
+      }
+
+      break;
+    }
+    //
+    // fall through otherwise
+    //
+
+  case EFI_NOT_FOUND:
+    UnicodeSPrintAsciiFormat (
+      (CHAR16 *) MainFormState->CurrentPreferredResolution,
+      sizeof MainFormState->CurrentPreferredResolution,
+      "Unset");
+    break;
+
+  default:
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  This function is called by the HII machinery when it fetches the form state.
+
+  See the precise documentation in the UEFI spec.
+
+  @param[in]  This      The Config Access Protocol instance.
+
+  @param[in]  Request   A <ConfigRequest> format UCS-2 string describing the
+                        query.
+
+  @param[out] Progress  A pointer into Request on output, identifying the query
+                        element where processing failed.
+
+  @param[out] Results   A <MultiConfigAltResp> format UCS-2 string that has
+                        all values filled in for the names in the Request
+                        string.
+
+  @retval EFI_SUCCESS  Extraction of form state in <MultiConfigAltResp>
+                       encoding successful.
+  @return              Status codes from underlying functions.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ExtractConfig (
+  IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
+  IN CONST  EFI_STRING                      Request,
+  OUT       EFI_STRING                      *Progress,
+  OUT       EFI_STRING                      *Results
+)
+{
+  MAIN_FORM_STATE MainFormState;
+  EFI_STATUS      Status;
+
+  DEBUG ((EFI_D_VERBOSE, "%a: Request=\"%s\"\n", __FUNCTION__, Request));
+
+  Status = PlatformConfigToFormState (&MainFormState);
+  if (EFI_ERROR (Status)) {
+    *Progress = Request;
+    return Status;
+  }
+
+  //
+  // Answer the textual request keying off the binary form state.
+  //
+  Status = gHiiConfigRouting->BlockToConfig (gHiiConfigRouting, Request,
+                                (VOID *) &MainFormState, sizeof MainFormState,
+                                Results, Progress);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "%a: BlockToConfig(): %r, Progress=\"%s\"\n",
+      __FUNCTION__, Status, (Status == EFI_DEVICE_ERROR) ? NULL : *Progress));
+  } else {
+    DEBUG ((EFI_D_VERBOSE, "%a: Results=\"%s\"\n", __FUNCTION__, *Results));
+  }
+  return Status;
+}
+
+
+/**
+  Interpret the binary form state and save it as persistent platform
+  configuration.
+
+  @param[in] MainFormState  Binary form/widget state to verify and save.
+
+  @retval EFI_SUCCESS  Platform configuration saved.
+  @return              Error codes from underlying functions.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FormStateToPlatformConfig (
+  IN CONST MAIN_FORM_STATE *MainFormState
+  )
+{
+  EFI_STATUS      Status;
+  PLATFORM_CONFIG PlatformConfig;
+  CONST GOP_MODE  *GopMode;
+
+  //
+  // There's nothing to do with the textual CurrentPreferredResolution field.
+  // We verify and translate the selection in the drop-down list.
+  //
+  if (MainFormState->NextPreferredResolution >= mNumGopModes) {
+    return EFI_INVALID_PARAMETER;
+  }
+  GopMode = mGopModes + MainFormState->NextPreferredResolution;
+
+  ZeroMem (&PlatformConfig, sizeof PlatformConfig);
+  PlatformConfig.HorizontalResolution = GopMode->X;
+  PlatformConfig.VerticalResolution   = GopMode->Y;
+
+  Status = PlatformConfigSave (&PlatformConfig);
+  return Status;
+}
+
+
+/**
+  This function is called by the HII machinery when it wants the driver to
+  interpret and persist the form state.
+
+  See the precise documentation in the UEFI spec.
+
+  @param[in]  This           The Config Access Protocol instance.
+
+  @param[in]  Configuration  A <ConfigResp> format UCS-2 string describing the
+                             form state.
+
+  @param[out] Progress       A pointer into Configuration on output,
+                             identifying the element where processing failed.
+
+  @retval EFI_SUCCESS  Configuration verified, state permanent.
+
+  @return              Status codes from underlying functions.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+RouteConfig (
+  IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
+  IN CONST  EFI_STRING                      Configuration,
+  OUT       EFI_STRING                      *Progress
+)
+{
+  MAIN_FORM_STATE MainFormState;
+  UINTN           BlockSize;
+  EFI_STATUS      Status;
+
+  DEBUG ((EFI_D_VERBOSE, "%a: Configuration=\"%s\"\n", __FUNCTION__,
+    Configuration));
+
+  //
+  // the "read" step in RMW
+  //
+  Status = PlatformConfigToFormState (&MainFormState);
+  if (EFI_ERROR (Status)) {
+    *Progress = Configuration;
+    return Status;
+  }
+
+  //
+  // the "modify" step in RMW
+  //
+  // (Update the binary form state. This update may be partial, which is why in
+  // general we must pre-load the form state from the platform config.)
+  //
+  BlockSize = sizeof MainFormState;
+  Status = gHiiConfigRouting->ConfigToBlock (gHiiConfigRouting, Configuration,
+                                (VOID *) &MainFormState, &BlockSize, Progress);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "%a: ConfigToBlock(): %r, Progress=\"%s\"\n",
+      __FUNCTION__, Status,
+      (Status == EFI_BUFFER_TOO_SMALL) ? NULL : *Progress));
+    return Status;
+  }
+
+  //
+  // the "write" step in RMW
+  //
+  Status = FormStateToPlatformConfig (&MainFormState);
+  if (EFI_ERROR (Status)) {
+    *Progress = Configuration;
+  }
+  return Status;
+}
+
+
+STATIC
+EFI_STATUS
+EFIAPI
+Callback (
+  IN     CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
+  IN     EFI_BROWSER_ACTION                     Action,
+  IN     EFI_QUESTION_ID                        QuestionId,
+  IN     UINT8                                  Type,
+  IN OUT EFI_IFR_TYPE_VALUE                     *Value,
+  OUT    EFI_BROWSER_ACTION_REQUEST             *ActionRequest
+  )
+{
+  DEBUG ((EFI_D_VERBOSE, "%a: Action=0x%Lx QuestionId=%d Type=%d\n",
+    __FUNCTION__, (UINT64) Action, QuestionId, Type));
+
+  if (Action != EFI_BROWSER_ACTION_CHANGED) {
+    return EFI_UNSUPPORTED;
+  }
+
+  switch (QuestionId) {
+  case QUESTION_SAVE_EXIT:
+    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+    break;
+
+  case QUESTION_DISCARD_EXIT:
+    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+    break;
+
+  default:
+    break;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Query and save all resolutions supported by the GOP.
+
+  @param[in]  Gop          The Graphics Output Protocol instance to query.
+
+  @param[out] NumGopModes  The number of modes supported by the GOP. On output,
+                           this parameter will be positive.
+
+  @param[out] GopModes     On output, a dynamically allocated array containing
+                           the resolutions returned by the GOP. The caller is
+                           responsible for freeing the array after use.
+
+  @retval EFI_UNSUPPORTED       No modes found.
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate GopModes.
+  @return                       Error codes from Gop->QueryMode().
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+QueryGopModes (
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,
+  OUT UINTN                        *NumGopModes,
+  OUT GOP_MODE                     **GopModes
+  )
+{
+  EFI_STATUS Status;
+  UINT32     ModeNumber;
+
+  if (Gop->Mode->MaxMode == 0) {
+    return EFI_UNSUPPORTED;
+  }
+  *NumGopModes = Gop->Mode->MaxMode;
+
+  *GopModes = AllocatePool (Gop->Mode->MaxMode * sizeof **GopModes);
+  if (*GopModes == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (ModeNumber = 0; ModeNumber < Gop->Mode->MaxMode; ++ModeNumber) {
+    EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+    UINTN                                SizeOfInfo;
+
+    Status = Gop->QueryMode (Gop, ModeNumber, &SizeOfInfo, &Info);
+    if (EFI_ERROR (Status)) {
+      goto FreeGopModes;
+    }
+
+    (*GopModes)[ModeNumber].X = Info->HorizontalResolution;
+    (*GopModes)[ModeNumber].Y = Info->VerticalResolution;
+    FreePool (Info);
+  }
+
+  return EFI_SUCCESS;
+
+FreeGopModes:
+  FreePool (*GopModes);
+
+  return Status;
+}
+
+
+/**
+  Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes,
+  based on available GOP resolutions, to be placed under a "one-of-many" (ie.
+  "drop down list") opcode.
+
+  @param[in]  PackageList   The package list with the formset and form for
+                            which the drop down options are produced. Option
+                            names are added as new strings to PackageList.
+
+  @param[out] OpCodeBuffer  On output, a dynamically allocated opcode buffer
+                            with drop down list options corresponding to GOP
+                            resolutions. The caller is responsible for freeing
+                            OpCodeBuffer with HiiFreeOpCodeHandle() after use.
+
+  @param[in]  NumGopModes   Number of entries in GopModes.
+
+  @param[in]  GopModes      Array of resolutions retrieved from the GOP.
+
+  @retval EFI_SUCESS  Opcodes have been successfully produced.
+
+  @return             Status codes from underlying functions. PackageList may
+                      have been extended with new strings. OpCodeBuffer is
+                      unchanged.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CreateResolutionOptions (
+  IN  EFI_HII_HANDLE  *PackageList,
+  OUT VOID            **OpCodeBuffer,
+  IN  UINTN           NumGopModes,
+  IN  GOP_MODE        *GopModes
+  )
+{
+  EFI_STATUS Status;
+  VOID       *OutputBuffer;
+  UINTN      ModeNumber;
+
+  OutputBuffer = HiiAllocateOpCodeHandle ();
+  if (OutputBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (ModeNumber = 0; ModeNumber < NumGopModes; ++ModeNumber) {
+    CHAR16        Desc[MAXSIZE_RES_CUR];
+    EFI_STRING_ID NewString;
+    VOID          *OpCode;
+
+    UnicodeSPrintAsciiFormat (Desc, sizeof Desc, "%Ldx%Ld",
+      (INT64) GopModes[ModeNumber].X, (INT64) GopModes[ModeNumber].Y);
+    NewString = HiiSetString (PackageList, 0 /* new string */, Desc,
+                  NULL /* for all languages */);
+    if (NewString == 0) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto FreeOutputBuffer;
+    }
+    OpCode = HiiCreateOneOfOptionOpCode (OutputBuffer, NewString,
+               0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4, ModeNumber);
+    if (OpCode == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto FreeOutputBuffer;
+    }
+  }
+
+  *OpCodeBuffer = OutputBuffer;
+  return EFI_SUCCESS;
+
+FreeOutputBuffer:
+  HiiFreeOpCodeHandle (OutputBuffer);
+
+  return Status;
+}
+
+
+/**
+  Populate the form identified by the (PackageList, FormSetGuid, FormId)
+  triplet.
+
+  The drop down list of video resolutions is generated from (NumGopModes,
+  GopModes).
+
+  @retval EFI_SUCESS  Form successfully updated.
+  @return             Status codes from underlying functions.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PopulateForm (
+  IN  EFI_HII_HANDLE  *PackageList,
+  IN  EFI_GUID        *FormSetGuid,
+  IN  EFI_FORM_ID     FormId,
+  IN  UINTN           NumGopModes,
+  IN  GOP_MODE        *GopModes
+  )
+{
+  EFI_STATUS         Status;
+  VOID               *OpCodeBuffer;
+  VOID               *OpCode;
+  EFI_IFR_GUID_LABEL *Anchor;
+  VOID               *OpCodeBuffer2;
+
+  OpCodeBuffer2 = NULL;
+
+  //
+  // 1. Allocate an empty opcode buffer.
+  //
+  OpCodeBuffer = HiiAllocateOpCodeHandle ();
+  if (OpCodeBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // 2. Create a label opcode (which is a Tiano extension) inside the buffer.
+  // The label's number must match the "anchor" label in the form.
+  //
+  OpCode = HiiCreateGuidOpCode (OpCodeBuffer, &gEfiIfrTianoGuid,
+             NULL /* optional copy origin */, sizeof *Anchor);
+  if (OpCode == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto FreeOpCodeBuffer;
+  }
+  Anchor               = OpCode;
+  Anchor->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+  Anchor->Number       = LABEL_RES_NEXT;
+
+  //
+  // 3. Create the opcodes inside the buffer that are to be inserted into the
+  // form.
+  //
+  // 3.1. Get a list of resolutions.
+  //
+  Status = CreateResolutionOptions (PackageList, &OpCodeBuffer2,
+             NumGopModes, GopModes);
+  if (EFI_ERROR (Status)) {
+    goto FreeOpCodeBuffer;
+  }
+
+  //
+  // 3.2. Create a one-of-many question with the above options.
+  //
+  OpCode = HiiCreateOneOfOpCode (
+             OpCodeBuffer,                        // create opcode inside this
+                                                  //   opcode buffer,
+             QUESTION_RES_NEXT,                   // ID of question,
+             FORMSTATEID_MAIN_FORM,               // identifies form state
+                                                  //   storage,
+             (UINT16) OFFSET_OF (MAIN_FORM_STATE, // value of question stored
+                        NextPreferredResolution), //   at this offset,
+             STRING_TOKEN (STR_RES_NEXT),         // Prompt,
+             STRING_TOKEN (STR_RES_NEXT_HELP),    // Help,
+             0,                                   // QuestionFlags,
+             EFI_IFR_NUMERIC_SIZE_4,              // see sizeof
+                                                  //   NextPreferredResolution,
+             OpCodeBuffer2,                       // buffer with possible
+                                                  //   choices,
+             NULL                                 // DEFAULT opcodes
+             );
+  if (OpCode == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto FreeOpCodeBuffer2;
+  }
+
+  //
+  // 4. Update the form with the opcode buffer.
+  //
+  Status = HiiUpdateForm (PackageList, FormSetGuid, FormId,
+             OpCodeBuffer, // buffer with head anchor, and new contents to be
+                           // inserted at it
+             NULL          // buffer with tail anchor, for deleting old
+                           // contents up to it
+             );
+
+FreeOpCodeBuffer2:
+  HiiFreeOpCodeHandle (OpCodeBuffer2);
+
+FreeOpCodeBuffer:
+  HiiFreeOpCodeHandle (OpCodeBuffer);
+
+  return Status;
+}
+
+
+/**
+  Load and execute the platform configuration.
+
+  @retval EFI_SUCCESS            Configuration loaded and executed.
+  @return                        Status codes from PlatformConfigLoad().
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ExecutePlatformConfig (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  PLATFORM_CONFIG PlatformConfig;
+  UINT64          OptionalElements;
+
+  Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
+  if (EFI_ERROR (Status)) {
+    DEBUG (((Status == EFI_NOT_FOUND) ? EFI_D_VERBOSE : EFI_D_ERROR,
+      "%a: failed to load platform config: %r\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
+    //
+    // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.
+    //
+    PcdSet32 (PcdVideoHorizontalResolution,
+      PlatformConfig.HorizontalResolution);
+    PcdSet32 (PcdVideoVerticalResolution,
+      PlatformConfig.VerticalResolution);
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Notification callback for GOP interface installation.
+
+  @param[in] Event    Event whose notification function is being invoked.
+
+  @param[in] Context  The pointer to the notification function's context, which
+                      is implementation-dependent.
+**/
+STATIC
+VOID
+EFIAPI
+GopInstalled (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
+
+  ASSERT (Event == mGopEvent);
+
+  //
+  // Check further GOPs.
+  //
+  for (;;) {
+    mNumGopModes = 0;
+    mGopModes = NULL;
+
+    Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, mGopTracker,
+                    (VOID **) &Gop);
+    if (EFI_ERROR (Status)) {
+      return;
+    }
+
+    Status = QueryGopModes (Gop, &mNumGopModes, &mGopModes);
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    Status = PopulateForm (mInstalledPackages, &gSimicsBoardConfigGuid,
+               FORMID_MAIN_FORM, mNumGopModes, mGopModes);
+    if (EFI_ERROR (Status)) {
+      FreePool (mGopModes);
+      continue;
+    }
+
+    break;
+  }
+
+  //
+  // Success -- so uninstall this callback. Closing the event removes all
+  // pending notifications and all protocol registrations.
+  //
+  Status = gBS->CloseEvent (mGopEvent);
+  ASSERT_EFI_ERROR (Status);
+  mGopEvent = NULL;
+  mGopTracker = NULL;
+}
+
+
+/**
+  Entry point for this driver.
+
+  @param[in] ImageHandle  Image handle of this driver.
+  @param[in] SystemTable  Pointer to SystemTable.
+
+  @retval EFI_SUCESS            Driver has loaded successfully.
+  @retval EFI_OUT_OF_RESOURCES  Failed to install HII packages.
+  @return                       Error codes from lower level functions.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformInit (
+  IN  EFI_HANDLE        ImageHandle,
+  IN  EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  ExecutePlatformConfig ();
+
+  mConfigAccess.ExtractConfig = &ExtractConfig;
+  mConfigAccess.RouteConfig   = &RouteConfig;
+  mConfigAccess.Callback      = &Callback;
+
+  //
+  // Declare ourselves suitable for HII communication.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
+                  &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,
+                  &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
+                  NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Publish the HII package list to HII Database.
+  //
+  mInstalledPackages = HiiAddPackages (
+                         &gEfiCallerIdGuid,  // PackageListGuid
+                         ImageHandle,        // associated DeviceHandle
+                         SimicsDxeStrings,   // 1st package
+                         PlatformFormsBin,   // 2nd package
+                         NULL                // terminator
+                         );
+  if (mInstalledPackages == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto UninstallProtocols;
+  }
+
+  Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, &GopInstalled,
+                  NULL /* Context */, &mGopEvent);
+  if (EFI_ERROR (Status)) {
+    goto RemovePackages;
+  }
+
+  Status = gBS->RegisterProtocolNotify (&gEfiGraphicsOutputProtocolGuid,
+                  mGopEvent, &mGopTracker);
+  if (EFI_ERROR (Status)) {
+    goto CloseGopEvent;
+  }
+
+  //
+  // Check already installed GOPs.
+  //
+  Status = gBS->SignalEvent (mGopEvent);
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+
+CloseGopEvent:
+  gBS->CloseEvent (mGopEvent);
+
+RemovePackages:
+  HiiRemovePackages (mInstalledPackages);
+
+UninstallProtocols:
+  gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
+         &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,
+         &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
+         NULL);
+  return Status;
+}
+
+/**
+  Unload the driver.
+
+  @param[in]  ImageHandle  Handle that identifies the image to evict.
+
+  @retval EFI_SUCCESS  The image has been unloaded.
+**/
+EFI_STATUS
+EFIAPI
+PlatformUnload (
+  IN  EFI_HANDLE  ImageHandle
+  )
+{
+  if (mGopEvent == NULL) {
+    //
+    // The GOP callback ran successfully and unregistered itself. Release the
+    // resources allocated there.
+    //
+    ASSERT (mGopModes != NULL);
+    FreePool (mGopModes);
+  } else {
+    //
+    // Otherwise we need to unregister the callback.
+    //
+    ASSERT (mGopModes == NULL);
+    gBS->CloseEvent (mGopEvent);
+  }
+
+  //
+  // Release resources allocated by the entry point.
+  //
+  HiiRemovePackages (mInstalledPackages);
+  gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
+         &gEfiDevicePathProtocolGuid,      &mPkgDevicePath,
+         &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
+         NULL);
+  return EFI_SUCCESS;
+}

+ 38 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/Platform.h

@@ -0,0 +1,38 @@
+/** @file
+  This driver effectuates QSP platform configuration settings and exposes
+  them via HII.
+
+  Copyright (C) 2014, Red Hat, Inc.
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PLATFORM_H_
+#define _PLATFORM_H_
+
+//
+// Macro and type definitions that connect the form with the HII driver code.
+//
+#define FORMSTATEID_MAIN_FORM  1
+#define FORMID_MAIN_FORM       1
+
+#define QUESTION_RES_CUR       1
+#define MAXSIZE_RES_CUR       16
+
+#define LABEL_RES_NEXT         1
+#define QUESTION_RES_NEXT      2
+
+#define QUESTION_SAVE_EXIT     3
+#define QUESTION_DISCARD_EXIT  4
+
+//
+// This structure describes the form state. Its fields relate strictly to the
+// visual widgets on the form.
+//
+typedef struct {
+  UINT16 CurrentPreferredResolution[MAXSIZE_RES_CUR];
+  UINT32 NextPreferredResolution;
+} MAIN_FORM_STATE;
+
+#endif // _PLATFORM_H_

+ 31 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/Platform.uni

@@ -0,0 +1,31 @@
+// *++
+//
+// Copyright (C) 2014, Red Hat, Inc.
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+//   Platform.uni
+//
+// Abstract:
+//
+//   String definitions for PlatformForms.vfr
+//
+// --*/
+
+/=#
+
+#langdef en-US "English"
+
+#string STR_FORMSET_TITLE        #language en-US "QSP Platform Configuration"
+#string STR_FORMSET_HELP         #language en-US "Change various QSP platform settings."
+#string STR_MAIN_FORM_TITLE      #language en-US "QSP Settings"
+#string STR_RES_CUR              #language en-US "Preferred Resolution at Next Boot"
+#string STR_RES_CUR_HELP         #language en-US "The preferred resolution of the Graphics Console at next boot. It might be unset, or even invalid (hence ignored) wrt. the video RAM size."
+#string STR_RES_NEXT             #language en-US "Change Preferred Resolution for Next Boot"
+#string STR_RES_NEXT_HELP        #language en-US "You can specify a new preference for the Graphics Console here. The list is filtered against the video RAM size."
+#string STR_SAVE_EXIT            #language en-US "Commit Changes and Exit"
+#string STR_DISCARD_EXIT         #language en-US "Discard Changes and Exit"
+

+ 124 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/PlatformConfig.c

@@ -0,0 +1,124 @@
+/** @file
+  Utility functions for serializing (persistently storing) and deserializing
+  SIMICS QSP's platform configuration.
+
+  Copyright (C) 2014, Red Hat, Inc.
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Guid/SimicsBoardConfig.h>
+
+#include "PlatformConfig.h"
+
+//
+// Name of the UEFI variable that we use for persistent storage.
+//
+STATIC CHAR16 mVariableName[] = L"PlatformConfig";
+
+
+/**
+  Serialize and persistently save platform configuration.
+
+  @param[in] PlatformConfig  The platform configuration to serialize and save.
+
+  @return  Status codes returned by gRT->SetVariable().
+**/
+EFI_STATUS
+EFIAPI
+PlatformConfigSave (
+  IN PLATFORM_CONFIG *PlatformConfig
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // We could implement any kind of translation here, as part of serialization.
+  // For example, we could expose the platform configuration in separate
+  // variables with human-readable contents, allowing other tools to access
+  // them more easily. For now, just save a binary dump.
+  //
+  Status = gRT->SetVariable (mVariableName, &gSimicsBoardConfigGuid,
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                    EFI_VARIABLE_RUNTIME_ACCESS,
+                  sizeof *PlatformConfig, PlatformConfig);
+  return Status;
+}
+
+
+/**
+  Load and deserialize platform configuration.
+
+  When the function fails, output parameters are indeterminate.
+
+  @param[out] PlatformConfig    The platform configuration to receive the
+                                loaded data.
+
+  @param[out] OptionalElements  This bitmap describes the presence of optional
+                                configuration elements that have been loaded.
+                                PLATFORM_CONFIG_F_DOWNGRADE means that some
+                                unknown elements, present in the wire format,
+                                have been ignored.
+
+  @retval  EFI_SUCCESS         Loading & deserialization successful.
+  @return                      Error codes returned by GetVariable2().
+**/
+EFI_STATUS
+EFIAPI
+PlatformConfigLoad (
+  OUT PLATFORM_CONFIG *PlatformConfig,
+  OUT UINT64          *OptionalElements
+  )
+{
+  VOID       *Data;
+  UINTN      DataSize;
+  EFI_STATUS Status;
+
+  //
+  // Any translation done in PlatformConfigSave() would have to be mirrored
+  // here. For now, just load the binary dump.
+  //
+  // Versioning of the binary wire format is implemented based on size
+  // (only incremental changes, ie. new fields), and on GUID.
+  // (Incompatible changes require a GUID change.)
+  //
+  Status = GetVariable2 (mVariableName, &gSimicsBoardConfigGuid, &Data,
+             &DataSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  *OptionalElements = 0;
+  if (DataSize > sizeof *PlatformConfig) {
+    //
+    // Handle firmware downgrade -- keep only leading part.
+    //
+    CopyMem (PlatformConfig, Data, sizeof *PlatformConfig);
+    *OptionalElements |= PLATFORM_CONFIG_F_DOWNGRADE;
+  } else {
+    CopyMem (PlatformConfig, Data, DataSize);
+
+    //
+    // Handle firmware upgrade -- zero out missing fields.
+    //
+    ZeroMem ((UINT8 *)PlatformConfig + DataSize,
+      sizeof *PlatformConfig - DataSize);
+  }
+
+  //
+  // Based on DataSize, report the optional features that we recognize.
+  //
+  if (DataSize >= (OFFSET_OF (PLATFORM_CONFIG, VerticalResolution) +
+                   sizeof PlatformConfig->VerticalResolution)) {
+    *OptionalElements |= PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION;
+  }
+
+  FreePool (Data);
+  return EFI_SUCCESS;
+}

+ 52 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/PlatformConfig.h

@@ -0,0 +1,52 @@
+/** @file
+  Utility functions for serializing (persistently storing) and deserializing
+  Simics's platform configuration.
+
+  Copyright (C) 2014, Red Hat, Inc.
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PLATFORM_CONFIG_H_
+#define _PLATFORM_CONFIG_H_
+
+#include <Base.h>
+
+//
+// This structure participates in driver configuration. It does not
+// (necessarily) reflect the wire format in the persistent store.
+//
+#pragma pack(1)
+typedef struct {
+  //
+  // preferred graphics console resolution when booting
+  //
+  UINT32 HorizontalResolution;
+  UINT32 VerticalResolution;
+} PLATFORM_CONFIG;
+#pragma pack()
+
+//
+// Please see the API documentation near the function definitions.
+//
+EFI_STATUS
+EFIAPI
+PlatformConfigSave (
+  IN PLATFORM_CONFIG *PlatformConfig
+  );
+
+EFI_STATUS
+EFIAPI
+PlatformConfigLoad (
+  OUT PLATFORM_CONFIG *PlatformConfig,
+  OUT UINT64          *OptionalElements
+  );
+
+//
+// Feature flags for OptionalElements.
+//
+#define PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION BIT0
+#define PLATFORM_CONFIG_F_DOWNGRADE           BIT63
+
+#endif // _PLATFORM_CONFIG_H_

+ 67 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/PlatformForms.vfr

@@ -0,0 +1,67 @@
+// *++
+//
+// Copyright (C) 2014, Red Hat, Inc.
+// Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// Module Name:
+//
+//   PlatformForms.vfr
+//
+// Abstract:
+//
+//   Form definitions for exposing some of OVMF's platform knobs via HII.
+//
+// --*/
+
+#include <Guid/SimicsBoardConfig.h>
+#include "Platform.h"
+
+formset
+  guid  = SIMICS_BOARD_CONFIG_GUID,
+  title = STRING_TOKEN(STR_FORMSET_TITLE),
+  help  = STRING_TOKEN(STR_FORMSET_HELP),
+
+  varstore MAIN_FORM_STATE,
+    varid = FORMSTATEID_MAIN_FORM,
+    name  = MainFormState,
+    guid  = SIMICS_BOARD_CONFIG_GUID;
+
+  form
+    formid = FORMID_MAIN_FORM,
+    title  = STRING_TOKEN(STR_MAIN_FORM_TITLE);
+
+    //
+    // Display the current preference in a read-only string field.
+    //
+    string
+      varid      = MainFormState.CurrentPreferredResolution,
+      questionid = QUESTION_RES_CUR,
+      prompt     = STRING_TOKEN(STR_RES_CUR),
+      help       = STRING_TOKEN(STR_RES_CUR_HELP),
+      flags      = READ_ONLY,
+      minsize    = 0,
+      maxsize    = MAXSIZE_RES_CUR,
+    endstring;
+
+    //
+    // We'll dynamically generate a one-of-many selection at this label.
+    //
+    label LABEL_RES_NEXT;
+
+    text
+      help  = STRING_TOKEN(STR_SAVE_EXIT),
+      text  = STRING_TOKEN(STR_SAVE_EXIT),
+      flags = INTERACTIVE,
+      key   = QUESTION_SAVE_EXIT;
+
+    text
+      help  = STRING_TOKEN(STR_DISCARD_EXIT),
+      text  = STRING_TOKEN(STR_DISCARD_EXIT),
+      flags = INTERACTIVE,
+      key   = QUESTION_DISCARD_EXIT;
+
+  endform;
+
+endformset;

+ 65 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsDxe/SimicsDxe.inf

@@ -0,0 +1,65 @@
+## @file
+#  This driver effectuates Simics X58 platform configuration settings and exposes
+#  them via HII.
+#
+#  Copyright (C) 2014, Red Hat, Inc.
+#  Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SimicsDxe
+  FILE_GUID                      = 74B64DC1-B0B6-4853-A6BD-C6426059AB1E
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PlatformInit
+  UNLOAD_IMAGE                   = PlatformUnload
+
+[Sources]
+  Platform.c
+  Platform.uni
+  PlatformConfig.c
+  PlatformForms.vfr
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+  MinPlatformPkg/MinPlatformPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DevicePathLib
+  HiiLib
+  MemoryAllocationLib
+  PrintLib
+  UefiBootServicesTableLib
+  UefiHiiServicesLib
+  UefiLib
+  UefiRuntimeServicesTableLib
+  UefiDriverEntryPoint
+  DxeServicesTableLib
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution
+
+[Protocols]
+  gEfiDevicePathProtocolGuid      ## PRODUCES
+  gEfiGraphicsOutputProtocolGuid  ## CONSUMES
+  gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+
+[Guids]
+  gEfiIfrTianoGuid
+  gSimicsBoardConfigGuid
+
+[Depex]
+  gEfiHiiConfigRoutingProtocolGuid  AND
+  gEfiHiiDatabaseProtocolGuid       AND
+  gEfiVariableArchProtocolGuid      AND
+  gEfiVariableWriteArchProtocolGuid

+ 57 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsPei/Cmos.c

@@ -0,0 +1,57 @@
+/** @file
+  PC/AT CMOS access routines
+
+  Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Cmos.h"
+#include "Library/IoLib.h"
+
+/**
+  Reads 8-bits of CMOS data.
+
+  Reads the 8-bits of CMOS data at the location specified by Index.
+  The 8-bit read value is returned.
+
+  @param  Index  The CMOS location to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+CmosRead8 (
+  IN      UINTN                     Index
+  )
+{
+  IoWrite8 (0x70, (UINT8) Index);
+  return IoRead8 (0x71);
+}
+
+
+/**
+  Writes 8-bits of CMOS data.
+
+  Writes 8-bits of CMOS data to the location specified by Index
+  with the value specified by Value and returns Value.
+
+  @param  Index  The CMOS location to write.
+  @param  Value  The value to write to CMOS.
+
+  @return The value written to CMOS.
+
+**/
+UINT8
+EFIAPI
+CmosWrite8 (
+  IN      UINTN                     Index,
+  IN      UINT8                     Value
+  )
+{
+  IoWrite8 (0x70, (UINT8) Index);
+  IoWrite8 (0x71, Value);
+  return Value;
+}
+

+ 50 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsPei/Cmos.h

@@ -0,0 +1,50 @@
+/** @file
+  PC/AT CMOS access routines
+
+  Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __CMOS_H__
+#define __CMOS_H__
+
+/**
+  Reads 8-bits of CMOS data.
+
+  Reads the 8-bits of CMOS data at the location specified by Index.
+  The 8-bit read value is returned.
+
+  @param  Index  The CMOS location to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+CmosRead8 (
+  IN      UINTN                     Index
+  );
+
+/**
+  Writes 8-bits of CMOS data.
+
+  Writes 8-bits of CMOS data to the location specified by Index
+  with the value specified by Value and returns Value.
+
+  @param  Index  The CMOS location to write.
+  @param  Value  The value to write to CMOS.
+
+  @return The value written to CMOS.
+
+**/
+UINT8
+EFIAPI
+CmosWrite8 (
+  IN      UINTN                     Index,
+  IN      UINT8                     Value
+  );
+
+
+#endif
+

+ 115 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsPei/FeatureControl.c

@@ -0,0 +1,115 @@
+/** @file
+  Install a callback when necessary for setting the Feature Control MSR on all
+  processors.
+
+  Copyright (C) 2016, Red Hat, Inc.
+  Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Ppi/MpServices.h>
+#include <Register/Intel/Msr/Core2Msr.h>
+
+#include "Platform.h"
+
+//
+// The value to be written to the Feature Control MSR, retrieved from fw_cfg.
+//
+STATIC UINT64 mFeatureControlValue = 0x00000005;
+
+/**
+  Write the Feature Control MSR on an Application Processor or the Boot
+  Processor.
+
+  All APs execute this function in parallel. The BSP executes the function
+  separately.
+
+  @param[in,out] WorkSpace  Pointer to the input/output argument workspace
+                            shared by all processors.
+**/
+STATIC
+VOID
+EFIAPI
+WriteFeatureControl (
+  IN OUT VOID *WorkSpace
+  )
+{
+  AsmWriteMsr64 (MSR_CORE2_FEATURE_CONTROL, mFeatureControlValue);
+}
+
+/**
+  Notification function called when EFI_PEI_MP_SERVICES_PPI becomes available.
+
+  @param[in] PeiServices      Indirect reference to the PEI Services Table.
+  @param[in] NotifyDescriptor Address of the notification descriptor data
+                              structure.
+  @param[in] Ppi              Address of the PPI that was installed.
+
+  @return  Status of the notification. The status code returned from this
+           function is ignored.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+OnMpServicesAvailable (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN VOID                       *Ppi
+  )
+{
+  EFI_PEI_MP_SERVICES_PPI *MpServices;
+  EFI_STATUS              Status;
+
+  DEBUG ((EFI_D_VERBOSE, "%a: %a\n", gEfiCallerBaseName, __FUNCTION__));
+  //
+  // Write the MSR on all the APs in parallel.
+  //
+  MpServices = Ppi;
+  Status = MpServices->StartupAllAPs (
+                         (CONST EFI_PEI_SERVICES **)PeiServices,
+                         MpServices,
+                         WriteFeatureControl, // Procedure
+                         FALSE,               // SingleThread
+                         0,                   // TimeoutInMicroSeconds: inf.
+                         NULL                 // ProcedureArgument
+                         );
+  if (EFI_ERROR (Status) && Status != EFI_NOT_STARTED) {
+    DEBUG ((EFI_D_ERROR, "%a: StartupAllAps(): %r\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  //
+  // Now write the MSR on the BSP too.
+  //
+  WriteFeatureControl (NULL);
+
+  return EFI_SUCCESS;
+}
+
+//
+// Notification object for registering the callback, for when
+// EFI_PEI_MP_SERVICES_PPI becomes available.
+//
+STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mMpServicesNotify = {
+  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | // Flags
+  EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+  &gEfiPeiMpServicesPpiGuid,               // Guid
+  OnMpServicesAvailable                    // Notify
+};
+
+VOID
+InstallFeatureControlCallback (
+  VOID
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = PeiServicesNotifyPpi (&mMpServicesNotify);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "%a: failed to set up MP Services callback: %r\n",
+      __FUNCTION__, Status));
+  }
+}

+ 568 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsPei/MemDetect.c

@@ -0,0 +1,568 @@
+/** @file
+  Memory Detection for Virtual Machines.
+
+  Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Library/MtrrLib.h>
+#include <SimicsPlatforms.h>
+#include <Guid/SmramMemoryReserve.h>
+
+#include "Platform.h"
+#include "Cmos.h"
+
+UINT8 mPhysMemAddressWidth;
+
+STATIC UINT32 mS3AcpiReservedMemoryBase;
+STATIC UINT32 mS3AcpiReservedMemorySize;
+
+STATIC UINT16 mX58TsegMbytes;
+
+VOID
+X58TsegMbytesInitialization(
+  VOID
+)
+{
+
+  if (mHostBridgeDevId != INTEL_ICH10_DEVICE_ID) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "
+      "only DID=0x%04x (X58) is supported\n",
+      __FUNCTION__,
+      mHostBridgeDevId,
+      INTEL_ICH10_DEVICE_ID
+      ));
+    ASSERT (FALSE);
+    CpuDeadLoop ();
+  }
+
+  //
+  // Check if QEMU offers an extended TSEG.
+  //
+  // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB
+  // register, and reading back the register.
+  //
+  // On a QEMU machine type that does not offer an extended TSEG, the initial
+  // write overwrites whatever value a malicious guest OS may have placed in
+  // the (unimplemented) register, before entering S3 or rebooting.
+  // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.
+  //
+  // On a QEMU machine type that offers an extended TSEG, the initial write
+  // triggers an update to the register. Subsequently, the value read back
+  // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the
+  // number of megabytes.
+  //
+  mX58TsegMbytes = FixedPcdGet8(PcdX58TsegMbytes);
+  return;
+}
+
+
+UINT32
+GetSystemMemorySizeBelow4gb (
+  VOID
+  )
+{
+  UINT8 Cmos0x34;
+  UINT8 Cmos0x35;
+
+  //
+  // CMOS 0x34/0x35 specifies the system memory above 16 MB.
+  // * CMOS(0x35) is the high byte
+  // * CMOS(0x34) is the low byte
+  // * The size is specified in 64kb chunks
+  // * Since this is memory above 16MB, the 16MB must be added
+  //   into the calculation to get the total memory size.
+  //
+
+  Cmos0x34 = (UINT8) CmosRead8 (0x34);
+  Cmos0x35 = (UINT8) CmosRead8 (0x35);
+
+  return (UINT32) (((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
+}
+
+
+STATIC
+UINT64
+GetSystemMemorySizeAbove4gb (
+  )
+{
+  UINT32 Size;
+  UINTN  CmosIndex;
+
+  //
+  // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
+  // * CMOS(0x5d) is the most significant size byte
+  // * CMOS(0x5c) is the middle size byte
+  // * CMOS(0x5b) is the least significant size byte
+  // * The size is specified in 64kb chunks
+  //
+
+  Size = 0;
+  for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
+    Size = (UINT32) (Size << 8) + (UINT32) CmosRead8 (CmosIndex);
+  }
+
+  return LShiftU64 (Size, 16);
+}
+
+
+/**
+  Return the highest address that DXE could possibly use, plus one.
+**/
+STATIC
+UINT64
+GetFirstNonAddress (
+  VOID
+  )
+{
+  UINT64               FirstNonAddress;
+  UINT64               Pci64Base, Pci64Size;
+
+  FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
+
+  //
+  // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
+  // resources to 32-bit anyway. See DegradeResource() in
+  // "PciResourceSupport.c".
+  //
+#ifdef MDE_CPU_IA32
+  if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+    return FirstNonAddress;
+  }
+#endif
+
+  //
+  // Otherwise, in order to calculate the highest address plus one, we must
+  // consider the 64-bit PCI host aperture too. Fetch the default size.
+  //
+  Pci64Size = PcdGet64 (PcdPciMmio64Size);
+
+  if (Pci64Size == 0) {
+    if (mBootMode != BOOT_ON_S3_RESUME) {
+      DEBUG ((EFI_D_INFO, "%a: disabling 64-bit PCI host aperture\n",
+        __FUNCTION__));
+      PcdSet64 (PcdPciMmio64Size, 0);
+    }
+
+    //
+    // There's nothing more to do; the amount of memory above 4GB fully
+    // determines the highest address plus one. The memory hotplug area (see
+    // below) plays no role for the firmware in this case.
+    //
+    return FirstNonAddress;
+  }
+
+  //
+  // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
+  // that the host can map it with 1GB hugepages. Follow suit.
+  //
+  Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
+  Pci64Size = ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);
+
+  //
+  // The 64-bit PCI host aperture should also be "naturally" aligned. The
+  // alignment is determined by rounding the size of the aperture down to the
+  // next smaller or equal power of two. That is, align the aperture by the
+  // largest BAR size that can fit into it.
+  //
+  Pci64Base = ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));
+
+  if (mBootMode != BOOT_ON_S3_RESUME) {
+    //
+    // The core PciHostBridgeDxe driver will automatically add this range to
+    // the GCD memory space map through our PciHostBridgeLib instance; here we
+    // only need to set the PCDs.
+    //
+    PcdSet64 (PcdPciMmio64Base, Pci64Base);
+    PcdSet64 (PcdPciMmio64Size, Pci64Size);
+    DEBUG ((EFI_D_INFO, "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
+      __FUNCTION__, Pci64Base, Pci64Size));
+  }
+
+  //
+  // The useful address space ends with the 64-bit PCI host aperture.
+  //
+  FirstNonAddress = Pci64Base + Pci64Size;
+  return FirstNonAddress;
+}
+
+
+/**
+  Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
+**/
+VOID
+AddressWidthInitialization (
+  VOID
+  )
+{
+  UINT64 FirstNonAddress;
+
+  //
+  // As guest-physical memory size grows, the permanent PEI RAM requirements
+  // are dominated by the identity-mapping page tables built by the DXE IPL.
+  // The DXL IPL keys off of the physical address bits advertized in the CPU
+  // HOB. To conserve memory, we calculate the minimum address width here.
+  //
+  FirstNonAddress      = GetFirstNonAddress ();
+  mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
+
+  //
+  // If FirstNonAddress is not an integral power of two, then we need an
+  // additional bit.
+  //
+  if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
+    ++mPhysMemAddressWidth;
+  }
+
+  //
+  // The minimum address width is 36 (covers up to and excluding 64 GB, which
+  // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
+  // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
+  // can simply assert that here, since 48 bits are good enough for 256 TB.
+  //
+  if (mPhysMemAddressWidth <= 36) {
+    mPhysMemAddressWidth = 36;
+  }
+  ASSERT (mPhysMemAddressWidth <= 48);
+}
+
+
+/**
+  Calculate the cap for the permanent PEI memory.
+**/
+STATIC
+UINT32
+GetPeiMemoryCap (
+  VOID
+  )
+{
+  BOOLEAN Page1GSupport;
+  UINT32  RegEax;
+  UINT32  RegEdx;
+  UINT32  Pml4Entries;
+  UINT32  PdpEntries;
+  UINTN   TotalPages;
+
+  //
+  // If DXE is 32-bit, then just return the traditional 64 MB cap.
+  //
+#ifdef MDE_CPU_IA32
+  if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+    return SIZE_64MB;
+  }
+#endif
+
+  //
+  // Dependent on physical address width, PEI memory allocations can be
+  // dominated by the page tables built for 64-bit DXE. So we key the cap off
+  // of those. The code below is based on CreateIdentityMappingPageTables() in
+  // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".
+  //
+  Page1GSupport = FALSE;
+  if (PcdGetBool (PcdUse1GPageTable)) {
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+    if (RegEax >= 0x80000001) {
+      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+      if ((RegEdx & BIT26) != 0) {
+        Page1GSupport = TRUE;
+      }
+    }
+  }
+
+  if (mPhysMemAddressWidth <= 39) {
+    Pml4Entries = 1;
+    PdpEntries = 1 << (mPhysMemAddressWidth - 30);
+    ASSERT (PdpEntries <= 0x200);
+  } else {
+    Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
+    ASSERT (Pml4Entries <= 0x200);
+    PdpEntries = 512;
+  }
+
+  TotalPages = Page1GSupport ? Pml4Entries + 1 :
+                               (PdpEntries + 1) * Pml4Entries + 1;
+  ASSERT (TotalPages <= 0x40201);
+
+  //
+  // Add 64 MB for miscellaneous allocations. Note that for
+  // mPhysMemAddressWidth values close to 36, the cap will actually be
+  // dominated by this increment.
+  //
+  return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);
+}
+
+
+/**
+  Publish PEI core memory
+
+  @return EFI_SUCCESS     The PEIM initialized successfully.
+
+**/
+EFI_STATUS
+PublishPeiMemory (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_PHYSICAL_ADDRESS        MemoryBase;
+  UINT64                      MemorySize;
+  UINT32                      LowerMemorySize;
+  UINT32                      PeiMemoryCap;
+
+  LowerMemorySize = GetSystemMemorySizeBelow4gb ();
+  if (FeaturePcdGet (PcdSmmSmramRequire)) {
+    //
+    // TSEG is chipped from the end of low RAM
+    //
+    LowerMemorySize -= mX58TsegMbytes * SIZE_1MB;
+  }
+
+  //
+  // If S3 is supported, then the S3 permanent PEI memory is placed next,
+  // downwards. Its size is primarily dictated by CpuMpPei. The formula below
+  // is an approximation.
+  //
+  if (mS3Supported) {
+    mS3AcpiReservedMemorySize = SIZE_512KB +
+      mMaxCpuCount *
+      PcdGet32 (PcdCpuApStackSize);
+    mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize;
+    LowerMemorySize = mS3AcpiReservedMemoryBase;
+  }
+
+  if (mBootMode == BOOT_ON_S3_RESUME) {
+    MemoryBase = mS3AcpiReservedMemoryBase;
+    MemorySize = mS3AcpiReservedMemorySize;
+  } else {
+    PeiMemoryCap = GetPeiMemoryCap ();
+    DEBUG ((EFI_D_INFO, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
+      __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));
+
+    //
+    // Determine the range of memory to use during PEI
+    //
+    // Technically we could lay the permanent PEI RAM over SEC's temporary
+    // decompression and scratch buffer even if "secure S3" is needed, since
+    // their lifetimes don't overlap. However, PeiFvInitialization() will cover
+    // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory
+    // allocation HOB, and other allocations served from the permanent PEI RAM
+    // shouldn't overlap with that HOB.
+    //
+    MemoryBase = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire) ?
+      PcdGet32 (PcdSimicsDecompressionScratchEnd) :
+      PcdGet32 (PcdSimicsDxeMemFvBase) + PcdGet32 (PcdSimicsDxeMemFvSize);
+    MemorySize = LowerMemorySize - MemoryBase;
+  }
+  DEBUG((EFI_D_INFO, "MemoryBase=0x%lx MemorySize=0x%lx\n", MemoryBase, MemorySize));
+  //
+  // Publish this memory to the PEI Core
+  //
+  Status = PublishSystemMemory(MemoryBase, MemorySize);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+
+/**
+  Peform Memory Detection for QEMU / KVM
+
+**/
+STATIC
+VOID
+QemuInitializeRam (
+  VOID
+  )
+{
+  UINT64                               LowerMemorySize;
+  UINT64                               UpperMemorySize;
+  UINTN                                 BufferSize;
+  UINT8                                 SmramIndex;
+  UINT8                                 SmramRanges;
+  EFI_PEI_HOB_POINTERS                  Hob;
+  EFI_SMRAM_HOB_DESCRIPTOR_BLOCK        *SmramHobDescriptorBlock;
+  UINT8                                 Index;
+
+  DEBUG ((EFI_D_INFO, "%a called\n", __FUNCTION__));
+
+  //
+  // Determine total memory size available
+  //
+  LowerMemorySize = GetSystemMemorySizeBelow4gb ();
+  UpperMemorySize = GetSystemMemorySizeAbove4gb ();
+
+  if (mBootMode == BOOT_ON_S3_RESUME) {
+    //
+    // Create the following memory HOB as an exception on the S3 boot path.
+    //
+    // Normally we'd create memory HOBs only on the normal boot path. However,
+    // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
+    // well, for "borrowing" a subset of it temporarily, for the AP startup
+    // vector.
+    //
+    // CpuMpPei saves the original contents of the borrowed area in permanent
+    // PEI RAM, in a backup buffer allocated with the normal PEI services.
+    // CpuMpPei restores the original contents ("returns" the borrowed area) at
+    // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
+    // transferring control to the OS's wakeup vector in the FACS.
+    //
+    // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
+    // restore the original contents. Furthermore, we expect all such PEIMs
+    // (CpuMpPei included) to claim the borrowed areas by producing memory
+    // allocation HOBs, and to honor preexistent memory allocation HOBs when
+    // looking for an area to borrow.
+    //
+    AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
+  } else {
+    //
+    // Create memory HOBs
+    //
+    AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
+
+    if (FeaturePcdGet (PcdSmmSmramRequire)) {
+      UINT32 TsegSize;
+
+      TsegSize = mX58TsegMbytes * SIZE_1MB;
+      AddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
+      AddReservedMemoryBaseSizeHob (LowerMemorySize - TsegSize, TsegSize,
+        TRUE);
+
+	  BufferSize = sizeof(EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);
+	  SmramRanges = 1;
+
+      Hob.Raw = BuildGuidHob(
+          &gEfiSmmPeiSmramMemoryReserveGuid,
+          BufferSize
+      );
+      ASSERT(Hob.Raw);
+
+      SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)(Hob.Raw);
+      SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;
+
+      SmramIndex = 0;
+      for (Index = 0; Index < SmramRanges; Index++) {
+        //
+        // This is an SMRAM range, create an SMRAM descriptor
+        //
+        SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = LowerMemorySize - TsegSize;
+        SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart = LowerMemorySize - TsegSize;
+        SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = TsegSize;
+        SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;
+        SmramIndex++;
+      }
+
+    } else {
+      AddMemoryRangeHob (BASE_1MB, LowerMemorySize);
+    }
+
+    //
+    // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM
+    // entries. Otherwise, create a single memory HOB with the flat >=4GB
+    // memory size read from the CMOS.
+    //
+    if (UpperMemorySize != 0) {
+      AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
+    }
+  }
+}
+
+/**
+  Publish system RAM and reserve memory regions
+
+**/
+VOID
+InitializeRamRegions (
+  VOID
+  )
+{
+  QemuInitializeRam ();
+
+  if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {
+    //
+    // This is the memory range that will be used for PEI on S3 resume
+    //
+    BuildMemoryAllocationHob (
+      mS3AcpiReservedMemoryBase,
+      mS3AcpiReservedMemorySize,
+      EfiACPIMemoryNVS
+      );
+
+    //
+    // Cover the initial RAM area used as stack and temporary PEI heap.
+    //
+    // This is reserved as ACPI NVS so it can be used on S3 resume.
+    //
+    BuildMemoryAllocationHob (
+      PcdGet32 (PcdSimicsSecPeiTempRamBase),
+      PcdGet32 (PcdSimicsSecPeiTempRamSize),
+      EfiACPIMemoryNVS
+      );
+
+    //
+    // SEC stores its table of GUIDed section handlers here.
+    //
+    BuildMemoryAllocationHob (
+      PcdGet64 (PcdGuidedExtractHandlerTableAddress),
+      PcdGet32 (PcdGuidedExtractHandlerTableSize),
+      EfiACPIMemoryNVS
+      );
+
+  }
+
+  if (mBootMode != BOOT_ON_S3_RESUME) {
+    if (!FeaturePcdGet (PcdSmmSmramRequire)) {
+      //
+      // Reserve the lock box storage area
+      //
+      // Since this memory range will be used on S3 resume, it must be
+      // reserved as ACPI NVS.
+      //
+      // If S3 is unsupported, then various drivers might still write to the
+      // LockBox area. We ought to prevent DXE from serving allocation requests
+      // such that they would overlap the LockBox storage.
+      //
+      ZeroMem (
+        (VOID*)(UINTN) PcdGet32 (PcdSimicsLockBoxStorageBase),
+        (UINTN) PcdGet32 (PcdSimicsLockBoxStorageSize)
+        );
+      BuildMemoryAllocationHob (
+        (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdSimicsLockBoxStorageBase),
+        (UINT64)(UINTN) PcdGet32 (PcdSimicsLockBoxStorageSize),
+        mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+        );
+    }
+
+    if (FeaturePcdGet (PcdSmmSmramRequire)) {
+      UINT32 TsegSize;
+
+      //
+      // Make sure the TSEG area that we reported as a reserved memory resource
+      // cannot be used for reserved memory allocations.
+      //
+      TsegSize = mX58TsegMbytes * SIZE_1MB;
+      BuildMemoryAllocationHob (
+        GetSystemMemorySizeBelow4gb() - TsegSize,
+        TsegSize,
+        EfiReservedMemoryType
+        );
+    }
+  }
+}

+ 630 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsPei/Platform.c

@@ -0,0 +1,630 @@
+/** @file
+  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Ppi/MasterBootMode.h>
+#include <IndustryStandard/Pci22.h>
+#include <SimicsPlatforms.h>
+
+#include "Platform.h"
+#include "Cmos.h"
+
+EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
+  { EfiACPIMemoryNVS,       0x004 },
+  { EfiACPIReclaimMemory,   0x008 },
+  { EfiReservedMemoryType,  0x004 },
+  { EfiRuntimeServicesData, 0x024 },
+  { EfiRuntimeServicesCode, 0x030 },
+  { EfiBootServicesCode,    0x180 },
+  { EfiBootServicesData,    0xF00 },
+  { EfiMaxMemoryType,       0x000 }
+};
+
+
+EFI_PEI_PPI_DESCRIPTOR   mPpiBootMode[] = {
+  {
+    EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+    &gEfiPeiMasterBootModePpiGuid,
+    NULL
+  }
+};
+
+
+UINT16 mHostBridgeDevId;
+
+EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
+
+BOOLEAN mS3Supported = FALSE;
+
+UINT32 mMaxCpuCount;
+
+VOID
+AddIoMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_MEMORY_MAPPED_IO,
+      EFI_RESOURCE_ATTRIBUTE_PRESENT     |
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_TESTED,
+    MemoryBase,
+    MemorySize
+    );
+}
+
+VOID
+AddReservedMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize,
+  BOOLEAN                     Cacheable
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_MEMORY_RESERVED,
+      EFI_RESOURCE_ATTRIBUTE_PRESENT     |
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+      (Cacheable ?
+       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
+       0
+       ) |
+      EFI_RESOURCE_ATTRIBUTE_TESTED,
+    MemoryBase,
+    MemorySize
+    );
+}
+
+VOID
+AddIoMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  )
+{
+  AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
+}
+
+
+VOID
+AddMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_SYSTEM_MEMORY,
+      EFI_RESOURCE_ATTRIBUTE_PRESENT |
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+      EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_TESTED,
+    MemoryBase,
+    MemorySize
+    );
+}
+
+
+VOID
+AddMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  )
+{
+  AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
+}
+
+
+VOID
+AddUntestedMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_SYSTEM_MEMORY,
+      EFI_RESOURCE_ATTRIBUTE_PRESENT |
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+      EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE,
+    MemoryBase,
+    MemorySize
+    );
+}
+
+
+VOID
+AddUntestedMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  )
+{
+  AddUntestedMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
+}
+
+VOID
+AddFlashDeviceRange (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_FIRMWARE_DEVICE,
+    (EFI_RESOURCE_ATTRIBUTE_PRESENT    |
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
+    MemoryBase,
+    MemorySize
+    );
+
+  BuildMemoryAllocationHob (
+    MemoryBase,
+    MemorySize,
+    EfiMemoryMappedIO
+    );
+}
+
+VOID
+MemMapInitialization (
+  VOID
+  )
+{
+  UINT64 PciIoBase;
+  UINT64 PciIoSize;
+
+  UINT32  TopOfLowRam;
+  UINT64  PciExBarBase;
+  UINT32  PciBase;
+  UINT32  PciSize;
+
+  PciIoBase = 0xC000;
+  PciIoSize = 0x4000;
+
+  //
+  // Create Memory Type Information HOB
+  //
+  BuildGuidDataHob (
+    &gEfiMemoryTypeInformationGuid,
+    mDefaultMemoryTypeInformation,
+    sizeof(mDefaultMemoryTypeInformation)
+    );
+
+  //
+  // Video memory + Legacy BIOS region
+  //
+  AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
+
+  TopOfLowRam = GetSystemMemorySizeBelow4gb ();
+  PciExBarBase = 0;
+  if (mHostBridgeDevId == INTEL_ICH10_DEVICE_ID) {
+    //
+    // The MMCONFIG area is expected to fall between the top of low RAM and
+    // the base of the 32-bit PCI host aperture.
+    //
+    PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
+    ASSERT (TopOfLowRam <= PciExBarBase);
+    ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
+    PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
+  } else {
+    PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;
+  }
+
+  //
+  // address       purpose   size
+  // ------------  --------  -------------------------
+  // 0x00000000    TopOfLowRam   0xDF000000
+  // 0xDF000000    Tseg+UMA      0x01000000
+  // 0xE0000000    PciExBarBase  0x10000000
+  // 0xF0000000    PciBase       0x0C000000
+  // -------------------------------------------------
+  // max(top, 2g)  PCI MMIO  0xFC000000 - max(top, 2g)
+  // 0xFC000000    gap                           44 MB
+  // 0xFEC00000    IO-APIC                        4 KB
+  // 0xFEC01000    gap                         1020 KB
+  // 0xFED00000    HPET                           1 KB
+  // 0xFED00400    gap                          111 KB
+  // 0xFED1C000    gap (PIIX4) / RCRB (ICH9)     16 KB
+  // 0xFED20000    gap                          896 KB
+  // 0xFEE00000    LAPIC                          1 MB
+  //
+  PciSize = 0xFC000000 - PciBase;
+  AddIoMemoryBaseSizeHob (PciBase, PciSize);
+  PcdSet64 (PcdPciMmio32Base, PciBase);
+  PcdSet64 (PcdPciMmio32Size, PciSize);
+  AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
+  AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
+  if (mHostBridgeDevId == INTEL_ICH10_DEVICE_ID) {
+    AddIoMemoryBaseSizeHob (ICH10_ROOT_COMPLEX_BASE, SIZE_16KB);
+    //
+    // Note: there should be an
+    //
+    //   AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
+    //   BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB, EfiMemoryMappedIO);
+    //
+    // call below, just like the one above for RCBA. However, Linux insists
+    // that the MMCONFIG area be marked in the E820 or UEFI memory map as
+    // "reserved memory" -- Linux does not content itself with a simple gap
+    // in the memory map wherever the MCFG ACPI table points to.
+    //
+    // This appears to be a safety measure. The PCI Firmware Specification
+    // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
+    // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
+    // [...]". (Emphasis added here.)
+    //
+    // Normally we add memory resource descriptor HOBs in
+    // QemuInitializeRam(), and pre-allocate from those with memory
+    // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
+    // is most definitely not RAM; so, as an exception, cover it with
+    // uncacheable reserved memory right here.
+    //
+      AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
+      BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB,
+        EfiReservedMemoryType);
+  }
+  AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB);
+
+  // Add PCI IO Port space available for PCI resource allocations.
+  //
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_IO,
+    EFI_RESOURCE_ATTRIBUTE_PRESENT     |
+    EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
+    PciIoBase,
+    PciIoSize
+    );
+  PcdSet64 (PcdPciIoBase, PciIoBase);
+  PcdSet64 (PcdPciIoSize, PciIoSize);
+
+  //
+  // Add flash range.
+  //
+  AddFlashDeviceRange (PcdGet32(PcdFlashAreaBaseAddress), PcdGet32(PcdFlashAreaSize));
+  //
+  // Video memory / ABSEG
+  //
+  AddIoMemoryBaseSizeHob (0x0A0000, 0x20000);
+  //
+  // Legacy BIOS region.
+  //
+  AddReservedMemoryBaseSizeHob (0xC0000, 0x40000, TRUE);
+}
+
+VOID
+MiscInitialization (
+  VOID
+  )
+{
+  UINTN         PmCmd;
+  UINTN         Pmba;
+  UINT32        PmbaAndVal;
+  UINT32        PmbaOrVal;
+  UINTN         AcpiCtlReg;
+  UINT8         AcpiEnBit;
+
+  //
+  // Disable A20 Mask
+  //
+  IoOr8 (0x92, BIT1);
+
+  //
+  // Build the CPU HOB with guest RAM size dependent address width and 16-bits
+  // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
+  // S3 resume as well, so we build it unconditionally.)
+  //
+  BuildCpuHob (mPhysMemAddressWidth, 16);
+
+  //
+  // Determine platform type and save Host Bridge DID to PCD
+  //
+  switch (mHostBridgeDevId) {
+    case INTEL_82441_DEVICE_ID:
+      PmCmd      = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
+      Pmba       = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
+      PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
+      PmbaOrVal  = PIIX4_PMBA_VALUE;
+      AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
+      AcpiEnBit  = PIIX4_PMREGMISC_PMIOSE;
+      break;
+    case INTEL_ICH10_DEVICE_ID:
+      PmCmd      = POWER_MGMT_REGISTER_ICH10 (PCI_COMMAND_OFFSET);
+      Pmba       = POWER_MGMT_REGISTER_ICH10 (ICH10_PMBASE);
+      PmbaAndVal = ~(UINT32)ICH10_PMBASE_MASK;
+      PmbaOrVal  = ICH10_PMBASE_VALUE;
+      AcpiCtlReg = POWER_MGMT_REGISTER_ICH10 (ICH10_ACPI_CNTL);
+      AcpiEnBit  = ICH10_ACPI_CNTL_ACPI_EN;
+      break;
+    default:
+      DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
+        __FUNCTION__, mHostBridgeDevId));
+      ASSERT (FALSE);
+      return;
+  }
+  PcdSet16 (PcdSimicsX58HostBridgePciDevId, mHostBridgeDevId);
+
+  //
+  // If the appropriate IOspace enable bit is set, assume the ACPI PMBA
+  // has been configured and skip the setup here.
+  // This matches the logic in AcpiTimerLibConstructor ().
+  //
+  if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
+    //
+    // The PEI phase should be exited with fully accessibe ACPI PM IO space:
+    // 1. set PMBA
+    //
+    PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
+
+    //
+    // 2. set PCICMD/IOSE
+    //
+    PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
+
+    //
+    // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
+    //
+    PciOr8 (AcpiCtlReg, AcpiEnBit);
+  }
+
+  if (mHostBridgeDevId == INTEL_ICH10_DEVICE_ID) {
+    //
+    // Set Root Complex Register Block BAR
+    //
+    PciWrite32 (
+      POWER_MGMT_REGISTER_ICH10 (ICH10_RCBA),
+      ICH10_ROOT_COMPLEX_BASE | ICH10_RCBA_EN
+      );
+
+  }
+  //
+  // Set the PM I/O base address to 0x400
+  //
+  PciAndThenOr32 (
+    PCI_LIB_ADDRESS (
+      0,
+      31,
+      0,
+      0x40
+      ),
+    (UINT32) ~0xfc0, ICH10_PMBASE_VALUE
+    );
+  //
+  // Enable AHCI and all ports on the SATA controller.
+  //
+  // Address MAP Reg, setting AHCI mode
+  //
+  PciOr16 (PCI_LIB_ADDRESS (0, 31, 2, 0x90), 0x0060);
+  //
+  //Enabling Ports 0-5
+  //
+  PciOr16 (PCI_LIB_ADDRESS (0, 31, 2, 0x92), 0x003F);
+  //
+  //Disabling Sata Controller 2, bit 25 = 1, bit 0 = 1
+  //
+  MmioWrite32(0xFED1F418, 0x02000001);
+  //
+  //Enable HPET at FED0_0000h ? FED0_03FFh
+  //
+  MmioWrite8(ICH10_ROOT_COMPLEX_BASE + 0x3404, 0x80);
+  //
+  //Config and enable APIC
+  //
+  MmioWrite32(0xFEC00000 + 0X0, 0);
+  MmioWrite32(0xFEC00000 + 0X10, PcdGet8(PcdIoApicId)<<24);
+  MmioWrite8(ICH10_ROOT_COMPLEX_BASE + 0x31FF, 0x01);
+}
+
+
+VOID
+BootModeInitialization (
+  VOID
+  )
+{
+  EFI_STATUS    Status;
+
+ DEBUG((EFI_D_INFO, "modeValue = %x\n", IoBitFieldRead16(ICH10_PMBASE_IO + 4, 10, 12)));
+  if (IoBitFieldRead16(ICH10_PMBASE_IO + 4, 10, 12) == 0x5) {
+    mBootMode = BOOT_ON_S3_RESUME;
+  }
+
+  Status = PeiServicesSetBootMode (mBootMode);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = PeiServicesInstallPpi (mPpiBootMode);
+  ASSERT_EFI_ERROR (Status);
+}
+
+
+VOID
+ReserveEmuVariableNvStore (
+  )
+{
+  EFI_PHYSICAL_ADDRESS VariableStore;
+
+  //
+  // Allocate storage for NV variables early on so it will be
+  // at a consistent address.  Since VM memory is preserved
+  // across reboots, this allows the NV variable storage to survive
+  // a VM reboot.
+  //
+  VariableStore =
+    (EFI_PHYSICAL_ADDRESS)(UINTN)
+      AllocateRuntimePages (
+        EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))
+        );
+  DEBUG ((EFI_D_INFO,
+          "Reserved variable store memory: 0x%lX; size: %dkb\n",
+          VariableStore,
+          (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
+        ));
+  PcdSet64 (PcdEmuVariableNvStoreReserved, VariableStore);
+}
+
+
+VOID
+SimicsVersionCheck(
+  VOID
+  )
+{
+
+  UINTN           PciAddrPtr;
+  UINT8           CapOffset;
+  STATIC CHAR8    SimicsStr[0x100];
+  UINTN           i;
+  UINT32          MajorVersion;
+  UINT32          MinorVersion;
+  UINT32          ModelNumber;
+
+  PciAddrPtr = PCI_LIB_ADDRESS(0, SIMICS_SIDEBANDPCI_DEV, SIMICS_SIDEBANDPCI_FUNC, 0);
+  CapOffset = PciRead8(PciAddrPtr + PCI_CAPBILITY_POINTER_OFFSET);
+  if (CapOffset != 0xFF) {
+    ModelNumber = PciRead32(PciAddrPtr + CapOffset + 4);
+    MajorVersion = PciRead32(PciAddrPtr + CapOffset + 8);
+    MinorVersion = PciRead32(PciAddrPtr + CapOffset + 0xc);
+    for (i = 0; i < 0x80; i++) {
+      SimicsStr[i] = PciRead8(PciAddrPtr + CapOffset + 0x10 + i);
+    }
+    DEBUG((EFI_D_INFO, "=============SIMICS Version info=============\n"));
+    DEBUG((EFI_D_INFO, "Model number = %d\n", ModelNumber));
+    DEBUG((EFI_D_INFO, "Major version = %d\n", MajorVersion));
+    DEBUG((EFI_D_INFO, "Minor version = %d\n", MinorVersion));
+    DEBUG((EFI_D_INFO, "%a\n", SimicsStr));
+    DEBUG((EFI_D_INFO, "=============================================\n"));
+  }
+}
+
+VOID
+DebugDumpCmos (
+  VOID
+  )
+{
+  UINT32 Loop;
+
+  DEBUG ((EFI_D_INFO, "CMOS:\n"));
+
+  for (Loop = 0; Loop < 0x80; Loop++) {
+    if ((Loop % 0x10) == 0) {
+      DEBUG ((EFI_D_INFO, "%02x:", Loop));
+    }
+    DEBUG ((EFI_D_INFO, " %02x", CmosRead8 (Loop)));
+    if ((Loop % 0x10) == 0xf) {
+      DEBUG ((EFI_D_INFO, "\n"));
+    }
+  }
+}
+
+
+/**
+  Fetch the number of boot CPUs from QEMU and expose it to UefiCpuPkg modules.
+  Set the mMaxCpuCount variable.
+**/
+VOID
+MaxCpuCountInitialization (
+  VOID
+  )
+{
+  mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+  return;
+}
+
+/**
+  Determine if S3 support is explicitly enabled.
+
+  @retval  TRUE   If S3 support is explicitly enabled. Other functions in this
+  library may be called (subject to their individual
+  restrictions).
+
+  FALSE  Otherwise. This includes unavailability of the firmware
+  configuration interface. No other function in this library
+  must be called.
+**/
+BOOLEAN
+EFIAPI
+QemuFwCfgS3Enabled(
+  VOID
+)
+{
+  //TO DO IF NEEDED
+  return TRUE;
+}
+
+/**
+  Perform Platform PEI initialization.
+
+  @param  FileHandle      Handle of the file being invoked.
+  @param  PeiServices     Describes the list of possible PEI Services.
+
+  @return EFI_SUCCESS     The PEIM initialized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePlatform (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  EFI_STATUS    Status;
+
+  DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n"));
+
+  SimicsVersionCheck ();
+  DebugDumpCmos ();
+
+  if (QemuFwCfgS3Enabled ()) {
+    DEBUG ((EFI_D_INFO, "S3 support was detected on SIMICS\n"));
+    mS3Supported = TRUE;
+    Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
+    ASSERT_EFI_ERROR (Status);
+  }
+  AddressWidthInitialization ();
+  MaxCpuCountInitialization ();
+
+  mHostBridgeDevId = PciRead16(SIMICS_HOSTBRIDGE_DID);
+
+  if (FeaturePcdGet (PcdSmmSmramRequire)) {
+    X58TsegMbytesInitialization ();
+  }
+
+  PublishPeiMemory ();
+
+  InitializeRamRegions ();
+
+  if (mBootMode != BOOT_ON_S3_RESUME) {
+    if (!FeaturePcdGet (PcdSmmSmramRequire)) {
+      ReserveEmuVariableNvStore ();
+    }
+    MemMapInitialization ();
+  }
+
+  MiscInitialization ();
+  InstallFeatureControlCallback ();
+
+  return EFI_SUCCESS;
+}

+ 88 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsPei/Platform.h

@@ -0,0 +1,88 @@
+/** @file
+  Platform PEI module include file.
+
+  Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PLATFORM_PEI_H_INCLUDED_
+#define _PLATFORM_PEI_H_INCLUDED_
+
+VOID
+AddIoMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  );
+
+VOID
+AddIoMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  );
+
+VOID
+AddMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  );
+
+VOID
+AddMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  );
+
+VOID
+AddUntestedMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  );
+
+VOID
+AddReservedMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize,
+  BOOLEAN                     Cacheable
+  );
+
+VOID
+AddressWidthInitialization (
+  VOID
+  );
+
+VOID
+X58TsegMbytesInitialization (
+  VOID
+  );
+
+EFI_STATUS
+PublishPeiMemory (
+  VOID
+  );
+
+UINT32
+GetSystemMemorySizeBelow4gb (
+  VOID
+  );
+
+VOID
+InitializeRamRegions (
+  VOID
+  );
+
+VOID
+InstallFeatureControlCallback (
+  VOID
+  );
+
+extern EFI_BOOT_MODE mBootMode;
+
+extern BOOLEAN mS3Supported;
+
+extern UINT8 mPhysMemAddressWidth;
+
+extern UINT32 mMaxCpuCount;
+
+extern UINT16 mHostBridgeDevId;
+#endif // _PLATFORM_PEI_H_INCLUDED_

+ 104 - 0
Platform/Intel/SimicsOpenBoardPkg/SimicsPei/SimicsPei.inf

@@ -0,0 +1,104 @@
+## @file
+#  Platform PEI driver
+#
+#  This module provides platform specific function to detect boot mode.
+# Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SimicsPei
+  FILE_GUID                      = 05116218-f9f1-41f8-8d17-c2207006ffff
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializePlatform
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  Cmos.c
+  FeatureControl.c
+  MemDetect.c
+  Platform.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+  MinPlatformPkg/MinPlatformPkg.dec
+  SimicsX58SktPkg/SktPkg.dec
+  SimicsIch10Pkg/Ich10Pkg.dec
+
+[Guids]
+  gEfiMemoryTypeInformationGuid
+  gEfiSmmPeiSmramMemoryReserveGuid              ## CONSUMES
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  HobLib
+  IoLib
+  PciLib
+  PeiResourcePublicationLib
+  PeiServicesLib
+  PeiServicesTablePointerLib
+  PeimEntryPoint
+  MtrrLib
+  PcdLib
+
+[Pcd]
+  gBoardModuleTokenSpaceGuid.PcdSimicsPeiMemFvBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsPeiMemFvSize
+  gBoardModuleTokenSpaceGuid.PcdSimicsDxeMemFvBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsDxeMemFvSize
+  gBoardModuleTokenSpaceGuid.PcdSimicsLockBoxStorageBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsLockBoxStorageSize
+  gBoardModuleTokenSpaceGuid.PcdSimicsSecPageTablesBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsSecPeiTempRamBase
+  gBoardModuleTokenSpaceGuid.PcdSimicsSecPeiTempRamSize
+  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
+  gBoardModuleTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
+  gBoardModuleTokenSpaceGuid.PcdSimicsDecompressionScratchEnd
+  gBoardModuleTokenSpaceGuid.PcdSimicsX58HostBridgePciDevId
+  gBoardModuleTokenSpaceGuid.PcdPciIoBase
+  gBoardModuleTokenSpaceGuid.PcdPciIoSize
+  gBoardModuleTokenSpaceGuid.PcdPciMmio32Base
+  gBoardModuleTokenSpaceGuid.PcdPciMmio32Size
+  gBoardModuleTokenSpaceGuid.PcdPciMmio64Base
+  gBoardModuleTokenSpaceGuid.PcdPciMmio64Size
+  gSimicsX58PkgTokenSpaceGuid.PcdX58TsegMbytes
+  gSimicsX58PkgTokenSpaceGuid.PcdSmmSmramRequire
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashAreaBaseAddress  ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdFlashAreaSize         ## CONSUMES
+  gMinPlatformPkgTokenSpaceGuid.PcdIoApicId
+
+[FixedPcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+
+
+[Ppis]
+  gEfiPeiMasterBootModePpiGuid
+  gEfiPeiMpServicesPpiGuid
+
+[Depex]
+  TRUE
+

+ 148 - 0
Platform/Intel/SimicsOpenBoardPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.c

@@ -0,0 +1,148 @@
+/** @file
+  This driver installs SMBIOS information for QSP
+
+  Copyright (c) 2011, Bei Guan <gbtju85@gmail.com>
+  Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "SmbiosPlatformDxe.h"
+
+
+/**
+Reads 8-bits of CMOS data.
+
+Reads the 8-bits of CMOS data at the location specified by Index.
+The 8-bit read value is returned.
+
+@param  Index  The CMOS location to read.
+
+@return The value read.
+
+**/
+UINT8
+EFIAPI
+CmosRead8(
+  IN      UINTN                     Index
+  )
+{
+  IoWrite8(0x70, (UINT8)Index);
+  return IoRead8(0x71);
+}
+
+UINT32
+GetSystemMemorySizeBelow4gb(
+  VOID
+  )
+{
+  UINT8 Cmos0x34;
+  UINT8 Cmos0x35;
+
+  //
+  // CMOS 0x34/0x35 specifies the system memory above 16 MB.
+  // * CMOS(0x35) is the high byte
+  // * CMOS(0x34) is the low byte
+  // * The size is specified in 64kb chunks
+  // * Since this is memory above 16MB, the 16MB must be added
+  //   into the calculation to get the total memory size.
+  //
+
+  Cmos0x34 = (UINT8)CmosRead8(0x34);
+  Cmos0x35 = (UINT8)CmosRead8(0x35);
+
+  return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
+}
+
+STATIC
+UINT64
+GetSystemMemorySizeAbove4gb(
+  VOID
+)
+{
+  UINT32 Size;
+  UINTN  CmosIndex;
+
+  //
+  // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
+  // * CMOS(0x5d) is the most significant size byte
+  // * CMOS(0x5c) is the middle size byte
+  // * CMOS(0x5b) is the least significant size byte
+  // * The size is specified in 64kb chunks
+  //
+
+  Size = 0;
+  for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
+    Size = (UINT32)(Size << 8) + (UINT32)CmosRead8(CmosIndex);
+  }
+
+  return LShiftU64(Size, 16);
+}
+
+/**
+  Installs SMBIOS information for SIMICS QSP
+
+  @param ImageHandle     Module's image handle
+  @param SystemTable     Pointer of EFI_SYSTEM_TABLE
+
+  @retval EFI_SUCCESS    Smbios data successfully installed
+  @retval Other          Smbios data was not installed
+
+**/
+EFI_STATUS
+EFIAPI
+SmbiosTablePublishEntry (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  EFI_STATUS                Status;
+  EFI_SMBIOS_PROTOCOL       *Smbios;
+  SMBIOS_TABLE_TYPE19       *Type19Record;
+  EFI_SMBIOS_HANDLE         MemArrayMappedAddrSmbiosHandle;
+  UINT8                     NumSlots;
+  UINT64                    TotalMemorySize;
+
+  //
+  // Find the SMBIOS protocol
+  //
+  Status = gBS->LocateProtocol (
+                  &gEfiSmbiosProtocolGuid,
+                  NULL,
+                  (VOID**)&Smbios
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Generate Memory Array Mapped Address info
+  //
+  NumSlots = 2;
+  TotalMemorySize = 0;
+  TotalMemorySize = GetSystemMemorySizeBelow4gb();
+  Type19Record = AllocatePool(sizeof(SMBIOS_TABLE_TYPE19));
+  ZeroMem(Type19Record, sizeof(SMBIOS_TABLE_TYPE19));
+  Type19Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS;
+  Type19Record->Hdr.Length = sizeof(SMBIOS_TABLE_TYPE19);
+  Type19Record->Hdr.Handle = 0;
+  Type19Record->StartingAddress = 0;
+  Type19Record->EndingAddress = (UINT32)RShiftU64(TotalMemorySize, 10) - 1;
+  Type19Record->MemoryArrayHandle = SMBIOS_HANDLE_PI_RESERVED;
+  Type19Record->PartitionWidth = (UINT8)(NumSlots);
+
+  MemArrayMappedAddrSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+  Status = Smbios->Add(Smbios, NULL, &MemArrayMappedAddrSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*)Type19Record);
+  ASSERT_EFI_ERROR(Status);
+
+  TotalMemorySize = GetSystemMemorySizeAbove4gb();
+  Type19Record->StartingAddress = 0xFFFFFFFF;
+  Type19Record->ExtendedStartingAddress = 0xFFFFFFFF;
+  Type19Record->ExtendedEndingAddress = TotalMemorySize + 0xFFFFFFFF - 1;
+
+  MemArrayMappedAddrSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+  Status = Smbios->Add(Smbios, NULL, &MemArrayMappedAddrSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*)Type19Record);
+  FreePool(Type19Record);
+  ASSERT_EFI_ERROR(Status);
+
+  return Status;
+}

+ 38 - 0
Platform/Intel/SimicsOpenBoardPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.h

@@ -0,0 +1,38 @@
+/** @file
+  This driver installs SMBIOS information for QSP
+
+  Copyright (c) 2011, Bei Guan <gbtju85@gmail.com>
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _SMBIOS_PLATFORM_DXE_H_
+#define _SMBIOS_PLATFORM_DXE_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/Smbios.h>
+#include <IndustryStandard/SmBios.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+
+/**
+  Validates the SMBIOS entry point structure
+
+  @param  EntryPointStructure  SMBIOS entry point structure
+
+  @retval TRUE   The entry point structure is valid
+  @retval FALSE  The entry point structure is not valid
+
+**/
+BOOLEAN
+IsEntryPointStructureValid (
+  IN SMBIOS_TABLE_ENTRY_POINT  *EntryPointStructure
+  );
+
+#endif

+ 51 - 0
Platform/Intel/SimicsOpenBoardPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf

@@ -0,0 +1,51 @@
+## @file
+#  This driver installs SMBIOS information for QSP
+#
+#  Copyright (c) 2011, Bei Guan <gbtju85@gmail.com>
+#  Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SmbiosPlatformDxe
+  FILE_GUID                      = 4b18323d-2d42-4afa-b9e5-91516a6fe505
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = SmbiosTablePublishEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC ARM AARCH64
+#
+
+[Sources]
+  SmbiosPlatformDxe.h
+  SmbiosPlatformDxe.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SimicsOpenBoardPkg/OpenBoardPkg.dec
+  AdvancedFeaturePkg/AdvancedFeaturePkg.dec
+
+[LibraryClasses]
+  UefiBootServicesTableLib
+  BaseMemoryLib
+  BaseLib
+  UefiDriverEntryPoint
+  DebugLib
+  HobLib
+  MemoryAllocationLib
+  IoLib
+
+[Protocols]
+  gEfiSmbiosProtocolGuid                      # PROTOCOL ALWAYS_CONSUMED
+
+[Depex]
+  gEfiSmbiosProtocolGuid
+