mbox series

[v8,00/15] x86: Trenchboot secure dynamic launch Linux kernel support

Message ID 20240214221847.2066632-1-ross.philipson@oracle.com
Headers show
Series x86: Trenchboot secure dynamic launch Linux kernel support | expand

Message

Ross Philipson Feb. 14, 2024, 10:18 p.m. UTC
The larger focus of the TrenchBoot project (https://github.com/TrenchBoot) is to
enhance the boot security and integrity in a unified manner. The first area of
focus has been on the Trusted Computing Group's Dynamic Launch for establishing
a hardware Root of Trust for Measurement, also know as DRTM (Dynamic Root of
Trust for Measurement). The project has been and continues to work on providing
a unified means to Dynamic Launch that is a cross-platform (Intel and AMD) and
cross-architecture (x86 and Arm), with our recent involvment in the upcoming
Arm DRTM specification. The order of introducing DRTM to the Linux kernel
follows the maturity of DRTM in the architectures. Intel's Trusted eXecution
Technology (TXT) is present today and only requires a preamble loader, e.g. a
boot loader, and an OS kernel that is TXT-aware. AMD DRTM implementation has
been present since the introduction of AMD-V but requires an additional
component that is AMD specific and referred to in the specification as the
Secure Loader, which the TrenchBoot project has an active prototype in
development. Finally Arm's implementation is in specification development stage
and the project is looking to support it when it becomes available.

This patchset provides detailed documentation of DRTM, the approach used for
adding the capbility, and relevant API/ABI documentation. In addition to the
documentation the patch set introduces Intel TXT support as the first platform
for Linux Secure Launch.

A quick note on terminology. The larger open source project itself is called
TrenchBoot, which is hosted on Github (links below). The kernel feature enabling
the use of Dynamic Launch technology is referred to as "Secure Launch" within
the kernel code. As such the prefixes sl_/SL_ or slaunch/SLAUNCH will be seen
in the code. The stub code discussed above is referred to as the SL stub.

The Secure Launch feature starts with patch #2. Patch #1 was authored by Arvind
Sankar. There is no further status on this patch at this point but
Secure Launch depends on it so it is included with the set.

Links:

The TrenchBoot project including documentation:

https://trenchboot.org

The TrenchBoot project on Github:

https://github.com/trenchboot

Intel TXT is documented in its own specification and in the SDM Instruction Set volume:

https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
https://software.intel.com/en-us/articles/intel-sdm

AMD SKINIT is documented in the System Programming manual:

https://www.amd.com/system/files/TechDocs/24593.pdf

The TrenchBoot project provides a quick start guide to help get a system
up and running with Secure Launch for Linux:

https://github.com/TrenchBoot/documentation/blob/master/QUICKSTART.md

Patch set based on commit:

torvolds/master/54be6c6c5ae8e0d93a6c4641cb7528eb0b6ba478

Thanks
Ross Philipson and Daniel P. Smith

Changes in v2:

 - Modified 32b entry code to prevent causing relocations in the compressed
   kernel.
 - Dropped patches for compressed kernel TPM PCR extender.
 - Modified event log code to insert log delimiter events and not rely
   on TPM access.
 - Stop extending PCRs in the early Secure Launch stub code.
 - Removed Kconfig options for hash algorithms and use the algorithms the
   ACM used.
 - Match Secure Launch measurement algorithm use to those reported in the
   TPM 2.0 event log.
 - Read the TPM events out of the TPM and extend them into the PCRs using
   the mainline TPM driver. This is done in the late initcall module.
 - Allow use of alternate PCR 19 and 20 for post ACM measurements.
 - Add Kconfig constraints needed by Secure Launch (disable KASLR
   and add x2apic dependency).
 - Fix testing of SL_FLAGS when determining if Secure Launch is active
   and the architecture is TXT.
 - Use SYM_DATA_START_LOCAL macros in early entry point code.
 - Security audit changes:
   - Validate buffers passed to MLE do not overlap the MLE and are
     properly laid out.
   - Validate buffers and memory regions used by the MLE are
     protected by IOMMU PMRs.
 - Force IOMMU to not use passthrough mode during a Secure Launch.
 - Prevent KASLR use during a Secure Launch.

Changes in v3:

 - Introduce x86 documentation patch to provide background, overview
   and configuration/ABI information for the Secure Launch kernel
   feature.
 - Remove the IOMMU patch with special cases for disabling IOMMU
   passthrough. Configuring the IOMMU is now a documentation matter
   in the previously mentioned new patch.
 - Remove special case KASLR disabling code. Configuring KASLR is now
   a documentation matter in the previously mentioned new patch.
 - Fix incorrect panic on TXT public register read.
 - Properly handle and measure setup_indirect bootparams in the early
   launch code.
 - Use correct compressed kernel image base address when testing buffers
   in the early launch stub code. This bug was introduced by the changes
   to avoid relocation in the compressed kernel.
 - Use CPUID feature bits instead of CPUID vendor strings to determine
   if SMX mode is supported and the system is Intel.
 - Remove early NMI re-enable on the BSP. This can be safely done later
   on the BSP after an IDT is setup.

Changes in v4:
 - Expand the cover letter to provide more context to the order that DRTM
   support will be added.
 - Removed debug tracing in TPM request locality funciton and fixed
   local variable declarations.
 - Fixed missing break in default case in slmodule.c.
 - Reworded commit messages in patches 1 and 2 per suggestions.

Changes in v5:
 - Comprehensive documentation rewrite.
 - Use boot param loadflags to communicate Secure Launch status to
   kernel proper.
 - Fix incorrect check of X86_FEATURE_BIT_SMX bit.
 - Rename the alternate details and authorities PCR support.
 - Refactor the securityfs directory and file setup in slmodule.c.
 - Misc. cleanup from internal code reviews.
 - Use reverse fir tree format for variables.

Changes in v6:
 - Support for the new Secure Launch Resourse Table that standardizes
   the information passed and forms the ABI between the pre and post
   launch code.
 - Support for booting Linux through the EFI stub entry point and
   then being able to do a Secure Launch once EFI stub is done and EBS
   is called.
 - Updates to the documentation to reflect the previous two items listed.

Changes in v7:
 - Switch to using MONITOR/MWAIT instead of NMIs to park the APs for
   later bringup by the SMP code.
 - Use static inline dummy functions instead of macros when the Secure
   Launch feature is disabled.
 - Move early SHA1 code to lib/crypto and pull it in from there.
 - Numerous formatting fixes from comments on LKML.
 - Remove efi-stub/DL stub patch temporarily for redesign/rework.

Changes in v8:
 - Reintroduce efi-stub Linux kernel booting through the dynamic launch
   stub (DL stub).
 - Add new approach to setting localities > 0 through kernel and sysfs
   interfaces in the TPM mainline driver.
 - General code cleanup from v7 post comments.

Arvind Sankar (1):
  x86/boot: Place kernel_info at a fixed offset

Daniel P. Smith (2):
  x86: Add early SHA support for Secure Launch early measurements
  x86: Secure Launch late initcall platform module

Ross Philipson (12):
  Documentation/x86: Secure Launch kernel documentation
  x86: Secure Launch Kconfig
  x86: Secure Launch Resource Table header file
  x86: Secure Launch main header file
  x86: Secure Launch kernel early boot stub
  x86: Secure Launch kernel late boot stub
  x86: Secure Launch SMP bringup support
  kexec: Secure Launch kexec SEXIT support
  reboot: Secure Launch SEXIT support on reboot paths
  tpm: Add ability to set the preferred locality the TPM chip uses
  tpm: Add sysfs interface to allow setting and querying the preferred
    locality
  x86: EFI stub DRTM launch support for Secure Launch

*** BLURB HERE ***

Arvind Sankar (1):
  x86/boot: Place kernel_info at a fixed offset

Daniel P. Smith (2):
  x86: Add early SHA support for Secure Launch early measurements
  x86: Secure Launch late initcall platform module

Ross Philipson (12):
  Documentation/x86: Secure Launch kernel documentation
  x86: Secure Launch Kconfig
  x86: Secure Launch Resource Table header file
  x86: Secure Launch main header file
  x86: Secure Launch kernel early boot stub
  x86: Secure Launch kernel late boot stub
  x86: Secure Launch SMP bringup support
  kexec: Secure Launch kexec SEXIT support
  reboot: Secure Launch SEXIT support on reboot paths
  tpm: Add ability to set the preferred locality the TPM chip uses
  tpm: Add sysfs interface to allow setting and querying the preferred
    locality
  x86: EFI stub DRTM launch support for Secure Launch

 Documentation/arch/x86/boot.rst               |  21 +
 Documentation/security/index.rst              |   1 +
 .../security/launch-integrity/index.rst       |  11 +
 .../security/launch-integrity/principles.rst  | 320 ++++++++
 .../secure_launch_details.rst                 | 584 +++++++++++++++
 .../secure_launch_overview.rst                | 226 ++++++
 arch/x86/Kconfig                              |  12 +
 arch/x86/boot/compressed/Makefile             |   3 +
 arch/x86/boot/compressed/early_sha1.c         |  12 +
 arch/x86/boot/compressed/early_sha256.c       |   6 +
 arch/x86/boot/compressed/head_64.S            |  34 +
 arch/x86/boot/compressed/kernel_info.S        |  53 +-
 arch/x86/boot/compressed/kernel_info.h        |  12 +
 arch/x86/boot/compressed/sl_main.c            | 582 +++++++++++++++
 arch/x86/boot/compressed/sl_stub.S            | 705 ++++++++++++++++++
 arch/x86/boot/compressed/vmlinux.lds.S        |   6 +
 arch/x86/include/asm/msr-index.h              |   5 +
 arch/x86/include/asm/realmode.h               |   3 +
 arch/x86/include/uapi/asm/bootparam.h         |   1 +
 arch/x86/kernel/Makefile                      |   2 +
 arch/x86/kernel/asm-offsets.c                 |  20 +
 arch/x86/kernel/reboot.c                      |  10 +
 arch/x86/kernel/setup.c                       |   3 +
 arch/x86/kernel/slaunch.c                     | 598 +++++++++++++++
 arch/x86/kernel/slmodule.c                    | 511 +++++++++++++
 arch/x86/kernel/smpboot.c                     |  58 +-
 arch/x86/realmode/init.c                      |   3 +
 arch/x86/realmode/rm/header.S                 |   3 +
 arch/x86/realmode/rm/trampoline_64.S          |  32 +
 drivers/char/tpm/tpm-chip.c                   |  24 +-
 drivers/char/tpm/tpm-interface.c              |  15 +
 drivers/char/tpm/tpm-sysfs.c                  |  30 +
 drivers/char/tpm/tpm.h                        |   1 +
 drivers/firmware/efi/libstub/x86-stub.c       |  55 ++
 drivers/iommu/intel/dmar.c                    |   4 +
 include/crypto/sha1.h                         |   1 +
 include/linux/slaunch.h                       | 542 ++++++++++++++
 include/linux/slr_table.h                     | 270 +++++++
 include/linux/tpm.h                           |  10 +
 kernel/kexec_core.c                           |   4 +
 lib/crypto/sha1.c                             |  81 ++
 41 files changed, 4867 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/security/launch-integrity/index.rst
 create mode 100644 Documentation/security/launch-integrity/principles.rst
 create mode 100644 Documentation/security/launch-integrity/secure_launch_details.rst
 create mode 100644 Documentation/security/launch-integrity/secure_launch_overview.rst
 create mode 100644 arch/x86/boot/compressed/early_sha1.c
 create mode 100644 arch/x86/boot/compressed/early_sha256.c
 create mode 100644 arch/x86/boot/compressed/kernel_info.h
 create mode 100644 arch/x86/boot/compressed/sl_main.c
 create mode 100644 arch/x86/boot/compressed/sl_stub.S
 create mode 100644 arch/x86/kernel/slaunch.c
 create mode 100644 arch/x86/kernel/slmodule.c
 create mode 100644 include/linux/slaunch.h
 create mode 100644 include/linux/slr_table.h

Comments

Ard Biesheuvel Feb. 15, 2024, 7:59 a.m. UTC | #1
On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
>
> Initial bits to bring in Secure Launch functionality. Add Kconfig
> options for compiling in/out the Secure Launch code.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
>  arch/x86/Kconfig | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 5edec175b9bf..d96d75f6f1a9 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2071,6 +2071,18 @@ config EFI_RUNTIME_MAP
>
>           See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
>
> +config SECURE_LAUNCH
> +       bool "Secure Launch support"
> +       default n

'n' is already the default, so you can drop this line.

> +       depends on X86_64 && X86_X2APIC

This depends on CONFIG_TCG_TPM as well (I got build failures without it)

> +       help
> +          The Secure Launch feature allows a kernel to be loaded
> +          directly through an Intel TXT measured launch. Intel TXT
> +          establishes a Dynamic Root of Trust for Measurement (DRTM)
> +          where the CPU measures the kernel image. This feature then
> +          continues the measurement chain over kernel configuration
> +          information and init images.
> +
>  source "kernel/Kconfig.hz"
>
>  config ARCH_SUPPORTS_KEXEC
> --
> 2.39.3
>
Ard Biesheuvel Feb. 15, 2024, 8:08 a.m. UTC | #2
On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
>
> Introduce the Secure Launch Resource Table which forms the formal
> interface between the pre and post launch code.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
>  include/linux/slr_table.h | 270 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 270 insertions(+)
>  create mode 100644 include/linux/slr_table.h
>
> diff --git a/include/linux/slr_table.h b/include/linux/slr_table.h
> new file mode 100644
> index 000000000000..42020988233a
> --- /dev/null
> +++ b/include/linux/slr_table.h
> @@ -0,0 +1,270 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Secure Launch Resource Table
> + *
> + * Copyright (c) 2023, Oracle and/or its affiliates.
> + */
> +
> +#ifndef _LINUX_SLR_TABLE_H
> +#define _LINUX_SLR_TABLE_H
> +
> +/* Put this in efi.h if it becomes a standard */
> +#define SLR_TABLE_GUID                         EFI_GUID(0x877a9b2a, 0x0385, 0x45d1, 0xa0, 0x34, 0x9d, 0xac, 0x9c, 0x9e, 0x56, 0x5f)
> +
> +/* SLR table header values */
> +#define SLR_TABLE_MAGIC                0x4452544d
> +#define SLR_TABLE_REVISION     1
> +
> +/* Current revisions for the policy and UEFI config */
> +#define SLR_POLICY_REVISION            1
> +#define SLR_UEFI_CONFIG_REVISION       1
> +
> +/* SLR defined architectures */
> +#define SLR_INTEL_TXT          1
> +#define SLR_AMD_SKINIT         2
> +
> +/* SLR defined bootloaders */
> +#define SLR_BOOTLOADER_INVALID 0
> +#define SLR_BOOTLOADER_GRUB    1
> +
> +/* Log formats */
> +#define SLR_DRTM_TPM12_LOG     1
> +#define SLR_DRTM_TPM20_LOG     2
> +
> +/* DRTM Policy Entry Flags */
> +#define SLR_POLICY_FLAG_MEASURED       0x1
> +#define SLR_POLICY_IMPLICIT_SIZE       0x2
> +
> +/* Array Lengths */
> +#define TPM_EVENT_INFO_LENGTH          32
> +#define TXT_VARIABLE_MTRRS_LENGTH      32
> +
> +/* Tags */
> +#define SLR_ENTRY_INVALID      0x0000
> +#define SLR_ENTRY_DL_INFO      0x0001
> +#define SLR_ENTRY_LOG_INFO     0x0002
> +#define SLR_ENTRY_ENTRY_POLICY 0x0003
> +#define SLR_ENTRY_INTEL_INFO   0x0004
> +#define SLR_ENTRY_AMD_INFO     0x0005
> +#define SLR_ENTRY_ARM_INFO     0x0006
> +#define SLR_ENTRY_UEFI_INFO    0x0007
> +#define SLR_ENTRY_UEFI_CONFIG  0x0008
> +#define SLR_ENTRY_END          0xffff
> +
> +/* Entity Types */
> +#define SLR_ET_UNSPECIFIED     0x0000
> +#define SLR_ET_SLRT            0x0001
> +#define SLR_ET_BOOT_PARAMS     0x0002
> +#define SLR_ET_SETUP_DATA      0x0003
> +#define SLR_ET_CMDLINE         0x0004
> +#define SLR_ET_UEFI_MEMMAP     0x0005
> +#define SLR_ET_RAMDISK         0x0006
> +#define SLR_ET_TXT_OS2MLE      0x0010
> +#define SLR_ET_UNUSED          0xffff
> +
> +#ifndef __ASSEMBLY__
> +
> +/*
> + * Primary SLR Table Header
> + */
> +struct slr_table {
> +       u32 magic;
> +       u16 revision;
> +       u16 architecture;
> +       u32 size;
> +       u32 max_size;
> +       /* entries[] */
> +} __packed;

Packing this struct has no effect on the layout so better drop the
__packed here. If this table is part of a structure that can appear
misaligned in memory, better to pack the outer struct or deal with it
there in another way.

> +
> +/*
> + * Common SLRT Table Header
> + */
> +struct slr_entry_hdr {
> +       u16 tag;
> +       u16 size;
> +} __packed;

Same here

> +
> +/*
> + * Boot loader context
> + */
> +struct slr_bl_context {
> +       u16 bootloader;
> +       u16 reserved;
> +       u64 context;
> +} __packed;
> +
> +/*
> + * DRTM Dynamic Launch Configuration
> + */
> +struct slr_entry_dl_info {
> +       struct slr_entry_hdr hdr;
> +       struct slr_bl_context bl_context;
> +       u64 dl_handler;

I noticed in the EFI patch that this is actually

void (*dl_handler)(struct slr_bl_context *bl_context);

so better declare it as such.

> +       u64 dce_base;
> +       u32 dce_size;
> +       u64 dlme_entry;
> +} __packed;
> +
> +/*
> + * TPM Log Information
> + */
> +struct slr_entry_log_info {
> +       struct slr_entry_hdr hdr;
> +       u16 format;
> +       u16 reserved;
> +       u64 addr;
> +       u32 size;
> +} __packed;
> +
> +/*
> + * DRTM Measurement Policy
> + */
> +struct slr_entry_policy {
> +       struct slr_entry_hdr hdr;
> +       u16 revision;
> +       u16 nr_entries;
> +       /* policy_entries[] */

Please use a flex array here:

  struct slr_policy_entry policy_entries[];

> +} __packed;
> +
> +/*
> + * DRTM Measurement Entry
> + */
> +struct slr_policy_entry {
> +       u16 pcr;
> +       u16 entity_type;
> +       u16 flags;
> +       u16 reserved;
> +       u64 entity;
> +       u64 size;
> +       char evt_info[TPM_EVENT_INFO_LENGTH];
> +} __packed;
> +
> +/*
> + * Secure Launch defined MTRR saving structures
> + */
> +struct slr_txt_mtrr_pair {
> +       u64 mtrr_physbase;
> +       u64 mtrr_physmask;
> +} __packed;
> +
> +struct slr_txt_mtrr_state {
> +       u64 default_mem_type;
> +       u64 mtrr_vcnt;
> +       struct slr_txt_mtrr_pair mtrr_pair[TXT_VARIABLE_MTRRS_LENGTH];
> +} __packed;
> +
> +/*
> + * Intel TXT Info table
> + */
> +struct slr_entry_intel_info {
> +       struct slr_entry_hdr hdr;
> +       u64 saved_misc_enable_msr;
> +       struct slr_txt_mtrr_state saved_bsp_mtrrs;
> +} __packed;
> +
> +/*
> + * AMD SKINIT Info table
> + */
> +struct slr_entry_amd_info {
> +       struct slr_entry_hdr hdr;
> +} __packed;
> +
> +/*
> + * ARM DRTM Info table
> + */
> +struct slr_entry_arm_info {
> +       struct slr_entry_hdr hdr;
> +} __packed;
> +

These two look preliminary, so better to drop them now and introduce
only once you know what they will look like.

> +struct slr_entry_uefi_config {
> +       struct slr_entry_hdr hdr;
> +       u16 revision;
> +       u16 nr_entries;
> +       /* uefi_cfg_entries[] */

Use a flex array

> +} __packed;
> +
> +struct slr_uefi_cfg_entry {
> +       u16 pcr;
> +       u16 reserved;
> +       u64 cfg; /* address or value */
> +       u32 size;
> +       char evt_info[TPM_EVENT_INFO_LENGTH];
> +} __packed;
> +
> +static inline void *slr_end_of_entrys(struct slr_table *table)

typo 'entrys' ?

> +{
> +       return (((void *)table) + table->size);

You can drop two sets of parens here

> +}
> +
> +static inline struct slr_entry_hdr *
> +slr_next_entry(struct slr_table *table,
> +              struct slr_entry_hdr *curr)
> +{
> +       struct slr_entry_hdr *next = (struct slr_entry_hdr *)
> +                               ((u8 *)curr + curr->size);
> +
> +       if ((void *)next >= slr_end_of_entrys(table))
> +               return NULL;
> +       if (next->tag == SLR_ENTRY_END)
> +               return NULL;
> +
> +       return next;
> +}
> +
> +static inline struct slr_entry_hdr *
> +slr_next_entry_by_tag(struct slr_table *table,
> +                     struct slr_entry_hdr *entry,
> +                     u16 tag)
> +{
> +       if (!entry) /* Start from the beginning */
> +               entry = (struct slr_entry_hdr *)(((u8 *)table) + sizeof(*table));
> +
> +       for ( ; ; ) {
> +               if (entry->tag == tag)
> +                       return entry;
> +
> +               entry = slr_next_entry(table, entry);
> +               if (!entry)
> +                       return NULL;
> +       }
> +
> +       return NULL;
> +}
> +
> +static inline int
> +slr_add_entry(struct slr_table *table,
> +             struct slr_entry_hdr *entry)
> +{
> +       struct slr_entry_hdr *end;
> +
> +       if ((table->size + entry->size) > table->max_size)
> +               return -1;
> +
> +       memcpy((u8 *)table + table->size - sizeof(*end), entry, entry->size);
> +       table->size += entry->size;
> +
> +       end  = (struct slr_entry_hdr *)((u8 *)table + table->size - sizeof(*end));
> +       end->tag = SLR_ENTRY_END;
> +       end->size = sizeof(*end);
> +
> +       return 0;
> +}
> +
> +static inline void
> +slr_init_table(struct slr_table *slrt, u16 architecture, u32 max_size)
> +{
> +       struct slr_entry_hdr *end;
> +
> +       slrt->magic = SLR_TABLE_MAGIC;
> +       slrt->revision = SLR_TABLE_REVISION;
> +       slrt->architecture = architecture;
> +       slrt->size = sizeof(*slrt) + sizeof(*end);
> +       slrt->max_size = max_size;
> +       end = (struct slr_entry_hdr *)((u8 *)slrt + sizeof(*slrt));
> +       end->tag = SLR_ENTRY_END;
> +       end->size = sizeof(*end);
> +}
> +
> +#endif /* !__ASSEMBLY */
> +
> +#endif /* _LINUX_SLR_TABLE_H */
> --
> 2.39.3
>
Ard Biesheuvel Feb. 15, 2024, 8:17 a.m. UTC | #3
On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
>
> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>
> The SHA algorithms are necessary to measure configuration information into
> the TPM as early as possible before using the values. This implementation
> uses the established approach of #including the SHA libraries directly in
> the code since the compressed kernel is not uncompressed at this point.
>
> The SHA code here has its origins in the code from the main kernel:
>
> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
>
> A modified version of this code was introduced to the lib/crypto/sha1.c
> to bring it in line with the sha256 code and allow it to be pulled into the
> setup kernel in the same manner as sha256 is.
>
> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>

We have had some discussions about this, and you really need to
capture the justification in the commit log for introducing new code
that implements an obsolete and broken hashing algorithm.

SHA-1 is broken and should no longer be used for anything. Introducing
new support for a highly complex boot security feature, and then
relying on SHA-1 in the implementation makes this whole effort seem
almost futile, *unless* you provide some rock solid reasons here why
this is still safe.

If the upshot would be that some people are stuck with SHA-1 so they
won't be able to use this feature, then I'm not convinced we should
obsess over that.

> ---
>  arch/x86/boot/compressed/Makefile       |  2 +
>  arch/x86/boot/compressed/early_sha1.c   | 12 ++++
>  arch/x86/boot/compressed/early_sha256.c |  6 ++



>  include/crypto/sha1.h                   |  1 +
>  lib/crypto/sha1.c                       | 81 +++++++++++++++++++++++++

This needs to be a separate patch in any case.


>  5 files changed, 102 insertions(+)
>  create mode 100644 arch/x86/boot/compressed/early_sha1.c
>  create mode 100644 arch/x86/boot/compressed/early_sha256.c
>
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index f19c038409aa..a1b018eb9801 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -118,6 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>  vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>  vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>
> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
> +
>  $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>         $(call if_changed,ld)
>
> diff --git a/arch/x86/boot/compressed/early_sha1.c b/arch/x86/boot/compressed/early_sha1.c
> new file mode 100644
> index 000000000000..0c7cf6f8157a
> --- /dev/null
> +++ b/arch/x86/boot/compressed/early_sha1.c
> @@ -0,0 +1,12 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2022 Apertus Solutions, LLC.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/linkage.h>
> +#include <linux/string.h>
> +#include <asm/boot.h>
> +#include <asm/unaligned.h>
> +
> +#include "../../../../lib/crypto/sha1.c"
> diff --git a/arch/x86/boot/compressed/early_sha256.c b/arch/x86/boot/compressed/early_sha256.c
> new file mode 100644
> index 000000000000..54930166ffee
> --- /dev/null
> +++ b/arch/x86/boot/compressed/early_sha256.c
> @@ -0,0 +1,6 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2022 Apertus Solutions, LLC
> + */
> +
> +#include "../../../../lib/crypto/sha256.c"
> diff --git a/include/crypto/sha1.h b/include/crypto/sha1.h
> index 044ecea60ac8..d715dd5332e1 100644
> --- a/include/crypto/sha1.h
> +++ b/include/crypto/sha1.h
> @@ -42,5 +42,6 @@ extern int crypto_sha1_finup(struct shash_desc *desc, const u8 *data,
>  #define SHA1_WORKSPACE_WORDS   16
>  void sha1_init(__u32 *buf);
>  void sha1_transform(__u32 *digest, const char *data, __u32 *W);
> +void sha1(const u8 *data, unsigned int len, u8 *out);
>
>  #endif /* _CRYPTO_SHA1_H */
> diff --git a/lib/crypto/sha1.c b/lib/crypto/sha1.c
> index 1aebe7be9401..10152125b338 100644
> --- a/lib/crypto/sha1.c
> +++ b/lib/crypto/sha1.c
> @@ -137,4 +137,85 @@ void sha1_init(__u32 *buf)
>  }
>  EXPORT_SYMBOL(sha1_init);
>
> +static void __sha1_transform(u32 *digest, const char *data)
> +{
> +       u32 ws[SHA1_WORKSPACE_WORDS];
> +
> +       sha1_transform(digest, data, ws);
> +
> +       memzero_explicit(ws, sizeof(ws));
> +}
> +
> +static void sha1_update(struct sha1_state *sctx, const u8 *data, unsigned int len)
> +{
> +       unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> +
> +       sctx->count += len;
> +
> +       if (likely((partial + len) >= SHA1_BLOCK_SIZE)) {
> +               int blocks;
> +
> +               if (partial) {
> +                       int p = SHA1_BLOCK_SIZE - partial;
> +
> +                       memcpy(sctx->buffer + partial, data, p);
> +                       data += p;
> +                       len -= p;
> +
> +                       __sha1_transform(sctx->state, sctx->buffer);
> +               }
> +
> +               blocks = len / SHA1_BLOCK_SIZE;
> +               len %= SHA1_BLOCK_SIZE;
> +
> +               if (blocks) {
> +                       while (blocks--) {
> +                               __sha1_transform(sctx->state, data);
> +                               data += SHA1_BLOCK_SIZE;
> +                       }
> +               }
> +               partial = 0;
> +       }
> +
> +       if (len)
> +               memcpy(sctx->buffer + partial, data, len);
> +}
> +
> +static void sha1_final(struct sha1_state *sctx, u8 *out)
> +{
> +       const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> +       unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> +       __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
> +       __be32 *digest = (__be32 *)out;
> +       int i;
> +
> +       sctx->buffer[partial++] = 0x80;
> +       if (partial > bit_offset) {
> +               memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial);
> +               partial = 0;
> +
> +               __sha1_transform(sctx->state, sctx->buffer);
> +       }
> +
> +       memset(sctx->buffer + partial, 0x0, bit_offset - partial);
> +       *bits = cpu_to_be64(sctx->count << 3);
> +       __sha1_transform(sctx->state, sctx->buffer);
> +
> +       for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
> +               put_unaligned_be32(sctx->state[i], digest++);
> +
> +       *sctx = (struct sha1_state){};
> +}
> +
> +void sha1(const u8 *data, unsigned int len, u8 *out)
> +{
> +       struct sha1_state sctx = {0};
> +
> +       sha1_init(sctx.state);
> +       sctx.count = 0;
> +       sha1_update(&sctx, data, len);
> +       sha1_final(&sctx, out);
> +}
> +EXPORT_SYMBOL(sha1);
> +
>  MODULE_LICENSE("GPL");
> --
> 2.39.3
>
Ard Biesheuvel Feb. 15, 2024, 8:29 a.m. UTC | #4
On Wed, 14 Feb 2024 at 23:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>
> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
> later AMD SKINIT) to vector to during the late launch. The symbol
> sl_stub_entry is that entry point and its offset into the kernel is
> conveyed to the launching code using the MLE (Measured Launch
> Environment) header in the structure named mle_header. The offset of the
> MLE header is set in the kernel_info. The routine sl_stub contains the
> very early late launch setup code responsible for setting up the basic
> environment to allow the normal kernel startup_32 code to proceed. It is
> also responsible for properly waking and handling the APs on Intel
> platforms. The routine sl_main which runs after entering 64b mode is
> responsible for measuring configuration and module information before
> it is used like the boot params, the kernel command line, the TXT heap,
> an external initramfs, etc.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
>  Documentation/arch/x86/boot.rst        |  21 +
>  arch/x86/boot/compressed/Makefile      |   3 +-
>  arch/x86/boot/compressed/head_64.S     |  34 ++
>  arch/x86/boot/compressed/kernel_info.S |  34 ++
>  arch/x86/boot/compressed/sl_main.c     | 582 ++++++++++++++++++++
>  arch/x86/boot/compressed/sl_stub.S     | 705 +++++++++++++++++++++++++
>  arch/x86/include/asm/msr-index.h       |   5 +
>  arch/x86/include/uapi/asm/bootparam.h  |   1 +
>  arch/x86/kernel/asm-offsets.c          |  20 +
>  9 files changed, 1404 insertions(+), 1 deletion(-)
>  create mode 100644 arch/x86/boot/compressed/sl_main.c
>  create mode 100644 arch/x86/boot/compressed/sl_stub.S
>
> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
> index c513855a54bb..ce6a51c6d4e7 100644
> --- a/Documentation/arch/x86/boot.rst
> +++ b/Documentation/arch/x86/boot.rst
> @@ -482,6 +482,14 @@ Protocol:  2.00+
>             - If 1, KASLR enabled.
>             - If 0, KASLR disabled.
>
> +  Bit 2 (kernel internal): SLAUNCH_FLAG
> +
> +       - Used internally by the compressed kernel to communicate

