Skip to content

Commit 89957c6

Browse files
author
Bin Lu
committed
Lazy-fpsimd support patch series#2: add fpsimd@Arm64 support to kvm module
Add fpsimd support to KVM module so that the test case "TestKernelFloatingPoint" can be passed on Arm64 platform. Signed-off-by: Bin Lu <[email protected]>
1 parent 4cb55a7 commit 89957c6

File tree

7 files changed

+83
-47
lines changed

7 files changed

+83
-47
lines changed

pkg/sentry/platform/kvm/bluepill_arm64.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ func bluepillArchExit(c *vCPU, context *arch.SignalContext64) {
5454
context.Pstate = regs.Pstate
5555
context.Pstate &^= uint64(ring0.UserFlagsClear)
5656
context.Pstate |= ring0.UserFlagsSet
57+
58+
lazyVfp := c.GetLazyVFP()
59+
if lazyVfp != 0 {
60+
fpsimd := fpsimdPtr((*byte)(c.floatingPointState))
61+
context.Fpsimd64.Fpsr = fpsimd.Fpsr
62+
context.Fpsimd64.Fpcr = fpsimd.Fpcr
63+
context.Fpsimd64.Vregs = fpsimd.Vregs
64+
}
5765
}
5866

5967
// KernelSyscall handles kernel syscalls.
@@ -64,6 +72,17 @@ func (c *vCPU) KernelSyscall() {
6472
if regs.Regs[8] != ^uint64(0) {
6573
regs.Pc -= 4 // Rewind.
6674
}
75+
76+
vfpEnable := ring0.CPACREL1()
77+
if vfpEnable != 0 {
78+
fpsimd := fpsimdPtr((*byte)(c.floatingPointState))
79+
fpcr := ring0.GetFPCR()
80+
fpsr := ring0.GetFPSR()
81+
fpsimd.Fpcr = uint32(fpcr)
82+
fpsimd.Fpsr = uint32(fpsr)
83+
ring0.SaveVRegs((*byte)(c.floatingPointState))
84+
}
85+
6786
ring0.Halt()
6887
}
6988

@@ -75,5 +94,16 @@ func (c *vCPU) KernelException(vector ring0.Vector) {
7594
if vector == ring0.Vector(bounce) {
7695
regs.Pc = 0
7796
}
97+
98+
vfpEnable := ring0.CPACREL1()
99+
if vfpEnable != 0 {
100+
fpsimd := fpsimdPtr((*byte)(c.floatingPointState))
101+
fpcr := ring0.GetFPCR()
102+
fpsr := ring0.GetFPSR()
103+
fpsimd.Fpcr = uint32(fpcr)
104+
fpsimd.Fpsr = uint32(fpsr)
105+
ring0.SaveVRegs((*byte)(c.floatingPointState))
106+
}
107+
78108
ring0.Halt()
79109
}

pkg/sentry/platform/kvm/bluepill_arm64_unsafe.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,26 @@
1717
package kvm
1818

1919
import (
20+
"unsafe"
21+
2022
"gvisor.dev/gvisor/pkg/sentry/arch"
2123
)
2224

25+
// fpsimdPtr returns a fpsimd64 for the given address.
26+
//
27+
//go:nosplit
28+
func fpsimdPtr(addr *byte) *arch.FpsimdContext {
29+
return (*arch.FpsimdContext)(unsafe.Pointer(addr))
30+
}
31+
2332
//go:nosplit
2433
func dieArchSetup(c *vCPU, context *arch.SignalContext64, guestRegs *userRegs) {
2534
// TODO(gvisor.dev/issue/1249): dieTrampoline supporting for Arm64.
2635
}
36+
37+
// bluepillArchFpContext returns the arch-specific fpsimd context.
38+
//
39+
//go:nosplit
40+
func bluepillArchFpContext(context unsafe.Pointer) *arch.FpsimdContext {
41+
return &((*arch.SignalContext64)(context).Fpsimd64)
42+
}

