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