decompressor

> +         Secure Launch status to kernel proper.
> +
> +           - If 1, Secure Launch enabled.
> +           - If 0, Secure Launch disabled.
> +
>    Bit 5 (write): QUIET_FLAG
>
>         - If 0, print early messages.
> @@ -1027,6 +1035,19 @@ Offset/size:     0x000c/4
>
>    This field contains maximal allowed type for setup_data and setup_indirect structs.
>
> +============   =================
> +Field name:    mle_header_offset
> +Offset/size:   0x0010/4
> +============   =================
> +
> +  This field contains the offset to the Secure Launch Measured Launch Environment
> +  (MLE) header. This offset is used to locate information needed during a secure
> +  late launch using Intel TXT. If the offset is zero, the kernel does not have
> +  Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
> +  following a success measured launch. The specific state of the processors is
> +  outlined in the TXT Software Development Guide, the latest can be found here:
> +  https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
> +
>
>  The Image Checksum
>  ==================
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index a1b018eb9801..012f7ca780c3 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>  vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>  vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>
> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
> +       $(obj)/sl_main.o $(obj)/sl_stub.o
>
>  $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>         $(call if_changed,ld)
> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> index bf4a10a5794f..6fa5bb87195b 100644
> --- a/arch/x86/boot/compressed/head_64.S
> +++ b/arch/x86/boot/compressed/head_64.S
> @@ -415,6 +415,17 @@ SYM_CODE_START(startup_64)
>         pushq   $0
>         popfq
>
> +#ifdef CONFIG_SECURE_LAUNCH
> +       pushq   %rsi
> +

This push and the associated pop are no longer needed.

> +       /* Ensure the relocation region coverd by a PMR */

'is covered'

> +       movq    %rbx, %rdi
> +       movl    $(_bss - startup_32), %esi
> +       callq   sl_check_region
> +
> +       popq    %rsi
> +#endif
> +
>  /*
>   * Copy the compressed kernel to the end of our buffer
>   * where decompression in place becomes safe.
> @@ -457,6 +468,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
>         shrq    $3, %rcx
>         rep     stosq
>
> +#ifdef CONFIG_SECURE_LAUNCH
> +       /*
> +        * Have to do the final early sl stub work in 64b area.
> +        *
> +        * *********** NOTE ***********
> +        *
> +        * Several boot params get used before we get a chance to measure
> +        * them in this call. This is a known issue and we currently don't
> +        * have a solution. The scratch field doesn't matter. There is no
> +        * obvious way to do anything about the use of kernel_alignment or
> +        * init_size though these seem low risk with all the PMR and overlap
> +        * checks in place.
> +        */
> +       movq    %r15, %rdi
> +       callq   sl_main
> +
> +       /* Ensure the decompression location is coverd by a PMR */

covered

