Implement the link layout that CONFIG_EFI_STUB_DRTM requires. This maps
vmlinux into the Dynamic Launch Measured Environment (DLME) defined by the
spec.

Broadly, Image fits into the spec defined DLME region memory layout in
this order:
 - Program headers and padding up to _stext. EFI can write to these while
   loading the stub so they do not have a stable measurement.
 - All the boot-time immutable data, including .text, .data, .init
   and so on (measured)
 - Data written by the EFI stub
 - .bss, padding and other 0'd data up to _end
 - The "DLME Data" written by the launch process. This is a datastructure
   the post launch kernel will parse to get trusted information about th
   launch.

New linker symbols are added to mark these areas and their offsets are
placed into the efi_image_info so both stubs can get them.

The spec's design of the DLME was intended to fit a typical OS image like
this, with two areas that are unmeasured and an inner measured region.

Linux zeroes the unmeasured area of .bss/etc after the DRTM launch so it
also reaches a known value. The DLME data is written by the launch and is
trusted. The EFI stub data is either ignored or will have to be sanitized.

Add a section for the unmeasured data before the PECOFF padding. This is
an allocated section so it is zero'd in the image and is only 64 bytes in
my builds. There is a high chance it gets absorbed into the padding
region.

The post-launch kernel will have to reserve the "DLME Data" before
starting the allocator since it falls outside the linker map. This will
happen in the first series to consume this data.

Signed-off-by: Jason Gunthorpe <[email protected]>
---
 arch/arm64/include/asm/image.h  |  8 +++++
 arch/arm64/kernel/vmlinux.lds.S | 64 ++++++++++++++++++++++++++++++++-
 2 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/image.h b/arch/arm64/include/asm/image.h
index 4a220c71f76c6a..a4af9a94037bfb 100644
--- a/arch/arm64/include/asm/image.h
+++ b/arch/arm64/include/asm/image.h
@@ -5,7 +5,11 @@
 
 #define ARM64_IMAGE_MAGIC      "ARM\x64"
 
+#ifdef CONFIG_ARM64_DRTM
+#define EFI_IMAGE_INFO_SIZE    40
+#else
 #define EFI_IMAGE_INFO_SIZE    8
+#endif
 
 #define ARM64_IMAGE_FLAG_BE_SHIFT              0
 #define ARM64_IMAGE_FLAG_PAGE_SIZE_SHIFT       (ARM64_IMAGE_FLAG_BE_SHIFT + 1)
@@ -62,6 +66,10 @@ struct arm64_image_header {
  */
 struct efi_image_info {
        __le64 code_size;
+#ifdef CONFIG_ARM64_DRTM
+       __le64 drtm_measured_start;
+       __le64 dlme_measured_size;
+#endif
 };
 static_assert(sizeof(struct efi_image_info) == EFI_IMAGE_INFO_SIZE);
 
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 8305b47995954b..18d9717fb26741 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -190,10 +190,24 @@ SECTIONS
 
        .head.text : {
                _text = .;
+#ifdef CONFIG_ARM64_DRTM
+               /* DEN0113 R314010: The DLME region must start at a 4KB aligned 
address. */
+               ASSERT((_text & (SZ_4K - 1)) == 0,
+                      "DLME region is not 4 KiB aligned")
+#endif
                HEAD_TEXT
        }
        .text : ALIGN(SEGMENT_ALIGN) {  /* Real text segment            */
                _stext = .;             /* Text and read-only data      */
+#ifdef CONFIG_ARM64_DRTM
+               __drtm_measured_start = _stext;
+               /*
+                * DEN0113 R314020: The DLME image must start at a 4KB aligned
+                * address. This happens always because SEGMENT_ALIGN is big.
+                */
+               ASSERT((__drtm_measured_start & (SZ_4K - 1)) == 0,
+                      "DLME measured start is not 4 KiB aligned")
+#endif
                        IRQENTRY_TEXT
                        SOFTIRQENTRY_TEXT
                        ENTRY_TEXT
@@ -285,6 +299,11 @@ SECTIONS
                EFI_IMAGE_INFO(
                        /* code_size */
                        EFI_IMAGE_INFO_OFFSET(__inittext_end);
+#ifdef CONFIG_ARM64_DRTM
+                       EFI_IMAGE_INFO_OFFSET(__drtm_measured_start);
+                       /* dlme_measured_size */
+                       EFI_IMAGE_INFO_ENTRY(__drtm_measured_end - 
__drtm_measured_start);
+#endif
                )
        }
        .exit.data : {
@@ -348,6 +367,44 @@ SECTIONS
                __mmuoff_data_end = .;
        }
 
+       /*
+        * DRTM layout for DEN0113 as it relates to the link layout, refer
+        * to Figure 8 in 1.4b. In that language:
+        *  "Free Space 1" is the PE header and padding between _text and
+        *        __drtm_measured_start (_stext)
+        *  "DLME Image" is from __drtm_measured_start to __drtm_measured_end
+        *  "Free Space 2" is kernel efi data/bss/etc till __drtm_dlme_start
+        *  "DLME Data" is a memory sized "Minimum Size of DLME data"
+        *        and is retained after boot for use by the kernel
+        *
+        * Thus, the DRTM_PARAMETERS follow from that:
+        *   DLME Region Address = _text's PA ie the start of Image
+        *   DLME Region Size = DLME Data Offset + "Minimum Size of DLME data"
+        *   DLME Image Start Offset = __drtm_measured_start - _text
+        *   DLME Image Size = __drtm_measured_end - __drtm_measured_start
+        *   DLME Data Offset = __drtm_dlme_start - _text
+        *   Normal World DCE region address = PA of __drtm_dlme_start +
+        *                                  "Minimum Size of DLME data"
+        *
+        * The EFI stub will place any optional "Normal World DCE" region
+        * immediately after the "DLME data". It is only used internally by the
+        * FW during the launch and has no effect on the link layout.
+        */
+#ifdef CONFIG_ARM64_DRTM
+       __drtm_measured_end = .;
+
+       /*
+        * Writable EFI stub state. When DRTM is being used the stub's mutable
+        * data cannot reside in the normal .init.data because that section
+        * will be measured.
+        */
+       .unmeasured.data : {
+               *(.unmeasured.data)
+               *(.init.efidata .init.efidata.*)
+               *(.init.efibss .init.efibss.*)
+       }
+#endif
+
        PECOFF_EDATA_PADDING
        __pecoff_data_rawsize = ABSOLUTE(. - __initdata_begin);
        _edata = .;
@@ -370,10 +427,15 @@ SECTIONS
 
        . += SZ_4K;             /* stack for the early C runtime */
        early_init_stack = .;
-
        . = ALIGN(SEGMENT_ALIGN);
        __pecoff_data_size = ABSOLUTE(. - __initdata_begin);
        _end = .;
+#ifdef CONFIG_ARM64_DRTM
+       /* DEN0113 R314030: The DLME data must start at a 4KB aligned address. 
*/
+       __drtm_dlme_start = .;
+       ASSERT((__drtm_dlme_start & (SZ_4K - 1)) == 0,
+              "DLME data is not 4 KiB aligned")
+#endif
        __pi__end = .;
 
        STABS_DEBUG
-- 
2.43.0


Reply via email to