pkg/sentry/platform/kvm/kvm_const_arm64.go

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,31 @@ const (
1919
_KVM_GET_ONE_REG = 0x4010aeab
2020
_KVM_SET_ONE_REG = 0x4010aeac
2121

22-
_KVM_ARM_PREFERRED_TARGET = 0x8020aeaf
23-
_KVM_ARM_VCPU_INIT = 0x4020aeae
24-
_KVM_ARM64_REGS_PSTATE = 0x6030000000100042
25-
_KVM_ARM64_REGS_SP_EL1 = 0x6030000000100044
26-
_KVM_ARM64_REGS_R0 = 0x6030000000100000
27-
_KVM_ARM64_REGS_R1 = 0x6030000000100002
28-
_KVM_ARM64_REGS_R2 = 0x6030000000100004
29-
_KVM_ARM64_REGS_R3 = 0x6030000000100006
30-
_KVM_ARM64_REGS_R8 = 0x6030000000100010
31-
_KVM_ARM64_REGS_R18 = 0x6030000000100024
32-
_KVM_ARM64_REGS_PC = 0x6030000000100040
33-
_KVM_ARM64_REGS_MAIR_EL1 = 0x603000000013c510
34-
_KVM_ARM64_REGS_TCR_EL1 = 0x603000000013c102
35-
_KVM_ARM64_REGS_TTBR0_EL1 = 0x603000000013c100
36-
_KVM_ARM64_REGS_TTBR1_EL1 = 0x603000000013c101
37-
_KVM_ARM64_REGS_SCTLR_EL1 = 0x603000000013c080
38-
_KVM_ARM64_REGS_CPACR_EL1 = 0x603000000013c082
39-
_KVM_ARM64_REGS_VBAR_EL1 = 0x603000000013c600
22+
_KVM_ARM_TARGET_GENERIC_V8 = 5
23+
_KVM_ARM_PREFERRED_TARGET = 0x8020aeaf
24+
_KVM_ARM_VCPU_INIT = 0x4020aeae
25+
_KVM_ARM64_REGS_PSTATE = 0x6030000000100042
26+
_KVM_ARM64_REGS_SP_EL1 = 0x6030000000100044
27+
_KVM_ARM64_REGS_R0 = 0x6030000000100000
28+
_KVM_ARM64_REGS_R1 = 0x6030000000100002
29+
_KVM_ARM64_REGS_R2 = 0x6030000000100004
30+
_KVM_ARM64_REGS_R3 = 0x6030000000100006
31+
_KVM_ARM64_REGS_R8 = 0x6030000000100010
32+
_KVM_ARM64_REGS_R18 = 0x6030000000100024
33+
_KVM_ARM64_REGS_PC = 0x6030000000100040
34+
_KVM_ARM64_REGS_MAIR_EL1 = 0x603000000013c510
35+
_KVM_ARM64_REGS_TCR_EL1 = 0x603000000013c102
36+
_KVM_ARM64_REGS_TTBR0_EL1 = 0x603000000013c100
37+
_KVM_ARM64_REGS_TTBR1_EL1 = 0x603000000013c101
38+
_KVM_ARM64_REGS_SCTLR_EL1 = 0x603000000013c080
39+
_KVM_ARM64_REGS_CPACR_EL1 = 0x603000000013c082
40+
_KVM_ARM64_REGS_VBAR_EL1 = 0x603000000013c600
4041
)
4142

4243
// Arm64: Architectural Feature Access Control Register EL1.
4344
const (
44-
_FPEN_NOTRAP = 0x3
45-
_FPEN_SHIFT = 0x20
45+
_FPEN_NOTRAP = 3
46+
_FPEN_SHIFT = 20
4647
)
4748

4849
// Arm64: System Control Register EL1.