> +       movq    %rbp, %rdi
> +       movq    output_len(%rip), %rsi
> +       callq   sl_check_region
> +#endif
> +
> +       pushq   %rsi
>         call    load_stage2_idt
>
>         /* Pass boot_params to initialize_identity_maps() */
> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
> index c18f07181dd5..e199b87764e9 100644
> --- a/arch/x86/boot/compressed/kernel_info.S
> +++ b/arch/x86/boot/compressed/kernel_info.S
> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
>         /* Maximal allowed type for setup_data and setup_indirect structs. */
>         .long   SETUP_TYPE_MAX
>
> +       /* Offset to the MLE header structure */
> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> +       .long   rva(mle_header)
> +#else
> +       .long   0
> +#endif
> +
>  kernel_info_var_len_data:
>         /* Empty for time being... */
>  SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
> +
> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> +       /*
> +        * The MLE Header per the TXT Specification, section 2.1
> +        * MLE capabilities, see table 4. Capabilities set:
> +        * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
> +        * bit 1: Support for RLP wakeup using MONITOR address
> +        * bit 2: The ECX register will contain the pointer to the MLE page table
> +        * bit 5: TPM 1.2 family: Details/authorities PCR usage support
> +        * bit 9: Supported format of TPM 2.0 event log - TCG compliant
> +        */
> +SYM_DATA_START(mle_header)
> +       .long   0x9082ac5a  /* UUID0 */
> +       .long   0x74a7476f  /* UUID1 */
> +       .long   0xa2555c0f  /* UUID2 */
> +       .long   0x42b651cb  /* UUID3 */
> +       .long   0x00000034  /* MLE header size */
> +       .long   0x00020002  /* MLE version 2.2 */
> +       .long   rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
> +       .long   0x00000000  /* First valid page of MLE */
> +       .long   0x00000000  /* Offset within binary of first byte of MLE */
> +       .long   rva(_edata) /* Offset within binary of last byte + 1 of MLE */
> +       .long   0x00000227  /* Bit vector of MLE-supported capabilities */
> +       .long   0x00000000  /* Starting linear address of command line (unused) */
> +       .long   0x00000000  /* Ending linear address of command line (unused) */
> +SYM_DATA_END(mle_header)
> +#endif
> diff --git a/arch/x86/boot/compressed/sl_main.c b/arch/x86/boot/compressed/sl_main.c
> new file mode 100644
> index 000000000000..cd9e5c1f1719
> --- /dev/null
> +++ b/arch/x86/boot/compressed/sl_main.c
> @@ -0,0 +1,582 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Secure Launch early measurement and validation routines.
> + *
> + * Copyright (c) 2022, Oracle and/or its affiliates.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/string.h>
> +#include <linux/linkage.h>
> +#include <asm/segment.h>
> +#include <asm/boot.h>
> +#include <asm/msr.h>
> +#include <asm/mtrr.h>
> +#include <asm/processor-flags.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/bootparam.h>
> +#include <asm/bootparam_utils.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
> +#include <crypto/sha1.h>
> +#include <crypto/sha2.h>
> +
> +#define CAPS_VARIABLE_MTRR_COUNT_MASK  0xff
> +
> +#define SL_TPM12_LOG           1
> +#define SL_TPM20_LOG           2
> +
> +#define SL_TPM20_MAX_ALGS      2
> +
> +#define SL_MAX_EVENT_DATA      64
> +#define SL_TPM12_LOG_SIZE      (sizeof(struct tcg_pcr_event) + \
> +                               SL_MAX_EVENT_DATA)
> +#define SL_TPM20_LOG_SIZE      (sizeof(struct tcg_pcr_event2_head) + \
> +                               SHA1_DIGEST_SIZE + SHA256_DIGEST_SIZE + \
> +                               sizeof(struct tcg_event_field) + \
> +                               SL_MAX_EVENT_DATA)
> +
> +static void *evtlog_base;
> +static u32 evtlog_size;
> +static struct txt_heap_event_log_pointer2_1_element *log20_elem;
> +static u32 tpm_log_ver = SL_TPM12_LOG;
> +static struct tcg_efi_specid_event_algs tpm_algs[SL_TPM20_MAX_ALGS] = {0};
> +
> +extern u32 sl_cpu_type;
> +extern u32 sl_mle_start;
> +
> +static u64 sl_txt_read(u32 reg)
> +{
> +       return readq((void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
> +}
> +
> +static void sl_txt_write(u32 reg, u64 val)
> +{
> +       writeq(val, (void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
> +}
> +
> +static void __noreturn sl_txt_reset(u64 error)
> +{
> +       /* Reading the E2STS register acts as a barrier for TXT registers */
> +       sl_txt_write(TXT_CR_ERRORCODE, error);
> +       sl_txt_read(TXT_CR_E2STS);
> +       sl_txt_write(TXT_CR_CMD_UNLOCK_MEM_CONFIG, 1);
> +       sl_txt_read(TXT_CR_E2STS);
> +       sl_txt_write(TXT_CR_CMD_RESET, 1);
> +
> +       for ( ; ; )
> +               asm volatile ("hlt");
> +
> +       unreachable();
> +}
> +
> +static u64 sl_rdmsr(u32 reg)
> +{
> +       u64 lo, hi;
> +
> +       asm volatile ("rdmsr" : "=a" (lo), "=d" (hi) : "c" (reg));
> +

No need for volatile.

> +       return (hi << 32) | lo;
> +}
> +
> +static struct slr_table *sl_locate_and_validate_slrt(void)
> +{
> +       struct txt_os_mle_data *os_mle_data;
> +       struct slr_table *slrt;
> +       void *txt_heap;
> +
> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> +       os_mle_data = txt_os_mle_data_start(txt_heap);
> +
> +       if (!os_mle_data->slrt)
> +               sl_txt_reset(SL_ERROR_INVALID_SLRT);
> +
> +       slrt = (struct slr_table *)os_mle_data->slrt;
> +
> +       if (slrt->magic != SLR_TABLE_MAGIC)
> +               sl_txt_reset(SL_ERROR_INVALID_SLRT);
> +
> +       if (slrt->architecture != SLR_INTEL_TXT)
> +               sl_txt_reset(SL_ERROR_INVALID_SLRT);
> +
> +       return slrt;
> +}
> +
> +static void sl_check_pmr_coverage(void *base, u32 size, bool allow_hi)
> +{
> +       struct txt_os_sinit_data *os_sinit_data;
> +       void *end = base + size;
> +       void *txt_heap;
> +
> +       if (!(sl_cpu_type & SL_CPU_INTEL))
> +               return;
> +
> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> +       os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> +       if ((end >= (void *)0x100000000ULL) && (base < (void *)0x100000000ULL))
> +               sl_txt_reset(SL_ERROR_REGION_STRADDLE_4GB);
> +
> +       /*
> +        * Note that the late stub code validates that the hi PMR covers
> +        * all memory above 4G. At this point the code can only check that
> +        * regions are within the hi PMR but that is sufficient.
> +        */
> +       if ((end > (void *)0x100000000ULL) && (base >= (void *)0x100000000ULL)) {
> +               if (allow_hi) {
> +                       if (end >= (void *)(os_sinit_data->vtd_pmr_hi_base +
> +                                          os_sinit_data->vtd_pmr_hi_size))
> +                               sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
> +               } else {
> +                       sl_txt_reset(SL_ERROR_REGION_ABOVE_4GB);
> +               }
> +       }
> +
> +       if (end >= (void *)os_sinit_data->vtd_pmr_lo_size)
> +               sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
> +}
> +
> +/*
> + * Some MSRs are modified by the pre-launch code including the MTRRs.
> + * The early MLE code has to restore these values. This code validates
> + * the values after they are measured.
> + */
> +static void sl_txt_validate_msrs(struct txt_os_mle_data *os_mle_data)
> +{
> +       struct slr_txt_mtrr_state *saved_bsp_mtrrs;
> +       u64 mtrr_caps, mtrr_def_type, mtrr_var;
> +       struct slr_entry_intel_info *txt_info;
> +       u64 misc_en_msr;
> +       u32 vcnt, i;
> +
> +       txt_info = (struct slr_entry_intel_info *)os_mle_data->txt_info;
> +       saved_bsp_mtrrs = &txt_info->saved_bsp_mtrrs;
> +
> +       mtrr_caps = sl_rdmsr(MSR_MTRRcap);
> +       vcnt = (u32)(mtrr_caps & CAPS_VARIABLE_MTRR_COUNT_MASK);
> +
> +       if (saved_bsp_mtrrs->mtrr_vcnt > vcnt)
> +               sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
> +       if (saved_bsp_mtrrs->mtrr_vcnt > TXT_OS_MLE_MAX_VARIABLE_MTRRS)
> +               sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
> +
> +       mtrr_def_type = sl_rdmsr(MSR_MTRRdefType);
> +       if (saved_bsp_mtrrs->default_mem_type != mtrr_def_type)
> +               sl_txt_reset(SL_ERROR_MTRR_INV_DEF_TYPE);
> +
> +       for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; i++) {
> +               mtrr_var = sl_rdmsr(MTRRphysBase_MSR(i));
> +               if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase != mtrr_var)
> +                       sl_txt_reset(SL_ERROR_MTRR_INV_BASE);
> +               mtrr_var = sl_rdmsr(MTRRphysMask_MSR(i));
> +               if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask != mtrr_var)
> +                       sl_txt_reset(SL_ERROR_MTRR_INV_MASK);
> +       }
> +
> +       misc_en_msr = sl_rdmsr(MSR_IA32_MISC_ENABLE);
> +       if (txt_info->saved_misc_enable_msr != misc_en_msr)
> +               sl_txt_reset(SL_ERROR_MSR_INV_MISC_EN);
> +}
> +
> +static void sl_find_drtm_event_log(struct slr_table *slrt)
> +{
> +       struct txt_os_sinit_data *os_sinit_data;
> +       struct slr_entry_log_info *log_info;
> +       void *txt_heap;
> +
> +       log_info = (struct slr_entry_log_info *)
> +                   slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
> +       if (!log_info)
> +               sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
> +
> +       evtlog_base = (void *)log_info->addr;
> +       evtlog_size = log_info->size;
> +
> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> +
> +       /*
> +        * For TPM 2.0, the event log 2.1 extended data structure has to also
> +        * be located and fixed up.
> +        */
> +       os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> +       /*
> +        * Only support version 6 and later that properly handle the
> +        * list of ExtDataElements in the OS-SINIT structure.
> +        */
> +       if (os_sinit_data->version < 6)
> +               sl_txt_reset(SL_ERROR_OS_SINIT_BAD_VERSION);
> +
> +       /* Find the TPM2.0 logging extended heap element */
> +       log20_elem = tpm20_find_log2_1_element(os_sinit_data);
> +
> +       /* If found, this implies TPM20 log and family */
> +       if (log20_elem)
> +               tpm_log_ver = SL_TPM20_LOG;
> +}
> +
> +static void sl_validate_event_log_buffer(void)
> +{
> +       struct txt_os_sinit_data *os_sinit_data;
> +       void *txt_heap, *txt_end;
> +       void *mle_base, *mle_end;
> +       void *evtlog_end;
> +
> +       if ((u64)evtlog_size > (LLONG_MAX - (u64)evtlog_base))
> +               sl_txt_reset(SL_ERROR_INTEGER_OVERFLOW);
> +       evtlog_end = evtlog_base + evtlog_size;
> +
> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> +       txt_end = txt_heap + sl_txt_read(TXT_CR_HEAP_SIZE);
> +       os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> +       mle_base = (void *)(u64)sl_mle_start;
> +       mle_end = mle_base + os_sinit_data->mle_size;
> +
> +       /*
> +        * This check is to ensure the event log buffer does not overlap with
> +        * the MLE image.
> +        */
> +       if (evtlog_base >= mle_end && evtlog_end > mle_end)
> +               goto pmr_check; /* above */
> +
> +       if (evtlog_end <= mle_base && evtlog_base < mle_base)
> +               goto pmr_check; /* below */
> +
> +       sl_txt_reset(SL_ERROR_MLE_BUFFER_OVERLAP);
> +
> +pmr_check:
> +       /*
> +        * The TXT heap is protected by the DPR. If the TPM event log is
> +        * inside the TXT heap, there is no need for a PMR check.
> +        */
> +       if (evtlog_base > txt_heap && evtlog_end < txt_end)
> +               return;
> +
> +       sl_check_pmr_coverage(evtlog_base, evtlog_size, true);
> +}
> +
> +static void sl_find_event_log_algorithms(void)
> +{
> +       struct tcg_efi_specid_event_head *efi_head =
> +               (struct tcg_efi_specid_event_head *)(evtlog_base +
> +                                       log20_elem->first_record_offset +
> +                                       sizeof(struct tcg_pcr_event));
> +
> +       if (efi_head->num_algs == 0 || efi_head->num_algs > 2)
> +               sl_txt_reset(SL_ERROR_TPM_NUMBER_ALGS);
> +
> +       memcpy(&tpm_algs[0], &efi_head->digest_sizes[0],
> +              sizeof(struct tcg_efi_specid_event_algs) * efi_head->num_algs);
> +}
> +
> +static void sl_tpm12_log_event(u32 pcr, u32 event_type,
> +                              const u8 *data, u32 length,
> +                              const u8 *event_data, u32 event_size)
> +{
> +       u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
> +       u8 log_buf[SL_TPM12_LOG_SIZE] = {0};
> +       struct tcg_pcr_event *pcr_event;
> +       u32 total_size;
> +
> +       pcr_event = (struct tcg_pcr_event *)log_buf;
> +       pcr_event->pcr_idx = pcr;
> +       pcr_event->event_type = event_type;
> +       if (length > 0) {
> +               sha1(data, length, &sha1_hash[0]);
> +               memcpy(&pcr_event->digest[0], &sha1_hash[0], SHA1_DIGEST_SIZE);
> +       }
> +       pcr_event->event_size = event_size;
> +       if (event_size > 0)
> +               memcpy((u8 *)pcr_event + sizeof(struct tcg_pcr_event),
> +                      event_data, event_size);
> +
> +       total_size = sizeof(struct tcg_pcr_event) + event_size;
> +
> +       if (tpm12_log_event(evtlog_base, evtlog_size, total_size, pcr_event))
> +               sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
> +}
> +
> +static void sl_tpm20_log_event(u32 pcr, u32 event_type,
> +                              const u8 *data, u32 length,
> +                              const u8 *event_data, u32 event_size)
> +{
> +       u8 sha256_hash[SHA256_DIGEST_SIZE] = {0};
> +       u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
> +       u8 log_buf[SL_TPM20_LOG_SIZE] = {0};
> +       struct sha256_state sctx256 = {0};
> +       struct tcg_pcr_event2_head *head;
> +       struct tcg_event_field *event;
> +       u32 total_size;
> +       u16 *alg_ptr;
> +       u8 *dgst_ptr;
> +
> +       head = (struct tcg_pcr_event2_head *)log_buf;
> +       head->pcr_idx = pcr;
> +       head->event_type = event_type;
> +       total_size = sizeof(struct tcg_pcr_event2_head);
> +       alg_ptr = (u16 *)(log_buf + sizeof(struct tcg_pcr_event2_head));
> +
> +       for ( ; head->count < 2; head->count++) {
> +               if (!tpm_algs[head->count].alg_id)
> +                       break;
> +
> +               *alg_ptr = tpm_algs[head->count].alg_id;
> +               dgst_ptr = (u8 *)alg_ptr + sizeof(u16);
> +
> +               if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256 &&
> +                   length) {
> +                       sha256_init(&sctx256);
> +                       sha256_update(&sctx256, data, length);
> +                       sha256_final(&sctx256, &sha256_hash[0]);
> +               } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1 &&
> +                          length) {
> +                       sha1(data, length, &sha1_hash[0]);
> +               }
> +
> +               if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256) {
> +                       memcpy(dgst_ptr, &sha256_hash[0], SHA256_DIGEST_SIZE);
> +                       total_size += SHA256_DIGEST_SIZE + sizeof(u16);
> +                       alg_ptr = (u16 *)((u8 *)alg_ptr + SHA256_DIGEST_SIZE + sizeof(u16));
> +               } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1) {
> +                       memcpy(dgst_ptr, &sha1_hash[0], SHA1_DIGEST_SIZE);
> +                       total_size += SHA1_DIGEST_SIZE + sizeof(u16);
> +                       alg_ptr = (u16 *)((u8 *)alg_ptr + SHA1_DIGEST_SIZE + sizeof(u16));
> +               } else {
> +                       sl_txt_reset(SL_ERROR_TPM_UNKNOWN_DIGEST);
> +               }
> +       }
> +
> +       event = (struct tcg_event_field *)(log_buf + total_size);
> +       event->event_size = event_size;
> +       if (event_size > 0)
> +               memcpy((u8 *)event + sizeof(struct tcg_event_field), event_data, event_size);
> +       total_size += sizeof(struct tcg_event_field) + event_size;
> +
> +       if (tpm20_log_event(log20_elem, evtlog_base, evtlog_size, total_size, &log_buf[0]))
> +               sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
> +}
> +
> +static void sl_tpm_extend_evtlog(u32 pcr, u32 type,
> +                                const u8 *data, u32 length, const char *desc)
> +{
> +       if (tpm_log_ver == SL_TPM20_LOG)
> +               sl_tpm20_log_event(pcr, type, data, length,
> +                                  (const u8 *)desc, strlen(desc));
> +       else
> +               sl_tpm12_log_event(pcr, type, data, length,
> +                                  (const u8 *)desc, strlen(desc));
> +}
> +
> +static struct setup_data *sl_handle_setup_data(struct setup_data *curr,
> +                                              struct slr_policy_entry *entry)
> +{
> +       struct setup_indirect *ind;
> +       struct setup_data *next;
> +
> +       if (!curr)
> +               return NULL;
> +
> +       next = (struct setup_data *)(unsigned long)curr->next;
> +
> +       /* SETUP_INDIRECT instances have to be handled differently */
> +       if (curr->type == SETUP_INDIRECT) {
> +               ind = (struct setup_indirect *)((u8 *)curr + offsetof(struct setup_data, data));
> +
> +               sl_check_pmr_coverage((void *)ind->addr, ind->len, true);
> +
> +               sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> +                                    (void *)ind->addr, ind->len,
> +                                    entry->evt_info);
> +
> +               return next;
> +       }
> +
> +       sl_check_pmr_coverage(((u8 *)curr) + sizeof(struct setup_data),
> +                             curr->len, true);
> +
> +       sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> +                            ((u8 *)curr) + sizeof(struct setup_data),
> +                            curr->len,
> +                            entry->evt_info);
> +
> +       return next;
> +}
> +
> +static void sl_extend_setup_data(struct slr_policy_entry *entry)
> +{
> +       struct setup_data *data;
> +
> +       /*
> +        * Measuring the boot params measured the fixed e820 memory map.
> +        * Measure any setup_data entries including e820 extended entries.
> +        */
> +       data = (struct setup_data *)(unsigned long)entry->entity;
> +       while (data)
> +               data = sl_handle_setup_data(data, entry);
> +}
> +
> +static void sl_extend_slrt(struct slr_policy_entry *entry)
> +{
> +       struct slr_table *slrt = (struct slr_table *)entry->entity;
> +       struct slr_entry_intel_info *intel_info;
> +
> +       /*
> +        * In revision one of the SLRT, the only table that needs to be
> +        * measured is the Intel info table. Everything else is meta-data,
> +        * addresses and sizes. Note the size of what to measure is not set.
> +        * The flag SLR_POLICY_IMPLICIT_SIZE leaves it to the measuring code
> +        * to sort out.
> +        */
> +       if (slrt->revision == 1) {
> +               intel_info = (struct slr_entry_intel_info *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
> +               if (!intel_info)
> +                       sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
> +
> +               sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> +                                    (void *)entry->entity, sizeof(struct slr_entry_intel_info),
> +                                    entry->evt_info);
> +       }
> +}
> +
> +static void sl_extend_txt_os2mle(struct slr_policy_entry *entry)
> +{
> +       struct txt_os_mle_data *os_mle_data;
> +       void *txt_heap;
> +
> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> +       os_mle_data = txt_os_mle_data_start(txt_heap);
> +
> +       /*
> +        * Version 1 of the OS-MLE heap structure has no fields to measure. It just
> +        * has addresses and sizes and a scratch buffer.
> +        */
> +       if (os_mle_data->version == 1)
> +               return;
> +}
> +
> +static void sl_process_extend_policy(struct slr_table *slrt)
> +{
> +       struct slr_entry_policy *policy;
> +       struct slr_policy_entry *entry;
> +       u16 i;
> +
> +       policy = (struct slr_entry_policy *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
> +       if (!policy)
> +               sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
> +
> +       entry = (struct slr_policy_entry *)((u8 *)policy + sizeof(*policy));
> +
> +       for (i = 0; i < policy->nr_entries; i++, entry++) {
> +               switch (entry->entity_type) {
> +               case SLR_ET_SETUP_DATA:
> +                       sl_extend_setup_data(entry);
> +                       break;
> +               case SLR_ET_SLRT:
> +                       sl_extend_slrt(entry);
> +                       break;
> +               case SLR_ET_TXT_OS2MLE:
> +                       sl_extend_txt_os2mle(entry);
> +                       break;
> +               case SLR_ET_UNUSED:
> +                       continue;
> +               default:
> +                       sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> +                                            (void *)entry->entity, entry->size,
> +                                            entry->evt_info);
> +               }
> +       }
> +}
> +
> +static void sl_process_extend_uefi_config(struct slr_table *slrt)
> +{
> +       struct slr_entry_uefi_config *uefi_config;
> +       struct slr_uefi_cfg_entry *uefi_entry;
> +       u64 i;
> +
> +       uefi_config =(struct slr_entry_uefi_config *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_UEFI_CONFIG);
> +
> +       /* Optionally here depending on how SL kernel was booted */
> +       if (!uefi_config)
> +               return;
> +
> +       uefi_entry = (struct slr_uefi_cfg_entry *)((u8 *)uefi_config + sizeof(*uefi_config));
> +
> +       for (i = 0; i < uefi_config->nr_entries; i++, uefi_entry++) {
> +               sl_tpm_extend_evtlog(uefi_entry->pcr, TXT_EVTYPE_SLAUNCH,
> +                                    (void *)uefi_entry->cfg, uefi_entry->size,
> +                                    uefi_entry->evt_info);
> +       }
> +}
> +
> +asmlinkage __visible void sl_check_region(void *base, u32 size)
> +{
> +       sl_check_pmr_coverage(base, size, false);
> +}
> +
> +asmlinkage __visible void sl_main(void *bootparams)
> +{
> +       struct boot_params *bp  = (struct boot_params *)bootparams;
> +       struct txt_os_mle_data *os_mle_data;
> +       struct slr_table *slrt;
> +       void *txt_heap;
> +
> +       /*
> +        * Ensure loadflags do not indicate a secure launch was done
> +        * unless it really was.
> +        */
> +       bp->hdr.loadflags &= ~SLAUNCH_FLAG;
> +
> +       /*
> +        * Currently only Intel TXT is supported for Secure Launch. Testing
> +        * this value also indicates that the kernel was booted successfully
> +        * through the Secure Launch entry point and is in SMX mode.
> +        */
> +       if (!(sl_cpu_type & SL_CPU_INTEL))
> +               return;
> +
> +       slrt = sl_locate_and_validate_slrt();
> +
> +       /* Locate the TPM event log. */
> +       sl_find_drtm_event_log(slrt);
> +
> +       /* Validate the location of the event log buffer before using it */
> +       sl_validate_event_log_buffer();
> +
> +       /*
> +        * Find the TPM hash algorithms used by the ACM and recorded in the
> +        * event log.
> +        */
> +       if (tpm_log_ver == SL_TPM20_LOG)
> +               sl_find_event_log_algorithms();
> +
> +       /*
> +        * Sanitize them before measuring. Set the SLAUNCH_FLAG early since if
> +        * anything fails, the system will reset anyway.
> +        */
> +       sanitize_boot_params(bp);
> +       bp->hdr.loadflags |= SLAUNCH_FLAG;
> +
> +       sl_check_pmr_coverage(bootparams, PAGE_SIZE, false);
> +
> +       /* Place event log SL specific tags before and after measurements */
> +       sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_START, NULL, 0, "");
> +
> +       /* Process all policy entries and extend the measurements to the evtlog */
> +       sl_process_extend_policy(slrt);
> +
> +       /* Process all EFI config entries and extend the measurements to the evtlog */
> +       sl_process_extend_uefi_config(slrt);
> +
> +       sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_END, NULL, 0, "");
> +
> +       /* No PMR check is needed, the TXT heap is covered by the DPR */
> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> +       os_mle_data = txt_os_mle_data_start(txt_heap);
> +
> +       /*
> +        * Now that the OS-MLE data is measured, ensure the MTRR and
> +        * misc enable MSRs are what we expect.
> +        */
> +       sl_txt_validate_msrs(os_mle_data);
> +}
> diff --git a/arch/x86/boot/compressed/sl_stub.S b/arch/x86/boot/compressed/sl_stub.S
> new file mode 100644
> index 000000000000..42a7436cf2ee
> --- /dev/null
> +++ b/arch/x86/boot/compressed/sl_stub.S
> @@ -0,0 +1,705 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/*
> + * Secure Launch protected mode entry point.
> + *
> + * Copyright (c) 2022, Oracle and/or its affiliates.
> + */
> +       .code32
> +       .text
> +#include <linux/linkage.h>
> +#include <asm/segment.h>
> +#include <asm/msr.h>
> +#include <asm/apicdef.h>
> +#include <asm/trapnr.h>
> +#include <asm/processor-flags.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/bootparam.h>
> +#include <asm/page_types.h>
> +#include <asm/irq_vectors.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
> +
> +/* CPUID: leaf 1, ECX, SMX feature bit */
> +#define X86_FEATURE_BIT_SMX    (1 << 6)
> +
> +#define IDT_VECTOR_LO_BITS     0
> +#define IDT_VECTOR_HI_BITS     6
> +
> +/*
> + * See the comment in head_64.S for detailed information on what this macro
> + * and others like it are used for. The comment appears right at the top of
> + * the file.
> + */
> +#define rva(X) ((X) - sl_stub_entry)
> +
> +/*
> + * The GETSEC op code is open coded because older versions of
> + * GCC do not support the getsec mnemonic.
> + */
> +.macro GETSEC leaf
> +       pushl   %ebx
> +       xorl    %ebx, %ebx      /* Must be zero for SMCTRL */
> +       movl    \leaf, %eax     /* Leaf function */
> +       .byte   0x0f, 0x37      /* GETSEC opcode */
> +       popl    %ebx
> +.endm
> +
> +.macro TXT_RESET error
> +       /*
> +        * Set a sticky error value and reset. Note the movs to %eax act as
> +        * TXT register barriers.
> +        */
> +       movl    \error, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
> +       movl    $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_NO_SECRETS)
> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
> +       movl    $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_UNLOCK_MEM_CONFIG)
> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
> +       movl    $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_RESET)
> +1:
> +       hlt
> +       jmp     1b
> +.endm
> +
> +       .code32
> +SYM_FUNC_START(sl_stub_entry)
> +       cli
> +       cld
> +
> +       /*
> +        * On entry, %ebx has the entry abs offset to sl_stub_entry. This
> +        * will be correctly scaled using the rva macro and avoid causing
> +        * relocations. Only %cs and %ds segments are known good.
> +        */
> +
> +       /* Load GDT, set segment regs and lret to __SL32_CS */
> +       leal    rva(sl_gdt_desc)(%ebx), %eax
> +       addl    %eax, 2(%eax)
> +       lgdt    (%eax)
> +
> +       movl    $(__SL32_DS), %eax
> +       movw    %ax, %ds
> +       movw    %ax, %es
> +       movw    %ax, %fs
> +       movw    %ax, %gs
> +       movw    %ax, %ss
> +
> +       /*
> +        * Now that %ss is known good, take the first stack for the BSP. The
> +        * AP stacks are only used on Intel.
> +        */
> +       leal    rva(sl_stacks_end)(%ebx), %esp
> +
> +       leal    rva(.Lsl_cs)(%ebx), %eax
> +       pushl   $(__SL32_CS)
> +       pushl   %eax
> +       lret
> +
> +.Lsl_cs:
> +       /* Save our base pointer reg and page table for MLE */
> +       pushl   %ebx
> +       pushl   %ecx
> +
> +       /* See if SMX feature is supported. */
> +       movl    $1, %eax
> +       cpuid
> +       testl   $(X86_FEATURE_BIT_SMX), %ecx
> +       jz      .Ldo_unknown_cpu
> +
> +       popl    %ecx
> +       popl    %ebx
> +
> +       /* Know it is Intel */
> +       movl    $(SL_CPU_INTEL), rva(sl_cpu_type)(%ebx)
> +
> +       /* Locate the base of the MLE using the page tables in %ecx */
> +       call    sl_find_mle_base
> +
> +       /* Increment CPU count for BSP */
> +       incl    rva(sl_txt_cpu_count)(%ebx)
> +
> +       /*
> +        * Enable SMI with GETSEC[SMCTRL] which were disabled by SENTER.
> +        * NMIs were also disabled by SENTER. Since there is no IDT for the BSP,
> +        * allow the mainline kernel re-enable them in the normal course of
> +        * booting.
> +        */
> +       GETSEC  $(SMX_X86_GETSEC_SMCTRL)
> +
> +       /* Clear the TXT error registers for a clean start of day */
> +       movl    $0, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
> +       movl    $0xffffffff, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ESTS)
> +
> +       /* On Intel, the zero page address is passed in the TXT heap */
> +       /* Read physical base of heap into EAX */
> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
> +       /* Read the size of the BIOS data into ECX (first 8 bytes) */
> +       movl    (%eax), %ecx
> +       /* Skip over BIOS data and size of OS to MLE data section */
> +       leal    8(%eax, %ecx), %eax
> +
> +       /* Need to verify the values in the OS-MLE struct passed in */
> +       call    sl_txt_verify_os_mle_struct
> +
> +       /*
> +        * Get the boot params address from the heap. Note %esi and %ebx MUST
> +        * be preserved across calls and operations.
> +        */
> +       movl    SL_boot_params_addr(%eax), %esi
> +
> +       /* Save %ebx so the APs can find their way home */
> +       movl    %ebx, (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax)
> +
> +       /* Fetch the AP wake code block address from the heap */
> +       movl    SL_ap_wake_block(%eax), %edi
> +       movl    %edi, rva(sl_txt_ap_wake_block)(%ebx)
> +
> +       /* Store the offset in the AP wake block to the jmp address */
> +       movl    $(sl_ap_jmp_offset - sl_txt_ap_wake_begin), \
> +               (SL_mle_scratch + SL_SCRATCH_AP_JMP_OFFSET)(%eax)
> +
> +       /* Store the offset in the AP wake block to the AP stacks block */
> +       movl    $(sl_stacks - sl_txt_ap_wake_begin), \
> +               (SL_mle_scratch + SL_SCRATCH_AP_STACKS_OFFSET)(%eax)
> +
> +       /* %eax still is the base of the OS-MLE block, save it */
> +       pushl   %eax
> +
> +       /* Relocate the AP wake code to the safe block */
> +       call    sl_txt_reloc_ap_wake
> +
> +       /*
> +        * Wake up all APs that are blocked in the ACM and wait for them to
> +        * halt. This should be done before restoring the MTRRs so the ACM is
> +        * still properly in WB memory.
> +        */
> +       call    sl_txt_wake_aps
> +
> +       /* Restore OS-MLE in %eax */
> +       popl    %eax
> +
> +       /*
> +        * %edi is used by this routine to find the MTRRs which are in the SLRT
> +        * in the Intel info.
> +        */
> +       movl    SL_txt_info(%eax), %edi
> +       call    sl_txt_load_regs
> +
> +       jmp     .Lcpu_setup_done
> +
> +.Ldo_unknown_cpu:
> +       /* Non-Intel CPUs are not yet supported */
> +       ud2
> +
> +.Lcpu_setup_done:
> +       /*
> +        * Don't enable MCE at this point. The kernel will enable
> +        * it on the BSP later when it is ready.
> +        */
> +
> +       /* Done, jump to normal 32b pm entry */
> +       jmp     startup_32
> +SYM_FUNC_END(sl_stub_entry)
> +
> +SYM_FUNC_START(sl_find_mle_base)
> +       /* %ecx has PDPT, get first PD */
> +       movl    (%ecx), %eax
> +       andl    $(PAGE_MASK), %eax
> +       /* Get first PT from first PDE */
> +       movl    (%eax), %eax
> +       andl    $(PAGE_MASK), %eax
> +       /* Get MLE base from first PTE */
> +       movl    (%eax), %eax
> +       andl    $(PAGE_MASK), %eax
> +
> +       movl    %eax, rva(sl_mle_start)(%ebx)
> +       ret
> +SYM_FUNC_END(sl_find_mle_base)
> +
> +SYM_FUNC_START(sl_check_buffer_mle_overlap)
> +       /* %ecx: buffer begin %edx: buffer end */
> +       /* %ebx: MLE begin %edi: MLE end */
> +
> +       cmpl    %edi, %ecx
> +       jb      .Lnext_check
> +       cmpl    %edi, %edx
> +       jbe     .Lnext_check
> +       jmp     .Lvalid /* Buffer above MLE */
> +
> +.Lnext_check:
> +       cmpl    %ebx, %edx
> +       ja      .Linvalid
> +       cmpl    %ebx, %ecx
> +       jae     .Linvalid
> +       jmp     .Lvalid /* Buffer below MLE */
> +
> +.Linvalid:
> +       TXT_RESET $(SL_ERROR_MLE_BUFFER_OVERLAP)
> +
> +.Lvalid:
> +       ret
> +SYM_FUNC_END(sl_check_buffer_mle_overlap)
> +
> +SYM_FUNC_START(sl_txt_verify_os_mle_struct)
> +       pushl   %ebx
> +       /*
> +        * %eax points to the base of the OS-MLE struct. Need to also
> +        * read some values from the OS-SINIT struct too.
> +        */
> +       movl    -8(%eax), %ecx
> +       /* Skip over OS to MLE data section and size of OS-SINIT structure */
> +       leal    (%eax, %ecx), %edx
> +
> +       /* Load MLE image base absolute offset */
> +       movl    rva(sl_mle_start)(%ebx), %ebx
> +
> +       /* Verify the value of the low PMR base. It should always be 0. */
> +       movl    SL_vtd_pmr_lo_base(%edx), %esi
> +       cmpl    $0, %esi
> +       jz      .Lvalid_pmr_base
> +       TXT_RESET $(SL_ERROR_LO_PMR_BASE)
> +
> +.Lvalid_pmr_base:
> +       /* Grab some values from OS-SINIT structure */
> +       movl    SL_mle_size(%edx), %edi
> +       addl    %ebx, %edi
> +       jc      .Loverflow_detected
> +       movl    SL_vtd_pmr_lo_size(%edx), %esi
> +
> +       /* Check the AP wake block */
> +       movl    SL_ap_wake_block(%eax), %ecx
> +       movl    SL_ap_wake_block_size(%eax), %edx
> +       addl    %ecx, %edx
> +       jc      .Loverflow_detected
> +       call    sl_check_buffer_mle_overlap
> +       cmpl    %esi, %edx
> +       ja      .Lbuffer_beyond_pmr
> +
> +       /* Check the boot params */
> +       movl    SL_boot_params_addr(%eax), %ecx
> +       movl    $(PAGE_SIZE), %edx
> +       addl    %ecx, %edx
> +       jc      .Loverflow_detected
> +       call    sl_check_buffer_mle_overlap
> +       cmpl    %esi, %edx
> +       ja      .Lbuffer_beyond_pmr
> +
> +       /* Check that the AP wake block is big enough */
> +       cmpl    $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), \
> +               SL_ap_wake_block_size(%eax)
> +       jae     .Lwake_block_ok
> +       TXT_RESET $(SL_ERROR_WAKE_BLOCK_TOO_SMALL)
> +
> +.Lwake_block_ok:
> +       popl    %ebx
> +       ret
> +
> +.Loverflow_detected:
> +       TXT_RESET $(SL_ERROR_INTEGER_OVERFLOW)
> +
> +.Lbuffer_beyond_pmr:
> +       TXT_RESET $(SL_ERROR_BUFFER_BEYOND_PMR)
> +SYM_FUNC_END(sl_txt_verify_os_mle_struct)
> +
> +SYM_FUNC_START(sl_txt_ap_entry)
> +       cli
> +       cld
> +       /*
> +        * The %cs and %ds segments are known good after waking the AP.
> +        * First order of business is to find where we are and
> +        * save it in %ebx.
> +        */
> +
> +       /* Read physical base of heap into EAX */
> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
> +       /* Read the size of the BIOS data into ECX (first 8 bytes) */
> +       movl    (%eax), %ecx
> +       /* Skip over BIOS data and size of OS to MLE data section */
> +       leal    8(%eax, %ecx), %eax
> +
> +       /* Saved %ebx from the BSP and stash OS-MLE pointer */
> +       movl    (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax), %ebx
> +
> +       /* Save TXT info ptr in %edi for call to sl_txt_load_regs */
> +       movl    SL_txt_info(%eax), %edi
> +
> +       /* Lock and get our stack index */
> +       movl    $1, %ecx
> +.Lspin:
> +       xorl    %eax, %eax
> +       lock cmpxchgl   %ecx, rva(sl_txt_spin_lock)(%ebx)
> +       pause
> +       jnz     .Lspin
> +
> +       /* Increment the stack index and use the next value inside lock */
> +       incl    rva(sl_txt_stack_index)(%ebx)
> +       movl    rva(sl_txt_stack_index)(%ebx), %eax
> +
> +       /* Unlock */
> +       movl    $0, rva(sl_txt_spin_lock)(%ebx)
> +
> +       /* Location of the relocated AP wake block */
> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %ecx
> +
> +       /* Load reloc GDT, set segment regs and lret to __SL32_CS */
> +       lgdt    (sl_ap_gdt_desc - sl_txt_ap_wake_begin)(%ecx)
> +
> +       movl    $(__SL32_DS), %edx
> +       movw    %dx, %ds
> +       movw    %dx, %es
> +       movw    %dx, %fs
> +       movw    %dx, %gs
> +       movw    %dx, %ss
> +
> +       /* Load our reloc AP stack */
> +       movl    $(TXT_BOOT_STACK_SIZE), %edx
> +       mull    %edx
> +       leal    (sl_stacks_end - sl_txt_ap_wake_begin)(%ecx), %esp
> +       subl    %eax, %esp
> +
> +       /* Switch to AP code segment */
> +       leal    rva(.Lsl_ap_cs)(%ebx), %eax
> +       pushl   $(__SL32_CS)
> +       pushl   %eax
> +       lret
> +
> +.Lsl_ap_cs:
> +       /* Load the relocated AP IDT */
> +       lidt    (sl_ap_idt_desc - sl_txt_ap_wake_begin)(%ecx)
> +
> +       /* Fixup MTRRs and misc enable MSR on APs too */
> +       call    sl_txt_load_regs
> +
> +       /* Enable SMI with GETSEC[SMCTRL] */
> +       GETSEC $(SMX_X86_GETSEC_SMCTRL)
> +
> +       /* IRET-to-self can be used to enable NMIs which SENTER disabled */
> +       leal    rva(.Lnmi_enabled_ap)(%ebx), %eax
> +       pushfl
> +       pushl   $(__SL32_CS)
> +       pushl   %eax
> +       iret
> +
> +.Lnmi_enabled_ap:
> +       /* Put APs in X2APIC mode like the BSP */
> +       movl    $(MSR_IA32_APICBASE), %ecx
> +       rdmsr
> +       orl     $(XAPIC_ENABLE | X2APIC_ENABLE), %eax
> +       wrmsr
> +
> +       /*
> +        * Basically done, increment the CPU count and jump off to the AP
> +        * wake block to wait.
> +        */
> +       lock incl       rva(sl_txt_cpu_count)(%ebx)
> +
> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %eax
> +       jmp     *%eax
> +SYM_FUNC_END(sl_txt_ap_entry)
> +
> +SYM_FUNC_START(sl_txt_reloc_ap_wake)
> +       /* Save boot params register */
> +       pushl   %esi
> +
> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %edi
> +
> +       /* Fixup AP IDT and GDT descriptor before relocating */
> +       leal    rva(sl_ap_idt_desc)(%ebx), %eax
> +       addl    %edi, 2(%eax)
> +       leal    rva(sl_ap_gdt_desc)(%ebx), %eax
> +       addl    %edi, 2(%eax)
> +
> +       /*
> +        * Copy the AP wake code and AP GDT/IDT to the protected wake block
> +        * provided by the loader. Destination already in %edi.
> +        */
> +       movl    $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), %ecx
> +       leal    rva(sl_txt_ap_wake_begin)(%ebx), %esi
> +       rep movsb
> +
> +       /* Setup the IDT for the APs to use in the relocation block */
> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %ecx
> +       addl    $(sl_ap_idt - sl_txt_ap_wake_begin), %ecx
> +       xorl    %edx, %edx
> +
> +       /* Form the default reset vector relocation address */
> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %esi
> +       addl    $(sl_txt_int_reset - sl_txt_ap_wake_begin), %esi
> +
> +1:
> +       cmpw    $(NR_VECTORS), %dx
> +       jz      .Lap_idt_done
> +
> +       cmpw    $(X86_TRAP_NMI), %dx
> +       jz      2f
> +
> +       /* Load all other fixed vectors with reset handler */
> +       movl    %esi, %eax
> +       movw    %ax, (IDT_VECTOR_LO_BITS)(%ecx)
> +       shrl    $16, %eax
> +       movw    %ax, (IDT_VECTOR_HI_BITS)(%ecx)
> +       jmp     3f
> +
> +2:
> +       /* Load single wake NMI IPI vector at the relocation address */
> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %eax
> +       addl    $(sl_txt_int_nmi - sl_txt_ap_wake_begin), %eax
> +       movw    %ax, (IDT_VECTOR_LO_BITS)(%ecx)
> +       shrl    $16, %eax
> +       movw    %ax, (IDT_VECTOR_HI_BITS)(%ecx)
> +
> +3:
> +       incw    %dx
> +       addl    $8, %ecx
> +       jmp     1b
> +
> +.Lap_idt_done:
> +       popl    %esi
> +       ret
> +SYM_FUNC_END(sl_txt_reloc_ap_wake)
> +
> +SYM_FUNC_START(sl_txt_load_regs)
> +       /* Save base pointer register */
> +       pushl   %ebx
> +
> +       /*
> +        * On Intel, the original variable MTRRs and Misc Enable MSR are
> +        * restored on the BSP at early boot. Each AP will also restore
> +        * its MTRRs and Misc Enable MSR.
> +        */
> +       pushl   %edi
> +       addl    $(SL_saved_bsp_mtrrs), %edi
> +       movl    (%edi), %ebx
> +       pushl   %ebx /* default_mem_type lo */
> +       addl    $4, %edi
> +       movl    (%edi), %ebx
> +       pushl   %ebx /* default_mem_type hi */
> +       addl    $4, %edi
> +       movl    (%edi), %ebx /* mtrr_vcnt lo, don't care about hi part */
> +       addl    $8, %edi /* now at MTRR pair array */
> +       /* Write the variable MTRRs */
> +       movl    $(MSR_MTRRphysBase0), %ecx
> +1:
> +       cmpl    $0, %ebx
> +       jz      2f
> +
> +       movl    (%edi), %eax /* MTRRphysBaseX lo */
> +       addl    $4, %edi
> +       movl    (%edi), %edx /* MTRRphysBaseX hi */
> +       wrmsr
> +       addl    $4, %edi
> +       incl    %ecx
> +       movl    (%edi), %eax /* MTRRphysMaskX lo */
> +       addl    $4, %edi
> +       movl    (%edi), %edx /* MTRRphysMaskX hi */
> +       wrmsr
> +       addl    $4, %edi
> +       incl    %ecx
> +
> +       decl    %ebx
> +       jmp     1b
> +2:
> +       /* Write the default MTRR register */
> +       popl    %edx
> +       popl    %eax
> +       movl    $(MSR_MTRRdefType), %ecx
> +       wrmsr
> +
> +       /* Return to beginning and write the misc enable msr */
> +       popl    %edi
> +       addl    $(SL_saved_misc_enable_msr), %edi
> +       movl    (%edi), %eax /* saved_misc_enable_msr lo */
> +       addl    $4, %edi
> +       movl    (%edi), %edx /* saved_misc_enable_msr hi */
> +       movl    $(MSR_IA32_MISC_ENABLE), %ecx
> +       wrmsr
> +
> +       popl    %ebx
> +       ret
> +SYM_FUNC_END(sl_txt_load_regs)
> +
> +SYM_FUNC_START(sl_txt_wake_aps)
> +       /* Save boot params register */
> +       pushl   %esi
> +
> +       /* First setup the MLE join structure and load it into TXT reg */
> +       leal    rva(sl_gdt)(%ebx), %eax
> +       leal    rva(sl_txt_ap_entry)(%ebx), %ecx
> +       leal    rva(sl_smx_rlp_mle_join)(%ebx), %edx
> +       movl    %eax, SL_rlp_gdt_base(%edx)
> +       movl    %ecx, SL_rlp_entry_point(%edx)
> +       movl    %edx, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_MLE_JOIN)
> +
> +       /* Another TXT heap walk to find various values needed to wake APs */
> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
> +       /* At BIOS data size, find the number of logical processors */
> +       movl    (SL_num_logical_procs + 8)(%eax), %edx
> +       /* Skip over BIOS data */
> +       movl    (%eax), %ecx
> +       addl    %ecx, %eax
> +       /* Skip over OS to MLE */
> +       movl    (%eax), %ecx
> +       addl    %ecx, %eax
> +       /* At OS-SNIT size, get capabilities to know how to wake up the APs */
> +       movl    (SL_capabilities + 8)(%eax), %esi
> +       /* Skip over OS to SNIT */
> +       movl    (%eax), %ecx
> +       addl    %ecx, %eax
> +       /* At SINIT-MLE size, get the AP wake MONITOR address */
> +       movl    (SL_rlp_wakeup_addr + 8)(%eax), %edi
> +
> +       /* Determine how to wake up the APs */
> +       testl   $(1 << TXT_SINIT_MLE_CAP_WAKE_MONITOR), %esi
> +       jz      .Lwake_getsec
> +
> +       /* Wake using MWAIT MONITOR */
> +       movl    $1, (%edi)
> +       jmp     .Laps_awake
> +
> +.Lwake_getsec:
> +       /* Wake using GETSEC(WAKEUP) */
> +       GETSEC  $(SMX_X86_GETSEC_WAKEUP)
> +
> +.Laps_awake:
> +       /*
> +        * All of the APs are woken up and rendesvous in the relocated wake
> +        * block starting at sl_txt_ap_wake_begin. Wait for all of them to
> +        * halt.
> +        */
> +       pause
> +       cmpl    rva(sl_txt_cpu_count)(%ebx), %edx
> +       jne     .Laps_awake
> +
> +       popl    %esi
> +       ret
> +SYM_FUNC_END(sl_txt_wake_aps)
> +
> +/* This is the beginning of the relocated AP wake code block */
> +       .global sl_txt_ap_wake_begin
> +sl_txt_ap_wake_begin:
> +
> +       /* Get the LAPIC ID for each AP and stash it on the stack */
> +       movl    $(MSR_IA32_X2APIC_APICID), %ecx
> +       rdmsr
> +       pushl   %eax
> +
> +       /*
> +        * Get a pointer to the monitor location on this APs stack to test below
> +        * after mwait returns. Currently %esp points to just past the pushed APIC
> +        * ID value.
> +        */
> +       movl    %esp, %eax
> +       subl    $(TXT_BOOT_STACK_SIZE - 4), %eax
> +       movl    $0, (%eax)
> +
> +       /* Clear ecx/edx so no invalid extensions or hints are passed to monitor */
> +       xorl    %ecx, %ecx
> +       xorl    %edx, %edx
> +
> +       /*
> +        * Arm the monitor and wait for it to be poked by he SMP bringup code. The mwait
> +        * instruction can return for a number of reasons. Test to see if it returned
> +        * because the monitor was written to.
> +        */
> +       monitor
> +
> +1:
> +       mfence
> +       mwait
> +       movl    (%eax), %edx
> +       testl   %edx, %edx
> +       jz      1b
> +
> +       /*
> +        * This is the long absolute jump to the 32b Secure Launch protected mode stub
> +        * code in sl_trampoline_start32() in the rmpiggy. The jump address will be
> +        * fixed in the SMP boot code when the first AP is brought up. This whole area
> +        * is provided and protected in the memory map by the prelaunch code.
> +        */
> +       .byte   0xea
> +sl_ap_jmp_offset:
> +       .long   0x00000000
> +       .word   __SL32_CS
> +
> +SYM_FUNC_START(sl_txt_int_nmi)
> +       /* NMI context, just IRET */
> +       iret
> +SYM_FUNC_END(sl_txt_int_nmi)
> +
> +SYM_FUNC_START(sl_txt_int_reset)
> +       TXT_RESET $(SL_ERROR_INV_AP_INTERRUPT)
> +SYM_FUNC_END(sl_txt_int_reset)
> +
> +       .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_idt_desc)
> +       .word   sl_ap_idt_end - sl_ap_idt - 1           /* Limit */
> +       .long   sl_ap_idt - sl_txt_ap_wake_begin        /* Base */
> +SYM_DATA_END_LABEL(sl_ap_idt_desc, SYM_L_LOCAL, sl_ap_idt_desc_end)
> +
> +       .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_idt)
> +       .rept   NR_VECTORS
> +       .word   0x0000          /* Offset 15 to 0 */
> +       .word   __SL32_CS       /* Segment selector */
> +       .word   0x8e00          /* Present, DPL=0, 32b Vector, Interrupt */
> +       .word   0x0000          /* Offset 31 to 16 */
> +       .endr
> +SYM_DATA_END_LABEL(sl_ap_idt, SYM_L_LOCAL, sl_ap_idt_end)
> +
> +       .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_gdt_desc)
> +       .word   sl_ap_gdt_end - sl_ap_gdt - 1
> +       .long   sl_ap_gdt - sl_txt_ap_wake_begin
> +SYM_DATA_END_LABEL(sl_ap_gdt_desc, SYM_L_LOCAL, sl_ap_gdt_desc_end)
> +
> +       .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_gdt)
> +       .quad   0x0000000000000000      /* NULL */
> +       .quad   0x00cf9a000000ffff      /* __SL32_CS */
> +       .quad   0x00cf92000000ffff      /* __SL32_DS */
> +SYM_DATA_END_LABEL(sl_ap_gdt, SYM_L_LOCAL, sl_ap_gdt_end)
> +
> +       /* Small stacks for BSP and APs to work with */
> +       .balign 64
> +SYM_DATA_START_LOCAL(sl_stacks)
> +       .fill (TXT_MAX_CPUS * TXT_BOOT_STACK_SIZE), 1, 0
> +SYM_DATA_END_LABEL(sl_stacks, SYM_L_LOCAL, sl_stacks_end)
> +
> +/* This is the end of the relocated AP wake code block */
> +       .global sl_txt_ap_wake_end
> +sl_txt_ap_wake_end:
> +
> +       .data
> +       .balign 8
> +SYM_DATA_START_LOCAL(sl_gdt_desc)
> +       .word   sl_gdt_end - sl_gdt - 1
> +       .long   sl_gdt - sl_gdt_desc
> +SYM_DATA_END_LABEL(sl_gdt_desc, SYM_L_LOCAL, sl_gdt_desc_end)
> +
> +       .balign 8
> +SYM_DATA_START_LOCAL(sl_gdt)
> +       .quad   0x0000000000000000      /* NULL */
> +       .quad   0x00cf9a000000ffff      /* __SL32_CS */
> +       .quad   0x00cf92000000ffff      /* __SL32_DS */
> +SYM_DATA_END_LABEL(sl_gdt, SYM_L_LOCAL, sl_gdt_end)
> +
> +       .balign 8
> +SYM_DATA_START_LOCAL(sl_smx_rlp_mle_join)
> +       .long   sl_gdt_end - sl_gdt - 1 /* GDT limit */
> +       .long   0x00000000              /* GDT base */
> +       .long   __SL32_CS       /* Seg Sel - CS (DS, ES, SS = seg_sel+8) */
> +       .long   0x00000000      /* Entry point physical address */
> +SYM_DATA_END(sl_smx_rlp_mle_join)
> +
> +SYM_DATA(sl_cpu_type, .long 0x00000000)
> +
> +SYM_DATA(sl_mle_start, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_spin_lock, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_stack_index, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_cpu_count, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_ap_wake_block, .long 0x00000000)
> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
> index f1bd7b91b3c6..aff899c4b6c3 100644
> --- a/arch/x86/include/asm/msr-index.h
> +++ b/arch/x86/include/asm/msr-index.h
> @@ -323,6 +323,9 @@
>  #define MSR_IA32_RTIT_OUTPUT_BASE      0x00000560
>  #define MSR_IA32_RTIT_OUTPUT_MASK      0x00000561
>
> +#define MSR_MTRRphysBase0              0x00000200
> +#define MSR_MTRRphysMask0              0x00000201
> +
>  #define MSR_MTRRfix64K_00000           0x00000250
>  #define MSR_MTRRfix16K_80000           0x00000258
>  #define MSR_MTRRfix16K_A0000           0x00000259
> @@ -804,6 +807,8 @@
>  #define MSR_IA32_APICBASE_ENABLE       (1<<11)
>  #define MSR_IA32_APICBASE_BASE         (0xfffff<<12)
>
> +#define MSR_IA32_X2APIC_APICID         0x00000802
> +
>  #define MSR_IA32_UCODE_WRITE           0x00000079
>  #define MSR_IA32_UCODE_REV             0x0000008b
>
> diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
> index 01d19fc22346..74e3e7df491e 100644
> --- a/arch/x86/include/uapi/asm/bootparam.h
> +++ b/arch/x86/include/uapi/asm/bootparam.h
> @@ -26,6 +26,7 @@
>  /* loadflags */
>  #define LOADED_HIGH    (1<<0)
>  #define KASLR_FLAG     (1<<1)
> +#define SLAUNCH_FLAG   (1<<2)
>  #define QUIET_FLAG     (1<<5)
>  #define KEEP_SEGMENTS  (1<<6)
>  #define CAN_USE_HEAP   (1<<7)
> diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
> index 6913b372ccf7..c7c4d392b7d3 100644
> --- a/arch/x86/kernel/asm-offsets.c
> +++ b/arch/x86/kernel/asm-offsets.c
> @@ -13,6 +13,8 @@
>  #include <linux/hardirq.h>
>  #include <linux/suspend.h>
>  #include <linux/kbuild.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
>  #include <asm/processor.h>
>  #include <asm/thread_info.h>
>  #include <asm/sigframe.h>
> @@ -120,4 +122,22 @@ static void __used common(void)
>         OFFSET(ARIA_CTX_rounds, aria_ctx, rounds);
>  #endif
>
> +#ifdef CONFIG_SECURE_LAUNCH
> +       BLANK();
> +       OFFSET(SL_txt_info, txt_os_mle_data, txt_info);
> +       OFFSET(SL_mle_scratch, txt_os_mle_data, mle_scratch);
> +       OFFSET(SL_boot_params_addr, txt_os_mle_data, boot_params_addr);
> +       OFFSET(SL_ap_wake_block, txt_os_mle_data, ap_wake_block);
> +       OFFSET(SL_ap_wake_block_size, txt_os_mle_data, ap_wake_block_size);
> +       OFFSET(SL_saved_misc_enable_msr, slr_entry_intel_info, saved_misc_enable_msr);
> +       OFFSET(SL_saved_bsp_mtrrs, slr_entry_intel_info, saved_bsp_mtrrs);
> +       OFFSET(SL_num_logical_procs, txt_bios_data, num_logical_procs);
> +       OFFSET(SL_capabilities, txt_os_sinit_data, capabilities);
> +       OFFSET(SL_mle_size, txt_os_sinit_data, mle_size);
> +       OFFSET(SL_vtd_pmr_lo_base, txt_os_sinit_data, vtd_pmr_lo_base);
> +       OFFSET(SL_vtd_pmr_lo_size, txt_os_sinit_data, vtd_pmr_lo_size);
> +       OFFSET(SL_rlp_wakeup_addr, txt_sinit_mle_data, rlp_wakeup_addr);
> +       OFFSET(SL_rlp_gdt_base, smx_rlp_mle_join, rlp_gdt_base);
> +       OFFSET(SL_rlp_entry_point, smx_rlp_mle_join, rlp_entry_point);
> +#endif
>  }
> --
> 2.39.3
>
Ard Biesheuvel Feb. 15, 2024, 8:40 a.m. UTC | #5
On Wed, 14 Feb 2024 at 23:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>
> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>
> The Secure Launch platform module is a late init module. During the
> init call, the TPM event log is read and measurements taken in the
> early boot stub code are located. These measurements are extended
> into the TPM PCRs using the mainline TPM kernel driver.
>
> The platform module also registers the securityfs nodes to allow
> access to TXT register fields on Intel along with the fetching of
> and writing events to the late launch TPM log.
>
> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> Signed-off-by: garnetgrimm <grimmg@ainfosec.com>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>

