Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6.6]Hygon: CSV3: Support attestation for CSV3 guest #473

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions arch/x86/include/asm/csv.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ void __init csv_early_update_memory_dec(u64 vaddr, u64 pages);
void __init csv_early_memory_enc_dec(u64 vaddr, u64 size, bool enc);

void csv_memory_enc_dec(u64 vaddr, u64 pages, bool enc);
int csv3_issue_request_report(phys_addr_t paddr, size_t size);

#else /* !CONFIG_HYGON_CSV */

Expand All @@ -79,6 +80,7 @@ static inline void __init csv_early_memory_enc_dec(u64 vaddr, u64 size,
bool enc) { }

static inline void csv_memory_enc_dec(u64 vaddr, u64 pages, bool enc) { }
static inline int csv3_issue_request_report(phys_addr_t paddr, size_t size) { return -EIO; }

#endif /* CONFIG_HYGON_CSV */

Expand Down
23 changes: 22 additions & 1 deletion arch/x86/kernel/csv-shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,33 @@
* CSV3_SECURE_CMD_UPDATE_SECURE_CALL_TABLE:
* CSV3 guest wants to change the secure call pages.
* The secure processor re-init the secure call context.
*
* CSV3_SECURE_CMD_REQ_REPORT:
* CSV3 guest wants to request attestation report.
* The secure processor will update the request message buffer and respond
* buffer to indicate the result of this request.
*/
enum csv3_secure_command_type {
CSV3_SECURE_CMD_ENC = 1,
/* The secure call request should below CSV3_SECURE_CMD_ACK */
CSV3_SECURE_CMD_ENC = 0x1,
CSV3_SECURE_CMD_DEC,
CSV3_SECURE_CMD_RESET,
CSV3_SECURE_CMD_UPDATE_SECURE_CALL_TABLE,
CSV3_SECURE_CMD_REQ_REPORT = 0x7,

/* SECURE_CMD_ACK indicates secure call request can be handled */
CSV3_SECURE_CMD_ACK = 0x6b,

/*
* The following values are the error code of the secure call
* when firmware can't handling the specific secure call command
* as expected.
*/
CSV3_SECURE_CMD_ERROR_INTERNAL = 0x6c,
CSV3_SECURE_CMD_ERROR_INVALID_COMMAND = 0x6d,
CSV3_SECURE_CMD_ERROR_INVALID_PARAM = 0x6e,
CSV3_SECURE_CMD_ERROR_INVALID_ADDRESS = 0x6f,
CSV3_SECURE_CMD_ERROR_INVALID_LENGTH = 0x70,
};

/*
Expand Down
73 changes: 73 additions & 0 deletions arch/x86/kernel/csv.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,76 @@ void csv_memory_enc_dec(u64 vaddr, u64 pages, bool enc)

__csv3_memory_enc_dec(csv3_secure_call, vaddr & PAGE_MASK, pages, enc);
}

static void print_secure_call_error(enum csv3_secure_command_type code)
{
switch (code) {
case CSV3_SECURE_CMD_ACK:
pr_debug("secure call: handled\n");
break;
case CSV3_SECURE_CMD_ERROR_INTERNAL:
pr_err("secure call: internal error\n");
break;
case CSV3_SECURE_CMD_ERROR_INVALID_COMMAND:
pr_err("secure call: unsupported cmd\n");
break;
case CSV3_SECURE_CMD_ERROR_INVALID_PARAM:
pr_err("secure call: invalid param\n");
break;
case CSV3_SECURE_CMD_ERROR_INVALID_ADDRESS:
pr_err("secure call: invalid address\n");
break;
case CSV3_SECURE_CMD_ERROR_INVALID_LENGTH:
pr_err("secure call: invalid length\n");
break;
default:
pr_err("secure call: shouldn't reach here\n");
break;
}
}

int csv3_issue_request_report(phys_addr_t paddr, size_t size)
{
struct secure_call_pages *sc_page_info;
struct csv3_secure_call_cmd *sc_wr, *sc_rd;
unsigned long flags;
int sc_page_idx;
enum csv3_secure_command_type sc_return_code;

/*
* secure call pages needs to access with IRQs disabled because it is
* using a per-CPU data.
*/
local_irq_save(flags);