pkg/sentry/platform/kvm/machine_arm64.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ type vCPUArchState struct {
2828
//
2929
// This starts above fixedKernelPCID.
3030
PCIDs *pagetables.PCIDs
31+
32+
// floatingPointState is the floating point state buffer used in guest
33+
// to host transitions. See usage in bluepill_arm64.go.
34+
floatingPointState *arch.FloatingPointData
3135
}
3236

3337
const (

pkg/sentry/platform/kvm/machine_arm64_unsafe.go

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,6 @@ import (
2929
"gvisor.dev/gvisor/pkg/usermem"
3030
)
3131

32-
// setMemoryRegion initializes a region.
33-
//
34-
// This may be called from bluepillHandler, and therefore returns an errno
35-
// directly (instead of wrapping in an error) to avoid allocations.
36-
//
37-
//go:nosplit
38-
func (m *machine) setMemoryRegion(slot int, physical, length, virtual uintptr) syscall.Errno {
39-
userRegion := userMemoryRegion{
40-
slot: uint32(slot),
41-
flags: 0,
42-
guestPhysAddr: uint64(physical),
43-
memorySize: uint64(length),
44-
userspaceAddr: uint64(virtual),
45-
}
46-
47-
// Set the region.
48-
_, _, errno := syscall.RawSyscall(
49-
syscall.SYS_IOCTL,
50-
uintptr(m.fd),
51-
_KVM_SET_USER_MEMORY_REGION,
52-
uintptr(unsafe.Pointer(&userRegion)))
53-
return errno
54-
}
55-
5632
type kvmVcpuInit struct {
5733
target uint32
5834
features [7]uint32
@@ -147,6 +123,7 @@ func (c *vCPU) initArchState() error {
147123
reg.addr = uint64(reflect.ValueOf(&data).Pointer())
148124
regGet.addr = uint64(reflect.ValueOf(&dataGet).Pointer())
149125

126+
vcpuInit.target = _KVM_ARM_TARGET_GENERIC_V8
150127
vcpuInit.features[0] |= (1 << _KVM_ARM_VCPU_PSCI_0_2)
151128
if _, _, errno := syscall.RawSyscall(
152129
syscall.SYS_IOCTL,
@@ -158,7 +135,8 @@ func (c *vCPU) initArchState() error {
158135

159136
// cpacr_el1
160137
reg.id = _KVM_ARM64_REGS_CPACR_EL1
161-
data = (_FPEN_NOTRAP << _FPEN_SHIFT)
138+
// It is off by default, and it is turned on only when in use.
139+
data = 0 // Disable fpsimd.
162140
if err := c.setOneRegister(&reg); err != nil {
163141
return err
164142
}
@@ -250,6 +228,7 @@ func (c *vCPU) initArchState() error {
250228
return err
251229
}
252230

231+
c.floatingPointState = arch.NewFloatingPointData()
253232
return nil
254233
}
255234

pkg/sentry/platform/ring0/defs_arm64.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ func (c *CPU) SetAppAddr(value uintptr) {
124124
c.appAddr = value
125125
}
126126

127+
// GetLazyVFP returns the value of cpacr_el1.
128+
//go:nosplit
129+
func (c *CPU) GetLazyVFP() (value uintptr) {
130+
return c.lazyVFP
131+
}
132+
127133
// SwitchArchOpts are embedded in SwitchOpts.
128134
type SwitchArchOpts struct {
129135
// UserASID indicates that the application ASID to be used on switch,

pkg/sentry/platform/ring0/lib_arm64.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ package ring0
2020
func CPACREL1() (value uintptr)
2121

2222
// FPCR returns the value of FPCR register.
23-
func FPCR() (value uintptr)
23+
func GetFPCR() (value uintptr)
2424

2525
// SetFPCR writes the FPCR value.
2626
func SetFPCR(value uintptr)
2727

2828
// FPSR returns the value of FPSR register.
29-
func FPSR() (value uintptr)
29+
func GetFPSR() (value uintptr)
3030

3131
// SetFPSR writes the FPSR value.
3232
func SetFPSR(value uintptr)

0 commit comments

Comments
 (0)