There is an awful amount of code that executes between the point where
the measurements are taken and the point where they are loaded into
the PCRs. All of this code could subvert the boot flow and hide this
fact, by replacing the actual taken measurement values with the known
'blessed' ones that will unseal the keys and/or phone home to do a
successful remote attestation.

At the very least, this should be documented somewhere. And if at all
possible, it should also be documented why this is ok, and to what
extent it limits the provided guarantees compared to a true D-RTM boot
where the early boot code measures straight into the TPMs before
proceeding.


> ---
>  arch/x86/kernel/Makefile   |   1 +
>  arch/x86/kernel/slmodule.c | 511 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 512 insertions(+)
>  create mode 100644 arch/x86/kernel/slmodule.c
>
> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> index 5848ea310175..948346ff4595 100644
> --- a/arch/x86/kernel/Makefile
> +++ b/arch/x86/kernel/Makefile
> @@ -75,6 +75,7 @@ obj-$(CONFIG_IA32_EMULATION)  += tls.o
>  obj-y                          += step.o
>  obj-$(CONFIG_INTEL_TXT)                += tboot.o
>  obj-$(CONFIG_SECURE_LAUNCH)    += slaunch.o
> +obj-$(CONFIG_SECURE_LAUNCH)    += slmodule.o
>  obj-$(CONFIG_ISA_DMA_API)      += i8237.o
>  obj-y                          += stacktrace.o
>  obj-y                          += cpu/
> diff --git a/arch/x86/kernel/slmodule.c b/arch/x86/kernel/slmodule.c
> new file mode 100644
> index 000000000000..52269f24902e
> --- /dev/null
> +++ b/arch/x86/kernel/slmodule.c
> @@ -0,0 +1,511 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Secure Launch late validation/setup, securityfs exposure and finalization.
> + *
> + * Copyright (c) 2022 Apertus Solutions, LLC
> + * Copyright (c) 2021 Assured Information Security, Inc.
> + * Copyright (c) 2022, Oracle and/or its affiliates.
> + *
> + * Co-developed-by: Garnet T. Grimm <grimmg@ainfosec.com>
> + * Signed-off-by: Garnet T. Grimm <grimmg@ainfosec.com>
> + * Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/linkage.h>
> +#include <linux/mm.h>
> +#include <linux/io.h>
> +#include <linux/uaccess.h>
> +#include <linux/security.h>
> +#include <linux/memblock.h>
> +#include <asm/segment.h>
> +#include <asm/sections.h>
> +#include <crypto/sha2.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
> +
> +/*
> + * The macro DECLARE_TXT_PUB_READ_U is used to read values from the TXT
> + * public registers as unsigned values.
> + */
> +#define DECLARE_TXT_PUB_READ_U(size, fmt, msg_size)                    \
> +static ssize_t txt_pub_read_u##size(unsigned int offset,               \
> +               loff_t *read_offset,                                    \
> +               size_t read_len,                                        \
> +               char __user *buf)                                       \
> +{                                                                      \
> +       char msg_buffer[msg_size];                                      \
> +       u##size reg_value = 0;                                          \
> +       void __iomem *txt;                                              \
> +                                                                       \
> +       txt = ioremap(TXT_PUB_CONFIG_REGS_BASE,                         \
> +                       TXT_NR_CONFIG_PAGES * PAGE_SIZE);               \
> +       if (!txt)                                                       \
> +               return -EFAULT;                                         \
> +       memcpy_fromio(&reg_value, txt + offset, sizeof(u##size));       \
> +       iounmap(txt);                                                   \
> +       snprintf(msg_buffer, msg_size, fmt, reg_value);                 \
> +       return simple_read_from_buffer(buf, read_len, read_offset,      \
> +                       &msg_buffer, msg_size);                         \
> +}
> +
> +DECLARE_TXT_PUB_READ_U(8, "%#04x\n", 6);
> +DECLARE_TXT_PUB_READ_U(32, "%#010x\n", 12);
> +DECLARE_TXT_PUB_READ_U(64, "%#018llx\n", 20);
> +
> +#define DECLARE_TXT_FOPS(reg_name, reg_offset, reg_size)               \
> +static ssize_t txt_##reg_name##_read(struct file *flip,                        \
> +               char __user *buf, size_t read_len, loff_t *read_offset) \
> +{                                                                      \
> +       return txt_pub_read_u##reg_size(reg_offset, read_offset,        \
> +                       read_len, buf);                                 \
> +}                                                                      \
> +static const struct file_operations reg_name##_ops = {                 \
> +       .read = txt_##reg_name##_read,                                  \
> +}
> +
> +DECLARE_TXT_FOPS(sts, TXT_CR_STS, 64);
> +DECLARE_TXT_FOPS(ests, TXT_CR_ESTS, 8);
> +DECLARE_TXT_FOPS(errorcode, TXT_CR_ERRORCODE, 32);
> +DECLARE_TXT_FOPS(didvid, TXT_CR_DIDVID, 64);
> +DECLARE_TXT_FOPS(e2sts, TXT_CR_E2STS, 64);
> +DECLARE_TXT_FOPS(ver_emif, TXT_CR_VER_EMIF, 32);
> +DECLARE_TXT_FOPS(scratchpad, TXT_CR_SCRATCHPAD, 64);
> +
> +/*
> + * Securityfs exposure
> + */
> +struct memfile {
> +       char *name;
> +       void *addr;
> +       size_t size;
> +};
> +
> +static struct memfile sl_evtlog = {"eventlog", NULL, 0};
> +static void *txt_heap;
> +static struct txt_heap_event_log_pointer2_1_element *evtlog20;
> +static DEFINE_MUTEX(sl_evt_log_mutex);
> +
> +static ssize_t sl_evtlog_read(struct file *file, char __user *buf,
> +                             size_t count, loff_t *pos)
> +{
> +       ssize_t size;
> +
> +       if (!sl_evtlog.addr)
> +               return 0;
> +
> +       mutex_lock(&sl_evt_log_mutex);
> +       size = simple_read_from_buffer(buf, count, pos, sl_evtlog.addr,
> +                                      sl_evtlog.size);
> +       mutex_unlock(&sl_evt_log_mutex);
> +
> +       return size;
> +}
> +
> +static ssize_t sl_evtlog_write(struct file *file, const char __user *buf,
> +                              size_t datalen, loff_t *ppos)
> +{
> +       ssize_t result;
> +       char *data;
> +
> +       if (!sl_evtlog.addr)
> +               return 0;
> +
> +       /* No partial writes. */
> +       result = -EINVAL;
> +       if (*ppos != 0)
> +               goto out;
> +
> +       data = memdup_user(buf, datalen);
> +       if (IS_ERR(data)) {
> +               result = PTR_ERR(data);
> +               goto out;
> +       }
> +
> +       mutex_lock(&sl_evt_log_mutex);
> +       if (evtlog20)
> +               result = tpm20_log_event(evtlog20, sl_evtlog.addr,
> +                                        sl_evtlog.size, datalen, data);
> +       else
> +               result = tpm12_log_event(sl_evtlog.addr, sl_evtlog.size,
> +                                        datalen, data);
> +       mutex_unlock(&sl_evt_log_mutex);
> +
> +       kfree(data);
> +out:
> +       return result;
> +}
> +
> +static const struct file_operations sl_evtlog_ops = {
> +       .read = sl_evtlog_read,
> +       .write = sl_evtlog_write,
> +       .llseek = default_llseek,
> +};
> +
> +struct sfs_file {
> +       const char *name;
> +       const struct file_operations *fops;
> +};
> +
> +#define SL_TXT_ENTRY_COUNT     7
> +static const struct sfs_file sl_txt_files[] = {
> +       { "sts", &sts_ops },
> +       { "ests", &ests_ops },
> +       { "errorcode", &errorcode_ops },
> +       { "didvid", &didvid_ops },
> +       { "ver_emif", &ver_emif_ops },
> +       { "scratchpad", &scratchpad_ops },
> +       { "e2sts", &e2sts_ops }
> +};
> +
> +/* sysfs file handles */
> +static struct dentry *slaunch_dir;
> +static struct dentry *event_file;
> +static struct dentry *txt_dir;
> +static struct dentry *txt_entries[SL_TXT_ENTRY_COUNT];
> +
> +static long slaunch_expose_securityfs(void)
> +{
> +       long ret = 0;
> +       int i;
> +
> +       slaunch_dir = securityfs_create_dir("slaunch", NULL);
> +       if (IS_ERR(slaunch_dir))
> +               return PTR_ERR(slaunch_dir);
> +
> +       if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) {
> +               txt_dir = securityfs_create_dir("txt", slaunch_dir);
> +               if (IS_ERR(txt_dir)) {
> +                       ret = PTR_ERR(txt_dir);
> +                       goto remove_slaunch;
> +               }
> +
> +               for (i = 0; i < ARRAY_SIZE(sl_txt_files); i++) {
> +                       txt_entries[i] = securityfs_create_file(
> +                                               sl_txt_files[i].name, 0440,
> +                                               txt_dir, NULL,
> +                                               sl_txt_files[i].fops);
> +                       if (IS_ERR(txt_entries[i])) {
> +                               ret = PTR_ERR(txt_entries[i]);
> +                               goto remove_files;
> +                       }
> +               }
> +       }
> +
> +       if (sl_evtlog.addr) {
> +               event_file = securityfs_create_file(sl_evtlog.name, 0440,
> +                                                   slaunch_dir, NULL,
> +                                                   &sl_evtlog_ops);
> +               if (IS_ERR(event_file)) {
> +                       ret = PTR_ERR(event_file);
> +                       goto remove_files;
> +               }
> +       }
> +
> +       return 0;
> +
> +remove_files:
> +       if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) {
> +               while (--i >= 0)
> +                       securityfs_remove(txt_entries[i]);
> +               securityfs_remove(txt_dir);
> +       }
> +
> +remove_slaunch:
> +       securityfs_remove(slaunch_dir);
> +
> +       return ret;
> +}
> +
> +static void slaunch_teardown_securityfs(void)
> +{
> +       int i;
> +
> +       securityfs_remove(event_file);
> +       if (sl_evtlog.addr) {
> +               memunmap(sl_evtlog.addr);
> +               sl_evtlog.addr = NULL;
> +       }
> +       sl_evtlog.size = 0;
> +
> +       if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) {
> +               for (i = 0; i < ARRAY_SIZE(sl_txt_files); i++)
> +                       securityfs_remove(txt_entries[i]);
> +
> +               securityfs_remove(txt_dir);
> +
> +               if (txt_heap) {
> +                       memunmap(txt_heap);
> +                       txt_heap = NULL;
> +               }
> +       }
> +
> +       securityfs_remove(slaunch_dir);
> +}
> +
> +static void slaunch_intel_evtlog(void __iomem *txt)
> +{
> +       struct slr_entry_log_info *log_info;
> +       struct txt_os_mle_data *params;
> +       struct slr_table *slrt;
> +       void *os_sinit_data;
> +       u64 base, size;
> +
> +       memcpy_fromio(&base, txt + TXT_CR_HEAP_BASE, sizeof(base));
> +       memcpy_fromio(&size, txt + TXT_CR_HEAP_SIZE, sizeof(size));
> +
> +       /* now map TXT heap */
> +       txt_heap = memremap(base, size, MEMREMAP_WB);
> +       if (!txt_heap)
> +               slaunch_txt_reset(txt, "Error failed to memremap TXT heap\n",
> +                                 SL_ERROR_HEAP_MAP);
> +
> +       params = (struct txt_os_mle_data *)txt_os_mle_data_start(txt_heap);
> +
> +       /* Get the SLRT and remap it */
> +       slrt = memremap(params->slrt, sizeof(*slrt), MEMREMAP_WB);
> +       if (!slrt)
> +               slaunch_txt_reset(txt, "Error failed to memremap SLR Table\n",
> +                                 SL_ERROR_SLRT_MAP);
> +       size = slrt->size;
> +       memunmap(slrt);
> +
> +       slrt = memremap(params->slrt, size, MEMREMAP_WB);
> +       if (!slrt)
> +               slaunch_txt_reset(txt, "Error failed to memremap SLR Table\n",
> +                                 SL_ERROR_SLRT_MAP);
> +
> +       log_info = (struct slr_entry_log_info *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
> +       if (!log_info)
> +               slaunch_txt_reset(txt, "Error failed to memremap SLR Table\n",
> +                                 SL_ERROR_SLRT_MISSING_ENTRY);
> +
> +       sl_evtlog.size = log_info->size;
> +       sl_evtlog.addr = memremap(log_info->addr, log_info->size,
> +                                 MEMREMAP_WB);
> +       if (!sl_evtlog.addr)
> +               slaunch_txt_reset(txt, "Error failed to memremap TPM event log\n",
> +                                 SL_ERROR_EVENTLOG_MAP);
> +
> +       memunmap(slrt);
> +
> +       /* Determine if this is TPM 1.2 or 2.0 event log */
> +       if (memcmp(sl_evtlog.addr + sizeof(struct tcg_pcr_event),
> +                   TCG_SPECID_SIG, sizeof(TCG_SPECID_SIG)))
> +               return; /* looks like it is not 2.0 */
> +
> +       /* For TPM 2.0 logs, the extended heap element must be located */
> +       os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> +       evtlog20 = tpm20_find_log2_1_element(os_sinit_data);
> +
> +       /*
> +        * If this fails, things are in really bad shape. Any attempt to write
> +        * events to the log will fail.
> +        */
> +       if (!evtlog20)
> +               slaunch_txt_reset(txt, "Error failed to find TPM20 event log element\n",
> +                                 SL_ERROR_TPM_INVALID_LOG20);
> +}
> +
> +static void slaunch_tpm20_extend_event(struct tpm_chip *tpm, void __iomem *txt,
> +                                      struct tcg_pcr_event2_head *event)
> +{
> +       u16 *alg_id_field = (u16 *)((u8 *)event + sizeof(struct tcg_pcr_event2_head));
> +       struct tpm_digest *digests;
> +       u8 *dptr;
> +       u32 i, j;
> +       int ret;
> +
> +       digests = kcalloc(tpm->nr_allocated_banks, sizeof(*digests),
> +                         GFP_KERNEL);
> +       if (!digests)
> +               slaunch_txt_reset(txt, "Failed to allocate array of digests\n",
> +                                 SL_ERROR_GENERIC);
> +
> +       for (i = 0; i < tpm->nr_allocated_banks; i++)
> +               digests[i].alg_id = tpm->allocated_banks[i].alg_id;
> +
> +       /* Early SL code ensured there was a max count of 2 digests */
> +       for (i = 0; i < event->count; i++) {
> +               dptr = (u8 *)alg_id_field + sizeof(u16);
> +
> +               for (j = 0; j < tpm->nr_allocated_banks; j++) {
> +                       if (digests[j].alg_id != *alg_id_field)
> +                               continue;
> +
> +                       switch (digests[j].alg_id) {
> +                       case TPM_ALG_SHA256:
> +                               memcpy(&digests[j].digest[0], dptr,
> +                                      SHA256_DIGEST_SIZE);
> +                               alg_id_field = (u16 *)((u8 *)alg_id_field +
> +                                       SHA256_DIGEST_SIZE + sizeof(u16));
> +                               break;
> +                       case TPM_ALG_SHA1:
> +                               memcpy(&digests[j].digest[0], dptr,
> +                                      SHA1_DIGEST_SIZE);
> +                               alg_id_field = (u16 *)((u8 *)alg_id_field +
> +                                       SHA1_DIGEST_SIZE + sizeof(u16));
> +                       default:
> +                               break;
> +                       }
> +               }
> +       }
> +
> +       ret = tpm_pcr_extend(tpm, event->pcr_idx, digests);
> +       if (ret) {
> +               pr_err("Error extending TPM20 PCR, result: %d\n", ret);
> +               slaunch_txt_reset(txt, "Failed to extend TPM20 PCR\n",
> +                                 SL_ERROR_TPM_EXTEND);
> +       }
> +
> +       kfree(digests);
> +}
> +
> +static void slaunch_tpm20_extend(struct tpm_chip *tpm, void __iomem *txt)
> +{
> +       struct tcg_pcr_event *event_header;
> +       struct tcg_pcr_event2_head *event;
> +       int start = 0, end = 0, size;
> +
> +       event_header = (struct tcg_pcr_event *)(sl_evtlog.addr +
> +                                               evtlog20->first_record_offset);
> +
> +       /* Skip first TPM 1.2 event to get to first TPM 2.0 event */
> +       event = (struct tcg_pcr_event2_head *)((u8 *)event_header +
> +                                               sizeof(struct tcg_pcr_event) +
> +                                               event_header->event_size);
> +
> +       while ((void  *)event < sl_evtlog.addr + evtlog20->next_record_offset) {
> +               size = __calc_tpm2_event_size(event, event_header, false);
> +               if (!size)
> +                       slaunch_txt_reset(txt, "TPM20 invalid event in event log\n",
> +                                         SL_ERROR_TPM_INVALID_EVENT);
> +
> +               /*
> +                * Marker events indicate where the Secure Launch early stub
> +                * started and ended adding post launch events.
> +                */
> +               if (event->event_type == TXT_EVTYPE_SLAUNCH_END) {
> +                       end = 1;
> +                       break;
> +               } else if (event->event_type == TXT_EVTYPE_SLAUNCH_START) {
> +                       start = 1;
> +                       goto next;
> +               }
> +
> +               if (start)
> +                       slaunch_tpm20_extend_event(tpm, txt, event);
> +
> +next:
> +               event = (struct tcg_pcr_event2_head *)((u8 *)event + size);
> +       }
> +
> +       if (!start || !end)
> +               slaunch_txt_reset(txt, "Missing start or end events for extending TPM20 PCRs\n",
> +                                 SL_ERROR_TPM_EXTEND);
> +}
> +
> +static void slaunch_tpm12_extend(struct tpm_chip *tpm, void __iomem *txt)
> +{
> +       struct tpm12_event_log_header *event_header;
> +       struct tcg_pcr_event *event;
> +       struct tpm_digest digest;
> +       int start = 0, end = 0;
> +       int size, ret;
> +
> +       event_header = (struct tpm12_event_log_header *)sl_evtlog.addr;
> +       event = (struct tcg_pcr_event *)((u8 *)event_header +
> +                               sizeof(struct tpm12_event_log_header));
> +
> +       while ((void  *)event < sl_evtlog.addr + event_header->next_event_offset) {
> +               size = sizeof(struct tcg_pcr_event) + event->event_size;
> +
> +               /*
> +                * Marker events indicate where the Secure Launch early stub
> +                * started and ended adding post launch events.
> +                */
> +               if (event->event_type == TXT_EVTYPE_SLAUNCH_END) {
> +                       end = 1;
> +                       break;
> +               } else if (event->event_type == TXT_EVTYPE_SLAUNCH_START) {
> +                       start = 1;
> +                       goto next;
> +               }
> +
> +               if (start) {
> +                       memset(&digest.digest[0], 0, TPM_MAX_DIGEST_SIZE);
> +                       digest.alg_id = TPM_ALG_SHA1;
> +                       memcpy(&digest.digest[0], &event->digest[0],
> +                              SHA1_DIGEST_SIZE);
> +
> +                       ret = tpm_pcr_extend(tpm, event->pcr_idx, &digest);
> +                       if (ret) {
> +                               pr_err("Error extending TPM12 PCR, result: %d\n", ret);
> +                               slaunch_txt_reset(txt, "Failed to extend TPM12 PCR\n",
> +                                                 SL_ERROR_TPM_EXTEND);
> +                       }
> +               }
> +
> +next:
> +               event = (struct tcg_pcr_event *)((u8 *)event + size);
> +       }
> +
> +       if (!start || !end)
> +               slaunch_txt_reset(txt, "Missing start or end events for extending TPM12 PCRs\n",
> +                                 SL_ERROR_TPM_EXTEND);
> +}
> +
> +static void slaunch_pcr_extend(void __iomem *txt)
> +{
> +       struct tpm_chip *tpm;
> +
> +       tpm = tpm_default_chip();
> +       if (!tpm)
> +               slaunch_txt_reset(txt, "Could not get default TPM chip\n",
> +                                 SL_ERROR_TPM_INIT);
> +
> +       if (!tpm_preferred_locality(tpm, 2))
> +               slaunch_txt_reset(txt, "Could not set TPM chip locality 2\n",
> +                                 SL_ERROR_TPM_INIT);
> +
> +       if (evtlog20)
> +               slaunch_tpm20_extend(tpm, txt);
> +       else
> +               slaunch_tpm12_extend(tpm, txt);
> +
> +       tpm_preferred_locality(tpm, 0);
> +}
> +
> +static int __init slaunch_module_init(void)
> +{
> +       void __iomem *txt;
> +
> +       /* Check to see if Secure Launch happened */
> +       if ((slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) !=
> +           (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT))
> +               return 0;
> +
> +       txt = ioremap(TXT_PRIV_CONFIG_REGS_BASE, TXT_NR_CONFIG_PAGES *
> +                     PAGE_SIZE);
> +       if (!txt)
> +               panic("Error ioremap of TXT priv registers\n");
> +
> +       /* Only Intel TXT is supported at this point */
> +       slaunch_intel_evtlog(txt);
> +       slaunch_pcr_extend(txt);
> +       iounmap(txt);
> +
> +       return slaunch_expose_securityfs();
> +}
> +
> +static void __exit slaunch_module_exit(void)
> +{
> +       slaunch_teardown_securityfs();
> +}
> +
> +late_initcall(slaunch_module_init);
> +__exitcall(slaunch_module_exit);
> --
> 2.39.3
>
Ard Biesheuvel Feb. 15, 2024, 9:01 a.m. UTC | #6
On Wed, 14 Feb 2024 at 23:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>
> This support allows the DRTM launch to be initiated after an EFI stub
> launch of the Linux kernel is done. This is accomplished by providing
> a handler to jump to when a Secure Launch is in progress. This has to be
> called after the EFI stub does Exit Boot Services.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
>  drivers/firmware/efi/libstub/x86-stub.c | 55 +++++++++++++++++++++++++
>  1 file changed, 55 insertions(+)
>
> diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
> index 0d510c9a06a4..4df2cf539194 100644
> --- a/drivers/firmware/efi/libstub/x86-stub.c
> +++ b/drivers/firmware/efi/libstub/x86-stub.c
> @@ -9,6 +9,7 @@
>  #include <linux/efi.h>
>  #include <linux/pci.h>
>  #include <linux/stddef.h>
> +#include <linux/slr_table.h>
>
>  #include <asm/efi.h>
>  #include <asm/e820/types.h>
> @@ -810,6 +811,57 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
>         return EFI_SUCCESS;
>  }
>
> +static void efi_secure_launch(struct boot_params *boot_params)
> +{
> +       struct slr_entry_uefi_config *uefi_config;
> +       struct slr_uefi_cfg_entry *uefi_entry;
> +       struct slr_entry_dl_info *dlinfo;
> +       efi_guid_t guid = SLR_TABLE_GUID;
> +       struct slr_table *slrt;
> +       u64 memmap_hi;
> +       void *table;
> +       u8 buf[64] = {0};
> +

If you add a flex array to slr_entry_uefi_config as I suggested in
response to the other patch, we could simplify this substantially

static struct slr_entry_uefi_config cfg = {
        .hdr.tag        = SLR_ENTRY_UEFI_CONFIG,
        .hdr.size       = sizeof(cfg),
        .revision       = SLR_UEFI_CONFIG_REVISION,
        .nr_entries     = 1,
        .entries[0]     = {
                .pcr    = 18,
                .evt_info = "Measured UEFI memory map",
        },
};

cfg.entries[0].cfg  = boot_params->efi_info.efi_memmap |
                      (u64)boot_params->efi_info.efi_memmap_hi << 32;
cfg.entries[0].size = boot_params->efi_info.efi_memmap_size;



> +       table = get_efi_config_table(guid);
> +
> +       /*
> +        * The presence of this table indicated a Secure Launch
> +        * is being requested.
> +        */
> +       if (!table)
> +               return;
> +
> +       slrt = (struct slr_table *)table;
> +
> +       if (slrt->magic != SLR_TABLE_MAGIC)
> +               return;
> +

slrt = (struct slr_table *)get_efi_config_table(guid);
if (!slrt || slrt->magic != SLR_TABLE_MAGIC)
        return;

> +       /* Add config information to measure the UEFI memory map */
> +       uefi_config = (struct slr_entry_uefi_config *)buf;
> +       uefi_config->hdr.tag = SLR_ENTRY_UEFI_CONFIG;
> +       uefi_config->hdr.size = sizeof(*uefi_config) + sizeof(*uefi_entry);
> +       uefi_config->revision = SLR_UEFI_CONFIG_REVISION;
> +       uefi_config->nr_entries = 1;
> +       uefi_entry = (struct slr_uefi_cfg_entry *)(buf + sizeof(*uefi_config));
> +       uefi_entry->pcr = 18;
> +       uefi_entry->cfg = boot_params->efi_info.efi_memmap;
> +       memmap_hi = boot_params->efi_info.efi_memmap_hi;
> +       uefi_entry->cfg |= memmap_hi << 32;
> +       uefi_entry->size = boot_params->efi_info.efi_memmap_size;
> +       memcpy(&uefi_entry->evt_info[0], "Measured UEFI memory map",
> +               strlen("Measured UEFI memory map"));
> +

Drop all of this

> +       if (slr_add_entry(slrt, (struct slr_entry_hdr *)uefi_config))

if (slr_add_entry(slrt, &uefi_config.hdr))


> +               return;
> +
> +       /* Jump through DL stub to initiate Secure Launch */
> +       dlinfo = (struct slr_entry_dl_info *)
> +               slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DL_INFO);
> +
> +       asm volatile ("jmp *%%rax"
> +                     : : "a" (dlinfo->dl_handler), "D" (&dlinfo->bl_context));