sc_page_info = this_cpu_read(secure_call_data);
sc_page_idx = this_cpu_read(secure_call_page_idx);

sc_wr = sc_page_idx ? &sc_page_info->page_a : &sc_page_info->page_b;
sc_rd = sc_page_idx ? &sc_page_info->page_b : &sc_page_info->page_a;

sc_wr->cmd_type = CSV3_SECURE_CMD_REQ_REPORT;
sc_wr->nums = 1;
sc_wr->unused = 0;
sc_wr->entry[0].base_address = (u64)paddr;
sc_wr->entry[0].size = size;

/*
* Write command in sc_wr must be done before retrieve status code
* from sc_rd, and it's ensured by the smp_mb below.
*/
smp_mb();

sc_return_code = sc_rd->cmd_type;

this_cpu_write(secure_call_page_idx, sc_page_idx ^ 1);

/* Leave per-CPU data access */
local_irq_restore(flags);

/* Print return code of the secure call */
print_secure_call_error(sc_return_code);

return sc_return_code == CSV3_SECURE_CMD_ACK ? 0 : -EIO;
}
EXPORT_SYMBOL_GPL(csv3_issue_request_report);
1 change: 1 addition & 0 deletions arch/x86/mm/mem_encrypt_hygon.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ bool noinstr csv3_active(void)
else
return false;
}
EXPORT_SYMBOL_GPL(csv3_active);

/******************************************************************************/
/**************************** CSV3 CMA interfaces *****************************/
Expand Down
127 changes: 122 additions & 5 deletions drivers/virt/coco/csv-guest/csv-guest.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,28 @@
#include <linux/slab.h>
#include <linux/cc_platform.h>
#include <linux/cacheflush.h>
#include <linux/psp-hygon.h>

#include <uapi/linux/kvm_para.h>

#include <asm/csv.h>

#include "csv-guest.h"

static long csv_get_report(void __user *argp)
/* Mutex to serialize the command handling. */
static DEFINE_MUTEX(csv_cmd_mutex);

static int csv_get_report(unsigned long arg)
{
u8 *csv_report;
long ret;
struct csv_report_req req;

if (copy_from_user(&req, argp, sizeof(struct csv_report_req)))
if (copy_from_user(&req, (void __user *)arg,
sizeof(struct csv_report_req)))
return -EFAULT;

if (req.len < CSV_REPORT_INPUT_DATA_LEN)
if (req.len < CSV_REPORT_INPUT_DATA_LEN || !req.report_data)
return -EINVAL;

csv_report = kzalloc(req.len, GFP_KERNEL);
Expand Down Expand Up @@ -54,14 +61,124 @@ static long csv_get_report(void __user *argp)
return ret;
}

