From 0df02d448aa677ff20a8f5004a881cae48dd885e Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Fri, 7 Feb 2025 13:43:52 -0800 Subject: [PATCH] ANDROID: virt: gunyah: Probe for the info_area page The Gunyah info_area page contains a series of descriptors of "information". Probe the info_area page during probe and expose a function to fetch information by its identifier. Bug: 395833312 Change-Id: I380fa59259f487f1ca9b48c12eb07957603ea099 Signed-off-by: Elliot Berman --- drivers/virt/gunyah/gunyah.c | 48 ++++++++++++++++++++++++++++++++++++ include/linux/gunyah.h | 12 +++++++++ 2 files changed, 60 insertions(+) diff --git a/drivers/virt/gunyah/gunyah.c b/drivers/virt/gunyah/gunyah.c index ef8a85f27590..7a6669a5675c 100644 --- a/drivers/virt/gunyah/gunyah.c +++ b/drivers/virt/gunyah/gunyah.c @@ -8,9 +8,45 @@ #include #include +struct gunyah_info_desc { + __le16 id; + __le16 owner; + __le32 size; + __le32 offset; +#define INFO_DESC_VALID BIT(31) + __le32 flags; +}; + +static void *info_area; + +void *gunyah_get_info(u16 owner, u16 id, size_t *size) +{ + struct gunyah_info_desc *desc = info_area; + __le16 le_owner = cpu_to_le16(owner); + __le16 le_id = cpu_to_le16(id); + + if (!desc) + return ERR_PTR(-ENOENT); + + for (desc = info_area; le32_to_cpu(desc->offset); desc++) { + if (!(le32_to_cpu(desc->flags) & INFO_DESC_VALID)) + continue; + mb(); + if (le_owner == desc->owner && le_id == desc->id) { + if (size) + *size = le32_to_cpu(desc->size); + return info_area + le32_to_cpu(desc->offset); + } + } + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL_GPL(gunyah_get_info); + static int gunyah_probe(struct platform_device *pdev) { struct gunyah_hypercall_hyp_identify_resp gunyah_api; + unsigned long info_ipa, info_size; + enum gunyah_error gh_error; if (!arch_is_gunyah_guest()) return -ENODEV; @@ -28,6 +64,18 @@ static int gunyah_probe(struct platform_device *pdev) return -ENODEV; } + gh_error = gunyah_hypercall_addrspace_find_info_area(&info_ipa, &info_size); + /* ignore errors for compatability with gh without info_area support */ + if (gh_error != GUNYAH_ERROR_OK) + goto out; + + info_area = memremap(info_ipa, info_size, MEMREMAP_WB); + if (!info_area) { + pr_err("Failed to map addrspace info area\n"); + return -ENOMEM; + } + +out: return devm_of_platform_populate(&pdev->dev); } diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h index cc16803536e4..d6b1023e7d10 100644 --- a/include/linux/gunyah.h +++ b/include/linux/gunyah.h @@ -363,6 +363,18 @@ enum gunyah_api_feature { bool arch_is_gunyah_guest(void); +enum gunyah_info_owner { + /* clang-format off */ + GUNYAH_INFO_OWNER_INVALID = 0, + GUNYAH_INFO_OWNER_HYP = 1, + GUNYAH_INFO_OWNER_ROOTVM = 2, + GUNYAH_INFO_OWNER_RM = 3, + GUNYAH_INFO_OWNER_QCRM = 16, + /* clang-format on */ +}; + +void *gunyah_get_info(u16 owner, u16 id, size_t *size); + #define GUNYAH_API_V1 1 /* Other bits reserved for future use and will be zero */