Revision c0532a76 target-i386/kvm.c

b/target-i386/kvm.c
46 46
#define MSR_KVM_WALL_CLOCK  0x11
47 47
#define MSR_KVM_SYSTEM_TIME 0x12
48 48

  
49
#ifndef BUS_MCEERR_AR
50
#define BUS_MCEERR_AR 4
51
#endif
52
#ifndef BUS_MCEERR_AO
53
#define BUS_MCEERR_AO 5
54
#endif
55

  
49 56
#ifdef KVM_CAP_EXT_CPUID
50 57

  
51 58
static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
......
192 199
    return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, m);
193 200
}
194 201

  
202
static int kvm_get_msr(CPUState *env, struct kvm_msr_entry *msrs, int n)
203
{
204
    struct kvm_msrs *kmsrs = qemu_malloc(sizeof *kmsrs + n * sizeof *msrs);
205
    int r;
206

  
207
    kmsrs->nmsrs = n;
208
    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
209
    r = kvm_vcpu_ioctl(env, KVM_GET_MSRS, kmsrs);
210
    memcpy(msrs, kmsrs->entries, n * sizeof *msrs);
211
    free(kmsrs);
212
    return r;
213
}
214

  
215
/* FIXME: kill this and kvm_get_msr, use env->mcg_status instead */
216
static int kvm_mce_in_exception(CPUState *env)
217
{
218
    struct kvm_msr_entry msr_mcg_status = {
219
        .index = MSR_MCG_STATUS,
220
    };
221
    int r;
222

  
223
    r = kvm_get_msr(env, &msr_mcg_status, 1);
224
    if (r == -1 || r == 0) {
225
        return -1;
226
    }
227
    return !!(msr_mcg_status.data & MCG_STATUS_MCIP);
228
}
229

  
195 230
struct kvm_x86_mce_data
196 231
{
197 232
    CPUState *env;
198 233
    struct kvm_x86_mce *mce;
234
    int abort_on_error;
199 235
};
200 236

  
201 237
static void kvm_do_inject_x86_mce(void *_data)
......
203 239
    struct kvm_x86_mce_data *data = _data;
204 240
    int r;
205 241

  
242
    /* If there is an MCE excpetion being processed, ignore this SRAO MCE */
243
    r = kvm_mce_in_exception(data->env);
244
    if (r == -1)
245
        fprintf(stderr, "Failed to get MCE status\n");
246
    else if (r && !(data->mce->status & MCI_STATUS_AR))
247
        return;
248

  
206 249
    r = kvm_set_mce(data->env, data->mce);
207
    if (r < 0)
250
    if (r < 0) {
208 251
        perror("kvm_set_mce FAILED");
252
        if (data->abort_on_error) {
253
            abort();
254
        }
255
    }
209 256
}
210 257
#endif
211 258

  
212 259
void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
213
                        uint64_t mcg_status, uint64_t addr, uint64_t misc)
260
                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
261
                        int abort_on_error)
214 262
{
215 263
#ifdef KVM_CAP_MCE
216 264
    struct kvm_x86_mce mce = {
......
225 273
            .mce = &mce,
226 274
    };
227 275

  
276
    if (!cenv->mcg_cap) {
277
        fprintf(stderr, "MCE support is not enabled!\n");
278
        return;
279
    }
280

  
228 281
    run_on_cpu(cenv, kvm_do_inject_x86_mce, &data);
282
#else
283
    if (abort_on_error)
284
        abort();
229 285
#endif
230 286
}
231 287

  
......
1528 1584
              ((env->segs[R_CS].selector  & 3) != 3);
