diff --git a/hypervisor/debug/shell.c b/hypervisor/debug/shell.c index 08896dbea..a42df004e 100644 --- a/hypervisor/debug/shell.c +++ b/hypervisor/debug/shell.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ static int32_t shell_cpuid(int32_t argc, char **argv); static int32_t shell_reboot(int32_t argc, char **argv); static int32_t shell_rdmsr(int32_t argc, char **argv); static int32_t shell_wrmsr(int32_t argc, char **argv); +static int32_t shell_vcpu_inject_exception(int32_t argc, char **argv); static int32_t shell_show_vmexit_profile(__unused int argc, __unused char **argv); static struct shell_cmd shell_cmds[] = { @@ -98,6 +100,12 @@ static struct shell_cmd shell_cmds[] = { .help_str = SHELL_CMD_DUMP_GUEST_MEM_HELP, .fcn = shell_dump_guest_mem, }, + { + .str = SHELL_CMD_INJ_GUEST_EXP, + .cmd_param = SHELL_CMD_INJ_GUEST_EXP_PARAM, + .help_str = SHELL_CMD_INJ_GUEST_EXP_HELP, + .fcn = shell_vcpu_inject_exception, + }, { .str = SHELL_CMD_VM_CONSOLE, .cmd_param = SHELL_CMD_VM_CONSOLE_PARAM, @@ -1455,6 +1463,84 @@ static int32_t shell_wrmsr(int32_t argc, char **argv) return ret; } +static void inject_vcpu_exception(void *data) +{ + struct vcpu_inject_exception *inject = data; + struct acrn_vcpu *vcpu = inject->vcpu; + uint32_t exception = inject->exception; + + (void)vcpu_queue_exception(vcpu, exception, 0); + + return; +} + +static int32_t shell_vcpu_inject_exception(int32_t argc, char **argv) +{ + char temp_str[MAX_STR_SIZE]; + int32_t status = 0; + uint16_t vm_id; + uint16_t vcpu_id, pcpu_id; + uint32_t exception; + struct acrn_vm *vm; + struct acrn_vcpu *vcpu; + uint64_t mask = 0UL; + struct vcpu_inject_exception inject; + + /* User input invalidation */ + if (argc != 4) { + shell_puts("Please enter cmd with \r\n"); + status = -EINVAL; + goto out; + } + + status = strtol_deci(argv[1]); + if (status < 0) { + goto out; + } + vm_id = sanitize_vmid((uint16_t)status); + vcpu_id = (uint16_t)strtol_deci(argv[2]); + exception = (uint32_t)strtol_deci(argv[3]); + + vm = get_vm_from_vmid(vm_id); + if (is_poweroff_vm(vm)) { + shell_puts("No vm found in the input \r\n"); + status = -EINVAL; + goto out; + } + + if (vcpu_id >= vm->hw.created_vcpus) { + shell_puts("vcpu id is out of range\r\n"); + status = -EINVAL; + goto out; + } + + vcpu = vcpu_from_vid(vm, vcpu_id); + if (vcpu->state == VCPU_OFFLINE) { + shell_puts("vcpu is offline\r\n"); + status = -EINVAL; + goto out; + } + + if (exception > 31U) { + shell_puts("invalid exception number\r\n"); + status = -EINVAL; + goto out; + } + + pcpu_id = pcpuid_from_vcpu(vcpu); + inject.vcpu = vcpu; + inject.exception = exception; + bitmap_set_nolock(pcpu_id, &mask); + smp_call_function(mask, inject_vcpu_exception, &inject); + snprintf(temp_str, MAX_STR_SIZE, "Exception %02x is injected to vm(0x%d): vcpu(0x%d)\r\n", + exception, vm->vm_id, vcpu->vcpu_id); + shell_puts(temp_str); + status = 0; + +out: + return status; +} + static void get_vmexit_profile_per_pcpu(char *str_arg, size_t str_max) { char *str = str_arg; diff --git a/hypervisor/debug/shell_priv.h b/hypervisor/debug/shell_priv.h index 81321f85a..5bd5e3b8e 100644 --- a/hypervisor/debug/shell_priv.h +++ b/hypervisor/debug/shell_priv.h @@ -107,6 +107,10 @@ struct shell { #define SHELL_CMD_WRMSR_HELP "Write value (in hexadecimal) to the MSR at msr_index (in hexadecimal) for CPU"\ " ID pcpu_id" +#define SHELL_CMD_INJ_GUEST_EXP "inj_guest_exp" +#define SHELL_CMD_INJ_GUEST_EXP_PARAM "" +#define SHELL_CMD_INJ_GUEST_EXP_HELP "Inject an exception to a specific vCPU" + #define SHELL_CMD_VMEXIT "vmexit" #define SHELL_CMD_VMEXIT_PARAM NULL #define SHELL_CMD_VMEXIT_HELP "show vmexit profiling, use: vmexit [clear | enable | disable] enabled by default" diff --git a/hypervisor/include/arch/x86/asm/guest/vcpu.h b/hypervisor/include/arch/x86/asm/guest/vcpu.h index 787aaf821..f1a4b4ddc 100644 --- a/hypervisor/include/arch/x86/asm/guest/vcpu.h +++ b/hypervisor/include/arch/x86/asm/guest/vcpu.h @@ -329,6 +329,11 @@ struct guest_mem_dump { uint64_t len; }; +struct vcpu_inject_exception { + struct acrn_vcpu *vcpu; + uint32_t exception; +}; + static inline bool is_vcpu_bsp(const struct acrn_vcpu *vcpu) { return (vcpu->vcpu_id == BSP_CPU_ID);