Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'loongarch-kvm-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson into HEAD

LoongArch KVM changes for v6.19

1. Get VM PMU capability from HW GCFG register.
2. Add AVEC basic support.
3. Use 64-bit register definition for EIOINTC.
4. Add KVM timer test cases for tools/selftests.

+536 -109
+8 -47
arch/loongarch/include/asm/kvm_eiointc.h
··· 10 10 11 11 #define EIOINTC_IRQS 256 12 12 #define EIOINTC_ROUTE_MAX_VCPUS 256 13 - #define EIOINTC_IRQS_U8_NUMS (EIOINTC_IRQS / 8) 14 - #define EIOINTC_IRQS_U16_NUMS (EIOINTC_IRQS_U8_NUMS / 2) 15 - #define EIOINTC_IRQS_U32_NUMS (EIOINTC_IRQS_U8_NUMS / 4) 16 - #define EIOINTC_IRQS_U64_NUMS (EIOINTC_IRQS_U8_NUMS / 8) 13 + #define EIOINTC_IRQS_U64_NUMS (EIOINTC_IRQS / 64) 17 14 /* map to ipnum per 32 irqs */ 18 15 #define EIOINTC_IRQS_NODETYPE_COUNT 16 19 16 ··· 61 64 uint32_t status; 62 65 63 66 /* hardware state */ 64 - union nodetype { 65 - u64 reg_u64[EIOINTC_IRQS_NODETYPE_COUNT / 4]; 66 - u32 reg_u32[EIOINTC_IRQS_NODETYPE_COUNT / 2]; 67 - u16 reg_u16[EIOINTC_IRQS_NODETYPE_COUNT]; 68 - u8 reg_u8[EIOINTC_IRQS_NODETYPE_COUNT * 2]; 69 - } nodetype; 67 + u64 nodetype[EIOINTC_IRQS_NODETYPE_COUNT / 4]; 70 68 71 69 /* one bit shows the state of one irq */ 72 - union bounce { 73 - u64 reg_u64[EIOINTC_IRQS_U64_NUMS]; 74 - u32 reg_u32[EIOINTC_IRQS_U32_NUMS]; 75 - u16 reg_u16[EIOINTC_IRQS_U16_NUMS]; 76 - u8 reg_u8[EIOINTC_IRQS_U8_NUMS]; 77 - } bounce; 78 - 79 - union isr { 80 - u64 reg_u64[EIOINTC_IRQS_U64_NUMS]; 81 - u32 reg_u32[EIOINTC_IRQS_U32_NUMS]; 82 - u16 reg_u16[EIOINTC_IRQS_U16_NUMS]; 83 - u8 reg_u8[EIOINTC_IRQS_U8_NUMS]; 84 - } isr; 85 - union coreisr { 86 - u64 reg_u64[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U64_NUMS]; 87 - u32 reg_u32[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U32_NUMS]; 88 - u16 reg_u16[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U16_NUMS]; 89 - u8 reg_u8[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U8_NUMS]; 90 - } coreisr; 91 - union enable { 92 - u64 reg_u64[EIOINTC_IRQS_U64_NUMS]; 93 - u32 reg_u32[EIOINTC_IRQS_U32_NUMS]; 94 - u16 reg_u16[EIOINTC_IRQS_U16_NUMS]; 95 - u8 reg_u8[EIOINTC_IRQS_U8_NUMS]; 96 - } enable; 70 + u64 bounce[EIOINTC_IRQS_U64_NUMS]; 71 + u64 isr[EIOINTC_IRQS_U64_NUMS]; 72 + u64 coreisr[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U64_NUMS]; 73 + u64 enable[EIOINTC_IRQS_U64_NUMS]; 97 74 98 75 /* use one byte to config ipmap for 32 irqs at once */ 99 - union ipmap { 100 - u64 reg_u64; 101 - u32 reg_u32[EIOINTC_IRQS_U32_NUMS / 4]; 102 - u16 reg_u16[EIOINTC_IRQS_U16_NUMS / 4]; 103 - u8 reg_u8[EIOINTC_IRQS_U8_NUMS / 4]; 104 - } ipmap; 76 + u64 ipmap; 105 77 /* use one byte to config coremap for one irq */ 106 - union coremap { 107 - u64 reg_u64[EIOINTC_IRQS / 8]; 108 - u32 reg_u32[EIOINTC_IRQS / 4]; 109 - u16 reg_u16[EIOINTC_IRQS / 2]; 110 - u8 reg_u8[EIOINTC_IRQS]; 111 - } coremap; 78 + u64 coremap[EIOINTC_IRQS / 8]; 112 79 113 80 DECLARE_BITMAP(sw_coreisr[EIOINTC_ROUTE_MAX_VCPUS][LOONGSON_IP_NUM], EIOINTC_IRQS); 114 81 uint8_t sw_coremap[EIOINTC_IRQS];
+8
arch/loongarch/include/asm/kvm_host.h
··· 126 126 struct kvm_phyid_map *phyid_map; 127 127 /* Enabled PV features */ 128 128 unsigned long pv_features; 129 + /* Supported KVM features */ 130 + unsigned long kvm_features; 129 131 130 132 s64 time_offset; 131 133 struct kvm_context __percpu *vmcs; ··· 293 291 static inline int kvm_get_pmu_num(struct kvm_vcpu_arch *arch) 294 292 { 295 293 return (arch->cpucfg[6] & CPUCFG6_PMNUM) >> CPUCFG6_PMNUM_SHIFT; 294 + } 295 + 296 + /* Check whether KVM support this feature (VMM may disable it) */ 297 + static inline bool kvm_vm_support(struct kvm_arch *arch, int feature) 298 + { 299 + return !!(arch->kvm_features & BIT_ULL(feature)); 296 300 } 297 301 298 302 bool kvm_arch_pmi_in_guest(struct kvm_vcpu *vcpu);
+1
arch/loongarch/include/asm/kvm_vcpu.h
··· 15 15 #define CPU_PMU (_ULCAST_(1) << 10) 16 16 #define CPU_TIMER (_ULCAST_(1) << 11) 17 17 #define CPU_IPI (_ULCAST_(1) << 12) 18 + #define CPU_AVEC (_ULCAST_(1) << 14) 18 19 19 20 /* Controlled by 0x52 guest exception VIP aligned to estat bit 5~12 */ 20 21 #define CPU_IP0 (_ULCAST_(1))
+2
arch/loongarch/include/asm/loongarch.h
··· 511 511 #define CSR_GCFG_GPERF_SHIFT 24 512 512 #define CSR_GCFG_GPERF_WIDTH 3 513 513 #define CSR_GCFG_GPERF (_ULCAST_(0x7) << CSR_GCFG_GPERF_SHIFT) 514 + #define CSR_GCFG_GPMP_SHIFT 23 515 + #define CSR_GCFG_GPMP (_ULCAST_(0x1) << CSR_GCFG_GPMP_SHIFT) 514 516 #define CSR_GCFG_GCI_SHIFT 20 515 517 #define CSR_GCFG_GCI_WIDTH 2 516 518 #define CSR_GCFG_GCI (_ULCAST_(0x3) << CSR_GCFG_GCI_SHIFT)
+1
arch/loongarch/include/uapi/asm/kvm.h
··· 104 104 #define KVM_LOONGARCH_VM_FEAT_PV_IPI 6 105 105 #define KVM_LOONGARCH_VM_FEAT_PV_STEALTIME 7 106 106 #define KVM_LOONGARCH_VM_FEAT_PTW 8 107 + #define KVM_LOONGARCH_VM_FEAT_MSGINT 9 107 108 108 109 /* Device Control API on vcpu fd */ 109 110 #define KVM_LOONGARCH_VCPU_CPUCFG 0
+40 -40
arch/loongarch/kvm/intc/eiointc.c
··· 13 13 struct kvm_vcpu *vcpu; 14 14 15 15 for (irq = 0; irq < EIOINTC_IRQS; irq++) { 16 - ipnum = s->ipmap.reg_u8[irq / 32]; 16 + ipnum = (s->ipmap >> (irq / 32 * 8)) & 0xff; 17 17 if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) { 18 18 ipnum = count_trailing_zeros(ipnum); 19 19 ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0; 20 20 } 21 21 22 - cpuid = s->coremap.reg_u8[irq]; 22 + cpuid = ((u8 *)s->coremap)[irq]; 23 23 vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid); 24 24 if (!vcpu) 25 25 continue; 26 26 27 27 cpu = vcpu->vcpu_id; 28 - if (test_bit(irq, (unsigned long *)s->coreisr.reg_u32[cpu])) 28 + if (test_bit(irq, (unsigned long *)s->coreisr[cpu])) 29 29 __set_bit(irq, s->sw_coreisr[cpu][ipnum]); 30 30 else 31 31 __clear_bit(irq, s->sw_coreisr[cpu][ipnum]); ··· 38 38 struct kvm_vcpu *vcpu; 39 39 struct kvm_interrupt vcpu_irq; 40 40 41 - ipnum = s->ipmap.reg_u8[irq / 32]; 41 + ipnum = (s->ipmap >> (irq / 32 * 8)) & 0xff; 42 42 if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) { 43 43 ipnum = count_trailing_zeros(ipnum); 44 44 ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0; ··· 53 53 54 54 if (level) { 55 55 /* if not enable return false */ 56 - if (!test_bit(irq, (unsigned long *)s->enable.reg_u32)) 56 + if (!test_bit(irq, (unsigned long *)s->enable)) 57 57 return; 58 - __set_bit(irq, (unsigned long *)s->coreisr.reg_u32[cpu]); 58 + __set_bit(irq, (unsigned long *)s->coreisr[cpu]); 59 59 found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS); 60 60 __set_bit(irq, s->sw_coreisr[cpu][ipnum]); 61 61 } else { 62 - __clear_bit(irq, (unsigned long *)s->coreisr.reg_u32[cpu]); 62 + __clear_bit(irq, (unsigned long *)s->coreisr[cpu]); 63 63 __clear_bit(irq, s->sw_coreisr[cpu][ipnum]); 64 64 found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS); 65 65 } ··· 94 94 if (s->sw_coremap[irq + i] == cpu) 95 95 continue; 96 96 97 - if (notify && test_bit(irq + i, (unsigned long *)s->isr.reg_u8)) { 97 + if (notify && test_bit(irq + i, (unsigned long *)s->isr)) { 98 98 /* lower irq at old cpu and raise irq at new cpu */ 99 99 eiointc_update_irq(s, irq + i, 0); 100 100 s->sw_coremap[irq + i] = cpu; ··· 108 108 void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level) 109 109 { 110 110 unsigned long flags; 111 - unsigned long *isr = (unsigned long *)s->isr.reg_u8; 111 + unsigned long *isr = (unsigned long *)s->isr; 112 112 113 113 spin_lock_irqsave(&s->lock, flags); 114 114 level ? __set_bit(irq, isr) : __clear_bit(irq, isr); ··· 127 127 switch (offset) { 128 128 case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: 129 129 index = (offset - EIOINTC_NODETYPE_START) >> 3; 130 - data = s->nodetype.reg_u64[index]; 130 + data = s->nodetype[index]; 131 131 break; 132 132 case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: 133 133 index = (offset - EIOINTC_IPMAP_START) >> 3; 134 - data = s->ipmap.reg_u64; 134 + data = s->ipmap; 135 135 break; 136 136 case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: 137 137 index = (offset - EIOINTC_ENABLE_START) >> 3; 138 - data = s->enable.reg_u64[index]; 138 + data = s->enable[index]; 139 139 break; 140 140 case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: 141 141 index = (offset - EIOINTC_BOUNCE_START) >> 3; 142 - data = s->bounce.reg_u64[index]; 142 + data = s->bounce[index]; 143 143 break; 144 144 case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: 145 145 index = (offset - EIOINTC_COREISR_START) >> 3; 146 - data = s->coreisr.reg_u64[vcpu->vcpu_id][index]; 146 + data = s->coreisr[vcpu->vcpu_id][index]; 147 147 break; 148 148 case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: 149 149 index = (offset - EIOINTC_COREMAP_START) >> 3; 150 - data = s->coremap.reg_u64[index]; 150 + data = s->coremap[index]; 151 151 break; 152 152 default: 153 153 ret = -EINVAL; ··· 223 223 switch (offset) { 224 224 case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: 225 225 index = (offset - EIOINTC_NODETYPE_START) >> 3; 226 - old = s->nodetype.reg_u64[index]; 227 - s->nodetype.reg_u64[index] = (old & ~mask) | data; 226 + old = s->nodetype[index]; 227 + s->nodetype[index] = (old & ~mask) | data; 228 228 break; 229 229 case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: 230 230 /* 231 231 * ipmap cannot be set at runtime, can be set only at the beginning 232 232 * of irqchip driver, need not update upper irq level 233 233 */ 234 - old = s->ipmap.reg_u64; 235 - s->ipmap.reg_u64 = (old & ~mask) | data; 234 + old = s->ipmap; 235 + s->ipmap = (old & ~mask) | data; 236 236 break; 237 237 case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: 238 238 index = (offset - EIOINTC_ENABLE_START) >> 3; 239 - old = s->enable.reg_u64[index]; 240 - s->enable.reg_u64[index] = (old & ~mask) | data; 239 + old = s->enable[index]; 240 + s->enable[index] = (old & ~mask) | data; 241 241 /* 242 242 * 1: enable irq. 243 243 * update irq when isr is set. 244 244 */ 245 - data = s->enable.reg_u64[index] & ~old & s->isr.reg_u64[index]; 245 + data = s->enable[index] & ~old & s->isr[index]; 246 246 while (data) { 247 247 irq = __ffs(data); 248 248 eiointc_update_irq(s, irq + index * 64, 1); ··· 252 252 * 0: disable irq. 253 253 * update irq when isr is set. 254 254 */ 255 - data = ~s->enable.reg_u64[index] & old & s->isr.reg_u64[index]; 255 + data = ~s->enable[index] & old & s->isr[index]; 256 256 while (data) { 257 257 irq = __ffs(data); 258 258 eiointc_update_irq(s, irq + index * 64, 0); ··· 262 262 case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: 263 263 /* do not emulate hw bounced irq routing */ 264 264 index = (offset - EIOINTC_BOUNCE_START) >> 3; 265 - old = s->bounce.reg_u64[index]; 266 - s->bounce.reg_u64[index] = (old & ~mask) | data; 265 + old = s->bounce[index]; 266 + s->bounce[index] = (old & ~mask) | data; 267 267 break; 268 268 case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: 269 269 index = (offset - EIOINTC_COREISR_START) >> 3; 270 270 /* use attrs to get current cpu index */ 271 271 cpu = vcpu->vcpu_id; 272 - old = s->coreisr.reg_u64[cpu][index]; 272 + old = s->coreisr[cpu][index]; 273 273 /* write 1 to clear interrupt */ 274 - s->coreisr.reg_u64[cpu][index] = old & ~data; 274 + s->coreisr[cpu][index] = old & ~data; 275 275 data &= old; 276 276 while (data) { 277 277 irq = __ffs(data); ··· 281 281 break; 282 282 case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: 283 283 index = (offset - EIOINTC_COREMAP_START) >> 3; 284 - old = s->coremap.reg_u64[index]; 285 - s->coremap.reg_u64[index] = (old & ~mask) | data; 286 - data = s->coremap.reg_u64[index]; 284 + old = s->coremap[index]; 285 + s->coremap[index] = (old & ~mask) | data; 286 + data = s->coremap[index]; 287 287 eiointc_update_sw_coremap(s, index * 8, data, sizeof(data), true); 288 288 break; 289 289 default: ··· 451 451 break; 452 452 case KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED: 453 453 eiointc_set_sw_coreisr(s); 454 - for (i = 0; i < (EIOINTC_IRQS / 4); i++) { 455 - start_irq = i * 4; 454 + for (i = 0; i < (EIOINTC_IRQS / 8); i++) { 455 + start_irq = i * 8; 456 456 eiointc_update_sw_coremap(s, start_irq, 457 - s->coremap.reg_u32[i], sizeof(u32), false); 457 + s->coremap[i], sizeof(u64), false); 458 458 } 459 459 break; 460 460 default: ··· 481 481 switch (addr) { 482 482 case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: 483 483 offset = (addr - EIOINTC_NODETYPE_START) / 4; 484 - p = &s->nodetype.reg_u32[offset]; 484 + p = s->nodetype + offset * 4; 485 485 break; 486 486 case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: 487 487 offset = (addr - EIOINTC_IPMAP_START) / 4; 488 - p = &s->ipmap.reg_u32[offset]; 488 + p = &s->ipmap + offset * 4; 489 489 break; 490 490 case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: 491 491 offset = (addr - EIOINTC_ENABLE_START) / 4; 492 - p = &s->enable.reg_u32[offset]; 492 + p = s->enable + offset * 4; 493 493 break; 494 494 case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: 495 495 offset = (addr - EIOINTC_BOUNCE_START) / 4; 496 - p = &s->bounce.reg_u32[offset]; 496 + p = s->bounce + offset * 4; 497 497 break; 498 498 case EIOINTC_ISR_START ... EIOINTC_ISR_END: 499 499 offset = (addr - EIOINTC_ISR_START) / 4; 500 - p = &s->isr.reg_u32[offset]; 500 + p = s->isr + offset * 4; 501 501 break; 502 502 case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: 503 503 if (cpu >= s->num_cpu) 504 504 return -EINVAL; 505 505 506 506 offset = (addr - EIOINTC_COREISR_START) / 4; 507 - p = &s->coreisr.reg_u32[cpu][offset]; 507 + p = s->coreisr[cpu] + offset * 4; 508 508 break; 509 509 case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: 510 510 offset = (addr - EIOINTC_COREMAP_START) / 4; 511 - p = &s->coremap.reg_u32[offset]; 511 + p = s->coremap + offset * 4; 512 512 break; 513 513 default: 514 514 kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr);
+13 -2
arch/loongarch/kvm/interrupt.c
··· 21 21 [INT_HWI5] = CPU_IP5, 22 22 [INT_HWI6] = CPU_IP6, 23 23 [INT_HWI7] = CPU_IP7, 24 + [INT_AVEC] = CPU_AVEC, 24 25 }; 25 26 26 27 static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority) ··· 31 30 clear_bit(priority, &vcpu->arch.irq_pending); 32 31 if (priority < EXCCODE_INT_NUM) 33 32 irq = priority_to_irq[priority]; 33 + 34 + if (cpu_has_msgint && (priority == INT_AVEC)) { 35 + set_gcsr_estat(irq); 36 + return 1; 37 + } 34 38 35 39 switch (priority) { 36 40 case INT_TI: ··· 64 58 if (priority < EXCCODE_INT_NUM) 65 59 irq = priority_to_irq[priority]; 66 60 61 + if (cpu_has_msgint && (priority == INT_AVEC)) { 62 + clear_gcsr_estat(irq); 63 + return 1; 64 + } 65 + 67 66 switch (priority) { 68 67 case INT_TI: 69 68 case INT_IPI: ··· 94 83 unsigned long *pending = &vcpu->arch.irq_pending; 95 84 unsigned long *pending_clr = &vcpu->arch.irq_clear; 96 85 97 - for_each_set_bit(priority, pending_clr, INT_IPI + 1) 86 + for_each_set_bit(priority, pending_clr, EXCCODE_INT_NUM) 98 87 kvm_irq_clear(vcpu, priority); 99 88 100 - for_each_set_bit(priority, pending, INT_IPI + 1) 89 + for_each_set_bit(priority, pending, EXCCODE_INT_NUM) 101 90 kvm_irq_deliver(vcpu, priority); 102 91 } 103 92
+17 -2
arch/loongarch/kvm/vcpu.c
··· 659 659 *v = GENMASK(31, 0); 660 660 return 0; 661 661 case LOONGARCH_CPUCFG1: 662 - /* CPUCFG1_MSGINT is not supported by KVM */ 663 - *v = GENMASK(25, 0); 662 + *v = GENMASK(26, 0); 664 663 return 0; 665 664 case LOONGARCH_CPUCFG2: 666 665 /* CPUCFG2 features unconditionally supported by KVM */ ··· 727 728 return -EINVAL; 728 729 729 730 switch (id) { 731 + case LOONGARCH_CPUCFG1: 732 + if ((val & CPUCFG1_MSGINT) && !cpu_has_msgint) 733 + return -EINVAL; 734 + return 0; 730 735 case LOONGARCH_CPUCFG2: 731 736 if (!(val & CPUCFG2_LLFTP)) 732 737 /* Guests must have a constant timer */ ··· 1660 1657 kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2); 1661 1658 kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3); 1662 1659 kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_LLBCTL); 1660 + if (cpu_has_msgint) { 1661 + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ISR0); 1662 + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ISR1); 1663 + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ISR2); 1664 + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ISR3); 1665 + } 1663 1666 1664 1667 /* Restore Root.GINTC from unused Guest.GINTC register */ 1665 1668 write_csr_gintc(csr->csrs[LOONGARCH_CSR_GINTC]); ··· 1755 1746 kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN1); 1756 1747 kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2); 1757 1748 kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3); 1749 + if (cpu_has_msgint) { 1750 + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ISR0); 1751 + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ISR1); 1752 + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ISR2); 1753 + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ISR3); 1754 + } 1758 1755 1759 1756 vcpu->arch.aux_inuse |= KVM_LARCH_SWCSR_LATEST; 1760 1757
+29 -15
arch/loongarch/kvm/vm.c
··· 6 6 #include <linux/kvm_host.h> 7 7 #include <asm/kvm_mmu.h> 8 8 #include <asm/kvm_vcpu.h> 9 + #include <asm/kvm_csr.h> 9 10 #include <asm/kvm_eiointc.h> 10 11 #include <asm/kvm_pch_pic.h> 11 12 ··· 24 23 .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE + 25 24 sizeof(kvm_vm_stats_desc), 26 25 }; 26 + 27 + static void kvm_vm_init_features(struct kvm *kvm) 28 + { 29 + unsigned long val; 30 + 31 + val = read_csr_gcfg(); 32 + if (val & CSR_GCFG_GPMP) 33 + kvm->arch.kvm_features |= BIT(KVM_LOONGARCH_VM_FEAT_PMU); 34 + 35 + /* Enable all PV features by default */ 36 + kvm->arch.pv_features = BIT(KVM_FEATURE_IPI); 37 + kvm->arch.kvm_features = BIT(KVM_LOONGARCH_VM_FEAT_PV_IPI); 38 + if (kvm_pvtime_supported()) { 39 + kvm->arch.pv_features |= BIT(KVM_FEATURE_STEAL_TIME); 40 + kvm->arch.kvm_features |= BIT(KVM_LOONGARCH_VM_FEAT_PV_STEALTIME); 41 + } 42 + } 27 43 28 44 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) 29 45 { ··· 60 42 spin_lock_init(&kvm->arch.phyid_map_lock); 61 43 62 44 kvm_init_vmcs(kvm); 63 - 64 - /* Enable all PV features by default */ 65 - kvm->arch.pv_features = BIT(KVM_FEATURE_IPI); 66 - if (kvm_pvtime_supported()) 67 - kvm->arch.pv_features |= BIT(KVM_FEATURE_STEAL_TIME); 45 + kvm_vm_init_features(kvm); 68 46 69 47 /* 70 48 * cpu_vabits means user address space only (a half of total). ··· 150 136 if (cpu_has_lbt_mips) 151 137 return 0; 152 138 return -ENXIO; 153 - case KVM_LOONGARCH_VM_FEAT_PMU: 154 - if (cpu_has_pmp) 155 - return 0; 156 - return -ENXIO; 157 - case KVM_LOONGARCH_VM_FEAT_PV_IPI: 158 - return 0; 159 - case KVM_LOONGARCH_VM_FEAT_PV_STEALTIME: 160 - if (kvm_pvtime_supported()) 161 - return 0; 162 - return -ENXIO; 163 139 case KVM_LOONGARCH_VM_FEAT_PTW: 164 140 if (cpu_has_ptw) 141 + return 0; 142 + return -ENXIO; 143 + case KVM_LOONGARCH_VM_FEAT_MSGINT: 144 + if (cpu_has_msgint) 145 + return 0; 146 + return -ENXIO; 147 + case KVM_LOONGARCH_VM_FEAT_PMU: 148 + case KVM_LOONGARCH_VM_FEAT_PV_IPI: 149 + case KVM_LOONGARCH_VM_FEAT_PV_STEALTIME: 150 + if (kvm_vm_support(&kvm->arch, attr->attr)) 165 151 return 0; 166 152 return -ENXIO; 167 153 default:
+1
tools/testing/selftests/kvm/Makefile.kvm
··· 212 212 TEST_GEN_PROGS_riscv += rseq_test 213 213 TEST_GEN_PROGS_riscv += steal_time 214 214 215 + TEST_GEN_PROGS_loongarch = arch_timer 215 216 TEST_GEN_PROGS_loongarch += coalesced_io_test 216 217 TEST_GEN_PROGS_loongarch += demand_paging_test 217 218 TEST_GEN_PROGS_loongarch += dirty_log_perf_test
+85
tools/testing/selftests/kvm/include/loongarch/arch_timer.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * LoongArch Constant Timer specific interface 4 + */ 5 + #ifndef SELFTEST_KVM_ARCH_TIMER_H 6 + #define SELFTEST_KVM_ARCH_TIMER_H 7 + 8 + #include "processor.h" 9 + 10 + /* LoongArch timer frequency is constant 100MHZ */ 11 + #define TIMER_FREQ (100UL << 20) 12 + #define msec_to_cycles(msec) (TIMER_FREQ * (unsigned long)(msec) / 1000) 13 + #define usec_to_cycles(usec) (TIMER_FREQ * (unsigned long)(usec) / 1000000) 14 + #define cycles_to_usec(cycles) ((unsigned long)(cycles) * 1000000 / TIMER_FREQ) 15 + 16 + static inline unsigned long timer_get_cycles(void) 17 + { 18 + unsigned long val = 0; 19 + 20 + __asm__ __volatile__( 21 + "rdtime.d %0, $zero\n\t" 22 + : "=r"(val) 23 + : 24 + ); 25 + 26 + return val; 27 + } 28 + 29 + static inline unsigned long timer_get_cfg(void) 30 + { 31 + return csr_read(LOONGARCH_CSR_TCFG); 32 + } 33 + 34 + static inline unsigned long timer_get_val(void) 35 + { 36 + return csr_read(LOONGARCH_CSR_TVAL); 37 + } 38 + 39 + static inline void disable_timer(void) 40 + { 41 + csr_write(0, LOONGARCH_CSR_TCFG); 42 + } 43 + 44 + static inline void timer_irq_enable(void) 45 + { 46 + unsigned long val; 47 + 48 + val = csr_read(LOONGARCH_CSR_ECFG); 49 + val |= ECFGF_TIMER; 50 + csr_write(val, LOONGARCH_CSR_ECFG); 51 + } 52 + 53 + static inline void timer_irq_disable(void) 54 + { 55 + unsigned long val; 56 + 57 + val = csr_read(LOONGARCH_CSR_ECFG); 58 + val &= ~ECFGF_TIMER; 59 + csr_write(val, LOONGARCH_CSR_ECFG); 60 + } 61 + 62 + static inline void timer_set_next_cmp_ms(unsigned int msec, bool period) 63 + { 64 + unsigned long val; 65 + 66 + val = msec_to_cycles(msec) & CSR_TCFG_VAL; 67 + val |= CSR_TCFG_EN; 68 + if (period) 69 + val |= CSR_TCFG_PERIOD; 70 + csr_write(val, LOONGARCH_CSR_TCFG); 71 + } 72 + 73 + static inline void __delay(uint64_t cycles) 74 + { 75 + uint64_t start = timer_get_cycles(); 76 + 77 + while ((timer_get_cycles() - start) < cycles) 78 + cpu_relax(); 79 + } 80 + 81 + static inline void udelay(unsigned long usec) 82 + { 83 + __delay(usec_to_cycles(usec)); 84 + } 85 + #endif /* SELFTEST_KVM_ARCH_TIMER_H */
+80 -1
tools/testing/selftests/kvm/include/loongarch/processor.h
··· 83 83 #define LOONGARCH_CSR_PRMD 0x1 84 84 #define LOONGARCH_CSR_EUEN 0x2 85 85 #define LOONGARCH_CSR_ECFG 0x4 86 + #define ECFGB_TIMER 11 87 + #define ECFGF_TIMER (BIT_ULL(ECFGB_TIMER)) 86 88 #define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ 89 + #define CSR_ESTAT_EXC_SHIFT 16 90 + #define CSR_ESTAT_EXC_WIDTH 6 91 + #define CSR_ESTAT_EXC (0x3f << CSR_ESTAT_EXC_SHIFT) 92 + #define EXCCODE_INT 0 /* Interrupt */ 93 + #define INT_TI 11 /* Timer interrupt*/ 87 94 #define LOONGARCH_CSR_ERA 0x6 /* ERA */ 88 95 #define LOONGARCH_CSR_BADV 0x7 /* Bad virtual address */ 89 96 #define LOONGARCH_CSR_EENTRY 0xc ··· 113 106 #define LOONGARCH_CSR_KS1 0x31 114 107 #define LOONGARCH_CSR_TMID 0x40 115 108 #define LOONGARCH_CSR_TCFG 0x41 109 + #define CSR_TCFG_VAL (BIT_ULL(48) - BIT_ULL(2)) 110 + #define CSR_TCFG_PERIOD_SHIFT 1 111 + #define CSR_TCFG_PERIOD (0x1UL << CSR_TCFG_PERIOD_SHIFT) 112 + #define CSR_TCFG_EN (0x1UL) 113 + #define LOONGARCH_CSR_TVAL 0x42 114 + #define LOONGARCH_CSR_TINTCLR 0x44 /* Timer interrupt clear */ 115 + #define CSR_TINTCLR_TI_SHIFT 0 116 + #define CSR_TINTCLR_TI (1 << CSR_TINTCLR_TI_SHIFT) 116 117 /* TLB refill exception entry */ 117 118 #define LOONGARCH_CSR_TLBRENTRY 0x88 118 119 #define LOONGARCH_CSR_TLBRSAVE 0x8b 119 120 #define LOONGARCH_CSR_TLBREHI 0x8e 120 121 #define CSR_TLBREHI_PS_SHIFT 0 121 122 #define CSR_TLBREHI_PS (0x3fUL << CSR_TLBREHI_PS_SHIFT) 123 + 124 + #define csr_read(csr) \ 125 + ({ \ 126 + register unsigned long __v; \ 127 + __asm__ __volatile__( \ 128 + "csrrd %[val], %[reg]\n\t" \ 129 + : [val] "=r" (__v) \ 130 + : [reg] "i" (csr) \ 131 + : "memory"); \ 132 + __v; \ 133 + }) 134 + 135 + #define csr_write(v, csr) \ 136 + ({ \ 137 + register unsigned long __v = v; \ 138 + __asm__ __volatile__ ( \ 139 + "csrwr %[val], %[reg]\n\t" \ 140 + : [val] "+r" (__v) \ 141 + : [reg] "i" (csr) \ 142 + : "memory"); \ 143 + __v; \ 144 + }) 122 145 123 146 #define EXREGS_GPRS (32) 124 147 ··· 161 124 unsigned long pc; 162 125 unsigned long estat; 163 126 unsigned long badv; 127 + unsigned long prmd; 164 128 }; 165 129 166 130 #define PC_OFFSET_EXREGS offsetof(struct ex_regs, pc) 167 131 #define ESTAT_OFFSET_EXREGS offsetof(struct ex_regs, estat) 168 132 #define BADV_OFFSET_EXREGS offsetof(struct ex_regs, badv) 133 + #define PRMD_OFFSET_EXREGS offsetof(struct ex_regs, prmd) 169 134 #define EXREGS_SIZE sizeof(struct ex_regs) 170 135 136 + #define VECTOR_NUM 64 137 + 138 + typedef void(*handler_fn)(struct ex_regs *); 139 + 140 + struct handlers { 141 + handler_fn exception_handlers[VECTOR_NUM]; 142 + }; 143 + 144 + void vm_init_descriptor_tables(struct kvm_vm *vm); 145 + void vm_install_exception_handler(struct kvm_vm *vm, int vector, handler_fn handler); 146 + 147 + static inline void cpu_relax(void) 148 + { 149 + asm volatile("nop" ::: "memory"); 150 + } 151 + 152 + static inline void local_irq_enable(void) 153 + { 154 + unsigned int flags = CSR_CRMD_IE; 155 + register unsigned int mask asm("$t0") = CSR_CRMD_IE; 156 + 157 + __asm__ __volatile__( 158 + "csrxchg %[val], %[mask], %[reg]\n\t" 159 + : [val] "+r" (flags) 160 + : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) 161 + : "memory"); 162 + } 163 + 164 + static inline void local_irq_disable(void) 165 + { 166 + unsigned int flags = 0; 167 + register unsigned int mask asm("$t0") = CSR_CRMD_IE; 168 + 169 + __asm__ __volatile__( 170 + "csrxchg %[val], %[mask], %[reg]\n\t" 171 + : [val] "+r" (flags) 172 + : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) 173 + : "memory"); 174 + } 171 175 #else 172 176 #define PC_OFFSET_EXREGS ((EXREGS_GPRS + 0) * 8) 173 177 #define ESTAT_OFFSET_EXREGS ((EXREGS_GPRS + 1) * 8) 174 178 #define BADV_OFFSET_EXREGS ((EXREGS_GPRS + 2) * 8) 175 - #define EXREGS_SIZE ((EXREGS_GPRS + 3) * 8) 179 + #define PRMD_OFFSET_EXREGS ((EXREGS_GPRS + 3) * 8) 180 + #define EXREGS_SIZE ((EXREGS_GPRS + 4) * 8) 176 181 #endif 177 182 178 183 #endif /* SELFTEST_KVM_PROCESSOR_H */
+6
tools/testing/selftests/kvm/lib/loongarch/exception.S
··· 51 51 st.d t0, sp, ESTAT_OFFSET_EXREGS 52 52 csrrd t0, LOONGARCH_CSR_BADV 53 53 st.d t0, sp, BADV_OFFSET_EXREGS 54 + csrrd t0, LOONGARCH_CSR_PRMD 55 + st.d t0, sp, PRMD_OFFSET_EXREGS 54 56 55 57 or a0, sp, zero 56 58 bl route_exception 59 + ld.d t0, sp, PC_OFFSET_EXREGS 60 + csrwr t0, LOONGARCH_CSR_ERA 61 + ld.d t0, sp, PRMD_OFFSET_EXREGS 62 + csrwr t0, LOONGARCH_CSR_PRMD 57 63 restore_gprs sp 58 64 csrrd sp, LOONGARCH_CSR_KS0 59 65 ertn
+45 -2
tools/testing/selftests/kvm/lib/loongarch/processor.c
··· 3 3 #include <assert.h> 4 4 #include <linux/compiler.h> 5 5 6 + #include <asm/kvm.h> 6 7 #include "kvm_util.h" 7 8 #include "processor.h" 8 9 #include "ucall_common.h" ··· 12 11 #define LOONGARCH_GUEST_STACK_VADDR_MIN 0x200000 13 12 14 13 static vm_paddr_t invalid_pgtable[4]; 14 + static vm_vaddr_t exception_handlers; 15 15 16 16 static uint64_t virt_pte_index(struct kvm_vm *vm, vm_vaddr_t gva, int level) 17 17 { ··· 185 183 186 184 void route_exception(struct ex_regs *regs) 187 185 { 186 + int vector; 188 187 unsigned long pc, estat, badv; 188 + struct handlers *handlers; 189 + 190 + handlers = (struct handlers *)exception_handlers; 191 + vector = (regs->estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT; 192 + if (handlers && handlers->exception_handlers[vector]) 193 + return handlers->exception_handlers[vector](regs); 189 194 190 195 pc = regs->pc; 191 196 badv = regs->badv; 192 197 estat = regs->estat; 193 198 ucall(UCALL_UNHANDLED, 3, pc, estat, badv); 194 199 while (1) ; 200 + } 201 + 202 + void vm_init_descriptor_tables(struct kvm_vm *vm) 203 + { 204 + void *addr; 205 + 206 + vm->handlers = __vm_vaddr_alloc(vm, sizeof(struct handlers), 207 + LOONGARCH_GUEST_STACK_VADDR_MIN, MEM_REGION_DATA); 208 + 209 + addr = addr_gva2hva(vm, vm->handlers); 210 + memset(addr, 0, vm->page_size); 211 + exception_handlers = vm->handlers; 212 + sync_global_to_guest(vm, exception_handlers); 213 + } 214 + 215 + void vm_install_exception_handler(struct kvm_vm *vm, int vector, handler_fn handler) 216 + { 217 + struct handlers *handlers = addr_gva2hva(vm, vm->handlers); 218 + 219 + assert(vector < VECTOR_NUM); 220 + handlers->exception_handlers[vector] = handler; 221 + } 222 + 223 + uint32_t guest_get_vcpuid(void) 224 + { 225 + return csr_read(LOONGARCH_CSR_CPUID); 195 226 } 196 227 197 228 void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) ··· 244 209 va_end(ap); 245 210 246 211 vcpu_regs_set(vcpu, &regs); 212 + } 213 + 214 + static void loongarch_set_reg(struct kvm_vcpu *vcpu, uint64_t id, uint64_t val) 215 + { 216 + __vcpu_set_reg(vcpu, id, val); 247 217 } 248 218 249 219 static void loongarch_get_csr(struct kvm_vcpu *vcpu, uint64_t id, void *addr) ··· 282 242 TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode); 283 243 } 284 244 285 - /* user mode and page enable mode */ 286 - val = PLV_USER | CSR_CRMD_PG; 245 + /* kernel mode and page enable mode */ 246 + val = PLV_KERN | CSR_CRMD_PG; 287 247 loongarch_set_csr(vcpu, LOONGARCH_CSR_CRMD, val); 288 248 loongarch_set_csr(vcpu, LOONGARCH_CSR_PRMD, val); 289 249 loongarch_set_csr(vcpu, LOONGARCH_CSR_EUEN, 1); ··· 291 251 loongarch_set_csr(vcpu, LOONGARCH_CSR_TCFG, 0); 292 252 loongarch_set_csr(vcpu, LOONGARCH_CSR_ASID, 1); 293 253 254 + /* time count start from 0 */ 294 255 val = 0; 256 + loongarch_set_reg(vcpu, KVM_REG_LOONGARCH_COUNTER, val); 257 + 295 258 width = vm->page_shift - 3; 296 259 297 260 switch (vm->pgtable_levels) {
+200
tools/testing/selftests/kvm/loongarch/arch_timer.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * The test validates periodic/one-shot constant timer IRQ using 4 + * CSR.TCFG and CSR.TVAL registers. 5 + */ 6 + #include "arch_timer.h" 7 + #include "kvm_util.h" 8 + #include "processor.h" 9 + #include "timer_test.h" 10 + #include "ucall_common.h" 11 + 12 + static void do_idle(void) 13 + { 14 + unsigned int intid; 15 + unsigned long estat; 16 + 17 + __asm__ __volatile__("idle 0" : : : "memory"); 18 + 19 + estat = csr_read(LOONGARCH_CSR_ESTAT); 20 + intid = !!(estat & BIT(INT_TI)); 21 + 22 + /* Make sure pending timer IRQ arrived */ 23 + GUEST_ASSERT_EQ(intid, 1); 24 + csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR); 25 + } 26 + 27 + static void guest_irq_handler(struct ex_regs *regs) 28 + { 29 + unsigned int intid; 30 + uint32_t cpu = guest_get_vcpuid(); 31 + uint64_t xcnt, val, cfg, xcnt_diff_us; 32 + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; 33 + 34 + intid = !!(regs->estat & BIT(INT_TI)); 35 + 36 + /* Make sure we are dealing with the correct timer IRQ */ 37 + GUEST_ASSERT_EQ(intid, 1); 38 + 39 + cfg = timer_get_cfg(); 40 + if (cfg & CSR_TCFG_PERIOD) { 41 + WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter - 1); 42 + if (shared_data->nr_iter == 0) 43 + disable_timer(); 44 + csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR); 45 + return; 46 + } 47 + 48 + /* 49 + * On real machine, value of LOONGARCH_CSR_TVAL is BIT_ULL(48) - 1 50 + * On virtual machine, its value counts down from BIT_ULL(48) - 1 51 + */ 52 + val = timer_get_val(); 53 + xcnt = timer_get_cycles(); 54 + xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt); 55 + 56 + /* Basic 'timer condition met' check */ 57 + __GUEST_ASSERT(val > cfg, 58 + "val = 0x%lx, cfg = 0x%lx, xcnt_diff_us = 0x%lx", 59 + val, cfg, xcnt_diff_us); 60 + 61 + csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR); 62 + WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1); 63 + } 64 + 65 + static void guest_test_period_timer(uint32_t cpu) 66 + { 67 + uint32_t irq_iter, config_iter; 68 + uint64_t us; 69 + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; 70 + 71 + shared_data->nr_iter = test_args.nr_iter; 72 + shared_data->xcnt = timer_get_cycles(); 73 + us = msecs_to_usecs(test_args.timer_period_ms) + test_args.timer_err_margin_us; 74 + timer_set_next_cmp_ms(test_args.timer_period_ms, true); 75 + 76 + for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { 77 + /* Setup a timeout for the interrupt to arrive */ 78 + udelay(us); 79 + } 80 + 81 + irq_iter = READ_ONCE(shared_data->nr_iter); 82 + __GUEST_ASSERT(irq_iter == 0, 83 + "irq_iter = 0x%x.\n" 84 + " Guest period timer interrupt was not triggered within the specified\n" 85 + " interval, try to increase the error margin by [-e] option.\n", 86 + irq_iter); 87 + } 88 + 89 + static void guest_test_oneshot_timer(uint32_t cpu) 90 + { 91 + uint32_t irq_iter, config_iter; 92 + uint64_t us; 93 + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; 94 + 95 + shared_data->nr_iter = 0; 96 + shared_data->guest_stage = 0; 97 + us = msecs_to_usecs(test_args.timer_period_ms) + test_args.timer_err_margin_us; 98 + for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { 99 + shared_data->xcnt = timer_get_cycles(); 100 + 101 + /* Setup the next interrupt */ 102 + timer_set_next_cmp_ms(test_args.timer_period_ms, false); 103 + /* Setup a timeout for the interrupt to arrive */ 104 + udelay(us); 105 + 106 + irq_iter = READ_ONCE(shared_data->nr_iter); 107 + __GUEST_ASSERT(config_iter + 1 == irq_iter, 108 + "config_iter + 1 = 0x%x, irq_iter = 0x%x.\n" 109 + " Guest timer interrupt was not triggered within the specified\n" 110 + " interval, try to increase the error margin by [-e] option.\n", 111 + config_iter + 1, irq_iter); 112 + } 113 + } 114 + 115 + static void guest_test_emulate_timer(uint32_t cpu) 116 + { 117 + uint32_t config_iter; 118 + uint64_t xcnt_diff_us, us; 119 + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; 120 + 121 + local_irq_disable(); 122 + shared_data->nr_iter = 0; 123 + us = msecs_to_usecs(test_args.timer_period_ms); 124 + for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { 125 + shared_data->xcnt = timer_get_cycles(); 126 + 127 + /* Setup the next interrupt */ 128 + timer_set_next_cmp_ms(test_args.timer_period_ms, false); 129 + do_idle(); 130 + 131 + xcnt_diff_us = cycles_to_usec(timer_get_cycles() - shared_data->xcnt); 132 + __GUEST_ASSERT(xcnt_diff_us >= us, 133 + "xcnt_diff_us = 0x%lx, us = 0x%lx.\n", 134 + xcnt_diff_us, us); 135 + } 136 + local_irq_enable(); 137 + } 138 + 139 + static void guest_time_count_test(uint32_t cpu) 140 + { 141 + uint32_t config_iter; 142 + unsigned long start, end, prev, us; 143 + 144 + /* Assuming that test case starts to run in 1 second */ 145 + start = timer_get_cycles(); 146 + us = msec_to_cycles(1000); 147 + __GUEST_ASSERT(start <= us, 148 + "start = 0x%lx, us = 0x%lx.\n", 149 + start, us); 150 + 151 + us = msec_to_cycles(test_args.timer_period_ms); 152 + for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { 153 + start = timer_get_cycles(); 154 + end = start + us; 155 + /* test time count growing up always */ 156 + while (start < end) { 157 + prev = start; 158 + start = timer_get_cycles(); 159 + __GUEST_ASSERT(prev <= start, 160 + "prev = 0x%lx, start = 0x%lx.\n", 161 + prev, start); 162 + } 163 + } 164 + } 165 + 166 + static void guest_code(void) 167 + { 168 + uint32_t cpu = guest_get_vcpuid(); 169 + 170 + /* must run at first */ 171 + guest_time_count_test(cpu); 172 + 173 + timer_irq_enable(); 174 + local_irq_enable(); 175 + guest_test_period_timer(cpu); 176 + guest_test_oneshot_timer(cpu); 177 + guest_test_emulate_timer(cpu); 178 + 179 + GUEST_DONE(); 180 + } 181 + 182 + struct kvm_vm *test_vm_create(void) 183 + { 184 + struct kvm_vm *vm; 185 + int nr_vcpus = test_args.nr_vcpus; 186 + 187 + vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); 188 + vm_init_descriptor_tables(vm); 189 + vm_install_exception_handler(vm, EXCCODE_INT, guest_irq_handler); 190 + 191 + /* Make all the test's cmdline args visible to the guest */ 192 + sync_global_to_guest(vm, test_args); 193 + 194 + return vm; 195 + } 196 + 197 + void test_vm_cleanup(struct kvm_vm *vm) 198 + { 199 + kvm_vm_free(vm); 200 + }