Fix the prototype and just do

dlinfo->dl_handler(&dlinfo->bl_context);
unreachable();


So in summary, this becomes

static void efi_secure_launch(struct boot_params *boot_params)
{
        static struct slr_entry_uefi_config cfg = {
                .hdr.tag        = SLR_ENTRY_UEFI_CONFIG,
                .hdr.size       = sizeof(cfg),
                .revision       = SLR_UEFI_CONFIG_REVISION,
                .nr_entries     = 1,
                .entries[0]     = {
                        .pcr    = 18,
                        .evt_info = "Measured UEFI memory map",
                },
        };
        struct slr_entry_dl_info *dlinfo;
        efi_guid_t guid = SLR_TABLE_GUID;
        struct slr_table *slrt;

        /*
         * The presence of this table indicated a Secure Launch
         * is being requested.
         */
        slrt = (struct slr_table *)get_efi_config_table(guid);
        if (!slrt || slrt->magic != SLR_TABLE_MAGIC)
                return;

        cfg.entries[0].cfg  = boot_params->efi_info.efi_memmap |
                              (u64)boot_params->efi_info.efi_memmap_hi << 32;
        cfg.entries[0].size = boot_params->efi_info.efi_memmap_size;

        if (slr_add_entry(slrt, &cfg.hdr))
                return;

        /* Jump through DL stub to initiate Secure Launch */
        dlinfo = (struct slr_entry_dl_info *)
                 slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DL_INFO);

        dlinfo->dl_handler(&dlinfo->bl_context);

        unreachable();
}


> +}
> +
>  static void __noreturn enter_kernel(unsigned long kernel_addr,
>                                     struct boot_params *boot_params)
>  {
> @@ -934,6 +986,9 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
>                 goto fail;
>         }
>
> +       /* If a Secure Launch is in progress, this never returns */

if (IS_ENABLED(CONFIG_SECURE_LAUNCH))

> +       efi_secure_launch(boot_params);
> +
>         /*
>          * Call the SEV init code while still running with the firmware's
>          * GDT/IDT, so #VC exceptions will be handled by EFI.
> --
> 2.39.3
>
Ross Philipson Feb. 15, 2024, 10:20 p.m. UTC | #7
On 2/14/24 11:59 PM, Ard Biesheuvel wrote:
> On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
>>
>> Initial bits to bring in Secure Launch functionality. Add Kconfig
>> options for compiling in/out the Secure Launch code.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>>   arch/x86/Kconfig | 12 ++++++++++++
>>   1 file changed, 12 insertions(+)
>>
>> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
>> index 5edec175b9bf..d96d75f6f1a9 100644
>> --- a/arch/x86/Kconfig
>> +++ b/arch/x86/Kconfig
>> @@ -2071,6 +2071,18 @@ config EFI_RUNTIME_MAP
>>
>>            See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
>>
>> +config SECURE_LAUNCH
>> +       bool "Secure Launch support"
>> +       default n
> 
> 'n' is already the default, so you can drop this line.

Ack

> 
>> +       depends on X86_64 && X86_X2APIC
> 
> This depends on CONFIG_TCG_TPM as well (I got build failures without it)

Yes I will add that. I may have to add a couple of other things too.

Thanks
Ross

> 
>> +       help
>> +          The Secure Launch feature allows a kernel to be loaded
>> +          directly through an Intel TXT measured launch. Intel TXT
>> +          establishes a Dynamic Root of Trust for Measurement (DRTM)
>> +          where the CPU measures the kernel image. This feature then
>> +          continues the measurement chain over kernel configuration
>> +          information and init images.
>> +
>>   source "kernel/Kconfig.hz"
>>
>>   config ARCH_SUPPORTS_KEXEC
>> --
>> 2.39.3
>>
>
Ross Philipson Feb. 15, 2024, 10:26 p.m. UTC | #8
On 2/15/24 12:29 AM, Ard Biesheuvel wrote:
> On Wed, 14 Feb 2024 at 23:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>>
>> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
>> later AMD SKINIT) to vector to during the late launch. The symbol
>> sl_stub_entry is that entry point and its offset into the kernel is
>> conveyed to the launching code using the MLE (Measured Launch
>> Environment) header in the structure named mle_header. The offset of the
>> MLE header is set in the kernel_info. The routine sl_stub contains the
>> very early late launch setup code responsible for setting up the basic
>> environment to allow the normal kernel startup_32 code to proceed. It is
>> also responsible for properly waking and handling the APs on Intel
>> platforms. The routine sl_main which runs after entering 64b mode is
>> responsible for measuring configuration and module information before
>> it is used like the boot params, the kernel command line, the TXT heap,
>> an external initramfs, etc.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>>   Documentation/arch/x86/boot.rst        |  21 +
>>   arch/x86/boot/compressed/Makefile      |   3 +-
>>   arch/x86/boot/compressed/head_64.S     |  34 ++
>>   arch/x86/boot/compressed/kernel_info.S |  34 ++
>>   arch/x86/boot/compressed/sl_main.c     | 582 ++++++++++++++++++++
>>   arch/x86/boot/compressed/sl_stub.S     | 705 +++++++++++++++++++++++++
>>   arch/x86/include/asm/msr-index.h       |   5 +
>>   arch/x86/include/uapi/asm/bootparam.h  |   1 +
>>   arch/x86/kernel/asm-offsets.c          |  20 +
>>   9 files changed, 1404 insertions(+), 1 deletion(-)
>>   create mode 100644 arch/x86/boot/compressed/sl_main.c
>>   create mode 100644 arch/x86/boot/compressed/sl_stub.S
>>
>> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
>> index c513855a54bb..ce6a51c6d4e7 100644
>> --- a/Documentation/arch/x86/boot.rst
>> +++ b/Documentation/arch/x86/boot.rst
>> @@ -482,6 +482,14 @@ Protocol:  2.00+
>>              - If 1, KASLR enabled.
>>              - If 0, KASLR disabled.
>>
>> +  Bit 2 (kernel internal): SLAUNCH_FLAG
>> +
>> +       - Used internally by the compressed kernel to communicate
> 
> decompressor

Yea or I will switch it to setup kernel to keep it consistent with other 
instances.

> 
>> +         Secure Launch status to kernel proper.
>> +
>> +           - If 1, Secure Launch enabled.
>> +           - If 0, Secure Launch disabled.
>> +
>>     Bit 5 (write): QUIET_FLAG
>>
>>          - If 0, print early messages.
>> @@ -1027,6 +1035,19 @@ Offset/size:     0x000c/4
>>
>>     This field contains maximal allowed type for setup_data and setup_indirect structs.
>>
>> +============   =================
>> +Field name:    mle_header_offset
>> +Offset/size:   0x0010/4
>> +============   =================
>> +
>> +  This field contains the offset to the Secure Launch Measured Launch Environment
>> +  (MLE) header. This offset is used to locate information needed during a secure
>> +  late launch using Intel TXT. If the offset is zero, the kernel does not have
>> +  Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
>> +  following a success measured launch. The specific state of the processors is
>> +  outlined in the TXT Software Development Guide, the latest can be found here:
>> +  https://urldefense.com/v3/__https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf__;!!ACWV5N9M2RV99hQ!LHWSKdqHGtnUNYJyVgZfPeQnsg3uWmOJqKGAFDxrHk040zu928199hWhzHehPJzI9IkV4InNQZI5yIX4$
>> +
>>
>>   The Image Checksum
>>   ==================
>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
>> index a1b018eb9801..012f7ca780c3 100644
>> --- a/arch/x86/boot/compressed/Makefile
>> +++ b/arch/x86/boot/compressed/Makefile
>> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>>   vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>>   vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>>
>> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
>> +       $(obj)/sl_main.o $(obj)/sl_stub.o
>>
>>   $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>>          $(call if_changed,ld)
>> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
>> index bf4a10a5794f..6fa5bb87195b 100644
>> --- a/arch/x86/boot/compressed/head_64.S
>> +++ b/arch/x86/boot/compressed/head_64.S
>> @@ -415,6 +415,17 @@ SYM_CODE_START(startup_64)
>>          pushq   $0
>>          popfq
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> +       pushq   %rsi >> +
>  > This push and the associated pop are no longer needed.

Hmm, I thought I got rid of that when I saw boot params had been moved 
to r15. Will fix.

> 
>> +       /* Ensure the relocation region coverd by a PMR */
> 
> 'is covered'

Ack

> 
>> +       movq    %rbx, %rdi
>> +       movl    $(_bss - startup_32), %esi
>> +       callq   sl_check_region
>> +
>> +       popq    %rsi
>> +#endif
>> +
>>   /*
>>    * Copy the compressed kernel to the end of our buffer
>>    * where decompression in place becomes safe.
>> @@ -457,6 +468,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
>>          shrq    $3, %rcx
>>          rep     stosq
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> +       /*
>> +        * Have to do the final early sl stub work in 64b area.
>> +        *
>> +        * *********** NOTE ***********
>> +        *
>> +        * Several boot params get used before we get a chance to measure
>> +        * them in this call. This is a known issue and we currently don't
>> +        * have a solution. The scratch field doesn't matter. There is no
>> +        * obvious way to do anything about the use of kernel_alignment or
>> +        * init_size though these seem low risk with all the PMR and overlap
>> +        * checks in place.
>> +        */
>> +       movq    %r15, %rdi
>> +       callq   sl_main
>> +
>> +       /* Ensure the decompression location is coverd by a PMR */
> 
> covered

Ack

