// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include #include #include /* {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");