From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: Chen Yu <yu.c.chen@intel.com>
Cc: linux-acpi@vger.kernel.org, Ard Biesheuvel <ardb@kernel.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
Len Brown <lenb@kernel.org>,
linux-kernel@vger.kernel.org, Ashok Raj <ashok.raj@intel.com>,
Andy Shevchenko <andriy.shevchenko@intel.com>,
Mike Rapoport <rppt@kernel.org>, Aubrey Li <aubrey.li@intel.com>
Subject: Re: [PATCH v4 3/4] drivers/acpi: Introduce Platform Firmware Runtime Update Telemetry
Date: Sat, 16 Oct 2021 17:10:25 +0200 [thread overview]
Message-ID: <YWrrYWeW7uaiJ51u@kroah.com> (raw)
In-Reply-To: <838245e376c7e6fd0fe1ef55d004ed53763846a2.1634310710.git.yu.c.chen@intel.com>
On Sat, Oct 16, 2021 at 06:44:31PM +0800, Chen Yu wrote:
> Platform Firmware Runtime Update(PFRU) Telemetry Service is part of RoT
> (Root of Trust), which allows PFRU handler and other PFRU drivers to
> produce telemetry data to upper layer OS consumer at runtime.
>
> The linux provides interfaces for the user to query the parameters of
> telemetry data, and the user could read out the telemetry data
> accordingly.
What type of interface is this? How does userspace interact with it?
>
> Also add the ABI documentation.
Add it where?
>
> Typical log looks like:
> [SmmRuntimeUpdateHandler.ProcessSmmRuntimeUpdate]
> ProcessSmmRuntimeUpdate = START, Action = 2
> [SmmRuntimeUpdateHandler.ProcessSmmRuntimeUpdate]
> FwVersion = 0, CodeInjectionVersion = 1
> [ShadowSmmRuntimeUpdateImage]
> Image = 0x74D9B000, ImageSize = 0x1172
> [ProcessSmmRuntimeUpdate]
> ShadowSmmRuntimeUpdateImage.Status = Success
> [ValidateSmmRuntimeUpdateImage]
> CapsuleHeader.CapsuleGuid = 6DCBD5ED-E82D-4C44-BDA1-7194199AD92A
> [ValidateSmmRuntimeUpdateImage]
> FmpCapHeader.Version = 1
> [ValidateSmmRuntimeUpdateImage]
> FmpCapImageHeader.UpdateImageTypeId = B2F84B79-7B6E-4E45-885F-3FB9BB185402
> [ValidateSmmRuntimeUpdateImage]
> SmmRuntimeUpdateVerifyImageWithDenylist.Status = Success
> [ValidateSmmRuntimeUpdateImage]
> SmmRuntimeUpdateVerifyImageWithAllowlist.Status = Success
> [SmmCodeInjectionVerifyPayloadHeader]
> PayloadHeader.Signature = 0x31494353
> [SmmCodeInjectionVerifyPayloadHeader]
> PayloadHeader.PlatformId = 63462139-A8B1-AA4E-9024-F2BB53EA4723
> [SmmCodeInjectionVerifyPayloadHeader]
> PayloadHeader.SupportedSmmFirmwareVersion = 0,
> PayloadHeader.SmmCodeInjectionRuntimeVersion = 1
> [ProcessSmmRuntimeUpdate]
> ValidateSmmRuntimeUpdateImage.Status = Success
> CPU CSR[0B102D28] Before = 7FBF830E
> CPU CSR[0B102D28] After = 7FBF8310
> [ProcessSmmRuntimeUpdate] ProcessSmmCodeInjection.Status = Success
> [SmmRuntimeUpdateHandler.ProcessSmmRuntimeUpdate]
> ProcessSmmRuntimeUpdate = End, Status = Success
This log does not make any sense to me, where is it from? Why the odd
line-wrapping?
>
> Signed-off-by: Chen Yu <yu.c.chen@intel.com>
> ---
> v4: Remove the telemetry kernel Kconfig and combine it with pfru
> (Rafael J. Wysocki)
> Remove redundant parens. (Rafael J. Wysocki)
> v3: Use __u32 instead of int and __64 instead of unsigned long
> in include/uapi/linux/pfru.h (Greg Kroah-Hartman)
> Rename the structure in uapi to start with a prefix pfru so as
> to avoid confusing in the global namespace. (Greg Kroah-Hartman)
> v2: Do similar clean up as pfru_update driver:
> Add sanity check for duplicated instance of ACPI device.
> Update the driver to work with allocated telem_device objects.
> (Mike Rapoport)
> For each switch case pair, get rid of the magic case numbers
> and add a default clause with the error handling.
> (Mike Rapoport)
> ---
> drivers/acpi/pfru/pfru_update.c | 380 +++++++++++++++++++++++++++++++-
> include/uapi/linux/pfru.h | 43 ++++
> 2 files changed, 421 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/acpi/pfru/pfru_update.c b/drivers/acpi/pfru/pfru_update.c
> index f57a39e79808..fe5b1bf0aeb3 100644
> --- a/drivers/acpi/pfru/pfru_update.c
> +++ b/drivers/acpi/pfru/pfru_update.c
> @@ -55,6 +55,27 @@ enum update_index {
> UPDATE_NR_IDX,
> };
>
> +enum log_index {
> + LOG_STATUS_IDX,
> + LOG_EXT_STATUS_IDX,
> + LOG_MAX_SZ_IDX,
> + LOG_CHUNK1_LO_IDX,
> + LOG_CHUNK1_HI_IDX,
> + LOG_CHUNK1_SZ_IDX,
> + LOG_CHUNK2_LO_IDX,
> + LOG_CHUNK2_HI_IDX,
> + LOG_CHUNK2_SZ_IDX,
> + LOG_ROLLOVER_CNT_IDX,
> + LOG_RESET_CNT_IDX,
> + LOG_NR_IDX,
> +};
> +
> +struct pfru_log_device {
> + struct device *dev;
> + guid_t uuid;
> + struct pfru_log_info info;
> +};
> +
> struct pfru_device {
> guid_t uuid, code_uuid, drv_uuid;
> int rev_id;
> @@ -62,6 +83,299 @@ struct pfru_device {
> };
>
> static struct pfru_device *pfru_dev;
> +static struct pfru_log_device *pfru_log_dev;
> +
> +static int get_pfru_log_data_info(struct pfru_log_data_info *data_info,
> + int log_type)
> +{
> + union acpi_object *out_obj, in_obj, in_buf;
> + acpi_handle handle;
> + int ret = -EINVAL;
> +
> + handle = ACPI_HANDLE(pfru_log_dev->dev);
> +
> + memset(&in_obj, 0, sizeof(in_obj));
> + memset(&in_buf, 0, sizeof(in_buf));
> + in_obj.type = ACPI_TYPE_PACKAGE;
> + in_obj.package.count = 1;
> + in_obj.package.elements = &in_buf;
> + in_buf.type = ACPI_TYPE_INTEGER;
> + in_buf.integer.value = log_type;
> +
> + out_obj = acpi_evaluate_dsm_typed(handle, &pfru_log_dev->uuid,
> + pfru_log_dev->info.log_revid, FUNC_GET_DATA,
> + &in_obj, ACPI_TYPE_PACKAGE);
> + if (!out_obj)
> + return ret;
> +
> + if (out_obj->package.count < LOG_NR_IDX)
> + goto free_acpi_buffer;
> +
> + if (out_obj->package.elements[LOG_STATUS_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->status = out_obj->package.elements[LOG_STATUS_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_EXT_STATUS_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->ext_status =
> + out_obj->package.elements[LOG_EXT_STATUS_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_MAX_SZ_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->max_data_size =
> + out_obj->package.elements[LOG_MAX_SZ_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_CHUNK1_LO_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->chunk1_addr_lo =
> + out_obj->package.elements[LOG_CHUNK1_LO_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_CHUNK1_HI_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->chunk1_addr_hi =
> + out_obj->package.elements[LOG_CHUNK1_HI_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_CHUNK1_SZ_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->chunk1_size =
> + out_obj->package.elements[LOG_CHUNK1_SZ_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_CHUNK2_LO_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->chunk2_addr_lo =
> + out_obj->package.elements[LOG_CHUNK2_LO_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_CHUNK2_HI_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->chunk2_addr_hi =
> + out_obj->package.elements[LOG_CHUNK2_HI_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_CHUNK2_SZ_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->chunk2_size =
> + out_obj->package.elements[LOG_CHUNK2_SZ_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_ROLLOVER_CNT_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->rollover_cnt =
> + out_obj->package.elements[LOG_ROLLOVER_CNT_IDX].integer.value;
> +
> + if (out_obj->package.elements[LOG_RESET_CNT_IDX].type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + data_info->reset_cnt =
> + out_obj->package.elements[LOG_RESET_CNT_IDX].integer.value;
> +
> + ret = 0;
> +free_acpi_buffer:
> + ACPI_FREE(out_obj);
> +
> + return ret;
> +}
> +
> +static int set_pfru_log_level(int level)
> +{
> + union acpi_object *out_obj, *obj, in_obj, in_buf;
> + enum pfru_dsm_status status;
> + acpi_handle handle;
> + int ret = -EINVAL;
> +
> + handle = ACPI_HANDLE(pfru_log_dev->dev);
> +
> + memset(&in_obj, 0, sizeof(in_obj));
> + memset(&in_buf, 0, sizeof(in_buf));
> + in_obj.type = ACPI_TYPE_PACKAGE;
> + in_obj.package.count = 1;
> + in_obj.package.elements = &in_buf;
> + in_buf.type = ACPI_TYPE_INTEGER;
> + in_buf.integer.value = level;
> +
> + out_obj = acpi_evaluate_dsm_typed(handle, &pfru_log_dev->uuid,
> + pfru_log_dev->info.log_revid, FUNC_SET_LEV,
> + &in_obj, ACPI_TYPE_PACKAGE);
> + if (!out_obj)
> + return -EINVAL;
> +
> + obj = &out_obj->package.elements[0];
> + status = obj->integer.value;
> + if (status)
> + goto free_acpi_buffer;
> +
> + obj = &out_obj->package.elements[1];
> + status = obj->integer.value;
> + if (status)
> + goto free_acpi_buffer;
> +
> + ret = 0;
> +
> +free_acpi_buffer:
> + ACPI_FREE(out_obj);
> +
> + return ret;
> +}
> +
> +static int get_pfru_log_level(int *level)
> +{
> + union acpi_object *out_obj, *obj;
> + enum pfru_dsm_status status;
> + acpi_handle handle;
> + int ret = -EINVAL;
> +
> + handle = ACPI_HANDLE(pfru_log_dev->dev);
> + out_obj = acpi_evaluate_dsm_typed(handle, &pfru_log_dev->uuid,
> + pfru_log_dev->info.log_revid, FUNC_GET_LEV,
> + NULL, ACPI_TYPE_PACKAGE);
> + if (!out_obj)
> + return -EINVAL;
> +
> + obj = &out_obj->package.elements[0];
> + if (obj->type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + status = obj->integer.value;
> + if (status)
> + goto free_acpi_buffer;
> +
> + obj = &out_obj->package.elements[1];
> + if (obj->type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + status = obj->integer.value;
> + if (status)
> + goto free_acpi_buffer;
> +
> + obj = &out_obj->package.elements[2];
> + if (obj->type != ACPI_TYPE_INTEGER)
> + goto free_acpi_buffer;
> +
> + *level = obj->integer.value;
> + ret = 0;
> +free_acpi_buffer:
> + ACPI_FREE(out_obj);
> +
> + return ret;
> +}
> +
> +static int valid_log_level(int level)
> +{
> + return level == LOG_ERR || level == LOG_WARN ||
> + level == LOG_INFO || level == LOG_VERB;
> +}
> +
> +static int valid_log_type(int type)
> +{
> + return type == LOG_EXEC_IDX || type == LOG_HISTORY_IDX;
> +}
> +
> +long pfru_log_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> +{
> + struct pfru_log_data_info data_info;
> + struct pfru_log_info info;
> + void __user *p;
> + int ret = 0;
> +
> + if (!pfru_log_dev)
> + return -ENODEV;
> +
> + p = (void __user *)arg;
> +
> + switch (cmd) {
> + case PFRU_LOG_IOC_SET_INFO:
> + if (copy_from_user(&info, p, sizeof(info)))
> + return -EFAULT;
> +
> + if (pfru_valid_revid(info.log_revid))
> + pfru_log_dev->info.log_revid = info.log_revid;
> +
> + if (valid_log_level(info.log_level)) {
> + ret = set_pfru_log_level(info.log_level);
> + if (ret)
> + return ret;
> + pfru_log_dev->info.log_level = info.log_level;
> + }
> +
> + if (valid_log_type(info.log_type))
> + pfru_log_dev->info.log_type = info.log_type;
> +
> + break;
> + case PFRU_LOG_IOC_GET_INFO:
> + ret = get_pfru_log_level(&info.log_level);
> + if (ret)
> + return ret;
> +
> + info.log_type = pfru_log_dev->info.log_type;
> + info.log_revid = pfru_log_dev->info.log_revid;
> + if (copy_to_user(p, &info, sizeof(info)))
> + ret = -EFAULT;
> +
> + break;
> + case PFRU_LOG_IOC_GET_DATA_INFO:
> + ret = get_pfru_log_data_info(&data_info, pfru_log_dev->info.log_type);
> + if (ret)
> + return ret;
> +
> + if (copy_to_user(p, &data_info, sizeof(struct pfru_log_data_info)))
> + ret = -EFAULT;
> +
> + break;
> + default:
> + ret = -ENOTTY;
> + break;
> + }
> + return ret;
> +}
> +
> +ssize_t pfru_log_read(struct file *filp, char __user *ubuf,
> + size_t size, loff_t *off)
> +{
> + struct pfru_log_data_info info;
> + phys_addr_t base_addr;
> + int buf_size, ret;
> + char *buf_ptr;
> +
> + if (!pfru_log_dev)
> + return -ENODEV;
> +
> + if (*off < 0)
> + return -EINVAL;
> +
> + ret = get_pfru_log_data_info(&info, pfru_log_dev->info.log_type);
> + if (ret)
> + return ret;
> +
> + base_addr = (phys_addr_t)(info.chunk2_addr_lo | (info.chunk2_addr_hi << 32));
> + /* pfru update has not been launched yet.*/
> + if (!base_addr)
> + return -EBUSY;
> +
> + buf_size = info.max_data_size;
> + if (*off >= buf_size)
> + return 0;
> +
> + buf_ptr = memremap(base_addr, buf_size, MEMREMAP_WB);
> + if (IS_ERR(buf_ptr))
> + return PTR_ERR(buf_ptr);
> +
> + size = min_t(size_t, size, buf_size - *off);
> + if (copy_to_user(ubuf, buf_ptr + *off, size))
> + ret = -EFAULT;
> + else
> + ret = 0;
As all you are doing is mapping some memory and reading from it, why do
you need a read() file operation at all? Why not just use mmap?
thanks,
greg k-h
next prev parent reply other threads:[~2021-10-16 15:10 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-16 10:26 [PATCH v4 0/4] Introduce Platform Firmware Runtime Update and Telemetry drivers Chen Yu
2021-10-16 10:31 ` [PATCH v4 1/4] efi: Introduce EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and corresponding structures Chen Yu
2021-10-16 10:40 ` [PATCH v4 2/4] drivers/acpi: Introduce Platform Firmware Runtime Update device driver Chen Yu
2021-10-16 15:16 ` Greg Kroah-Hartman
2021-10-19 16:33 ` Rafael J. Wysocki
2021-10-20 8:00 ` Chen Yu
2021-10-16 10:44 ` [PATCH v4 3/4] drivers/acpi: Introduce Platform Firmware Runtime Update Telemetry Chen Yu
2021-10-16 15:10 ` Greg Kroah-Hartman [this message]
2021-10-20 8:29 ` Chen Yu
2021-10-20 8:27 ` Greg Kroah-Hartman
2021-10-20 8:53 ` Mike Rapoport
2021-10-20 9:17 ` Chen Yu
2021-10-21 6:37 ` kernel test robot
2021-10-21 6:37 ` kernel test robot
2021-10-16 10:47 ` [PATCH v4 4/4] tools: Introduce power/acpi/pfru/pfru Chen Yu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YWrrYWeW7uaiJ51u@kroah.com \
--to=gregkh@linuxfoundation.org \
--cc=andriy.shevchenko@intel.com \
--cc=ardb@kernel.org \
--cc=ashok.raj@intel.com \
--cc=aubrey.li@intel.com \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rafael@kernel.org \
--cc=rppt@kernel.org \
--cc=yu.c.chen@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.