> 
>> +       movq    %rbp, %rdi
>> +       movq    output_len(%rip), %rsi
>> +       callq   sl_check_region
>> +#endif
>> +
>> +       pushq   %rsi
>>          call    load_stage2_idt
>>
>>          /* Pass boot_params to initialize_identity_maps() */
>> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
>> index c18f07181dd5..e199b87764e9 100644
>> --- a/arch/x86/boot/compressed/kernel_info.S
>> +++ b/arch/x86/boot/compressed/kernel_info.S
>> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
>>          /* Maximal allowed type for setup_data and setup_indirect structs. */
>>          .long   SETUP_TYPE_MAX
>>
>> +       /* Offset to the MLE header structure */
>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>> +       .long   rva(mle_header)
>> +#else
>> +       .long   0
>> +#endif
>> +
>>   kernel_info_var_len_data:
>>          /* Empty for time being... */
>>   SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
>> +
>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>> +       /*
>> +        * The MLE Header per the TXT Specification, section 2.1
>> +        * MLE capabilities, see table 4. Capabilities set:
>> +        * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
>> +        * bit 1: Support for RLP wakeup using MONITOR address
>> +        * bit 2: The ECX register will contain the pointer to the MLE page table
>> +        * bit 5: TPM 1.2 family: Details/authorities PCR usage support
>> +        * bit 9: Supported format of TPM 2.0 event log - TCG compliant
>> +        */
>> +SYM_DATA_START(mle_header)
>> +       .long   0x9082ac5a  /* UUID0 */
>> +       .long   0x74a7476f  /* UUID1 */
>> +       .long   0xa2555c0f  /* UUID2 */
>> +       .long   0x42b651cb  /* UUID3 */
>> +       .long   0x00000034  /* MLE header size */
>> +       .long   0x00020002  /* MLE version 2.2 */
>> +       .long   rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
>> +       .long   0x00000000  /* First valid page of MLE */
>> +       .long   0x00000000  /* Offset within binary of first byte of MLE */
>> +       .long   rva(_edata) /* Offset within binary of last byte + 1 of MLE */
>> +       .long   0x00000227  /* Bit vector of MLE-supported capabilities */
>> +       .long   0x00000000  /* Starting linear address of command line (unused) */
>> +       .long   0x00000000  /* Ending linear address of command line (unused) */
>> +SYM_DATA_END(mle_header)
>> +#endif
>> diff --git a/arch/x86/boot/compressed/sl_main.c b/arch/x86/boot/compressed/sl_main.c
>> new file mode 100644
>> index 000000000000..cd9e5c1f1719
>> --- /dev/null
>> +++ b/arch/x86/boot/compressed/sl_main.c
>> @@ -0,0 +1,582 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Secure Launch early measurement and validation routines.
>> + *
>> + * Copyright (c) 2022, Oracle and/or its affiliates.
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/string.h>
>> +#include <linux/linkage.h>
>> +#include <asm/segment.h>
>> +#include <asm/boot.h>
>> +#include <asm/msr.h>
>> +#include <asm/mtrr.h>
>> +#include <asm/processor-flags.h>
>> +#include <asm/asm-offsets.h>
>> +#include <asm/bootparam.h>
>> +#include <asm/bootparam_utils.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>> +#include <crypto/sha1.h>
>> +#include <crypto/sha2.h>
>> +
>> +#define CAPS_VARIABLE_MTRR_COUNT_MASK  0xff
>> +
>> +#define SL_TPM12_LOG           1
>> +#define SL_TPM20_LOG           2
>> +
>> +#define SL_TPM20_MAX_ALGS      2
>> +
>> +#define SL_MAX_EVENT_DATA      64
>> +#define SL_TPM12_LOG_SIZE      (sizeof(struct tcg_pcr_event) + \
>> +                               SL_MAX_EVENT_DATA)
>> +#define SL_TPM20_LOG_SIZE      (sizeof(struct tcg_pcr_event2_head) + \
>> +                               SHA1_DIGEST_SIZE + SHA256_DIGEST_SIZE + \
>> +                               sizeof(struct tcg_event_field) + \
>> +                               SL_MAX_EVENT_DATA)
>> +
>> +static void *evtlog_base;
>> +static u32 evtlog_size;
>> +static struct txt_heap_event_log_pointer2_1_element *log20_elem;
>> +static u32 tpm_log_ver = SL_TPM12_LOG;
>> +static struct tcg_efi_specid_event_algs tpm_algs[SL_TPM20_MAX_ALGS] = {0};
>> +
>> +extern u32 sl_cpu_type;
>> +extern u32 sl_mle_start;
>> +
>> +static u64 sl_txt_read(u32 reg)
>> +{
>> +       return readq((void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
>> +}
>> +
>> +static void sl_txt_write(u32 reg, u64 val)
>> +{
>> +       writeq(val, (void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
>> +}
>> +
>> +static void __noreturn sl_txt_reset(u64 error)
>> +{
>> +       /* Reading the E2STS register acts as a barrier for TXT registers */
>> +       sl_txt_write(TXT_CR_ERRORCODE, error);
>> +       sl_txt_read(TXT_CR_E2STS);
>> +       sl_txt_write(TXT_CR_CMD_UNLOCK_MEM_CONFIG, 1);
>> +       sl_txt_read(TXT_CR_E2STS);
>> +       sl_txt_write(TXT_CR_CMD_RESET, 1);
>> +
>> +       for ( ; ; )
>> +               asm volatile ("hlt");
>> +
>> +       unreachable();
>> +}
>> +
>> +static u64 sl_rdmsr(u32 reg)
>> +{
>> +       u64 lo, hi;
>> +
>> +       asm volatile ("rdmsr" : "=a" (lo), "=d" (hi) : "c" (reg));
>> +
> 
> No need for volatile.

Ok.

Thanks
Ross

> 
>> +       return (hi << 32) | lo;
>> +}
>> +
>> +static struct slr_table *sl_locate_and_validate_slrt(void)
>> +{
>> +       struct txt_os_mle_data *os_mle_data;
>> +       struct slr_table *slrt;
>> +       void *txt_heap;
>> +
>> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> +       os_mle_data = txt_os_mle_data_start(txt_heap);
>> +
>> +       if (!os_mle_data->slrt)
>> +               sl_txt_reset(SL_ERROR_INVALID_SLRT);
>> +
>> +       slrt = (struct slr_table *)os_mle_data->slrt;
>> +
>> +       if (slrt->magic != SLR_TABLE_MAGIC)
>> +               sl_txt_reset(SL_ERROR_INVALID_SLRT);
>> +
>> +       if (slrt->architecture != SLR_INTEL_TXT)
>> +               sl_txt_reset(SL_ERROR_INVALID_SLRT);
>> +
>> +       return slrt;
>> +}
>> +
>> +static void sl_check_pmr_coverage(void *base, u32 size, bool allow_hi)
>> +{
>> +       struct txt_os_sinit_data *os_sinit_data;
>> +       void *end = base + size;
>> +       void *txt_heap;
>> +
>> +       if (!(sl_cpu_type & SL_CPU_INTEL))
>> +               return;
>> +
>> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> +       os_sinit_data = txt_os_sinit_data_start(txt_heap);
>> +
>> +       if ((end >= (void *)0x100000000ULL) && (base < (void *)0x100000000ULL))
>> +               sl_txt_reset(SL_ERROR_REGION_STRADDLE_4GB);
>> +
>> +       /*
>> +        * Note that the late stub code validates that the hi PMR covers
>> +        * all memory above 4G. At this point the code can only check that
>> +        * regions are within the hi PMR but that is sufficient.
>> +        */
>> +       if ((end > (void *)0x100000000ULL) && (base >= (void *)0x100000000ULL)) {
>> +               if (allow_hi) {
>> +                       if (end >= (void *)(os_sinit_data->vtd_pmr_hi_base +
>> +                                          os_sinit_data->vtd_pmr_hi_size))
>> +                               sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
>> +               } else {
>> +                       sl_txt_reset(SL_ERROR_REGION_ABOVE_4GB);
>> +               }
>> +       }
>> +
>> +       if (end >= (void *)os_sinit_data->vtd_pmr_lo_size)
>> +               sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
>> +}
>> +
>> +/*
>> + * Some MSRs are modified by the pre-launch code including the MTRRs.
>> + * The early MLE code has to restore these values. This code validates
>> + * the values after they are measured.
>> + */
>> +static void sl_txt_validate_msrs(struct txt_os_mle_data *os_mle_data)
>> +{
>> +       struct slr_txt_mtrr_state *saved_bsp_mtrrs;
>> +       u64 mtrr_caps, mtrr_def_type, mtrr_var;
>> +       struct slr_entry_intel_info *txt_info;
>> +       u64 misc_en_msr;
>> +       u32 vcnt, i;
>> +
>> +       txt_info = (struct slr_entry_intel_info *)os_mle_data->txt_info;
>> +       saved_bsp_mtrrs = &txt_info->saved_bsp_mtrrs;
>> +
>> +       mtrr_caps = sl_rdmsr(MSR_MTRRcap);
>> +       vcnt = (u32)(mtrr_caps & CAPS_VARIABLE_MTRR_COUNT_MASK);
>> +
>> +       if (saved_bsp_mtrrs->mtrr_vcnt > vcnt)
>> +               sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
>> +       if (saved_bsp_mtrrs->mtrr_vcnt > TXT_OS_MLE_MAX_VARIABLE_MTRRS)
>> +               sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
>> +
>> +       mtrr_def_type = sl_rdmsr(MSR_MTRRdefType);
>> +       if (saved_bsp_mtrrs->default_mem_type != mtrr_def_type)
>> +               sl_txt_reset(SL_ERROR_MTRR_INV_DEF_TYPE);
>> +
>> +       for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; i++) {
>> +               mtrr_var = sl_rdmsr(MTRRphysBase_MSR(i));
>> +               if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase != mtrr_var)
>> +                       sl_txt_reset(SL_ERROR_MTRR_INV_BASE);
>> +               mtrr_var = sl_rdmsr(MTRRphysMask_MSR(i));
>> +               if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask != mtrr_var)
>> +                       sl_txt_reset(SL_ERROR_MTRR_INV_MASK);
>> +       }
>> +
>> +       misc_en_msr = sl_rdmsr(MSR_IA32_MISC_ENABLE);
>> +       if (txt_info->saved_misc_enable_msr != misc_en_msr)
>> +               sl_txt_reset(SL_ERROR_MSR_INV_MISC_EN);
>> +}
>> +
>> +static void sl_find_drtm_event_log(struct slr_table *slrt)
>> +{
>> +       struct txt_os_sinit_data *os_sinit_data;
>> +       struct slr_entry_log_info *log_info;
>> +       void *txt_heap;
>> +
>> +       log_info = (struct slr_entry_log_info *)
>> +                   slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
>> +       if (!log_info)
>> +               sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
>> +
>> +       evtlog_base = (void *)log_info->addr;
>> +       evtlog_size = log_info->size;
>> +
>> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> +
>> +       /*
>> +        * For TPM 2.0, the event log 2.1 extended data structure has to also
>> +        * be located and fixed up.
>> +        */
>> +       os_sinit_data = txt_os_sinit_data_start(txt_heap);
>> +
>> +       /*
>> +        * Only support version 6 and later that properly handle the
>> +        * list of ExtDataElements in the OS-SINIT structure.
>> +        */
>> +       if (os_sinit_data->version < 6)
>> +               sl_txt_reset(SL_ERROR_OS_SINIT_BAD_VERSION);
>> +
>> +       /* Find the TPM2.0 logging extended heap element */
>> +       log20_elem = tpm20_find_log2_1_element(os_sinit_data);
>> +
>> +       /* If found, this implies TPM20 log and family */
>> +       if (log20_elem)
>> +               tpm_log_ver = SL_TPM20_LOG;
>> +}
>> +
>> +static void sl_validate_event_log_buffer(void)
>> +{
>> +       struct txt_os_sinit_data *os_sinit_data;
>> +       void *txt_heap, *txt_end;
>> +       void *mle_base, *mle_end;
>> +       void *evtlog_end;
>> +
>> +       if ((u64)evtlog_size > (LLONG_MAX - (u64)evtlog_base))
>> +               sl_txt_reset(SL_ERROR_INTEGER_OVERFLOW);
>> +       evtlog_end = evtlog_base + evtlog_size;
>> +
>> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> +       txt_end = txt_heap + sl_txt_read(TXT_CR_HEAP_SIZE);
>> +       os_sinit_data = txt_os_sinit_data_start(txt_heap);
>> +
>> +       mle_base = (void *)(u64)sl_mle_start;
>> +       mle_end = mle_base + os_sinit_data->mle_size;
>> +
>> +       /*
>> +        * This check is to ensure the event log buffer does not overlap with
>> +        * the MLE image.
>> +        */
>> +       if (evtlog_base >= mle_end && evtlog_end > mle_end)
>> +               goto pmr_check; /* above */
>> +
>> +       if (evtlog_end <= mle_base && evtlog_base < mle_base)
>> +               goto pmr_check; /* below */
>> +
>> +       sl_txt_reset(SL_ERROR_MLE_BUFFER_OVERLAP);
>> +
>> +pmr_check:
>> +       /*
>> +        * The TXT heap is protected by the DPR. If the TPM event log is
>> +        * inside the TXT heap, there is no need for a PMR check.
>> +        */
>> +       if (evtlog_base > txt_heap && evtlog_end < txt_end)
>> +               return;
>> +
>> +       sl_check_pmr_coverage(evtlog_base, evtlog_size, true);
>> +}
>> +
>> +static void sl_find_event_log_algorithms(void)
>> +{
>> +       struct tcg_efi_specid_event_head *efi_head =
>> +               (struct tcg_efi_specid_event_head *)(evtlog_base +
>> +                                       log20_elem->first_record_offset +
>> +                                       sizeof(struct tcg_pcr_event));
>> +
>> +       if (efi_head->num_algs == 0 || efi_head->num_algs > 2)
>> +               sl_txt_reset(SL_ERROR_TPM_NUMBER_ALGS);
>> +
>> +       memcpy(&tpm_algs[0], &efi_head->digest_sizes[0],
>> +              sizeof(struct tcg_efi_specid_event_algs) * efi_head->num_algs);
>> +}
>> +
>> +static void sl_tpm12_log_event(u32 pcr, u32 event_type,
>> +                              const u8 *data, u32 length,
>> +                              const u8 *event_data, u32 event_size)
>> +{
>> +       u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
>> +       u8 log_buf[SL_TPM12_LOG_SIZE] = {0};
>> +       struct tcg_pcr_event *pcr_event;
>> +       u32 total_size;
>> +
>> +       pcr_event = (struct tcg_pcr_event *)log_buf;
>> +       pcr_event->pcr_idx = pcr;
>> +       pcr_event->event_type = event_type;
>> +       if (length > 0) {
>> +               sha1(data, length, &sha1_hash[0]);
>> +               memcpy(&pcr_event->digest[0], &sha1_hash[0], SHA1_DIGEST_SIZE);
>> +       }
>> +       pcr_event->event_size = event_size;
>> +       if (event_size > 0)
>> +               memcpy((u8 *)pcr_event + sizeof(struct tcg_pcr_event),
>> +                      event_data, event_size);
>> +
>> +       total_size = sizeof(struct tcg_pcr_event) + event_size;
>> +
>> +       if (tpm12_log_event(evtlog_base, evtlog_size, total_size, pcr_event))
>> +               sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
>> +}
>> +
>> +static void sl_tpm20_log_event(u32 pcr, u32 event_type,
>> +                              const u8 *data, u32 length,
>> +                              const u8 *event_data, u32 event_size)
>> +{
>> +       u8 sha256_hash[SHA256_DIGEST_SIZE] = {0};
>> +       u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
>> +       u8 log_buf[SL_TPM20_LOG_SIZE] = {0};
>> +       struct sha256_state sctx256 = {0};
>> +       struct tcg_pcr_event2_head *head;
>> +       struct tcg_event_field *event;
>> +       u32 total_size;
>> +       u16 *alg_ptr;
>> +       u8 *dgst_ptr;
>> +
>> +       head = (struct tcg_pcr_event2_head *)log_buf;
>> +       head->pcr_idx = pcr;
>> +       head->event_type = event_type;
>> +       total_size = sizeof(struct tcg_pcr_event2_head);
>> +       alg_ptr = (u16 *)(log_buf + sizeof(struct tcg_pcr_event2_head));
>> +
>> +       for ( ; head->count < 2; head->count++) {
>> +               if (!tpm_algs[head->count].alg_id)
>> +                       break;
>> +
>> +               *alg_ptr = tpm_algs[head->count].alg_id;
>> +               dgst_ptr = (u8 *)alg_ptr + sizeof(u16);
>> +
>> +               if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256 &&
>> +                   length) {
>> +                       sha256_init(&sctx256);
>> +                       sha256_update(&sctx256, data, length);
>> +                       sha256_final(&sctx256, &sha256_hash[0]);
>> +               } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1 &&
>> +                          length) {
>> +                       sha1(data, length, &sha1_hash[0]);
>> +               }
>> +
>> +               if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256) {
>> +                       memcpy(dgst_ptr, &sha256_hash[0], SHA256_DIGEST_SIZE);
>> +                       total_size += SHA256_DIGEST_SIZE + sizeof(u16);
>> +                       alg_ptr = (u16 *)((u8 *)alg_ptr + SHA256_DIGEST_SIZE + sizeof(u16));
>> +               } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1) {
>> +                       memcpy(dgst_ptr, &sha1_hash[0], SHA1_DIGEST_SIZE);
>> +                       total_size += SHA1_DIGEST_SIZE + sizeof(u16);
>> +                       alg_ptr = (u16 *)((u8 *)alg_ptr + SHA1_DIGEST_SIZE + sizeof(u16));
>> +               } else {
>> +                       sl_txt_reset(SL_ERROR_TPM_UNKNOWN_DIGEST);
>> +               }
>> +       }
>> +
>> +       event = (struct tcg_event_field *)(log_buf + total_size);
>> +       event->event_size = event_size;
>> +       if (event_size > 0)
>> +               memcpy((u8 *)event + sizeof(struct tcg_event_field), event_data, event_size);
>> +       total_size += sizeof(struct tcg_event_field) + event_size;
>> +
>> +       if (tpm20_log_event(log20_elem, evtlog_base, evtlog_size, total_size, &log_buf[0]))
>> +               sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
>> +}
>> +
>> +static void sl_tpm_extend_evtlog(u32 pcr, u32 type,
>> +                                const u8 *data, u32 length, const char *desc)
>> +{
>> +       if (tpm_log_ver == SL_TPM20_LOG)
>> +               sl_tpm20_log_event(pcr, type, data, length,
>> +                                  (const u8 *)desc, strlen(desc));
>> +       else
>> +               sl_tpm12_log_event(pcr, type, data, length,
>> +                                  (const u8 *)desc, strlen(desc));
>> +}
>> +
>> +static struct setup_data *sl_handle_setup_data(struct setup_data *curr,
>> +                                              struct slr_policy_entry *entry)
>> +{
>> +       struct setup_indirect *ind;
>> +       struct setup_data *next;
>> +
>> +       if (!curr)
>> +               return NULL;
>> +
>> +       next = (struct setup_data *)(unsigned long)curr->next;
>> +
>> +       /* SETUP_INDIRECT instances have to be handled differently */
>> +       if (curr->type == SETUP_INDIRECT) {
>> +               ind = (struct setup_indirect *)((u8 *)curr + offsetof(struct setup_data, data));
>> +
>> +               sl_check_pmr_coverage((void *)ind->addr, ind->len, true);
>> +
>> +               sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> +                                    (void *)ind->addr, ind->len,
>> +                                    entry->evt_info);
>> +
>> +               return next;
>> +       }
>> +
>> +       sl_check_pmr_coverage(((u8 *)curr) + sizeof(struct setup_data),
>> +                             curr->len, true);
>> +
>> +       sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> +                            ((u8 *)curr) + sizeof(struct setup_data),
>> +                            curr->len,
>> +                            entry->evt_info);
>> +
>> +       return next;
>> +}
>> +
>> +static void sl_extend_setup_data(struct slr_policy_entry *entry)
>> +{
>> +       struct setup_data *data;
>> +
>> +       /*
>> +        * Measuring the boot params measured the fixed e820 memory map.
>> +        * Measure any setup_data entries including e820 extended entries.
>> +        */
>> +       data = (struct setup_data *)(unsigned long)entry->entity;
>> +       while (data)
>> +               data = sl_handle_setup_data(data, entry);
>> +}
>> +
>> +static void sl_extend_slrt(struct slr_policy_entry *entry)
>> +{
>> +       struct slr_table *slrt = (struct slr_table *)entry->entity;
>> +       struct slr_entry_intel_info *intel_info;
>> +
>> +       /*
>> +        * In revision one of the SLRT, the only table that needs to be
>> +        * measured is the Intel info table. Everything else is meta-data,
>> +        * addresses and sizes. Note the size of what to measure is not set.
>> +        * The flag SLR_POLICY_IMPLICIT_SIZE leaves it to the measuring code
>> +        * to sort out.
>> +        */
>> +       if (slrt->revision == 1) {
>> +               intel_info = (struct slr_entry_intel_info *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
>> +               if (!intel_info)
>> +                       sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
>> +
>> +               sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> +                                    (void *)entry->entity, sizeof(struct slr_entry_intel_info),
>> +                                    entry->evt_info);
>> +       }
>> +}
>> +
>> +static void sl_extend_txt_os2mle(struct slr_policy_entry *entry)
>> +{
>> +       struct txt_os_mle_data *os_mle_data;
>> +       void *txt_heap;
>> +
>> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> +       os_mle_data = txt_os_mle_data_start(txt_heap);
>> +
>> +       /*
>> +        * Version 1 of the OS-MLE heap structure has no fields to measure. It just
>> +        * has addresses and sizes and a scratch buffer.
>> +        */
>> +       if (os_mle_data->version == 1)
>> +               return;
>> +}
>> +
>> +static void sl_process_extend_policy(struct slr_table *slrt)
>> +{
>> +       struct slr_entry_policy *policy;
>> +       struct slr_policy_entry *entry;
>> +       u16 i;
>> +
>> +       policy = (struct slr_entry_policy *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
>> +       if (!policy)
>> +               sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
>> +
>> +       entry = (struct slr_policy_entry *)((u8 *)policy + sizeof(*policy));
>> +
>> +       for (i = 0; i < policy->nr_entries; i++, entry++) {
>> +               switch (entry->entity_type) {
>> +               case SLR_ET_SETUP_DATA:
>> +                       sl_extend_setup_data(entry);
>> +                       break;
>> +               case SLR_ET_SLRT:
>> +                       sl_extend_slrt(entry);
>> +                       break;
>> +               case SLR_ET_TXT_OS2MLE:
>> +                       sl_extend_txt_os2mle(entry);
>> +                       break;
>> +               case SLR_ET_UNUSED:
>> +                       continue;
>> +               default:
>> +                       sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> +                                            (void *)entry->entity, entry->size,
>> +                                            entry->evt_info);
>> +               }
>> +       }
>> +}
>> +
>> +static void sl_process_extend_uefi_config(struct slr_table *slrt)
>> +{
>> +       struct slr_entry_uefi_config *uefi_config;
>> +       struct slr_uefi_cfg_entry *uefi_entry;
>> +       u64 i;
>> +
>> +       uefi_config =(struct slr_entry_uefi_config *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_UEFI_CONFIG);
>> +
>> +       /* Optionally here depending on how SL kernel was booted */
>> +       if (!uefi_config)
>> +               return;
>> +
>> +       uefi_entry = (struct slr_uefi_cfg_entry *)((u8 *)uefi_config + sizeof(*uefi_config));
>> +
>> +       for (i = 0; i < uefi_config->nr_entries; i++, uefi_entry++) {
>> +               sl_tpm_extend_evtlog(uefi_entry->pcr, TXT_EVTYPE_SLAUNCH,
>> +                                    (void *)uefi_entry->cfg, uefi_entry->size,
>> +                                    uefi_entry->evt_info);
>> +       }
>> +}
>> +
>> +asmlinkage __visible void sl_check_region(void *base, u32 size)
>> +{
>> +       sl_check_pmr_coverage(base, size, false);
>> +}
>> +
>> +asmlinkage __visible void sl_main(void *bootparams)
>> +{
>> +       struct boot_params *bp  = (struct boot_params *)bootparams;
>> +       struct txt_os_mle_data *os_mle_data;
>> +       struct slr_table *slrt;
>> +       void *txt_heap;
>> +
>> +       /*
>> +        * Ensure loadflags do not indicate a secure launch was done
>> +        * unless it really was.
>> +        */
>> +       bp->hdr.loadflags &= ~SLAUNCH_FLAG;
>> +
>> +       /*
>> +        * Currently only Intel TXT is supported for Secure Launch. Testing
>> +        * this value also indicates that the kernel was booted successfully
>> +        * through the Secure Launch entry point and is in SMX mode.
>> +        */
>> +       if (!(sl_cpu_type & SL_CPU_INTEL))
>> +               return;
>> +
>> +       slrt = sl_locate_and_validate_slrt();
>> +
>> +       /* Locate the TPM event log. */
>> +       sl_find_drtm_event_log(slrt);
>> +
>> +       /* Validate the location of the event log buffer before using it */
>> +       sl_validate_event_log_buffer();
>> +
>> +       /*
>> +        * Find the TPM hash algorithms used by the ACM and recorded in the
>> +        * event log.
>> +        */
>> +       if (tpm_log_ver == SL_TPM20_LOG)
>> +               sl_find_event_log_algorithms();
>> +
>> +       /*
>> +        * Sanitize them before measuring. Set the SLAUNCH_FLAG early since if
>> +        * anything fails, the system will reset anyway.
>> +        */
>> +       sanitize_boot_params(bp);
>> +       bp->hdr.loadflags |= SLAUNCH_FLAG;
>> +
>> +       sl_check_pmr_coverage(bootparams, PAGE_SIZE, false);
>> +
>> +       /* Place event log SL specific tags before and after measurements */
>> +       sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_START, NULL, 0, "");
>> +
>> +       /* Process all policy entries and extend the measurements to the evtlog */
>> +       sl_process_extend_policy(slrt);
>> +
>> +       /* Process all EFI config entries and extend the measurements to the evtlog */
>> +       sl_process_extend_uefi_config(slrt);
>> +
>> +       sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_END, NULL, 0, "");
>> +
>> +       /* No PMR check is needed, the TXT heap is covered by the DPR */
>> +       txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> +       os_mle_data = txt_os_mle_data_start(txt_heap);
>> +
>> +       /*
>> +        * Now that the OS-MLE data is measured, ensure the MTRR and
>> +        * misc enable MSRs are what we expect.
>> +        */
>> +       sl_txt_validate_msrs(os_mle_data);
>> +}
>> diff --git a/arch/x86/boot/compressed/sl_stub.S b/arch/x86/boot/compressed/sl_stub.S
>> new file mode 100644
>> index 000000000000..42a7436cf2ee
>> --- /dev/null
>> +++ b/arch/x86/boot/compressed/sl_stub.S
>> @@ -0,0 +1,705 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +
>> +/*
>> + * Secure Launch protected mode entry point.
>> + *
>> + * Copyright (c) 2022, Oracle and/or its affiliates.
>> + */
>> +       .code32
>> +       .text
>> +#include <linux/linkage.h>
>> +#include <asm/segment.h>
>> +#include <asm/msr.h>
>> +#include <asm/apicdef.h>
>> +#include <asm/trapnr.h>
>> +#include <asm/processor-flags.h>
>> +#include <asm/asm-offsets.h>
>> +#include <asm/bootparam.h>
>> +#include <asm/page_types.h>
>> +#include <asm/irq_vectors.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>> +
>> +/* CPUID: leaf 1, ECX, SMX feature bit */
>> +#define X86_FEATURE_BIT_SMX    (1 << 6)
>> +
>> +#define IDT_VECTOR_LO_BITS     0
>> +#define IDT_VECTOR_HI_BITS     6
>> +
>> +/*
>> + * See the comment in head_64.S for detailed information on what this macro
>> + * and others like it are used for. The comment appears right at the top of
>> + * the file.
>> + */
>> +#define rva(X) ((X) - sl_stub_entry)
>> +
>> +/*
>> + * The GETSEC op code is open coded because older versions of
>> + * GCC do not support the getsec mnemonic.
>> + */
>> +.macro GETSEC leaf
>> +       pushl   %ebx
>> +       xorl    %ebx, %ebx      /* Must be zero for SMCTRL */
>> +       movl    \leaf, %eax     /* Leaf function */
>> +       .byte   0x0f, 0x37      /* GETSEC opcode */
>> +       popl    %ebx
>> +.endm
>> +
>> +.macro TXT_RESET error
>> +       /*
>> +        * Set a sticky error value and reset. Note the movs to %eax act as
>> +        * TXT register barriers.
>> +        */
>> +       movl    \error, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
>> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
>> +       movl    $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_NO_SECRETS)
>> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
>> +       movl    $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_UNLOCK_MEM_CONFIG)
>> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
>> +       movl    $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_RESET)
>> +1:
>> +       hlt
>> +       jmp     1b
>> +.endm
>> +
>> +       .code32
>> +SYM_FUNC_START(sl_stub_entry)
>> +       cli
>> +       cld
>> +
>> +       /*
>> +        * On entry, %ebx has the entry abs offset to sl_stub_entry. This
>> +        * will be correctly scaled using the rva macro and avoid causing
>> +        * relocations. Only %cs and %ds segments are known good.
>> +        */
>> +
>> +       /* Load GDT, set segment regs and lret to __SL32_CS */
>> +       leal    rva(sl_gdt_desc)(%ebx), %eax
>> +       addl    %eax, 2(%eax)
>> +       lgdt    (%eax)
>> +
>> +       movl    $(__SL32_DS), %eax
>> +       movw    %ax, %ds
>> +       movw    %ax, %es
>> +       movw    %ax, %fs
>> +       movw    %ax, %gs
>> +       movw    %ax, %ss
>> +
>> +       /*
>> +        * Now that %ss is known good, take the first stack for the BSP. The
>> +        * AP stacks are only used on Intel.
>> +        */
>> +       leal    rva(sl_stacks_end)(%ebx), %esp
>> +
>> +       leal    rva(.Lsl_cs)(%ebx), %eax
>> +       pushl   $(__SL32_CS)
>> +       pushl   %eax
>> +       lret
>> +
>> +.Lsl_cs:
>> +       /* Save our base pointer reg and page table for MLE */
>> +       pushl   %ebx
>> +       pushl   %ecx
>> +
>> +       /* See if SMX feature is supported. */
>> +       movl    $1, %eax
>> +       cpuid
>> +       testl   $(X86_FEATURE_BIT_SMX), %ecx
>> +       jz      .Ldo_unknown_cpu
>> +
>> +       popl    %ecx
>> +       popl    %ebx
>> +
>> +       /* Know it is Intel */
>> +       movl    $(SL_CPU_INTEL), rva(sl_cpu_type)(%ebx)
>> +
>> +       /* Locate the base of the MLE using the page tables in %ecx */
>> +       call    sl_find_mle_base
>> +
>> +       /* Increment CPU count for BSP */
>> +       incl    rva(sl_txt_cpu_count)(%ebx)
>> +
>> +       /*
>> +        * Enable SMI with GETSEC[SMCTRL] which were disabled by SENTER.
>> +        * NMIs were also disabled by SENTER. Since there is no IDT for the BSP,
>> +        * allow the mainline kernel re-enable them in the normal course of
>> +        * booting.
>> +        */
>> +       GETSEC  $(SMX_X86_GETSEC_SMCTRL)
>> +
>> +       /* Clear the TXT error registers for a clean start of day */
>> +       movl    $0, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
>> +       movl    $0xffffffff, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ESTS)
>> +
>> +       /* On Intel, the zero page address is passed in the TXT heap */
>> +       /* Read physical base of heap into EAX */
>> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
>> +       /* Read the size of the BIOS data into ECX (first 8 bytes) */
>> +       movl    (%eax), %ecx
>> +       /* Skip over BIOS data and size of OS to MLE data section */
>> +       leal    8(%eax, %ecx), %eax
>> +
>> +       /* Need to verify the values in the OS-MLE struct passed in */
>> +       call    sl_txt_verify_os_mle_struct
>> +
>> +       /*
>> +        * Get the boot params address from the heap. Note %esi and %ebx MUST
>> +        * be preserved across calls and operations.
>> +        */
>> +       movl    SL_boot_params_addr(%eax), %esi
>> +
>> +       /* Save %ebx so the APs can find their way home */
>> +       movl    %ebx, (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax)
>> +
>> +       /* Fetch the AP wake code block address from the heap */
>> +       movl    SL_ap_wake_block(%eax), %edi
>> +       movl    %edi, rva(sl_txt_ap_wake_block)(%ebx)
>> +
>> +       /* Store the offset in the AP wake block to the jmp address */
>> +       movl    $(sl_ap_jmp_offset - sl_txt_ap_wake_begin), \
>> +               (SL_mle_scratch + SL_SCRATCH_AP_JMP_OFFSET)(%eax)
>> +
>> +       /* Store the offset in the AP wake block to the AP stacks block */
>> +       movl    $(sl_stacks - sl_txt_ap_wake_begin), \
>> +               (SL_mle_scratch + SL_SCRATCH_AP_STACKS_OFFSET)(%eax)
>> +
>> +       /* %eax still is the base of the OS-MLE block, save it */
>> +       pushl   %eax
>> +
>> +       /* Relocate the AP wake code to the safe block */
>> +       call    sl_txt_reloc_ap_wake
>> +
>> +       /*
>> +        * Wake up all APs that are blocked in the ACM and wait for them to
>> +        * halt. This should be done before restoring the MTRRs so the ACM is
>> +        * still properly in WB memory.
>> +        */
>> +       call    sl_txt_wake_aps
>> +
>> +       /* Restore OS-MLE in %eax */
>> +       popl    %eax
>> +
>> +       /*
>> +        * %edi is used by this routine to find the MTRRs which are in the SLRT
>> +        * in the Intel info.
>> +        */
>> +       movl    SL_txt_info(%eax), %edi
>> +       call    sl_txt_load_regs
>> +
>> +       jmp     .Lcpu_setup_done
>> +
>> +.Ldo_unknown_cpu:
>> +       /* Non-Intel CPUs are not yet supported */
>> +       ud2
>> +
>> +.Lcpu_setup_done:
>> +       /*
>> +        * Don't enable MCE at this point. The kernel will enable
>> +        * it on the BSP later when it is ready.
>> +        */
>> +
>> +       /* Done, jump to normal 32b pm entry */
>> +       jmp     startup_32
>> +SYM_FUNC_END(sl_stub_entry)
>> +
>> +SYM_FUNC_START(sl_find_mle_base)
>> +       /* %ecx has PDPT, get first PD */
>> +       movl    (%ecx), %eax
>> +       andl    $(PAGE_MASK), %eax
>> +       /* Get first PT from first PDE */
>> +       movl    (%eax), %eax
>> +       andl    $(PAGE_MASK), %eax
>> +       /* Get MLE base from first PTE */
>> +       movl    (%eax), %eax
>> +       andl    $(PAGE_MASK), %eax
>> +
>> +       movl    %eax, rva(sl_mle_start)(%ebx)
>> +       ret
>> +SYM_FUNC_END(sl_find_mle_base)
>> +
>> +SYM_FUNC_START(sl_check_buffer_mle_overlap)
>> +       /* %ecx: buffer begin %edx: buffer end */
>> +       /* %ebx: MLE begin %edi: MLE end */
>> +
>> +       cmpl    %edi, %ecx
>> +       jb      .Lnext_check
>> +       cmpl    %edi, %edx
>> +       jbe     .Lnext_check
>> +       jmp     .Lvalid /* Buffer above MLE */
>> +
>> +.Lnext_check:
>> +       cmpl    %ebx, %edx
>> +       ja      .Linvalid
>> +       cmpl    %ebx, %ecx
>> +       jae     .Linvalid
>> +       jmp     .Lvalid /* Buffer below MLE */
>> +
>> +.Linvalid:
>> +       TXT_RESET $(SL_ERROR_MLE_BUFFER_OVERLAP)
>> +
>> +.Lvalid:
>> +       ret
>> +SYM_FUNC_END(sl_check_buffer_mle_overlap)
>> +
>> +SYM_FUNC_START(sl_txt_verify_os_mle_struct)
>> +       pushl   %ebx
>> +       /*
>> +        * %eax points to the base of the OS-MLE struct. Need to also
>> +        * read some values from the OS-SINIT struct too.
>> +        */
>> +       movl    -8(%eax), %ecx
>> +       /* Skip over OS to MLE data section and size of OS-SINIT structure */
>> +       leal    (%eax, %ecx), %edx
>> +
>> +       /* Load MLE image base absolute offset */
>> +       movl    rva(sl_mle_start)(%ebx), %ebx
>> +
>> +       /* Verify the value of the low PMR base. It should always be 0. */
>> +       movl    SL_vtd_pmr_lo_base(%edx), %esi
>> +       cmpl    $0, %esi
>> +       jz      .Lvalid_pmr_base
>> +       TXT_RESET $(SL_ERROR_LO_PMR_BASE)
>> +
>> +.Lvalid_pmr_base:
>> +       /* Grab some values from OS-SINIT structure */
>> +       movl    SL_mle_size(%edx), %edi
>> +       addl    %ebx, %edi
>> +       jc      .Loverflow_detected
>> +       movl    SL_vtd_pmr_lo_size(%edx), %esi
>> +
>> +       /* Check the AP wake block */
>> +       movl    SL_ap_wake_block(%eax), %ecx
>> +       movl    SL_ap_wake_block_size(%eax), %edx
>> +       addl    %ecx, %edx
>> +       jc      .Loverflow_detected
>> +       call    sl_check_buffer_mle_overlap
>> +       cmpl    %esi, %edx
>> +       ja      .Lbuffer_beyond_pmr
>> +
>> +       /* Check the boot params */
>> +       movl    SL_boot_params_addr(%eax), %ecx
>> +       movl    $(PAGE_SIZE), %edx
>> +       addl    %ecx, %edx
>> +       jc      .Loverflow_detected
>> +       call    sl_check_buffer_mle_overlap
>> +       cmpl    %esi, %edx
>> +       ja      .Lbuffer_beyond_pmr
>> +
>> +       /* Check that the AP wake block is big enough */
>> +       cmpl    $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), \
>> +               SL_ap_wake_block_size(%eax)
>> +       jae     .Lwake_block_ok
>> +       TXT_RESET $(SL_ERROR_WAKE_BLOCK_TOO_SMALL)
>> +
>> +.Lwake_block_ok:
>> +       popl    %ebx
>> +       ret
>> +
>> +.Loverflow_detected:
>> +       TXT_RESET $(SL_ERROR_INTEGER_OVERFLOW)
>> +
>> +.Lbuffer_beyond_pmr:
>> +       TXT_RESET $(SL_ERROR_BUFFER_BEYOND_PMR)
>> +SYM_FUNC_END(sl_txt_verify_os_mle_struct)
>> +
>> +SYM_FUNC_START(sl_txt_ap_entry)
>> +       cli
>> +       cld
>> +       /*
>> +        * The %cs and %ds segments are known good after waking the AP.
>> +        * First order of business is to find where we are and
>> +        * save it in %ebx.
>> +        */
>> +
>> +       /* Read physical base of heap into EAX */
>> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
>> +       /* Read the size of the BIOS data into ECX (first 8 bytes) */
>> +       movl    (%eax), %ecx
>> +       /* Skip over BIOS data and size of OS to MLE data section */
>> +       leal    8(%eax, %ecx), %eax
>> +
>> +       /* Saved %ebx from the BSP and stash OS-MLE pointer */
>> +       movl    (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax), %ebx
>> +
>> +       /* Save TXT info ptr in %edi for call to sl_txt_load_regs */
>> +       movl    SL_txt_info(%eax), %edi
>> +
>> +       /* Lock and get our stack index */
>> +       movl    $1, %ecx
>> +.Lspin:
>> +       xorl    %eax, %eax
>> +       lock cmpxchgl   %ecx, rva(sl_txt_spin_lock)(%ebx)
>> +       pause
>> +       jnz     .Lspin
>> +
>> +       /* Increment the stack index and use the next value inside lock */
>> +       incl    rva(sl_txt_stack_index)(%ebx)
>> +       movl    rva(sl_txt_stack_index)(%ebx), %eax
>> +
>> +       /* Unlock */
>> +       movl    $0, rva(sl_txt_spin_lock)(%ebx)
>> +
>> +       /* Location of the relocated AP wake block */
>> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %ecx
>> +
>> +       /* Load reloc GDT, set segment regs and lret to __SL32_CS */
>> +       lgdt    (sl_ap_gdt_desc - sl_txt_ap_wake_begin)(%ecx)
>> +
>> +       movl    $(__SL32_DS), %edx
>> +       movw    %dx, %ds
>> +       movw    %dx, %es
>> +       movw    %dx, %fs
>> +       movw    %dx, %gs
>> +       movw    %dx, %ss
>> +
>> +       /* Load our reloc AP stack */
>> +       movl    $(TXT_BOOT_STACK_SIZE), %edx
>> +       mull    %edx
>> +       leal    (sl_stacks_end - sl_txt_ap_wake_begin)(%ecx), %esp
>> +       subl    %eax, %esp
>> +
>> +       /* Switch to AP code segment */
>> +       leal    rva(.Lsl_ap_cs)(%ebx), %eax
>> +       pushl   $(__SL32_CS)
>> +       pushl   %eax
>> +       lret
>> +
>> +.Lsl_ap_cs:
>> +       /* Load the relocated AP IDT */
>> +       lidt    (sl_ap_idt_desc - sl_txt_ap_wake_begin)(%ecx)
>> +
>> +       /* Fixup MTRRs and misc enable MSR on APs too */
>> +       call    sl_txt_load_regs
>> +
>> +       /* Enable SMI with GETSEC[SMCTRL] */
>> +       GETSEC $(SMX_X86_GETSEC_SMCTRL)
>> +
>> +       /* IRET-to-self can be used to enable NMIs which SENTER disabled */
>> +       leal    rva(.Lnmi_enabled_ap)(%ebx), %eax
>> +       pushfl
>> +       pushl   $(__SL32_CS)
>> +       pushl   %eax
>> +       iret
>> +
>> +.Lnmi_enabled_ap:
>> +       /* Put APs in X2APIC mode like the BSP */
>> +       movl    $(MSR_IA32_APICBASE), %ecx
>> +       rdmsr
>> +       orl     $(XAPIC_ENABLE | X2APIC_ENABLE), %eax
>> +       wrmsr
>> +
>> +       /*
>> +        * Basically done, increment the CPU count and jump off to the AP
>> +        * wake block to wait.
>> +        */
>> +       lock incl       rva(sl_txt_cpu_count)(%ebx)
>> +
>> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %eax
>> +       jmp     *%eax
>> +SYM_FUNC_END(sl_txt_ap_entry)
>> +
>> +SYM_FUNC_START(sl_txt_reloc_ap_wake)
>> +       /* Save boot params register */
>> +       pushl   %esi
>> +
>> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %edi
>> +
>> +       /* Fixup AP IDT and GDT descriptor before relocating */
>> +       leal    rva(sl_ap_idt_desc)(%ebx), %eax
>> +       addl    %edi, 2(%eax)
>> +       leal    rva(sl_ap_gdt_desc)(%ebx), %eax
>> +       addl    %edi, 2(%eax)
>> +
>> +       /*
>> +        * Copy the AP wake code and AP GDT/IDT to the protected wake block
>> +        * provided by the loader. Destination already in %edi.
>> +        */
>> +       movl    $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), %ecx
>> +       leal    rva(sl_txt_ap_wake_begin)(%ebx), %esi
>> +       rep movsb
>> +
>> +       /* Setup the IDT for the APs to use in the relocation block */
>> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %ecx
>> +       addl    $(sl_ap_idt - sl_txt_ap_wake_begin), %ecx
>> +       xorl    %edx, %edx
>> +
>> +       /* Form the default reset vector relocation address */
>> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %esi
>> +       addl    $(sl_txt_int_reset - sl_txt_ap_wake_begin), %esi
>> +
>> +1:
>> +       cmpw    $(NR_VECTORS), %dx
>> +       jz      .Lap_idt_done
>> +
>> +       cmpw    $(X86_TRAP_NMI), %dx
>> +       jz      2f
>> +
>> +       /* Load all other fixed vectors with reset handler */
>> +       movl    %esi, %eax
>> +       movw    %ax, (IDT_VECTOR_LO_BITS)(%ecx)
>> +       shrl    $16, %eax
>> +       movw    %ax, (IDT_VECTOR_HI_BITS)(%ecx)
>> +       jmp     3f
>> +
>> +2:
>> +       /* Load single wake NMI IPI vector at the relocation address */
>> +       movl    rva(sl_txt_ap_wake_block)(%ebx), %eax
>> +       addl    $(sl_txt_int_nmi - sl_txt_ap_wake_begin), %eax
>> +       movw    %ax, (IDT_VECTOR_LO_BITS)(%ecx)
>> +       shrl    $16, %eax
>> +       movw    %ax, (IDT_VECTOR_HI_BITS)(%ecx)
>> +
>> +3:
>> +       incw    %dx
>> +       addl    $8, %ecx
>> +       jmp     1b
>> +
>> +.Lap_idt_done:
>> +       popl    %esi
>> +       ret
>> +SYM_FUNC_END(sl_txt_reloc_ap_wake)
>> +
>> +SYM_FUNC_START(sl_txt_load_regs)
>> +       /* Save base pointer register */
>> +       pushl   %ebx
>> +
>> +       /*
>> +        * On Intel, the original variable MTRRs and Misc Enable MSR are
>> +        * restored on the BSP at early boot. Each AP will also restore
>> +        * its MTRRs and Misc Enable MSR.
>> +        */
>> +       pushl   %edi
>> +       addl    $(SL_saved_bsp_mtrrs), %edi
>> +       movl    (%edi), %ebx
>> +       pushl   %ebx /* default_mem_type lo */
>> +       addl    $4, %edi
>> +       movl    (%edi), %ebx
>> +       pushl   %ebx /* default_mem_type hi */
>> +       addl    $4, %edi
>> +       movl    (%edi), %ebx /* mtrr_vcnt lo, don't care about hi part */
>> +       addl    $8, %edi /* now at MTRR pair array */
>> +       /* Write the variable MTRRs */
>> +       movl    $(MSR_MTRRphysBase0), %ecx
>> +1:
>> +       cmpl    $0, %ebx
>> +       jz      2f
>> +
>> +       movl    (%edi), %eax /* MTRRphysBaseX lo */
>> +       addl    $4, %edi
>> +       movl    (%edi), %edx /* MTRRphysBaseX hi */
>> +       wrmsr
>> +       addl    $4, %edi
>> +       incl    %ecx
>> +       movl    (%edi), %eax /* MTRRphysMaskX lo */
>> +       addl    $4, %edi
>> +       movl    (%edi), %edx /* MTRRphysMaskX hi */
>> +       wrmsr
>> +       addl    $4, %edi
>> +       incl    %ecx
>> +
>> +       decl    %ebx
>> +       jmp     1b
>> +2:
>> +       /* Write the default MTRR register */
>> +       popl    %edx
>> +       popl    %eax
>> +       movl    $(MSR_MTRRdefType), %ecx
>> +       wrmsr
>> +
>> +       /* Return to beginning and write the misc enable msr */
>> +       popl    %edi
>> +       addl    $(SL_saved_misc_enable_msr), %edi
>> +       movl    (%edi), %eax /* saved_misc_enable_msr lo */
>> +       addl    $4, %edi
>> +       movl    (%edi), %edx /* saved_misc_enable_msr hi */
>> +       movl    $(MSR_IA32_MISC_ENABLE), %ecx
>> +       wrmsr
>> +
>> +       popl    %ebx
>> +       ret
>> +SYM_FUNC_END(sl_txt_load_regs)
>> +
>> +SYM_FUNC_START(sl_txt_wake_aps)
>> +       /* Save boot params register */
>> +       pushl   %esi
>> +
>> +       /* First setup the MLE join structure and load it into TXT reg */
>> +       leal    rva(sl_gdt)(%ebx), %eax
>> +       leal    rva(sl_txt_ap_entry)(%ebx), %ecx
>> +       leal    rva(sl_smx_rlp_mle_join)(%ebx), %edx
>> +       movl    %eax, SL_rlp_gdt_base(%edx)
>> +       movl    %ecx, SL_rlp_entry_point(%edx)
>> +       movl    %edx, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_MLE_JOIN)
>> +
>> +       /* Another TXT heap walk to find various values needed to wake APs */
>> +       movl    (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
>> +       /* At BIOS data size, find the number of logical processors */
>> +       movl    (SL_num_logical_procs + 8)(%eax), %edx
>> +       /* Skip over BIOS data */
>> +       movl    (%eax), %ecx
>> +       addl    %ecx, %eax
>> +       /* Skip over OS to MLE */
>> +       movl    (%eax), %ecx
>> +       addl    %ecx, %eax
>> +       /* At OS-SNIT size, get capabilities to know how to wake up the APs */
>> +       movl    (SL_capabilities + 8)(%eax), %esi
>> +       /* Skip over OS to SNIT */
>> +       movl    (%eax), %ecx
>> +       addl    %ecx, %eax
>> +       /* At SINIT-MLE size, get the AP wake MONITOR address */
>> +       movl    (SL_rlp_wakeup_addr + 8)(%eax), %edi
>> +
>> +       /* Determine how to wake up the APs */
>> +       testl   $(1 << TXT_SINIT_MLE_CAP_WAKE_MONITOR), %esi
>> +       jz      .Lwake_getsec
>> +
>> +       /* Wake using MWAIT MONITOR */
>> +       movl    $1, (%edi)
>> +       jmp     .Laps_awake
>> +
>> +.Lwake_getsec:
>> +       /* Wake using GETSEC(WAKEUP) */
>> +       GETSEC  $(SMX_X86_GETSEC_WAKEUP)
>> +
>> +.Laps_awake:
>> +       /*
>> +        * All of the APs are woken up and rendesvous in the relocated wake
>> +        * block starting at sl_txt_ap_wake_begin. Wait for all of them to
>> +        * halt.
>> +        */
>> +       pause
>> +       cmpl    rva(sl_txt_cpu_count)(%ebx), %edx
>> +       jne     .Laps_awake
>> +
>> +       popl    %esi
>> +       ret
>> +SYM_FUNC_END(sl_txt_wake_aps)
>> +
>> +/* This is the beginning of the relocated AP wake code block */
>> +       .global sl_txt_ap_wake_begin
>> +sl_txt_ap_wake_begin:
>> +
>> +       /* Get the LAPIC ID for each AP and stash it on the stack */
>> +       movl    $(MSR_IA32_X2APIC_APICID), %ecx
>> +       rdmsr
>> +       pushl   %eax
>> +
>> +       /*
>> +        * Get a pointer to the monitor location on this APs stack to test below
>> +        * after mwait returns. Currently %esp points to just past the pushed APIC
>> +        * ID value.
>> +        */
>> +       movl    %esp, %eax
>> +       subl    $(TXT_BOOT_STACK_SIZE - 4), %eax
>> +       movl    $0, (%eax)
>> +
>> +       /* Clear ecx/edx so no invalid extensions or hints are passed to monitor */
>> +       xorl    %ecx, %ecx
>> +       xorl    %edx, %edx
>> +
>> +       /*
>> +        * Arm the monitor and wait for it to be poked by he SMP bringup code. The mwait
>> +        * instruction can return for a number of reasons. Test to see if it returned
>> +        * because the monitor was written to.
>> +        */
>> +       monitor
>> +
>> +1:
>> +       mfence
>> +       mwait
>> +       movl    (%eax), %edx
>> +       testl   %edx, %edx
>> +       jz      1b
>> +
>> +       /*
>> +        * This is the long absolute jump to the 32b Secure Launch protected mode stub
>> +        * code in sl_trampoline_start32() in the rmpiggy. The jump address will be
>> +        * fixed in the SMP boot code when the first AP is brought up. This whole area
>> +        * is provided and protected in the memory map by the prelaunch code.
>> +        */
>> +       .byte   0xea
>> +sl_ap_jmp_offset:
>> +       .long   0x00000000
>> +       .word   __SL32_CS
>> +
>> +SYM_FUNC_START(sl_txt_int_nmi)
>> +       /* NMI context, just IRET */
>> +       iret
>> +SYM_FUNC_END(sl_txt_int_nmi)
>> +
>> +SYM_FUNC_START(sl_txt_int_reset)
>> +       TXT_RESET $(SL_ERROR_INV_AP_INTERRUPT)
>> +SYM_FUNC_END(sl_txt_int_reset)
>> +
>> +       .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_idt_desc)
>> +       .word   sl_ap_idt_end - sl_ap_idt - 1           /* Limit */
>> +       .long   sl_ap_idt - sl_txt_ap_wake_begin        /* Base */
>> +SYM_DATA_END_LABEL(sl_ap_idt_desc, SYM_L_LOCAL, sl_ap_idt_desc_end)
>> +
>> +       .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_idt)
>> +       .rept   NR_VECTORS
>> +       .word   0x0000          /* Offset 15 to 0 */
>> +       .word   __SL32_CS       /* Segment selector */
>> +       .word   0x8e00          /* Present, DPL=0, 32b Vector, Interrupt */
>> +       .word   0x0000          /* Offset 31 to 16 */
>> +       .endr
>> +SYM_DATA_END_LABEL(sl_ap_idt, SYM_L_LOCAL, sl_ap_idt_end)
>> +
>> +       .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_gdt_desc)
>> +       .word   sl_ap_gdt_end - sl_ap_gdt - 1
>> +       .long   sl_ap_gdt - sl_txt_ap_wake_begin
>> +SYM_DATA_END_LABEL(sl_ap_gdt_desc, SYM_L_LOCAL, sl_ap_gdt_desc_end)
>> +
>> +       .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_gdt)
>> +       .quad   0x0000000000000000      /* NULL */
>> +       .quad   0x00cf9a000000ffff      /* __SL32_CS */
>> +       .quad   0x00cf92000000ffff      /* __SL32_DS */
>> +SYM_DATA_END_LABEL(sl_ap_gdt, SYM_L_LOCAL, sl_ap_gdt_end)
>> +
>> +       /* Small stacks for BSP and APs to work with */
>> +       .balign 64
>> +SYM_DATA_START_LOCAL(sl_stacks)
>> +       .fill (TXT_MAX_CPUS * TXT_BOOT_STACK_SIZE), 1, 0
>> +SYM_DATA_END_LABEL(sl_stacks, SYM_L_LOCAL, sl_stacks_end)
>> +
>> +/* This is the end of the relocated AP wake code block */
>> +       .global sl_txt_ap_wake_end
>> +sl_txt_ap_wake_end:
>> +
>> +       .data
>> +       .balign 8
>> +SYM_DATA_START_LOCAL(sl_gdt_desc)
>> +       .word   sl_gdt_end - sl_gdt - 1
>> +       .long   sl_gdt - sl_gdt_desc
>> +SYM_DATA_END_LABEL(sl_gdt_desc, SYM_L_LOCAL, sl_gdt_desc_end)
>> +
>> +       .balign 8
>> +SYM_DATA_START_LOCAL(sl_gdt)
>> +       .quad   0x0000000000000000      /* NULL */
>> +       .quad   0x00cf9a000000ffff      /* __SL32_CS */
>> +       .quad   0x00cf92000000ffff      /* __SL32_DS */
>> +SYM_DATA_END_LABEL(sl_gdt, SYM_L_LOCAL, sl_gdt_end)
>> +
>> +       .balign 8
>> +SYM_DATA_START_LOCAL(sl_smx_rlp_mle_join)
>> +       .long   sl_gdt_end - sl_gdt - 1 /* GDT limit */
>> +       .long   0x00000000              /* GDT base */
>> +       .long   __SL32_CS       /* Seg Sel - CS (DS, ES, SS = seg_sel+8) */
>> +       .long   0x00000000      /* Entry point physical address */
>> +SYM_DATA_END(sl_smx_rlp_mle_join)
>> +
>> +SYM_DATA(sl_cpu_type, .long 0x00000000)
>> +
>> +SYM_DATA(sl_mle_start, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_spin_lock, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_stack_index, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_cpu_count, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_ap_wake_block, .long 0x00000000)
>> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
>> index f1bd7b91b3c6..aff899c4b6c3 100644
>> --- a/arch/x86/include/asm/msr-index.h
>> +++ b/arch/x86/include/asm/msr-index.h
>> @@ -323,6 +323,9 @@
>>   #define MSR_IA32_RTIT_OUTPUT_BASE      0x00000560
>>   #define MSR_IA32_RTIT_OUTPUT_MASK      0x00000561
>>
>> +#define MSR_MTRRphysBase0              0x00000200
>> +#define MSR_MTRRphysMask0              0x00000201
>> +
>>   #define MSR_MTRRfix64K_00000           0x00000250
>>   #define MSR_MTRRfix16K_80000           0x00000258
>>   #define MSR_MTRRfix16K_A0000           0x00000259
>> @@ -804,6 +807,8 @@
>>   #define MSR_IA32_APICBASE_ENABLE       (1<<11)
>>   #define MSR_IA32_APICBASE_BASE         (0xfffff<<12)
>>
>> +#define MSR_IA32_X2APIC_APICID         0x00000802
>> +
>>   #define MSR_IA32_UCODE_WRITE           0x00000079
>>   #define MSR_IA32_UCODE_REV             0x0000008b
>>
>> diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
>> index 01d19fc22346..74e3e7df491e 100644
>> --- a/arch/x86/include/uapi/asm/bootparam.h
>> +++ b/arch/x86/include/uapi/asm/bootparam.h
>> @@ -26,6 +26,7 @@
>>   /* loadflags */
>>   #define LOADED_HIGH    (1<<0)
>>   #define KASLR_FLAG     (1<<1)
>> +#define SLAUNCH_FLAG   (1<<2)
>>   #define QUIET_FLAG     (1<<5)
>>   #define KEEP_SEGMENTS  (1<<6)
>>   #define CAN_USE_HEAP   (1<<7)
>> diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
>> index 6913b372ccf7..c7c4d392b7d3 100644
>> --- a/arch/x86/kernel/asm-offsets.c
>> +++ b/arch/x86/kernel/asm-offsets.c
>> @@ -13,6 +13,8 @@
>>   #include <linux/hardirq.h>
>>   #include <linux/suspend.h>
>>   #include <linux/kbuild.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>>   #include <asm/processor.h>
>>   #include <asm/thread_info.h>
>>   #include <asm/sigframe.h>
>> @@ -120,4 +122,22 @@ static void __used common(void)
>>          OFFSET(ARIA_CTX_rounds, aria_ctx, rounds);
>>   #endif
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> +       BLANK();
>> +       OFFSET(SL_txt_info, txt_os_mle_data, txt_info);
>> +       OFFSET(SL_mle_scratch, txt_os_mle_data, mle_scratch);
>> +       OFFSET(SL_boot_params_addr, txt_os_mle_data, boot_params_addr);
>> +       OFFSET(SL_ap_wake_block, txt_os_mle_data, ap_wake_block);
>> +       OFFSET(SL_ap_wake_block_size, txt_os_mle_data, ap_wake_block_size);
>> +       OFFSET(SL_saved_misc_enable_msr, slr_entry_intel_info, saved_misc_enable_msr);
>> +       OFFSET(SL_saved_bsp_mtrrs, slr_entry_intel_info, saved_bsp_mtrrs);
>> +       OFFSET(SL_num_logical_procs, txt_bios_data, num_logical_procs);
>> +       OFFSET(SL_capabilities, txt_os_sinit_data, capabilities);
>> +       OFFSET(SL_mle_size, txt_os_sinit_data, mle_size);
>> +       OFFSET(SL_vtd_pmr_lo_base, txt_os_sinit_data, vtd_pmr_lo_base);
>> +       OFFSET(SL_vtd_pmr_lo_size, txt_os_sinit_data, vtd_pmr_lo_size);
>> +       OFFSET(SL_rlp_wakeup_addr, txt_sinit_mle_data, rlp_wakeup_addr);
>> +       OFFSET(SL_rlp_gdt_base, smx_rlp_mle_join, rlp_gdt_base);
>> +       OFFSET(SL_rlp_entry_point, smx_rlp_mle_join, rlp_entry_point);
>> +#endif
>>   }
>> --
>> 2.39.3
>>
Ross Philipson Feb. 21, 2024, 8:17 p.m. UTC | #9
On 2/15/24 1:01 AM, Ard Biesheuvel wrote:
> On Wed, 14 Feb 2024 at 23:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>>
>> This support allows the DRTM launch to be initiated after an EFI stub
>> launch of the Linux kernel is done. This is accomplished by providing
>> a handler to jump to when a Secure Launch is in progress. This has to be
>> called after the EFI stub does Exit Boot Services.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>>   drivers/firmware/efi/libstub/x86-stub.c | 55 +++++++++++++++++++++++++
>>   1 file changed, 55 insertions(+)
>>
>> diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
>> index 0d510c9a06a4..4df2cf539194 100644
>> --- a/drivers/firmware/efi/libstub/x86-stub.c
>> +++ b/drivers/firmware/efi/libstub/x86-stub.c
>> @@ -9,6 +9,7 @@
>>   #include <linux/efi.h>
>>   #include <linux/pci.h>
>>   #include <linux/stddef.h>
>> +#include <linux/slr_table.h>
>>
>>   #include <asm/efi.h>
>>   #include <asm/e820/types.h>
>> @@ -810,6 +811,57 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
>>          return EFI_SUCCESS;
>>   }
>>
>> +static void efi_secure_launch(struct boot_params *boot_params)
>> +{
>> +       struct slr_entry_uefi_config *uefi_config;
>> +       struct slr_uefi_cfg_entry *uefi_entry;
>> +       struct slr_entry_dl_info *dlinfo;
>> +       efi_guid_t guid = SLR_TABLE_GUID;
>> +       struct slr_table *slrt;
>> +       u64 memmap_hi;
>> +       void *table;
>> +       u8 buf[64] = {0};
>> +
> 
> If you add a flex array to slr_entry_uefi_config as I suggested in
> response to the other patch, we could simplify this substantially

I feel like there is some reason why we did not use flex arrays. We were 
talking and we seem to remember we used to use them and someone asked us 
to remove them. We are still looking into it. But if we can go back to 
them, I will take all the changes you recommended here.

Thanks
Ross

> 
> static struct slr_entry_uefi_config cfg = {
>          .hdr.tag        = SLR_ENTRY_UEFI_CONFIG,
>          .hdr.size       = sizeof(cfg),
>          .revision       = SLR_UEFI_CONFIG_REVISION,
>          .nr_entries     = 1,
>          .entries[0]     = {
>                  .pcr    = 18,
>                  .evt_info = "Measured UEFI memory map",
>          },
> };
> 
> cfg.entries[0].cfg  = boot_params->efi_info.efi_memmap |
>                        (u64)boot_params->efi_info.efi_memmap_hi << 32;
> cfg.entries[0].size = boot_params->efi_info.efi_memmap_size;
> 
> 
> 
>> +       table = get_efi_config_table(guid);
>> +
>> +       /*
>> +        * The presence of this table indicated a Secure Launch
>> +        * is being requested.
>> +        */
>> +       if (!table)
>> +               return;
>> +
>> +       slrt = (struct slr_table *)table;
>> +
>> +       if (slrt->magic != SLR_TABLE_MAGIC)
>> +               return;
>> +
> 
> slrt = (struct slr_table *)get_efi_config_table(guid);
> if (!slrt || slrt->magic != SLR_TABLE_MAGIC)
>          return;
> 
>> +       /* Add config information to measure the UEFI memory map */
>> +       uefi_config = (struct slr_entry_uefi_config *)buf;
>> +       uefi_config->hdr.tag = SLR_ENTRY_UEFI_CONFIG;
>> +       uefi_config->hdr.size = sizeof(*uefi_config) + sizeof(*uefi_entry);
>> +       uefi_config->revision = SLR_UEFI_CONFIG_REVISION;
>> +       uefi_config->nr_entries = 1;
>> +       uefi_entry = (struct slr_uefi_cfg_entry *)(buf + sizeof(*uefi_config));
>> +       uefi_entry->pcr = 18;
>> +       uefi_entry->cfg = boot_params->efi_info.efi_memmap;
>> +       memmap_hi = boot_params->efi_info.efi_memmap_hi;
>> +       uefi_entry->cfg |= memmap_hi << 32;
>> +       uefi_entry->size = boot_params->efi_info.efi_memmap_size;
>> +       memcpy(&uefi_entry->evt_info[0], "Measured UEFI memory map",
>> +               strlen("Measured UEFI memory map"));
>> +
> 
> Drop all of this
> 
>> +       if (slr_add_entry(slrt, (struct slr_entry_hdr *)uefi_config))
> 
> if (slr_add_entry(slrt, &uefi_config.hdr))
> 
> 
>> +               return;
>> +
>> +       /* Jump through DL stub to initiate Secure Launch */
>> +       dlinfo = (struct slr_entry_dl_info *)
>> +               slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DL_INFO);
>> +
>> +       asm volatile ("jmp *%%rax"
>> +                     : : "a" (dlinfo->dl_handler), "D" (&dlinfo->bl_context));
> 
> Fix the prototype and just do
> 
> dlinfo->dl_handler(&dlinfo->bl_context);
> unreachable();
> 
> 
> So in summary, this becomes
> 
> static void efi_secure_launch(struct boot_params *boot_params)
> {
>          static struct slr_entry_uefi_config cfg = {
>                  .hdr.tag        = SLR_ENTRY_UEFI_CONFIG,
>                  .hdr.size       = sizeof(cfg),
>                  .revision       = SLR_UEFI_CONFIG_REVISION,
>                  .nr_entries     = 1,
>                  .entries[0]     = {
>                          .pcr    = 18,
>                          .evt_info = "Measured UEFI memory map",
>                  },
>          };
>          struct slr_entry_dl_info *dlinfo;
>          efi_guid_t guid = SLR_TABLE_GUID;
>          struct slr_table *slrt;
> 
>          /*
>           * The presence of this table indicated a Secure Launch
>           * is being requested.
>           */
>          slrt = (struct slr_table *)get_efi_config_table(guid);
>          if (!slrt || slrt->magic != SLR_TABLE_MAGIC)
>                  return;
> 
>          cfg.entries[0].cfg  = boot_params->efi_info.efi_memmap |
>                                (u64)boot_params->efi_info.efi_memmap_hi << 32;
>          cfg.entries[0].size = boot_params->efi_info.efi_memmap_size;
> 
>          if (slr_add_entry(slrt, &cfg.hdr))
>                  return;
> 
>          /* Jump through DL stub to initiate Secure Launch */
>          dlinfo = (struct slr_entry_dl_info *)
>                   slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DL_INFO);
> 
>          dlinfo->dl_handler(&dlinfo->bl_context);
> 
>          unreachable();
> }
> 
> 
>> +}
>> +
>>   static void __noreturn enter_kernel(unsigned long kernel_addr,
>>                                      struct boot_params *boot_params)
>>   {
>> @@ -934,6 +986,9 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
>>                  goto fail;
>>          }
>>
>> +       /* If a Secure Launch is in progress, this never returns */
> 
> if (IS_ENABLED(CONFIG_SECURE_LAUNCH))
> 
>> +       efi_secure_launch(boot_params);
>> +
>>          /*
>>           * Call the SEV init code while still running with the firmware's
>>           * GDT/IDT, so #VC exceptions will be handled by EFI.
>> --
>> 2.39.3
>>
>
Ard Biesheuvel Feb. 23, 2024, 9:27 a.m. UTC | #10
On Thu, 22 Feb 2024 at 13:30, Andrew Cooper <andrew.cooper3@citrix.com> wrote:
>
> On 22/02/2024 9:34 am, Ard Biesheuvel wrote:
> > On Thu, 22 Feb 2024 at 04:05, Andrew Cooper <andrew.cooper3@citrix.com> wrote:
> >> On 15/02/2024 8:17 am, Ard Biesheuvel wrote:
> >>> On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
> >>>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
> >>>>
> >>>> The SHA algorithms are necessary to measure configuration information into
> >>>> the TPM as early as possible before using the values. This implementation
> >>>> uses the established approach of #including the SHA libraries directly in
> >>>> the code since the compressed kernel is not uncompressed at this point.
> >>>>
> >>>> The SHA code here has its origins in the code from the main kernel:
> >>>>
> >>>> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
> >>>>
> >>>> A modified version of this code was introduced to the lib/crypto/sha1.c
> >>>> to bring it in line with the sha256 code and allow it to be pulled into the
> >>>> setup kernel in the same manner as sha256 is.
> >>>>
> >>>> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> >>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> >>> We have had some discussions about this, and you really need to
> >>> capture the justification in the commit log for introducing new code
> >>> that implements an obsolete and broken hashing algorithm.
> >>>
> >>> SHA-1 is broken and should no longer be used for anything. Introducing
> >>> new support for a highly complex boot security feature, and then
> >>> relying on SHA-1 in the implementation makes this whole effort seem
> >>> almost futile, *unless* you provide some rock solid reasons here why
> >>> this is still safe.
> >>>
> >>> If the upshot would be that some people are stuck with SHA-1 so they
> >>> won't be able to use this feature, then I'm not convinced we should
> >>> obsess over that.
> >> To be absolutely crystal clear here.
> >>
> >> The choice of hash algorithm(s) are determined by the OEM and the
> >> platform, not by Linux.
> >>
> >> Failing to (at least) cap a PCR in a bank which the OEM/platform left
> >> active is a security vulnerability.  It permits the unsealing of secrets
> >> if an attacker can replay a good set of measurements into an unused bank.
> >>
> >> The only way to get rid of the requirement for SHA-1 here is to lobby
> >> the IHVs/OEMs, or perhaps the TCG, to produce/spec a platform where the
> >> SHA-1 banks can be disabled.  There are no known such platforms in the
> >> market today, to the best of our knowledge.
> >>
> > OK, so mainline Linux does not support secure launch at all today. At
> > this point, we need to decide whether or not tomorrow's mainline Linux
> > will support secure launch with SHA1 or without, right?
>
> I'd argue that's a slightly unfair characterisation.
>

Fair enough. I'm genuinely trying to have a precise understanding of
this, not trying to be dismissive.

> We want tomorrow's mainline to support Secure Launch.  What that entails
> under the hood is largely outside of the control of the end user.
>

So the debate is really whether it makes sense at all to support
Secure Launch on systems that are stuck on an obsolete and broken hash
algorithm. This is not hyperbole: SHA-1 is broken today and once these
changes hit production 1-2 years down the line, the situation will
only have deteriorated. And another 2-3 years later, we will be the
ones chasing obscure bugs on systems that were already obsolete when
this support was added.

So what is the value proposition here? An end user today, who is
mindful enough of security to actively invest the effort to migrate
their system from ordinary measured boot to secure launch, is really
going to do so on a system that only implements SHA-1 support?

> > And the point you are making here is that we need SHA-1 not only to a)
> > support systems that are on TPM 1.2 and support nothing else, but also
> > to b) ensure that crypto agile TPM 2.0 with both SHA-1 and SHA-256
> > enabled can be supported in a safe manner, which would involve
> > measuring some terminating event into the SHA-1 PCRs to ensure they
> > are not left in a dangling state that might allow an adversary to
> > trick the TPM into unsealing a secret that it shouldn't.
>
> Yes.  Also c) because if the end user wants to use SHA-1, they should be
> able to.
>

The end user can do whatever they want, of course. Whether it belongs
in the upstream is an entirely different matter, though, especially
because we will effectively be forced to support this forever.


> > So can we support b) without a), and if so, does measuring an
> > arbitrary dummy event into a PCR that is only meant to keep sealed
> > forever really require a SHA-1 implementation, or could we just use an
> > arbitrary (not even random) sequence of 160 bits and use that instead?
>
> a) and b) are in principle independent, but we cannot support b) without
> SHA-1.
>
> To cap a PCR, the event log still needs to be kept accurate, and that's
> at least one SHA-1 calculation.  If you were to simply extend a dummy
> value, the system hopefully fails safe, but the user gets "something
> went wrong, you're on your own", rather than "we intentionally blocked
> the use of SHA-1, everything is good".
>
> And frankly, you need SHA-1 just to read the event log, if any component
> (including TXT itself) wrote a SHA-1 entry into it.
>
>
> To be blunt.  SHA-1 support is not viably optional today as far as
> Secure Launch is concerned.  If there's a suitable Kconfig symbol to use
> for people who want a completely SHA-1-less kernel, then we can make
> Secure Launch depend on that until such time as the hardware ecosystem
> has caught up.
>

Yes, this crossed my mind as well. There is a Kconfig symbol
CRYPTO_USER_API_ENABLE_OBSOLETE I added a while ago for a similar
purpose.

I am still disappointed that we have to go down this path, but I
understand the concerns now that you have explained them to me (again)
in more detail.

These considerations need to be recorded in the documentation or
commit logs as well, so that we can easily refer back to them without
having to dig through the mail archives.
Andrew Cooper Feb. 23, 2024, 6:20 p.m. UTC | #11
On 23/02/2024 5:54 pm, Eric Biggers wrote:
> On Fri, Feb 23, 2024 at 04:42:11PM +0000, Andrew Cooper wrote:
>> Yes, and I agree.  We're not looking to try and force this in with
>> underhand tactics.
>>
>> But a blind "nack to any SHA-1" is similarly damaging in the opposite
>> direction.
>>
> Well, reviewers have said they'd prefer that SHA-1 not be included and given
> some thoughtful reasons for that.  But also they've given suggestions on how to
> make the SHA-1 support more palatable, such as splitting it into a separate
> patch and giving it a proper justification.
>
> All suggestions have been ignored.

The public record demonstrates otherwise.

But are you saying that you'd be happy if the commit message read
something more like:

---8<---
For better or worse, Secure Launch needs SHA-1 and SHA-256.

The choice of hashes used lie with the platform firmware, not with
software, and is often outside of the users control.

Even if we'd prefer to use SHA-256-only, if firmware elected to start us
with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
to safely use SHA-256 for everything else.
---

?

~Andrew
Kim Phillips March 29, 2024, 10:38 p.m. UTC | #12
Hi Ross,

On 2/14/24 4:18 PM, Ross Philipson wrote:
> Introduce the Secure Launch Resource Table which forms the formal
> interface between the pre and post launch code.
> 
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
>   include/linux/slr_table.h | 270 ++++++++++++++++++++++++++++++++++++++
>   1 file changed, 270 insertions(+)
>   create mode 100644 include/linux/slr_table.h

> diff --git a/include/linux/slr_table.h b/include/linux/slr_table.h
> new file mode 100644
> index 000000000000..42020988233a
> --- /dev/null
> +++ b/include/linux/slr_table.h
> @@ -0,0 +1,270 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Secure Launch Resource Table
> + *
> + * Copyright (c) 2023, Oracle and/or its affiliates.
> + */
> +
> +#ifndef _LINUX_SLR_TABLE_H
> +#define _LINUX_SLR_TABLE_H
> +
> +/* Put this in efi.h if it becomes a standard */
> +#define SLR_TABLE_GUID				EFI_GUID(0x877a9b2a, 0x0385, 0x45d1, 0xa0, 0x34, 0x9d, 0xac, 0x9c, 0x9e, 0x56, 0x5f)
> +
> +/* SLR table header values */
> +#define SLR_TABLE_MAGIC		0x4452544d
> +#define SLR_TABLE_REVISION	1
> +
> +/* Current revisions for the policy and UEFI config */
> +#define SLR_POLICY_REVISION		1
> +#define SLR_UEFI_CONFIG_REVISION	1
> +
> +/* SLR defined architectures */
> +#define SLR_INTEL_TXT		1
> +#define SLR_AMD_SKINIT		2
> +
> +/* SLR defined bootloaders */
> +#define SLR_BOOTLOADER_INVALID	0
> +#define SLR_BOOTLOADER_GRUB	1
> +
> +/* Log formats */
> +#define SLR_DRTM_TPM12_LOG	1
> +#define SLR_DRTM_TPM20_LOG	2
> +
> +/* DRTM Policy Entry Flags */
> +#define SLR_POLICY_FLAG_MEASURED	0x1
> +#define SLR_POLICY_IMPLICIT_SIZE	0x2
> +
> +/* Array Lengths */
> +#define TPM_EVENT_INFO_LENGTH		32
> +#define TXT_VARIABLE_MTRRS_LENGTH	32
> +
> +/* Tags */
> +#define SLR_ENTRY_INVALID	0x0000
> +#define SLR_ENTRY_DL_INFO	0x0001
> +#define SLR_ENTRY_LOG_INFO	0x0002
> +#define SLR_ENTRY_ENTRY_POLICY	0x0003
> +#define SLR_ENTRY_INTEL_INFO	0x0004
> +#define SLR_ENTRY_AMD_INFO	0x0005
> +#define SLR_ENTRY_ARM_INFO	0x0006
> +#define SLR_ENTRY_UEFI_INFO	0x0007
> +#define SLR_ENTRY_UEFI_CONFIG	0x0008
> +#define SLR_ENTRY_END		0xffff
> +
> +/* Entity Types */
> +#define SLR_ET_UNSPECIFIED	0x0000
> +#define SLR_ET_SLRT		0x0001
> +#define SLR_ET_BOOT_PARAMS	0x0002
> +#define SLR_ET_SETUP_DATA	0x0003
> +#define SLR_ET_CMDLINE		0x0004
> +#define SLR_ET_UEFI_MEMMAP	0x0005
> +#define SLR_ET_RAMDISK		0x0006
> +#define SLR_ET_TXT_OS2MLE	0x0010
> +#define SLR_ET_UNUSED		0xffff
> +
> +#ifndef __ASSEMBLY__
> +
> +/*
> + * Primary SLR Table Header
> + */
> +struct slr_table {
> +	u32 magic;
> +	u16 revision;
> +	u16 architecture;
> +	u32 size;
> +	u32 max_size;

Do these need to have their endianness specified with, e.g., __le32?

> +	/* entries[] */

Instead of the above line, a legit 'entries' can be enabled using:

DECLARE_FLEX_ARRAY(struct slr_entry_hdr, entries);

> +} __packed;