1529 1585
}
1530 1586

  
1587
static void hardware_memory_error(void)
1588
{
1589
    fprintf(stderr, "Hardware memory error!\n");
1590
    exit(1);
1591
}
1592

  
1593
int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
1594
{
1595
#if defined(KVM_CAP_MCE)
1596
    struct kvm_x86_mce mce = {
1597
            .bank = 9,
1598
    };
1599
    void *vaddr;
1600
    ram_addr_t ram_addr;
1601
    target_phys_addr_t paddr;
1602
    int r;
1603

  
1604
    if ((env->mcg_cap & MCG_SER_P) && addr
1605
        && (code == BUS_MCEERR_AR
1606
            || code == BUS_MCEERR_AO)) {
1607
        if (code == BUS_MCEERR_AR) {
1608
            /* Fake an Intel architectural Data Load SRAR UCR */
1609
            mce.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
1610
                | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
1611
                | MCI_STATUS_AR | 0x134;
1612
            mce.misc = (MCM_ADDR_PHYS << 6) | 0xc;
1613
            mce.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
1614
        } else {
1615
            /*
1616
             * If there is an MCE excpetion being processed, ignore
1617
             * this SRAO MCE
1618
             */
1619
            r = kvm_mce_in_exception(env);
1620
            if (r == -1) {
1621
                fprintf(stderr, "Failed to get MCE status\n");
1622
            } else if (r) {
1623
                return 0;
1624
            }
1625
            /* Fake an Intel architectural Memory scrubbing UCR */
1626
            mce.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
1627
                | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
1628
                | 0xc0;
1629
            mce.misc = (MCM_ADDR_PHYS << 6) | 0xc;
1630
            mce.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
1631
        }
1632
        vaddr = (void *)addr;
1633
        if (qemu_ram_addr_from_host(vaddr, &ram_addr) ||
1634
            !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr, &paddr)) {
1635
            fprintf(stderr, "Hardware memory error for memory used by "
1636
                    "QEMU itself instead of guest system!\n");
1637
            /* Hope we are lucky for AO MCE */
1638
            if (code == BUS_MCEERR_AO) {
1639
                return 0;
1640
            } else {
1641
                hardware_memory_error();
1642
            }
1643
        }
1644
        mce.addr = paddr;
1645
        r = kvm_set_mce(env, &mce);
1646
        if (r < 0) {
1647
            fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
1648
            abort();
1649
        }
1650
    } else
1651
#endif
1652
    {
1653
        if (code == BUS_MCEERR_AO) {
1654
            return 0;
1655
        } else if (code == BUS_MCEERR_AR) {
1656
            hardware_memory_error();
1657
        } else {
1658
            return 1;
1659
        }
1660
    }
1661
    return 0;
1662
}
1663

  
1664
int kvm_on_sigbus(int code, void *addr)
1665
{
1666
#if defined(KVM_CAP_MCE)
1667
    if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) {
1668
        uint64_t status;
1669
        void *vaddr;
1670
        ram_addr_t ram_addr;
1671
        target_phys_addr_t paddr;
1672
        CPUState *cenv;
1673

  
1674
        /* Hope we are lucky for AO MCE */
1675
        vaddr = addr;
1676
        if (qemu_ram_addr_from_host(vaddr, &ram_addr) ||
1677
            !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr, &paddr)) {
1678
            fprintf(stderr, "Hardware memory error for memory used by "
1679
                    "QEMU itself instead of guest system!: %p\n", addr);
1680
            return 0;
1681
        }
1682
        status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
1683
            | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
1684
            | 0xc0;
1685
        kvm_inject_x86_mce(first_cpu, 9, status,
1686
                           MCG_STATUS_MCIP | MCG_STATUS_RIPV, paddr,
1687
                           (MCM_ADDR_PHYS << 6) | 0xc, 1);
1688
        for (cenv = first_cpu->next_cpu; cenv != NULL; cenv = cenv->next_cpu) {
1689
            kvm_inject_x86_mce(cenv, 1, MCI_STATUS_VAL | MCI_STATUS_UC,
1690
                               MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0, 1);
1691
        }
1692
    } else
1693
#endif
1694
    {
1695
        if (code == BUS_MCEERR_AO) {
1696
            return 0;
1697
        } else if (code == BUS_MCEERR_AR) {
1698
            hardware_memory_error();
1699
        } else {
1700
            return 1;
1701
        }
1702
    }
1703
    return 0;
1704
}

Also available in: Unified diff