|
|
1.1 ! root 1: /* ! 2: * KVM in-kernel APIC support ! 3: * ! 4: * Copyright (c) 2011 Siemens AG ! 5: * ! 6: * Authors: ! 7: * Jan Kiszka <[email protected]> ! 8: * ! 9: * This work is licensed under the terms of the GNU GPL version 2. ! 10: * See the COPYING file in the top-level directory. ! 11: */ ! 12: #include "hw/apic_internal.h" ! 13: #include "kvm.h" ! 14: ! 15: static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic, ! 16: int reg_id, uint32_t val) ! 17: { ! 18: *((uint32_t *)(kapic->regs + (reg_id << 4))) = val; ! 19: } ! 20: ! 21: static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic, ! 22: int reg_id) ! 23: { ! 24: return *((uint32_t *)(kapic->regs + (reg_id << 4))); ! 25: } ! 26: ! 27: void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic) ! 28: { ! 29: APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); ! 30: int i; ! 31: ! 32: memset(kapic, 0, sizeof(*kapic)); ! 33: kvm_apic_set_reg(kapic, 0x2, s->id << 24); ! 34: kvm_apic_set_reg(kapic, 0x8, s->tpr); ! 35: kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24); ! 36: kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff); ! 37: kvm_apic_set_reg(kapic, 0xf, s->spurious_vec); ! 38: for (i = 0; i < 8; i++) { ! 39: kvm_apic_set_reg(kapic, 0x10 + i, s->isr[i]); ! 40: kvm_apic_set_reg(kapic, 0x18 + i, s->tmr[i]); ! 41: kvm_apic_set_reg(kapic, 0x20 + i, s->irr[i]); ! 42: } ! 43: kvm_apic_set_reg(kapic, 0x28, s->esr); ! 44: kvm_apic_set_reg(kapic, 0x30, s->icr[0]); ! 45: kvm_apic_set_reg(kapic, 0x31, s->icr[1]); ! 46: for (i = 0; i < APIC_LVT_NB; i++) { ! 47: kvm_apic_set_reg(kapic, 0x32 + i, s->lvt[i]); ! 48: } ! 49: kvm_apic_set_reg(kapic, 0x38, s->initial_count); ! 50: kvm_apic_set_reg(kapic, 0x3e, s->divide_conf); ! 51: } ! 52: ! 53: void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic) ! 54: { ! 55: APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); ! 56: int i, v; ! 57: ! 58: s->id = kvm_apic_get_reg(kapic, 0x2) >> 24; ! 59: s->tpr = kvm_apic_get_reg(kapic, 0x8); ! 60: s->arb_id = kvm_apic_get_reg(kapic, 0x9); ! 61: s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24; ! 62: s->dest_mode = kvm_apic_get_reg(kapic, 0xe) >> 28; ! 63: s->spurious_vec = kvm_apic_get_reg(kapic, 0xf); ! 64: for (i = 0; i < 8; i++) { ! 65: s->isr[i] = kvm_apic_get_reg(kapic, 0x10 + i); ! 66: s->tmr[i] = kvm_apic_get_reg(kapic, 0x18 + i); ! 67: s->irr[i] = kvm_apic_get_reg(kapic, 0x20 + i); ! 68: } ! 69: s->esr = kvm_apic_get_reg(kapic, 0x28); ! 70: s->icr[0] = kvm_apic_get_reg(kapic, 0x30); ! 71: s->icr[1] = kvm_apic_get_reg(kapic, 0x31); ! 72: for (i = 0; i < APIC_LVT_NB; i++) { ! 73: s->lvt[i] = kvm_apic_get_reg(kapic, 0x32 + i); ! 74: } ! 75: s->initial_count = kvm_apic_get_reg(kapic, 0x38); ! 76: s->divide_conf = kvm_apic_get_reg(kapic, 0x3e); ! 77: ! 78: v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); ! 79: s->count_shift = (v + 1) & 7; ! 80: ! 81: s->initial_count_load_time = qemu_get_clock_ns(vm_clock); ! 82: apic_next_timer(s, s->initial_count_load_time); ! 83: } ! 84: ! 85: static void kvm_apic_set_base(APICCommonState *s, uint64_t val) ! 86: { ! 87: s->apicbase = val; ! 88: } ! 89: ! 90: static void kvm_apic_set_tpr(APICCommonState *s, uint8_t val) ! 91: { ! 92: s->tpr = (val & 0x0f) << 4; ! 93: } ! 94: ! 95: static uint8_t kvm_apic_get_tpr(APICCommonState *s) ! 96: { ! 97: return s->tpr >> 4; ! 98: } ! 99: ! 100: static void kvm_apic_enable_tpr_reporting(APICCommonState *s, bool enable) ! 101: { ! 102: struct kvm_tpr_access_ctl ctl = { ! 103: .enabled = enable ! 104: }; ! 105: ! 106: kvm_vcpu_ioctl(s->cpu_env, KVM_TPR_ACCESS_REPORTING, &ctl); ! 107: } ! 108: ! 109: static void kvm_apic_vapic_base_update(APICCommonState *s) ! 110: { ! 111: struct kvm_vapic_addr vapid_addr = { ! 112: .vapic_addr = s->vapic_paddr, ! 113: }; ! 114: int ret; ! 115: ! 116: ret = kvm_vcpu_ioctl(s->cpu_env, KVM_SET_VAPIC_ADDR, &vapid_addr); ! 117: if (ret < 0) { ! 118: fprintf(stderr, "KVM: setting VAPIC address failed (%s)\n", ! 119: strerror(-ret)); ! 120: abort(); ! 121: } ! 122: } ! 123: ! 124: static void do_inject_external_nmi(void *data) ! 125: { ! 126: APICCommonState *s = data; ! 127: CPUX86State *env = s->cpu_env; ! 128: uint32_t lvt; ! 129: int ret; ! 130: ! 131: cpu_synchronize_state(env); ! 132: ! 133: lvt = s->lvt[APIC_LVT_LINT1]; ! 134: if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) { ! 135: ret = kvm_vcpu_ioctl(env, KVM_NMI); ! 136: if (ret < 0) { ! 137: fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n", ! 138: strerror(-ret)); ! 139: } ! 140: } ! 141: } ! 142: ! 143: static void kvm_apic_external_nmi(APICCommonState *s) ! 144: { ! 145: run_on_cpu(s->cpu_env, do_inject_external_nmi, s); ! 146: } ! 147: ! 148: static void kvm_apic_init(APICCommonState *s) ! 149: { ! 150: memory_region_init_reservation(&s->io_memory, "kvm-apic-msi", ! 151: MSI_SPACE_SIZE); ! 152: } ! 153: ! 154: static void kvm_apic_class_init(ObjectClass *klass, void *data) ! 155: { ! 156: APICCommonClass *k = APIC_COMMON_CLASS(klass); ! 157: ! 158: k->init = kvm_apic_init; ! 159: k->set_base = kvm_apic_set_base; ! 160: k->set_tpr = kvm_apic_set_tpr; ! 161: k->get_tpr = kvm_apic_get_tpr; ! 162: k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting; ! 163: k->vapic_base_update = kvm_apic_vapic_base_update; ! 164: k->external_nmi = kvm_apic_external_nmi; ! 165: } ! 166: ! 167: static TypeInfo kvm_apic_info = { ! 168: .name = "kvm-apic", ! 169: .parent = TYPE_APIC_COMMON, ! 170: .instance_size = sizeof(APICCommonState), ! 171: .class_init = kvm_apic_class_init, ! 172: }; ! 173: ! 174: static void kvm_apic_register_types(void) ! 175: { ! 176: type_register_static(&kvm_apic_info); ! 177: } ! 178: ! 179: type_init(kvm_apic_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.