You'd have to move this above struct slr_table which would need it:

> +/*
> + * Common SLRT Table Header
> + */
> +struct slr_entry_hdr {
> +	u16 tag;
> +	u16 size;
> +} __packed;
> +
> +/*
> + * Boot loader context
> + */
> +struct slr_bl_context {
> +	u16 bootloader;
> +	u16 reserved;
> +	u64 context;
> +} __packed;
> +
> +/*
> + * DRTM Dynamic Launch Configuration
> + */
> +struct slr_entry_dl_info {
> +	struct slr_entry_hdr hdr;
> +	struct slr_bl_context bl_context;
> +	u64 dl_handler;
> +	u64 dce_base;
> +	u32 dce_size;
> +	u64 dlme_entry;
> +} __packed;
> +
> +/*
> + * TPM Log Information
> + */
> +struct slr_entry_log_info {
> +	struct slr_entry_hdr hdr;
> +	u16 format;
> +	u16 reserved;
> +	u64 addr;
> +	u32 size;
> +} __packed;
> +
> +/*
> + * DRTM Measurement Policy
> + */
> +struct slr_entry_policy {
> +	struct slr_entry_hdr hdr;
> +	u16 revision;
> +	u16 nr_entries;
> +	/* policy_entries[] */
> +} __packed;
> +
> +/*
> + * DRTM Measurement Entry
> + */
> +struct slr_policy_entry {
> +	u16 pcr;
> +	u16 entity_type;
> +	u16 flags;
> +	u16 reserved;
> +	u64 entity;
> +	u64 size;
> +	char evt_info[TPM_EVENT_INFO_LENGTH];
> +} __packed;
> +
> +/*
> + * Secure Launch defined MTRR saving structures
> + */
> +struct slr_txt_mtrr_pair {
> +	u64 mtrr_physbase;
> +	u64 mtrr_physmask;
> +} __packed;
> +
> +struct slr_txt_mtrr_state {
> +	u64 default_mem_type;
> +	u64 mtrr_vcnt;
> +	struct slr_txt_mtrr_pair mtrr_pair[TXT_VARIABLE_MTRRS_LENGTH];
> +} __packed;
> +
> +/*
> + * Intel TXT Info table
> + */
> +struct slr_entry_intel_info {
> +	struct slr_entry_hdr hdr;
> +	u64 saved_misc_enable_msr;
> +	struct slr_txt_mtrr_state saved_bsp_mtrrs;
> +} __packed;
> +
> +/*
> + * AMD SKINIT Info table
> + */
> +struct slr_entry_amd_info {
> +	struct slr_entry_hdr hdr;
> +} __packed;
> +
> +/*
> + * ARM DRTM Info table
> + */
> +struct slr_entry_arm_info {
> +	struct slr_entry_hdr hdr;
> +} __packed;

