History

MIPS: KVM: Expose FPU registers

Add KVM register numbers for the MIPS FPU registers, and implement access to them with the KVM_GET_ONE_REG / KVM_SET_ONE_REG ioctls when the FPU capability is enabled (exposed in a later patch) and present in the guest according to its Config1.FP bit. The registers are accessible in the current mode of the guest, with each sized access showing what the guest would see with an equivalent access, and like the architecture they may become UNPREDICTABLE if the FR mode is changed. When FR=0, odd doubles are inaccessible as they do not exist in that mode.

James Hogan committed 11 years ago

Commit 379245c1 parent 1c0cd663 files · +114 −11Browse files

Unified · Split

3 files
  1. Documentation/virtual/kvm/api.txt +16 −0
  2. arch/mips/include/uapi/asm/kvm.h +27 −10
  3. arch/mips/kvm/mips.c +71 −1
Documentation/virtual/kvm/api.txt+16−0
@@ -1979,6 +1979,10 @@ registers, find a list below: · 1978 unmodified lines
19791979 MIPS | KVM_REG_MIPS_COUNT_CTL | 64
19801980 MIPS | KVM_REG_MIPS_COUNT_RESUME | 64
19811981 MIPS | KVM_REG_MIPS_COUNT_HZ | 64
1982+ MIPS | KVM_REG_MIPS_FPR_32(0..31) | 32
1983+ MIPS | KVM_REG_MIPS_FPR_64(0..31) | 64
1984+ MIPS | KVM_REG_MIPS_FCR_IR | 32
1985+ MIPS | KVM_REG_MIPS_FCR_CSR | 32
19821986
19831987 ARM registers are mapped using the lower 32 bits. The upper 16 of that
19841988 is the register group type, or coprocessor number:
@@ -2032,6 +2036,18 @@ patterns depending on whether they're 32-bit or 64-bit registers: · 47 unmodified lines
20322036 MIPS KVM control registers (see above) have the following id bit patterns:
20332037 0x7030 0000 0002 <reg:16>
20342038
2039+MIPS FPU registers (see KVM_REG_MIPS_FPR_{32,64}() above) have the following
2040+id bit patterns depending on the size of the register being accessed. They are
2041+always accessed according to the current guest FPU mode (Status.FR and
2042+Config5.FRE), i.e. as the guest would see them, and they become unpredictable
2043+if the guest FPU mode is changed:
2044+ 0x7020 0000 0003 00 <0:3> <reg:5> (32-bit FPU registers)
2045+ 0x7030 0000 0003 00 <0:3> <reg:5> (64-bit FPU registers)
2046+
2047+MIPS FPU control registers (see KVM_REG_MIPS_FCR_{IR,CSR} above) have the
2048+following id bit patterns:
2049+ 0x7020 0000 0003 01 <0:3> <reg:5>
2050+
20352051
20362052 4.69 KVM_GET_ONE_REG
20372053
arch/mips/include/uapi/asm/kvm.h+27−10
@@ -36,18 +36,8 @@ struct kvm_regs { · 35 unmodified lines
3636
3737 /*
3838 * for KVM_GET_FPU and KVM_SET_FPU
39− *
40− * If Status[FR] is zero (32-bit FPU), the upper 32-bits of the FPRs
41− * are zero filled.
4239 */
4340 struct kvm_fpu {
44− __u64 fpr[32];
45− __u32 fir;
46− __u32 fccr;
47− __u32 fexr;
48− __u32 fenr;
49− __u32 fcsr;
50− __u32 pad;
5141 };
5242
5343
@@ -68,6 +58,8 @@ struct kvm_fpu { · 14 unmodified lines
6858 *
6959 * Register set = 2: KVM specific registers (see definitions below).
7060 *
61+ * Register set = 3: FPU registers (see definitions below).
62+ *
7163 * Other sets registers may be added in the future. Each set would
7264 * have its own identifier in bits[31..16].
7365 */
@@ -75,6 +67,7 @@ struct kvm_fpu { · 1 unmodified line
7567 #define KVM_REG_MIPS_GP (KVM_REG_MIPS | 0x0000000000000000ULL)
7668 #define KVM_REG_MIPS_CP0 (KVM_REG_MIPS | 0x0000000000010000ULL)
7769 #define KVM_REG_MIPS_KVM (KVM_REG_MIPS | 0x0000000000020000ULL)
70+#define KVM_REG_MIPS_FPU (KVM_REG_MIPS | 0x0000000000030000ULL)
7871
7972
8073 /*
@@ -154,6 +147,30 @@ struct kvm_fpu { · 73 unmodified lines
154147 #define KVM_REG_MIPS_COUNT_HZ (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 2)
155148
156149
150+/*
151+ * KVM_REG_MIPS_FPU - Floating Point registers.
152+ *
153+ * bits[15..8] - Register subset (see definitions below).
154+ * bits[7..5] - Must be zero.
155+ * bits[4..0] - Register number within register subset.
156+ */
157+
158+#define KVM_REG_MIPS_FPR (KVM_REG_MIPS_FPU | 0x0000000000000000ULL)
159+#define KVM_REG_MIPS_FCR (KVM_REG_MIPS_FPU | 0x0000000000000100ULL)
160+
161+/*
162+ * KVM_REG_MIPS_FPR - Floating point / Vector registers.
163+ */
164+#define KVM_REG_MIPS_FPR_32(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U32 | (n))
165+#define KVM_REG_MIPS_FPR_64(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U64 | (n))
166+
167+/*
168+ * KVM_REG_MIPS_FCR - Floating point control registers.
169+ */
170+#define KVM_REG_MIPS_FCR_IR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 0)
171+#define KVM_REG_MIPS_FCR_CSR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 31)
172+
173+
157174 /*
158175 * KVM MIPS specific structures and definitions
159176 *
arch/mips/kvm/mips.c+71−1
@@ -526,10 +526,13 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, · 525 unmodified lines
526526 const struct kvm_one_reg *reg)
527527 {
528528 struct mips_coproc *cop0 = vcpu->arch.cop0;
529+ struct mips_fpu_struct *fpu = &vcpu->arch.fpu;
529530 int ret;
530531 s64 v;
532+ unsigned int idx;
531533
532534 switch (reg->id) {
535+ /* General purpose registers */
533536 case KVM_REG_MIPS_R0 ... KVM_REG_MIPS_R31:
534537 v = (long)vcpu->arch.gprs[reg->id - KVM_REG_MIPS_R0];
535538 break;
@@ -543,6 +546,38 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, · 7 unmodified lines
543546 v = (long)vcpu->arch.pc;
544547 break;
545548
549+ /* Floating point registers */
550+ case KVM_REG_MIPS_FPR_32(0) ... KVM_REG_MIPS_FPR_32(31):
551+ if (!kvm_mips_guest_has_fpu(&vcpu->arch))
552+ return -EINVAL;
553+ idx = reg->id - KVM_REG_MIPS_FPR_32(0);
554+ /* Odd singles in top of even double when FR=0 */
555+ if (kvm_read_c0_guest_status(cop0) & ST0_FR)
556+ v = get_fpr32(&fpu->fpr[idx], 0);
557+ else
558+ v = get_fpr32(&fpu->fpr[idx & ~1], idx & 1);
559+ break;
560+ case KVM_REG_MIPS_FPR_64(0) ... KVM_REG_MIPS_FPR_64(31):
561+ if (!kvm_mips_guest_has_fpu(&vcpu->arch))
562+ return -EINVAL;
563+ idx = reg->id - KVM_REG_MIPS_FPR_64(0);
564+ /* Can't access odd doubles in FR=0 mode */
565+ if (idx & 1 && !(kvm_read_c0_guest_status(cop0) & ST0_FR))
566+ return -EINVAL;
567+ v = get_fpr64(&fpu->fpr[idx], 0);
568+ break;
569+ case KVM_REG_MIPS_FCR_IR:
570+ if (!kvm_mips_guest_has_fpu(&vcpu->arch))
571+ return -EINVAL;
572+ v = boot_cpu_data.fpu_id;
573+ break;
574+ case KVM_REG_MIPS_FCR_CSR:
575+ if (!kvm_mips_guest_has_fpu(&vcpu->arch))
576+ return -EINVAL;
577+ v = fpu->fcr31;
578+ break;
579+
580+ /* Co-processor 0 registers */
546581 case KVM_REG_MIPS_CP0_INDEX:
547582 v = (long)kvm_read_c0_guest_index(cop0);
548583 break;
@@ -636,7 +671,9 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, · 87 unmodified lines
636671 const struct kvm_one_reg *reg)
637672 {
638673 struct mips_coproc *cop0 = vcpu->arch.cop0;
639− u64 v;
674+ struct mips_fpu_struct *fpu = &vcpu->arch.fpu;
675+ s64 v;
676+ unsigned int idx;
640677
641678 if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) {
642679 u64 __user *uaddr64 = (u64 __user *)(long)reg->addr;
@@ -655,6 +692,7 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, · 12 unmodified lines
655692 }
656693
657694 switch (reg->id) {
695+ /* General purpose registers */
658696 case KVM_REG_MIPS_R0:
659697 /* Silently ignore requests to set $0 */
660698 break;
@@ -671,6 +709,38 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, · 10 unmodified lines
671709 vcpu->arch.pc = v;
672710 break;
673711
712+ /* Floating point registers */
713+ case KVM_REG_MIPS_FPR_32(0) ... KVM_REG_MIPS_FPR_32(31):
714+ if (!kvm_mips_guest_has_fpu(&vcpu->arch))
715+ return -EINVAL;
716+ idx = reg->id - KVM_REG_MIPS_FPR_32(0);
717+ /* Odd singles in top of even double when FR=0 */
718+ if (kvm_read_c0_guest_status(cop0) & ST0_FR)
719+ set_fpr32(&fpu->fpr[idx], 0, v);
720+ else
721+ set_fpr32(&fpu->fpr[idx & ~1], idx & 1, v);
722+ break;
723+ case KVM_REG_MIPS_FPR_64(0) ... KVM_REG_MIPS_FPR_64(31):
724+ if (!kvm_mips_guest_has_fpu(&vcpu->arch))
725+ return -EINVAL;
726+ idx = reg->id - KVM_REG_MIPS_FPR_64(0);
727+ /* Can't access odd doubles in FR=0 mode */
728+ if (idx & 1 && !(kvm_read_c0_guest_status(cop0) & ST0_FR))
729+ return -EINVAL;
730+ set_fpr64(&fpu->fpr[idx], 0, v);
731+ break;
732+ case KVM_REG_MIPS_FCR_IR:
733+ if (!kvm_mips_guest_has_fpu(&vcpu->arch))
734+ return -EINVAL;
735+ /* Read-only */
736+ break;
737+ case KVM_REG_MIPS_FCR_CSR:
738+ if (!kvm_mips_guest_has_fpu(&vcpu->arch))
739+ return -EINVAL;
740+ fpu->fcr31 = v;
741+ break;
742+
743+ /* Co-processor 0 registers */
674744 case KVM_REG_MIPS_CP0_INDEX:
675745 kvm_write_c0_guest_index(cop0, v);
676746 break;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t