123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include <linux/arm-smccc.h>
- #include <linux/module.h>
- #include <linux/gunyah.h>
- #include <linux/uuid.h>
- /* {c1d58fcd-a453-5fdb-9265-ce36673d5f14} */
- static const uuid_t GUNYAH_UUID =
- UUID_INIT(0xc1d58fcd, 0xa453, 0x5fdb, 0x92, 0x65, 0xce, 0x36, 0x67, 0x3d, 0x5f, 0x14);
- bool arch_is_gh_guest(void)
- {
- struct arm_smccc_res res;
- uuid_t uuid;
- u32 *up;
- arm_smccc_1_1_hvc(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, &res);
- up = (u32 *)&uuid.b[0];
- up[0] = lower_32_bits(res.a0);
- up[1] = lower_32_bits(res.a1);
- up[2] = lower_32_bits(res.a2);
- up[3] = lower_32_bits(res.a3);
- return uuid_equal(&uuid, &GUNYAH_UUID);
- }
- EXPORT_SYMBOL_GPL(arch_is_gh_guest);
- #define GH_HYPERCALL(fn) ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \
- ARM_SMCCC_OWNER_VENDOR_HYP, \
- fn)
- #define GH_HYPERCALL_HYP_IDENTIFY GH_HYPERCALL(0x8000)
- #define GH_HYPERCALL_BELL_SEND GH_HYPERCALL(0x8012)
- #define GH_HYPERCALL_BELL_SET_MASK GH_HYPERCALL(0x8015)
- #define GH_HYPERCALL_MSGQ_SEND GH_HYPERCALL(0x801B)
- #define GH_HYPERCALL_MSGQ_RECV GH_HYPERCALL(0x801C)
- #define GH_HYPERCALL_VCPU_RUN GH_HYPERCALL(0x8065)
- /**
- * gh_hypercall_hyp_identify() - Returns build information and feature flags
- * supported by Gunyah.
- * @hyp_identity: filled by the hypercall with the API info and feature flags.
- */
- void gh_hypercall_hyp_identify(struct gh_hypercall_hyp_identify_resp *hyp_identity)
- {
- struct arm_smccc_res res;
- arm_smccc_1_1_hvc(GH_HYPERCALL_HYP_IDENTIFY, &res);
- hyp_identity->api_info = res.a0;
- hyp_identity->flags[0] = res.a1;
- hyp_identity->flags[1] = res.a2;
- hyp_identity->flags[2] = res.a3;
- }
- EXPORT_SYMBOL_GPL(gh_hypercall_hyp_identify);
- enum gh_error gh_hypercall_bell_send(u64 capid, u64 new_flags, u64 *old_flags)
- {
- struct arm_smccc_res res;
- arm_smccc_1_1_hvc(GH_HYPERCALL_BELL_SEND, capid, new_flags, 0, &res);
- if (res.a0 == GH_ERROR_OK && old_flags)
- *old_flags = res.a1;
- return res.a0;
- }
- EXPORT_SYMBOL_GPL(gh_hypercall_bell_send);
- enum gh_error gh_hypercall_bell_set_mask(u64 capid, u64 enable_mask, u64 ack_mask)
- {
- struct arm_smccc_res res;
- arm_smccc_1_1_hvc(GH_HYPERCALL_BELL_SET_MASK, capid, enable_mask, ack_mask, 0, &res);
- return res.a0;
- }
- EXPORT_SYMBOL_GPL(gh_hypercall_bell_set_mask);
- enum gh_error gh_hypercall_msgq_send(u64 capid, size_t size, void *buff, u64 tx_flags, bool *ready)
- {
- struct arm_smccc_res res;
- arm_smccc_1_1_hvc(GH_HYPERCALL_MSGQ_SEND, capid, size, (uintptr_t)buff, tx_flags, 0, &res);
- if (res.a0 == GH_ERROR_OK)
- *ready = !!res.a1;
- return res.a0;
- }
- EXPORT_SYMBOL_GPL(gh_hypercall_msgq_send);
- enum gh_error gh_hypercall_msgq_recv(u64 capid, void *buff, size_t size, size_t *recv_size,
- bool *ready)
- {
- struct arm_smccc_res res;
- arm_smccc_1_1_hvc(GH_HYPERCALL_MSGQ_RECV, capid, (uintptr_t)buff, size, 0, &res);
- if (res.a0 == GH_ERROR_OK) {
- *recv_size = res.a1;
- *ready = !!res.a2;
- }
- return res.a0;
- }
- EXPORT_SYMBOL_GPL(gh_hypercall_msgq_recv);
- enum gh_error gh_hypercall_vcpu_run(u64 capid, u64 *resume_data,
- struct gh_hypercall_vcpu_run_resp *resp)
- {
- struct arm_smccc_1_2_regs args = {
- .a0 = GH_HYPERCALL_VCPU_RUN,
- .a1 = capid,
- .a2 = resume_data[0],
- .a3 = resume_data[1],
- .a4 = resume_data[2],
- /* C language says this will be implictly zero. Gunyah requires 0, so be explicit */
- .a5 = 0,
- };
- struct arm_smccc_1_2_regs res;
- arm_smccc_1_2_hvc(&args, &res);
- if (res.a0 == GH_ERROR_OK) {
- resp->sized_state = res.a1;
- resp->state_data[0] = res.a2;
- resp->state_data[1] = res.a3;
- resp->state_data[2] = res.a4;
- }
- return res.a0;
- }
- EXPORT_SYMBOL_GPL(gh_hypercall_vcpu_run);
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("Gunyah Hypervisor Hypercalls");
|