static int csv3_get_report(unsigned long arg)
{
struct csv_report_req input;
struct page *page = NULL;
struct csv3_data_attestation_report *cmd_buff = NULL;
void *req_buff = NULL;
void *resp_buff = NULL;
int ret;

if (copy_from_user(&input, (void __user *)arg, sizeof(input)))
return -EFAULT;

if (!input.len || !input.report_data)
return -EINVAL;

/* Use alloc_page for alignment */
page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
if (!page)
return -ENOMEM;
cmd_buff = (struct csv3_data_attestation_report *)page_address(page);

/*
* Query the firmware to get minimum length of request buffer and
* respond buffer.
*/
ret = csv3_issue_request_report(__pa(cmd_buff), sizeof(*cmd_buff));

/*
* The input.len must be the maxinum length of the req and resp buffer
* at least, otherwise return with error.
*/
if (input.len < max(cmd_buff->req_len, cmd_buff->resp_len)) {
ret = -EINVAL;
goto err;
}

/* Use alloc_page for alignment */
page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
if (!page) {
ret = -ENOMEM;
goto err;
}
req_buff = page_address(page);

/* Use alloc_page for alignment */
page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
if (!page) {
ret = -ENOMEM;
goto err;
}
resp_buff = page_address(page);

/* Copy user's input data */
if (copy_from_user(req_buff, input.report_data, cmd_buff->req_len)) {
ret = -EFAULT;
goto err;
}

/*
* The req_len and resp_len fields has already been filled by firmware
* when we query the lengths from firmware.
*/
cmd_buff->req_gpa = __pa(req_buff);
cmd_buff->resp_gpa = __pa(resp_buff);

ret = csv3_issue_request_report(__pa(cmd_buff), sizeof(*cmd_buff));
if (ret || (!ret && cmd_buff->fw_error_code)) {
pr_err("%s: fail to generate report, fw_error:%#x ret:%d\n",
__func__, cmd_buff->fw_error_code, ret);
ret = -EIO;
goto err;
}

/* Copy attestation report to user */
if (copy_to_user(input.report_data, resp_buff, cmd_buff->resp_len))
ret = -EFAULT;

err:
if (resp_buff)
free_page((unsigned long)resp_buff);
if (req_buff)
free_page((unsigned long)req_buff);
if (cmd_buff)
free_page((unsigned long)cmd_buff);

return ret;
}

static int get_report(unsigned long arg)
{
int ret = -ENOTTY;

lockdep_assert_held(&csv_cmd_mutex);

if (csv3_active())
ret = csv3_get_report(arg);
else if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
ret = csv_get_report(arg);
return ret;
}

static long csv_guest_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = -ENOTTY;

mutex_lock(&csv_cmd_mutex);

switch (cmd) {
case CSV_CMD_GET_REPORT:
return csv_get_report((void __user *)arg);
ret = get_report(arg);
break;
default:
return -ENOTTY;
break;
}

mutex_unlock(&csv_cmd_mutex);

return ret;
}

static const struct file_operations csv_guest_fops = {
Expand Down
22 changes: 22 additions & 0 deletions include/linux/psp-hygon.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,28 @@ struct csv3_data_dbg_read_mem {
u32 size; /* In */
} __packed;

/**
* struct csv3_data_attestation_report - ATTESTATION secure call command parameters
*
* @handle: handle of the VM to process
* @resp_gpa: guest physical address to save the generated report
* @resp_length: length of the generated report
* @req_gpa: guest physical address of the input for the report
* @req_length: length of the input for the report
* @fw_error_code: firmware status code when generating the report
*/
struct csv3_data_attestation_report {
u32 handle; /* Out */
u32 reserved1;
u64 resp_gpa; /* In */
u8 reserved2[16];
u32 resp_len; /* In/Out */
u32 reserved3;
u64 req_gpa; /* In */
u32 req_len; /* In,Out */
u32 fw_error_code; /* Out */
} __packed;

/**
* struct csv3_data_send_encrypt_data - SEND_ENCRYPT_DATA command parameters
*
Expand Down
13 changes: 13 additions & 0 deletions include/uapi/linux/psp-hygon.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,17 @@ struct csv_user_data_download_firmware {
__u32 length; /* In */
} __packed;

/**
* struct csv_guest_user_data_attestation - ATTESTATION command parameters
*
* @user_data: user specified data for the attestation report
* @mnonce: user's random nonce
* @hash: sm3 hash of the @user_data and @mnonce
*/
struct csv_guest_user_data_attestation {
__u8 user_data[64]; /* In */
__u8 monce[16]; /* In */
__u8 hash[32]; /* In */
} __packed;

#endif /* __PSP_HYGON_USER_H__ */
Loading