Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

crypto: ccp - Send PSP_CMD_TEE_RING_DESTROY when PSP_CMD_TEE_RING_INIT fails

The hibernate resume sequence involves loading a resume kernel that is just
used for loading the hibernate image before shifting back to the existing
kernel.

During that hibernate resume sequence the resume kernel may have loaded
the ccp driver. If this happens the resume kernel will also have called
PSP_CMD_TEE_RING_INIT but it will never have called
PSP_CMD_TEE_RING_DESTROY.

This is problematic because the existing kernel needs to re-initialize the
ring. One could argue that the existing kernel should call destroy
as part of restore() but there is no guarantee that the resume kernel did
or didn't load the ccp driver. There is also no callback opportunity for
the resume kernel to destroy before handing back control to the existing
kernel.

Similar problems could potentially exist with the use of kdump and
crash handling. I actually reproduced this issue like this:

1) rmmod ccp
2) hibernate the system
3) resume the system
4) modprobe ccp

The resume kernel will have loaded ccp but never destroyed and then when
I try to modprobe it fails.

Because of these possible cases add a flow that checks the error code from
the PSP_CMD_TEE_RING_INIT call and tries to call PSP_CMD_TEE_RING_DESTROY
if it failed. If this succeeds then call PSP_CMD_TEE_RING_INIT again.

Fixes: f892a21f51162 ("crypto: ccp - use generic power management")
Reported-by: Lars Francke <lars.francke@gmail.com>
Closes: https://lore.kernel.org/platform-driver-x86/CAD-Ua_gfJnQSo8ucS_7ZwzuhoBRJ14zXP7s8b-zX3ZcxcyWePw@mail.gmail.com/
Tested-by: Yijun Shen <Yijun.Shen@Dell.com>
Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
Reviewed-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
Link: https://patch.msgid.link/20260116041132.153674-6-superm1@kernel.org
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

authored by

Mario Limonciello (AMD) and committed by
Ilpo Järvinen
7b85137c d95f87a6

+15
+14
drivers/crypto/ccp/tee-dev.c
··· 113 113 { 114 114 int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd); 115 115 struct tee_init_ring_cmd *cmd; 116 + bool retry = false; 116 117 unsigned int reg; 117 118 int ret; 118 119 ··· 136 135 /* Send command buffer details to Trusted OS by writing to 137 136 * CPU-PSP message registers 138 137 */ 138 + retry_init: 139 139 ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_INIT, cmd, 140 140 TEE_DEFAULT_CMD_TIMEOUT, &reg); 141 141 if (ret) { ··· 147 145 } 148 146 149 147 if (FIELD_GET(PSP_CMDRESP_STS, reg)) { 148 + /* 149 + * During the hibernate resume sequence driver may have gotten loaded 150 + * but the ring not properly destroyed. If the ring doesn't work, try 151 + * to destroy and re-init once. 152 + */ 153 + if (!retry && FIELD_GET(PSP_CMDRESP_STS, reg) == PSP_TEE_STS_RING_BUSY) { 154 + dev_info(tee->dev, "tee: ring init command failed with busy status, retrying\n"); 155 + if (tee_send_destroy_cmd(tee)) { 156 + retry = true; 157 + goto retry_init; 158 + } 159 + } 150 160 dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n", 151 161 FIELD_GET(PSP_CMDRESP_STS, reg)); 152 162 tee_free_ring(tee);
+1
include/linux/psp.h
··· 18 18 * and should include an appropriate local definition in their source file. 19 19 */ 20 20 #define PSP_CMDRESP_STS GENMASK(15, 0) 21 + #define PSP_TEE_STS_RING_BUSY 0x0000000d /* Ring already initialized */ 21 22 #define PSP_CMDRESP_CMD GENMASK(23, 16) 22 23 #define PSP_CMDRESP_RESERVED GENMASK(29, 24) 23 24 #define PSP_CMDRESP_RECOVERY BIT(30)