2018-10-31 02:02:29 +08:00
|
|
|
.. _hv-hypercall:
|
|
|
|
|
2021-07-02 11:47:31 +08:00
|
|
|
Hypercall / HSM Upcall
|
2018-10-31 02:02:29 +08:00
|
|
|
######################
|
|
|
|
|
2019-11-09 06:28:46 +08:00
|
|
|
The hypercall/upcall is used to request services between the Guest VM and the hypervisor.
|
|
|
|
The hypercall is from the Guest VM to hypervisor, and the upcall is from the hypervisor to the Guest VM.
|
|
|
|
The hypervisor currently supports hypercall APIs for VM management, I/O request
|
|
|
|
distribution, interrupt injection, PCI assignment, guest memory mapping,
|
|
|
|
power management, and secure world switch.
|
2018-10-31 02:02:29 +08:00
|
|
|
|
2019-10-15 12:08:12 +08:00
|
|
|
There are some restrictions for hypercall and upcall:
|
|
|
|
|
hv: hypercalls: refactor permission-checking and dispatching logic
The current permission-checking and dispatching mechanism of hypercalls is
not unified because:
1. Some hypercalls require the exact vCPU initiating the call, while the
others only need to know the VM.
2. Different hypercalls have different permission requirements: the
trusty-related ones are enabled by a guest flag, while the others
require the initiating VM to be the Service OS.
Without a unified logic it could be hard to scale when more kinds of
hypercalls are added later.
The objectives of this patch are as follows.
1. All hypercalls have the same prototype and are dispatched by a unified
logic.
2. Permissions are checked by a unified logic without consulting the
hypercall ID.
To achieve the first objective, this patch modifies the type of the first
parameter of hcall_* functions (which are the callbacks implementing the
hypercalls) from `struct acrn_vm *` to `struct acrn_vcpu *`. The
doxygen-style documentations are updated accordingly.
To achieve the second objective, this patch adds to `struct hc_dispatch` a
`permission_flags` field which specifies the guest flags that must ALL be
set for a VM to be able to invoke the hypercall. The default value (which
is 0UL) indicates that this hypercall is for SOS only. Currently only the
`permission_flag` of trusty-related hypercalls have the non-zero value
GUEST_FLAG_SECURE_WORLD_ENABLED.
With `permission_flag`, the permission checking logic of hypercalls is
unified as follows.
1. General checks
i. If the VM is neither SOS nor having any guest flag that allows
certain hypercalls, it gets #UD upon executing the `vmcall`
instruction.
ii. If the VM is allowed to execute the `vmcall` instruction, but
attempts to execute it in ring 1, 2 or 3, the VM gets #GP(0).
2. Hypercall-specific checks
i. If the hypercall is for SOS (i.e. `permission_flag` is 0), the
initiating VM must be SOS and the specified target VM cannot be a
pre-launched VM. Otherwise the hypercall returns -EINVAL without
further actions.
ii. If the hypercall requires certain guest flags, the initiating VM
must have all the required flags. Otherwise the hypercall returns
-EINVAL without further actions.
iii. A hypercall with an unknown hypercall ID makes the hypercall
returns -EINVAL without further actions.
The logic above is different from the current implementation in the
following aspects.
1. A pre-launched VM now gets #UD (rather than #GP(0)) when it attempts
to execute `vmcall` in ring 1, 2 or 3.
2. A pre-launched VM now gets #UD (rather than the return value -EPERM)
when it attempts to execute a trusty hypercall in ring 0.
3. The SOS now gets the return value -EINVAL (rather than -EPERM) when it
attempts to invoke a trusty hypercall.
4. A post-launched VM with trusty support now gets the return value
-EINVAL (rather than #UD) when it attempts to invoke a non-trusty
hypercall or an invalid hypercall.
v1 -> v2:
- Update documentation that describe hypercall behavior.
- Fix Doxygen warnings
Tracked-On: #5924
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
2021-05-07 13:17:22 +08:00
|
|
|
#. Only specific VMs (currently the Service VM and the VM with trusty enabled)
|
|
|
|
can invoke hypercalls. A VM that cannot invoke hypercalls will get ``#UD``
|
|
|
|
(i.e. invalid opcode exception).
|
2019-11-09 06:28:46 +08:00
|
|
|
#. Only ring 0 hypercalls from the guest VM are handled by the hypervisor;
|
hv: hypercalls: refactor permission-checking and dispatching logic
The current permission-checking and dispatching mechanism of hypercalls is
not unified because:
1. Some hypercalls require the exact vCPU initiating the call, while the
others only need to know the VM.
2. Different hypercalls have different permission requirements: the
trusty-related ones are enabled by a guest flag, while the others
require the initiating VM to be the Service OS.
Without a unified logic it could be hard to scale when more kinds of
hypercalls are added later.
The objectives of this patch are as follows.
1. All hypercalls have the same prototype and are dispatched by a unified
logic.
2. Permissions are checked by a unified logic without consulting the
hypercall ID.
To achieve the first objective, this patch modifies the type of the first
parameter of hcall_* functions (which are the callbacks implementing the
hypercalls) from `struct acrn_vm *` to `struct acrn_vcpu *`. The
doxygen-style documentations are updated accordingly.
To achieve the second objective, this patch adds to `struct hc_dispatch` a
`permission_flags` field which specifies the guest flags that must ALL be
set for a VM to be able to invoke the hypercall. The default value (which
is 0UL) indicates that this hypercall is for SOS only. Currently only the
`permission_flag` of trusty-related hypercalls have the non-zero value
GUEST_FLAG_SECURE_WORLD_ENABLED.
With `permission_flag`, the permission checking logic of hypercalls is
unified as follows.
1. General checks
i. If the VM is neither SOS nor having any guest flag that allows
certain hypercalls, it gets #UD upon executing the `vmcall`
instruction.
ii. If the VM is allowed to execute the `vmcall` instruction, but
attempts to execute it in ring 1, 2 or 3, the VM gets #GP(0).
2. Hypercall-specific checks
i. If the hypercall is for SOS (i.e. `permission_flag` is 0), the
initiating VM must be SOS and the specified target VM cannot be a
pre-launched VM. Otherwise the hypercall returns -EINVAL without
further actions.
ii. If the hypercall requires certain guest flags, the initiating VM
must have all the required flags. Otherwise the hypercall returns
-EINVAL without further actions.
iii. A hypercall with an unknown hypercall ID makes the hypercall
returns -EINVAL without further actions.
The logic above is different from the current implementation in the
following aspects.
1. A pre-launched VM now gets #UD (rather than #GP(0)) when it attempts
to execute `vmcall` in ring 1, 2 or 3.
2. A pre-launched VM now gets #UD (rather than the return value -EPERM)
when it attempts to execute a trusty hypercall in ring 0.
3. The SOS now gets the return value -EINVAL (rather than -EPERM) when it
attempts to invoke a trusty hypercall.
4. A post-launched VM with trusty support now gets the return value
-EINVAL (rather than #UD) when it attempts to invoke a non-trusty
hypercall or an invalid hypercall.
v1 -> v2:
- Update documentation that describe hypercall behavior.
- Fix Doxygen warnings
Tracked-On: #5924
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
2021-05-07 13:17:22 +08:00
|
|
|
otherwise, the hypervisor will inject ``#GP(0)`` (i.e. generation protection
|
|
|
|
exception with error code ``0``) to the Guest VM.
|
|
|
|
#. Each VM is permitted to invoke a certain subset of hypercalls. Currently a VM
|
|
|
|
with trusty enabled is allowed to invoke trusty hypercalls, and the Service
|
|
|
|
VM is allowed to invoke the other hypercalls. A VM that invokes an
|
|
|
|
unpermitted hypercall will get the return value ``-EINVAL``.
|
2019-10-15 12:08:12 +08:00
|
|
|
see :ref:`secure-hypervisor-interface` for a detailed description.
|
2019-11-09 06:28:46 +08:00
|
|
|
#. The hypervisor needs to protect the critical resources such as global VM and VCPU structures
|
2019-10-15 12:08:12 +08:00
|
|
|
for VM and VCPU management hypercalls.
|
2019-11-09 06:28:46 +08:00
|
|
|
#. Upcall is only used for the Service VM.
|
2018-10-31 02:02:29 +08:00
|
|
|
|
2019-10-15 12:08:12 +08:00
|
|
|
|
2019-11-09 06:28:46 +08:00
|
|
|
HV and Service VM both use the same vector (0xF3) reserved as x86 platform
|
|
|
|
IPI vector for HV notification to the Service VM. This upcall is necessary whenever
|
|
|
|
there is device emulation requirement to the Service VM. The upcall vector (0xF3) is
|
2020-12-29 06:42:13 +08:00
|
|
|
injected to Service VM vCPU0. The Service VM will register the IRQ handler for vector (0xF3) and notify the I/O emulation
|
|
|
|
module in the Service VM once the IRQ is triggered.
|
2019-11-09 06:28:46 +08:00
|
|
|
View the detailed upcall process at :ref:`ipi-management`
|
2019-10-15 12:08:12 +08:00
|
|
|
|
2021-02-13 08:27:24 +08:00
|
|
|
Hypercall APIs Reference:
|
2019-10-15 12:08:12 +08:00
|
|
|
*************************
|
|
|
|
|
2019-11-09 06:28:46 +08:00
|
|
|
:ref:`hypercall_apis` for the Service VM
|
2019-10-15 12:08:12 +08:00
|
|
|
|
|
|
|
:ref:`trusty-hypercalls` for Trusty
|
2018-10-31 02:02:29 +08:00
|
|
|
|
|
|
|
|