Commit bb44e0d1 authored by Jan Kiszka's avatar Jan Kiszka Committed by Marcelo Tosatti
Browse files

kvm: Improve reporting of fatal errors



Report KVM_EXIT_UNKNOWN, KVM_EXIT_FAIL_ENTRY, and KVM_EXIT_EXCEPTION
with more details to stderr. The latter two are so far x86-only, so move
them into the arch-specific handler. Integrate the Intel real mode
warning on KVM_EXIT_FAIL_ENTRY that qemu-kvm carries, but actually
restrict it to Intel CPUs. Moreover, always dump the CPU state in case
we fail.

Signed-off-by: default avatarJan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
parent 73aaec4a
Loading
Loading
Loading
Loading
+8 −14
Original line number Diff line number Diff line
@@ -817,22 +817,22 @@ static int kvm_handle_io(uint16_t port, void *data, int direction, int size,
#ifdef KVM_CAP_INTERNAL_ERROR_DATA
static int kvm_handle_internal_error(CPUState *env, struct kvm_run *run)
{

    fprintf(stderr, "KVM internal error.");
    if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) {
        int i;

        fprintf(stderr, "KVM internal error. Suberror: %d\n",
                run->internal.suberror);

        fprintf(stderr, " Suberror: %d\n", run->internal.suberror);
        for (i = 0; i < run->internal.ndata; ++i) {
            fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
                    i, (uint64_t)run->internal.data[i]);
        }
    } else {
        fprintf(stderr, "\n");
    }
    cpu_dump_state(env, stderr, fprintf, 0);
    if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
        fprintf(stderr, "emulation failure\n");
        if (!kvm_arch_stop_on_emulation_error(env)) {
            cpu_dump_state(env, stderr, fprintf, 0);
            return 0;
        }
    }
@@ -966,15 +966,8 @@ int kvm_cpu_exec(CPUState *env)
            ret = 1;
            break;
        case KVM_EXIT_UNKNOWN:
            DPRINTF("kvm_exit_unknown\n");
            ret = -1;
            break;
        case KVM_EXIT_FAIL_ENTRY:
            DPRINTF("kvm_exit_fail_entry\n");
            ret = -1;
            break;
        case KVM_EXIT_EXCEPTION:
            DPRINTF("kvm_exit_exception\n");
            fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n",
                    (uint64_t)run->hw.hardware_exit_reason);
            ret = -1;
            break;
#ifdef KVM_CAP_INTERNAL_ERROR_DATA
@@ -1001,6 +994,7 @@ int kvm_cpu_exec(CPUState *env)
    } while (ret > 0);

    if (ret < 0) {
        cpu_dump_state(env, stderr, fprintf, 0);
        vm_stop(0);
        env->exit_request = 1;
    }
+2 −0
Original line number Diff line number Diff line
@@ -874,6 +874,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                   uint32_t *ecx, uint32_t *edx);
int cpu_x86_register (CPUX86State *env, const char *cpu_model);
void cpu_clear_apic_feature(CPUX86State *env);
void host_cpuid(uint32_t function, uint32_t count,
                uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);

/* helper.c */
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+2 −3
Original line number Diff line number Diff line
@@ -103,9 +103,8 @@ typedef struct model_features_t {
int check_cpuid = 0;
int enforce_cpuid = 0;

static void host_cpuid(uint32_t function, uint32_t count,
                       uint32_t *eax, uint32_t *ebx,
                       uint32_t *ecx, uint32_t *edx)
void host_cpuid(uint32_t function, uint32_t count,
                uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
#if defined(CONFIG_KVM)
    uint32_t vec[4];
+33 −0
Original line number Diff line number Diff line
@@ -1525,8 +1525,19 @@ static int kvm_handle_halt(CPUState *env)
    return 1;
}

static bool host_supports_vmx(void)
{
    uint32_t ecx, unused;

    host_cpuid(1, 0, &unused, &unused, &ecx, &unused);
    return ecx & CPUID_EXT_VMX;
}

#define VMX_INVALID_GUEST_STATE 0x80000021

int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
{
    uint64_t code;
    int ret = 0;

    switch (run->exit_reason) {
@@ -1537,6 +1548,28 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
    case KVM_EXIT_SET_TPR:
        ret = 1;
        break;
    case KVM_EXIT_FAIL_ENTRY:
        code = run->fail_entry.hardware_entry_failure_reason;
        fprintf(stderr, "KVM: entry failed, hardware error 0x%" PRIx64 "\n",
                code);
        if (host_supports_vmx() && code == VMX_INVALID_GUEST_STATE) {
            fprintf(stderr,
                    "\nIf you're runnning a guest on an Intel machine without "
                        "unrestricted mode\n"
                    "support, the failure can be most likely due to the guest "
                        "entering an invalid\n"
                    "state for Intel VT. For example, the guest maybe running "
                        "in big real mode\n"
                    "which is not supported on less recent Intel processors."
                        "\n\n");
        }
        ret = -1;
        break;
    case KVM_EXIT_EXCEPTION:
        fprintf(stderr, "KVM: exception %d exit (error code 0x%x)\n",
                run->ex.exception, run->ex.error_code);
        ret = -1;
        break;
    default:
        fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
        ret = -1;