Shouldn't these three structs be added as part of their
separate per-vendor enablement patches?

> +struct slr_entry_uefi_config {
> +	struct slr_entry_hdr hdr;
> +	u16 revision;
> +	u16 nr_entries;
> +	/* uefi_cfg_entries[] */
> +} __packed;
> +
> +struct slr_uefi_cfg_entry {
> +	u16 pcr;
> +	u16 reserved;
> +	u64 cfg; /* address or value */
> +	u32 size;
> +	char evt_info[TPM_EVENT_INFO_LENGTH];
> +} __packed;
> +
> +static inline void *slr_end_of_entrys(struct slr_table *table)
> +{
> +	return (((void *)table) + table->size);
> +}
> +
> +static inline struct slr_entry_hdr *
> +slr_next_entry(struct slr_table *table,
> +	       struct slr_entry_hdr *curr)
> +{
> +	struct slr_entry_hdr *next = (struct slr_entry_hdr *)
> +				((u8 *)curr + curr->size);
> +
> +	if ((void *)next >= slr_end_of_entrys(table))
> +		return NULL;
> +	if (next->tag == SLR_ENTRY_END)
> +		return NULL;
> +
> +	return next;
> +}
> +
> +static inline struct slr_entry_hdr *
> +slr_next_entry_by_tag(struct slr_table *table,
> +		      struct slr_entry_hdr *entry,
> +		      u16 tag)
> +{
> +	if (!entry) /* Start from the beginning */
> +		entry = (struct slr_entry_hdr *)(((u8 *)table) + sizeof(*table));

Back to the 'entries', the above line can now be made more readable:

entry = table->entries;

That's just one example, this flex array simplification can be made
in other structs in this series, too.

Cheers,

Kim

> +
> +	for ( ; ; ) {
> +		if (entry->tag == tag)
> +			return entry;
> +
> +		entry = slr_next_entry(table, entry);
> +		if (!entry)
> +			return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +static inline int
> +slr_add_entry(struct slr_table *table,
> +	      struct slr_entry_hdr *entry)
> +{
> +	struct slr_entry_hdr *end;
> +
> +	if ((table->size + entry->size) > table->max_size)
> +		return -1;
> +
> +	memcpy((u8 *)table + table->size - sizeof(*end), entry, entry->size);
> +	table->size += entry->size;
> +
> +	end  = (struct slr_entry_hdr *)((u8 *)table + table->size - sizeof(*end));
> +	end->tag = SLR_ENTRY_END;
> +	end->size = sizeof(*end);
> +
> +	return 0;
> +}
> +
> +static inline void
> +slr_init_table(struct slr_table *slrt, u16 architecture, u32 max_size)
> +{
> +	struct slr_entry_hdr *end;
> +
> +	slrt->magic = SLR_TABLE_MAGIC;
> +	slrt->revision = SLR_TABLE_REVISION;
> +	slrt->architecture = architecture;
> +	slrt->size = sizeof(*slrt) + sizeof(*end);
> +	slrt->max_size = max_size;
> +	end = (struct slr_entry_hdr *)((u8 *)slrt + sizeof(*slrt));
> +	end->tag = SLR_ENTRY_END;
> +	end->size = sizeof(*end);
> +}
> +
> +#endif /* !__ASSEMBLY */
> +
> +#endif /* _LINUX_SLR_TABLE_H */
Andy Lutomirski April 3, 2024, 4:32 p.m. UTC | #13
On Fri, Feb 23, 2024, at 10:30 AM, Eric Biggers wrote:
> On Fri, Feb 23, 2024 at 06:20:27PM +0000, Andrew Cooper wrote:
>> On 23/02/2024 5:54 pm, Eric Biggers wrote:
>> > On Fri, Feb 23, 2024 at 04:42:11PM +0000, Andrew Cooper wrote:
>> >> Yes, and I agree.  We're not looking to try and force this in with
>> >> underhand tactics.
>> >>
>> >> But a blind "nack to any SHA-1" is similarly damaging in the opposite
>> >> direction.
>> >>
>> > Well, reviewers have said they'd prefer that SHA-1 not be included and given
>> > some thoughtful reasons for that.  But also they've given suggestions on how to
>> > make the SHA-1 support more palatable, such as splitting it into a separate
>> > patch and giving it a proper justification.
>> >
>> > All suggestions have been ignored.
>> 
>> The public record demonstrates otherwise.
>> 
>> But are you saying that you'd be happy if the commit message read
>> something more like:
>> 
>> ---8<---
>> For better or worse, Secure Launch needs SHA-1 and SHA-256.
>> 
>> The choice of hashes used lie with the platform firmware, not with
>> software, and is often outside of the users control.
>> 
>> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
>> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
>> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
>> to safely use SHA-256 for everything else.
>> ---
>
> Please take some time to read through the comments that reviewers have left on
> previous versions of the patchset.

So I went and read through the old comments, and I'm lost.  In brief summary:

If the hardware+firmware only supports SHA-1, then some reviewers would prefer Linux not to support DRTM.  I personally think this is a bit silly, but it's not entirely unreasonable.  Maybe it should be a config option?

If the hardware+firmware does support SHA-256, then it sounds (to me, reading this -- I haven't dug into the right spec pages) that, for optimal security, something still needs to effectively turn SHA-1 *off* at runtime by capping the event log properly.  And that requires computing a SHA-1 hash.  And, to be clear, (a) this is only on systems that already support SHA-256 and that we should support and (b) *not* doing so leaves us potentially more vulnerable to SHA-1 attacks than doing so.  And no SHA-256-supporting tooling will actually be compromised by a SHA-1 compromise if we cap the event log.

So is there a way forward?  Just saying "read through the comments" seems like a dead end.

Thanks,
Andy
Ross Philipson April 4, 2024, 4:55 a.m. UTC | #14
On 4/3/24 4:56 PM, Eric Biggers wrote:
> On Wed, Apr 03, 2024 at 09:32:02AM -0700, Andy Lutomirski wrote:
>> On Fri, Feb 23, 2024, at 10:30 AM, Eric Biggers wrote:
>>> On Fri, Feb 23, 2024 at 06:20:27PM +0000, Andrew Cooper wrote:
>>>> On 23/02/2024 5:54 pm, Eric Biggers wrote:
>>>>> On Fri, Feb 23, 2024 at 04:42:11PM +0000, Andrew Cooper wrote:
>>>>>> Yes, and I agree.  We're not looking to try and force this in with
>>>>>> underhand tactics.
>>>>>>
>>>>>> But a blind "nack to any SHA-1" is similarly damaging in the opposite
>>>>>> direction.
>>>>>>
>>>>> Well, reviewers have said they'd prefer that SHA-1 not be included and given
>>>>> some thoughtful reasons for that.  But also they've given suggestions on how to
>>>>> make the SHA-1 support more palatable, such as splitting it into a separate
>>>>> patch and giving it a proper justification.
>>>>>
>>>>> All suggestions have been ignored.
>>>>
>>>> The public record demonstrates otherwise.
>>>>
>>>> But are you saying that you'd be happy if the commit message read
>>>> something more like:
>>>>
>>>> ---8<---
>>>> For better or worse, Secure Launch needs SHA-1 and SHA-256.
>>>>
>>>> The choice of hashes used lie with the platform firmware, not with
>>>> software, and is often outside of the users control.
>>>>
>>>> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
>>>> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
>>>> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
>>>> to safely use SHA-256 for everything else.
>>>> ---
>>>
>>> Please take some time to read through the comments that reviewers have left on
>>> previous versions of the patchset.
>>
>> So I went and read through the old comments, and I'm lost.  In brief summary:
>>
>> If the hardware+firmware only supports SHA-1, then some reviewers would prefer
>> Linux not to support DRTM.  I personally think this is a bit silly, but it's
>> not entirely unreasonable.  Maybe it should be a config option?
>>
>> If the hardware+firmware does support SHA-256, then it sounds (to me, reading
>> this -- I haven't dug into the right spec pages) that, for optimal security,
>> something still needs to effectively turn SHA-1 *off* at runtime by capping
>> the event log properly.  And that requires computing a SHA-1 hash.  And, to be
>> clear, (a) this is only on systems that already support SHA-256 and that we
>> should support and (b) *not* doing so leaves us potentially more vulnerable to
>> SHA-1 attacks than doing so.  And no SHA-256-supporting tooling will actually
>> be compromised by a SHA-1 compromise if we cap the event log.
>>
>> So is there a way forward?  Just saying "read through the comments" seems like
>> a dead end.
>>
> 
> It seems there may be a justification for some form of SHA-1 support in this
> feature.  As I've said, the problem is that it's not explained in the patchset
> itself.  Rather, it just talks about "SHA" and pretends like SHA-1 and SHA-2 are
> basically the same.  In fact, SHA-1 differs drastically from SHA-2 in terms of
> security.  SHA-1 support should be added in a separate patch, with a clearly
> explained rationale *in the patch itself* for the SHA-1 support *specifically*.

For the record, we were never trying to "pretend" or obfuscate the use 
of SHA-1. It was simply expedient to put the hash algorithm changes in 
one patch. We have now separated the patches for clarity and will add 
any text that explains our use and/or explain the issues with its use.

We went back through the comments and tried to address everything that 
came up about the use of SHA-1. We will review it all again before 
posting another patch set.

Thank you for your feedback.
Ross

> 
> - Eric
Jarkko Sakkinen April 4, 2024, 2:55 p.m. UTC | #15
On Thu Apr 4, 2024 at 2:56 AM EEST, Eric Biggers wrote:
> On Wed, Apr 03, 2024 at 09:32:02AM -0700, Andy Lutomirski wrote:
> > On Fri, Feb 23, 2024, at 10:30 AM, Eric Biggers wrote:
> > > On Fri, Feb 23, 2024 at 06:20:27PM +0000, Andrew Cooper wrote:
> > >> On 23/02/2024 5:54 pm, Eric Biggers wrote:
> > >> > On Fri, Feb 23, 2024 at 04:42:11PM +0000, Andrew Cooper wrote:
> > >> >> Yes, and I agree.  We're not looking to try and force this in with
> > >> >> underhand tactics.
> > >> >>
> > >> >> But a blind "nack to any SHA-1" is similarly damaging in the opposite
> > >> >> direction.
> > >> >>
> > >> > Well, reviewers have said they'd prefer that SHA-1 not be included and given
> > >> > some thoughtful reasons for that.  But also they've given suggestions on how to
> > >> > make the SHA-1 support more palatable, such as splitting it into a separate
> > >> > patch and giving it a proper justification.
> > >> >
> > >> > All suggestions have been ignored.
> > >> 
> > >> The public record demonstrates otherwise.
> > >> 
> > >> But are you saying that you'd be happy if the commit message read
> > >> something more like:
> > >> 
> > >> ---8<---
> > >> For better or worse, Secure Launch needs SHA-1 and SHA-256.
> > >> 
> > >> The choice of hashes used lie with the platform firmware, not with
> > >> software, and is often outside of the users control.
> > >> 
> > >> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
> > >> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
> > >> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
> > >> to safely use SHA-256 for everything else.
> > >> ---
> > >
> > > Please take some time to read through the comments that reviewers have left on
> > > previous versions of the patchset.
> > 
> > So I went and read through the old comments, and I'm lost.  In brief summary:
> > 
> > If the hardware+firmware only supports SHA-1, then some reviewers would prefer
> > Linux not to support DRTM.  I personally think this is a bit silly, but it's
> > not entirely unreasonable.  Maybe it should be a config option?
> > 
> > If the hardware+firmware does support SHA-256, then it sounds (to me, reading
> > this -- I haven't dug into the right spec pages) that, for optimal security,
> > something still needs to effectively turn SHA-1 *off* at runtime by capping
> > the event log properly.  And that requires computing a SHA-1 hash.  And, to be
> > clear, (a) this is only on systems that already support SHA-256 and that we
> > should support and (b) *not* doing so leaves us potentially more vulnerable to
> > SHA-1 attacks than doing so.  And no SHA-256-supporting tooling will actually
> > be compromised by a SHA-1 compromise if we cap the event log.
> > 
> > So is there a way forward?  Just saying "read through the comments" seems like
> > a dead end.
> > 
>
> It seems there may be a justification for some form of SHA-1 support in this
> feature.  As I've said, the problem is that it's not explained in the patchset
> itself.  Rather, it just talks about "SHA" and pretends like SHA-1 and SHA-2 are
> basically the same.  In fact, SHA-1 differs drastically from SHA-2 in terms of
> security.  SHA-1 support should be added in a separate patch, with a clearly
> explained rationale *in the patch itself* for the SHA-1 support *specifically*.

Yeah, this is important so that we don't end up deleting that support
by accident. Just adding to denote that this more than just a "process
issue".

> - Eric

BR, Jarkko