arch/x86/virt/vmx/tdx/seamldr.c

Source file repositories/reference/linux-study-clean/arch/x86/virt/vmx/tdx/seamldr.c

File Facts

System
Linux kernel
Corpus path
arch/x86/virt/vmx/tdx/seamldr.c
Extension
.c
Size
9628 bytes
Lines
369
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct seamldr_params {
	u32	version;
	u32	scenario;
	u64	sigstruct_pages_pa_list[SEAMLDR_MAX_NR_SIG_PAGES];
	u8	reserved[104];
	u64	module_nr_pages;
	u64	module_pages_pa_list[SEAMLDR_MAX_NR_MODULE_PAGES];
} __packed;

static_assert(sizeof(struct seamldr_params) == 4096);

/*
 * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
 * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
 * be made with interrupts disabled, where plain spinlocks are prohibited in
 * PREEMPT_RT kernels as they become sleeping locks.
 */
static DEFINE_RAW_SPINLOCK(seamldr_lock);

static int seamldr_call(u64 fn, struct tdx_module_args *args)
{
	/*
	 * With this bug, P-SEAMLDR calls corrupt the VMCS
	 * pointer and must be avoided. This path should be
	 * unreachable since sysfs hides the ABIs.
	 */
	if (boot_cpu_has_bug(X86_BUG_SEAMRET_INVD_VMCS)) {
		WARN_ON(1);
		return -EINVAL;
	}

	guard(raw_spinlock)(&seamldr_lock);
	return seamcall_prerr(fn, args);
}

int seamldr_get_info(struct seamldr_info *seamldr_info)
{
	struct tdx_module_args args = {};

	/*
	 * Use slow_virt_to_phys() since @seamldr_info may be allocated on
	 * the stack.
	 */
	args.rcx = slow_virt_to_phys(seamldr_info);
	return seamldr_call(P_SEAMLDR_INFO, &args);
}
EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");

/* Call into P-SEAMLDR to install a TDX module update */
static int seamldr_install(const struct seamldr_params *params)
{
	struct tdx_module_args args = {};

	args.rcx = __pa(params);
	return seamldr_call(P_SEAMLDR_INSTALL, &args);
}

#define TDX_IMAGE_VERSION_2		0x200

/* First page of the on-disk module update image: */
struct tdx_image_header {
	u16	version;
	u16	checksum;
	u8	signature[8];
	u32	sigstruct_nr_pages;
	u32	module_nr_pages;
	u8	reserved[4076];
} __packed;

#define TDX_IMAGE_HEADER_SIZE sizeof(struct tdx_image_header)
static_assert(TDX_IMAGE_HEADER_SIZE == 4096);

/*
 * Intel TDX module update ABI structure. aka. "TDX module blob".
 * This is the on-disk format that fw_upload lands in a kernel
 * buffer.
 *
 * @payload contains sigstruct pages followed by module pages.
 */
struct tdx_image {
	struct tdx_image_header header;
	u8 payload[];
};

/*
 * Given a vmalloc() allocation, write all of the backing physical
 * addresses to pa_list[]. Caller guarantees that the array is big
 * enough.
 */
static void populate_pa_list(u64 *pa_list, const u8 *vmalloc_addr, u32 vmalloc_len_pages)

Annotation

Implementation Notes