Currently the OS fails the PSP initialization when the file specified at
'init_ex_path' does not exist or has invalid content. However the SEV
spec just requires users to allocate 32KB of 0xFF in the file, which can
be taken care of by the OS easily.
To improve the robustness during the PSP init, leverage the retry
mechanism and continue the init process:
During the first INIT_EX call, if the content is invalid or missing,
continue the process by feeding those contents into PSP instead of
aborting. PSP will then override it with 32KB 0xFF and return
SEV_RET_SECURE_DATA_INVALID status code. In the second INIT_EX call,
this 32KB 0xFF content will then be fed and PSP will write the valid
data to the file.
In order to do this, it's also needed to skip the sev_read_init_ex_file
in the second INIT_EX call to prevent the file content from being
overwritten by the 32KB 0xFF data provided by PSP in the first INIT_EX
call.
Co-developed-by: Peter Gonda <pgonda@xxxxxxxxxx>
Signed-off-by: Peter Gonda <pgonda@xxxxxxxxxx>
Signed-off-by: Jacky Li <jackyli@xxxxxxxxxx>
Reported-by: Alper Gun <alpergun@xxxxxxxxxx>
---
.../virt/kvm/x86/amd-memory-encryption.rst | 5 ++--
drivers/crypto/ccp/sev-dev.c | 29 +++++++++++++------
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/Documentation/virt/kvm/x86/amd-memory-encryption.rst b/Documentation/virt/kvm/x86/amd-memory-encryption.rst
index 2d307811978c..935aaeb97fe6 100644
--- a/Documentation/virt/kvm/x86/amd-memory-encryption.rst
+++ b/Documentation/virt/kvm/x86/amd-memory-encryption.rst
@@ -89,9 +89,8 @@ context. In a typical workflow, this command should be the first command issued.
The firmware can be initialized either by using its own non-volatile storage or
the OS can manage the NV storage for the firmware using the module parameter
-``init_ex_path``. The file specified by ``init_ex_path`` must exist. To create
-a new NV storage file allocate the file with 32KB bytes of 0xFF as required by
-the SEV spec.
+``init_ex_path``. If the file specified by ``init_ex_path`` does not exist or
+is invalid, the OS will create or override the file with output from PSP.
Returns: 0 on success, -negative on error
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 799b476fc3e8..5bb2ae250d38 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -75,6 +75,7 @@ static void *sev_es_tmr;
*/
#define NV_LENGTH (32 * 1024)
static void *sev_init_ex_buffer;
+static bool nv_file_loaded;
static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
{
@@ -211,18 +212,19 @@ static int sev_read_init_ex_file(void)
if (IS_ERR(fp)) {
int ret = PTR_ERR(fp);
- dev_err(sev->dev,
- "SEV: could not open %s for read, error %d\n",
- init_ex_path, ret);
+ if (ret != -ENOENT) {
+ dev_err(sev->dev,
+ "SEV: could not open %s for read, error %d\n",
+ init_ex_path, ret);
+ }
return ret;
}
nread = kernel_read(fp, sev_init_ex_buffer, NV_LENGTH, NULL);
if (nread != NV_LENGTH) {
- dev_err(sev->dev,
- "SEV: failed to read %u bytes to non volatile memory area, ret %ld\n",
+ dev_info(sev->dev,
+ "SEV: could not read %u bytes to non volatile memory area, ret %ld\n",
NV_LENGTH, nread);
- return -EIO;
}
dev_dbg(sev->dev, "SEV: read %ld bytes from NV file\n", nread);
@@ -417,9 +419,18 @@ static int __sev_init_ex_locked(int *error)
data.nv_address = __psp_pa(sev_init_ex_buffer);
data.nv_len = NV_LENGTH;
- ret = sev_read_init_ex_file();
- if (ret)
- return ret;
+ /*
+ * The caller of INIT_EX will retry if it fails. Furthermore, if the
+ * failure is due to sev_init_ex_buffer being invalid, the PSP will have
+ * properly initialized the buffer already. Therefore, do not initialize
+ * it a second time.
+ */
+ if (!nv_file_loaded) {
+ ret = sev_read_init_ex_file();
+ if (ret && ret != -ENOENT)
+ return ret;
+ nv_file_loaded = true;
+ }
if (sev_es_tmr) {
/*