From b1c2a1490d7e592591daa6d073809cb671d950cd Mon Sep 17 00:00:00 2001 From: Prakruthi Deepak Heragu Date: Tue, 14 Jan 2020 14:03:25 -0800 Subject: [PATCH] haven: Add VM management support for clients Add VM management APIs so that clients can start VMs and allocate/get vmids associated with VMs. Change-Id: I7a9138a9479665f6c09aae98390a30c23011b3b1 Signed-off-by: Prakruthi Deepak Heragu Signed-off-by: Elliot Berman --- drivers/virt/haven/hh_rm_drv_private.h | 27 +++++ drivers/virt/haven/hh_rm_iface.c | 153 +++++++++++++++++++++++++ include/linux/haven/hh_common.h | 6 + include/linux/haven/hh_rm_drv.h | 6 + 4 files changed, 192 insertions(+) diff --git a/drivers/virt/haven/hh_rm_drv_private.h b/drivers/virt/haven/hh_rm_drv_private.h index 2c830c23a1a9..cbfc02f7484a 100644 --- a/drivers/virt/haven/hh_rm_drv_private.h +++ b/drivers/virt/haven/hh_rm_drv_private.h @@ -27,6 +27,11 @@ struct hh_rm_rpc_reply_hdr { u32 err_code; } __packed; +/* VM specific properties to be cached */ +struct hh_vm_property { + hh_vmid_t vmid; +}; + /* RPC Header versions */ #define HH_RM_RPC_HDR_VERSION_ONE 0x1 @@ -87,6 +92,26 @@ struct hh_rm_rpc_reply_hdr { /* End Call type Message IDs */ /* End RPC Message IDs */ +/* Call: VM_ALLOCATE */ +struct hh_vm_allocate_req_payload { + u8 vmid:4; + u8 reserved:4; +} __packed; + +struct hh_vm_allocate_resp_payload { + u32 vmid; +} __packed; + +/* Call: VM_START */ +struct hh_vm_start_req_payload { + u8 vmid:4; + u8 reserved:4; +} __packed; + +struct hh_vm_start_resp_payload { + u32 response; +} __packed; + /* Message ID headers */ /* Call: VM_GET_HYP_RESOURCES */ #define HH_RM_RES_TYPE_DB_TX 0 @@ -129,6 +154,8 @@ struct hh_vm_irq_accept_resp_payload { /* End Message ID headers */ /* Common function declerations */ +int hh_update_vm_prop_table(enum hh_vm_names vm_name, + struct hh_vm_property *vm_prop); void *hh_rm_call(hh_rm_msgid_t message_id, void *req_buff, size_t req_buff_size, size_t *resp_buff_size, int *reply_err_code); diff --git a/drivers/virt/haven/hh_rm_iface.c b/drivers/virt/haven/hh_rm_iface.c index a18747957fcd..b0b4d6d712bf 100644 --- a/drivers/virt/haven/hh_rm_iface.c +++ b/drivers/virt/haven/hh_rm_iface.c @@ -12,6 +12,65 @@ #include "hh_rm_drv_private.h" +static struct hh_vm_property hh_vm_table[HH_VM_MAX]; + +int hh_update_vm_prop_table(enum hh_vm_names vm_name, + struct hh_vm_property *vm_prop) +{ + if (vm_prop->vmid <= 0) + return -EINVAL; + hh_vm_table[vm_name].vmid = vm_prop->vmid; + + return 0; +} + +/** + * hh_rm_get_vmid: Translate VM name to vmid + * @vm_name: VM name to lookup + * @vmid: out pointer to store found vmid if VM is ofund + * + * If no VM is known to RM with the supplied name, -EINVAL is returned. + * 0 otherwise. + */ +int hh_rm_get_vmid(enum hh_vm_names vm_name, hh_vmid_t *vmid) +{ + hh_vmid_t _vmid = hh_vm_table[vm_name].vmid; + + if (!_vmid) { + pr_err("%s: No vmid associated with the vm\n", __func__); + return -EINVAL; + } + + if (vmid) + *vmid = _vmid; + + return 0; +} +EXPORT_SYMBOL(hh_rm_get_vmid); + +/** + * hh_rm_get_vm_name: Translate vmid to vm name + * @vmid: vmid to lookup + * @vm_name: out pointer to store found VM name if vmid is found + * + * If no VM is known to RM with the supplied VMID, -EINVAL is returned. + * 0 otherwise. + */ +int hh_rm_get_vm_name(hh_vmid_t vmid, enum hh_vm_names *vm_name) +{ + enum hh_vm_names i; + + for (i = 0; i < HH_VM_MAX; i++) + if (hh_vm_table[i].vmid == vmid) { + if (vm_name) + *vm_name = i; + return 0; + } + + return -EINVAL; +} +EXPORT_SYMBOL(hh_rm_get_vm_name); + /** * hh_rm_vm_get_hyp_res: Get info about a series of resources for this VM * @vmid: vmid whose info is needed. Pass 0 for self @@ -125,3 +184,97 @@ out: kfree(resp_payload); return ret; } + +/** + * hh_rm_vm_alloc_vmid: Return a vmid associated with the vm loaded into + * memory. This call should be called only during + initialization. + * @vm_name: The enum value of the vm that has been loaded. + * + * The function encodes the error codes via ERR_PTR. Hence, the caller is + * responsible to check it with IS_ERR_OR_NULL(). + */ +int hh_rm_vm_alloc_vmid(enum hh_vm_names vm_name) +{ + struct hh_vm_allocate_resp_payload *resp_payload; + struct hh_vm_allocate_req_payload req_payload; + size_t resp_payload_size; + struct hh_vm_property vm_prop; + int err, reply_err_code; + + /* Look up for the vm_name<->vmid pair if already present. + * If so, return. + */ + if (!hh_vm_table[vm_name].vmid) { + pr_err("%s: VM_ALLOCATE already called for this VM\n", + __func__); + return -EINVAL; + } + + req_payload.vmid = 0; + + resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_ALLOCATE, + &req_payload, sizeof(req_payload), + &resp_payload_size, &reply_err_code); + if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) { + err = PTR_ERR(resp_payload); + pr_err("%s: VM_ALLOCATE failed with err: %d\n", + __func__, err); + return err; + } + + if (resp_payload_size != sizeof(*resp_payload)) { + pr_err("%s: Invalid size received for VM_ALLOCATE: %u\n", + __func__, resp_payload_size); + kfree(resp_payload); + return -EINVAL; + } + + vm_prop.vmid = resp_payload->vmid; + err = hh_update_vm_prop_table(vm_name, &vm_prop); + + if (err) { + pr_err("%s: Invalid vmid sent for updating table: %u\n", + __func__, resp_payload_size); + return -EINVAL; + } + return resp_payload->vmid; +} +EXPORT_SYMBOL(hh_rm_vm_alloc_vmid); + +/** + * hh_rm_vm_start: Send a request to Resource Manager VM to start a VM. + * @vmid: The vmid of the vm to be started. + * + * The function encodes the error codes via ERR_PTR. Hence, the caller is + * responsible to check it with IS_ERR_OR_NULL(). + */ +int hh_rm_vm_start(int vmid) +{ + struct hh_vm_start_resp_payload *resp_payload; + struct hh_vm_start_req_payload req_payload; + size_t resp_payload_size; + int err, reply_err_code; + + req_payload.vmid = (hh_vmid_t) vmid; + + resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_START, + &req_payload, sizeof(req_payload), + &resp_payload_size, &reply_err_code); + if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) { + err = PTR_ERR(resp_payload); + pr_err("%s: VM_ALLOCATE failed with err: %d\n", + __func__, err); + return err; + } + + if (resp_payload_size != sizeof(*resp_payload)) { + pr_err("%s: Invalid size received for VM_IRQ_ACCEPT: %u\n", + __func__, resp_payload_size); + kfree(resp_payload); + return -EINVAL; + } + + return resp_payload->response; +} +EXPORT_SYMBOL(hh_rm_vm_start); diff --git a/include/linux/haven/hh_common.h b/include/linux/haven/hh_common.h index 90e8ea72fed1..0b57c24ddc75 100644 --- a/include/linux/haven/hh_common.h +++ b/include/linux/haven/hh_common.h @@ -15,4 +15,10 @@ typedef u32 hh_label_t; typedef u64 hh_capid_t; typedef u64 hh_dbl_flags_t; +enum hh_vm_names { + HH_PRIMARY_VM, + HH_TRUSTED_VM, + HH_VM_MAX +}; + #endif diff --git a/include/linux/haven/hh_rm_drv.h b/include/linux/haven/hh_rm_drv.h index 57a4a20b7351..1b74fa2905a1 100644 --- a/include/linux/haven/hh_rm_drv.h +++ b/include/linux/haven/hh_rm_drv.h @@ -116,4 +116,10 @@ int hh_rm_register_notifier(struct notifier_block *nb); int hh_rm_unregister_notifier(struct notifier_block *nb); int hh_rm_vm_irq_accept(hh_virq_handle_t virq_handle, int virq); +/* Client APIs for VM management */ +int hh_rm_vm_alloc_vmid(enum hh_vm_names vm_name); +int hh_rm_get_vmid(enum hh_vm_names vm_name, hh_vmid_t *vmid); +int hh_rm_get_vm_name(hh_vmid_t vmid, enum hh_vm_names *vm_name); +int hh_rm_vm_start(int vmid); + #endif