Merge pull request #2711 from lubinszARM:pr_mmio

PiperOrigin-RevId: 315812219
This commit is contained in:
gVisor bot
2020-06-10 18:51:41 -07:00
8 changed files with 81 additions and 16 deletions
@@ -53,3 +53,10 @@ func dieArchSetup(c *vCPU, context *arch.SignalContext64, guestRegs *userRegs) {
context.Rbx = uint64(uintptr(unsafe.Pointer(c)))
context.Rip = uint64(dieTrampolineAddr)
}
// getHypercallID returns hypercall ID.
//
//go:nosplit
func getHypercallID(addr uintptr) int {
return _KVM_HYPERCALL_MAX
}
@@ -61,3 +61,16 @@ func dieArchSetup(c *vCPU, context *arch.SignalContext64, guestRegs *userRegs) {
func bluepillArchFpContext(context unsafe.Pointer) *arch.FpsimdContext {
return &((*arch.SignalContext64)(context).Fpsimd64)
}
// getHypercallID returns hypercall ID.
//
// On Arm64, the MMIO address should be 64-bit aligned.
//
//go:nosplit
func getHypercallID(addr uintptr) int {
if addr < arm64HypercallMMIOBase || addr >= (arm64HypercallMMIOBase+_AARCH64_HYPERCALL_MMIO_SIZE) {
return _KVM_HYPERCALL_MAX
} else {
return int(((addr) - arm64HypercallMMIOBase) >> 3)
}
}
+26 -13
View File
@@ -58,6 +58,24 @@ func bluepillArchContext(context unsafe.Pointer) *arch.SignalContext64 {
return &((*arch.UContext64)(context).MContext)
}
// bluepillHandleHlt is reponsible for handling VM-Exit.
//
//go:nosplit
func bluepillGuestExit(c *vCPU, context unsafe.Pointer) {
// Copy out registers.
bluepillArchExit(c, bluepillArchContext(context))
// Return to the vCPUReady state; notify any waiters.
user := atomic.LoadUint32(&c.state) & vCPUUser
switch atomic.SwapUint32(&c.state, user) {
case user | vCPUGuest: // Expected case.
case user | vCPUGuest | vCPUWaiter:
c.notify()
default:
throw("invalid state")
}
}
// bluepillHandler is called from the signal stub.
//
// The world may be stopped while this is executing, and it executes on the
@@ -159,25 +177,20 @@ func bluepillHandler(context unsafe.Pointer) {
c.die(bluepillArchContext(context), "debug")
return
case _KVM_EXIT_HLT:
// Copy out registers.
bluepillArchExit(c, bluepillArchContext(context))
// Return to the vCPUReady state; notify any waiters.
user := atomic.LoadUint32(&c.state) & vCPUUser
switch atomic.SwapUint32(&c.state, user) {
case user | vCPUGuest: // Expected case.
case user | vCPUGuest | vCPUWaiter:
c.notify()
default:
throw("invalid state")
}
bluepillGuestExit(c, context)
return
case _KVM_EXIT_MMIO:
physical := uintptr(c.runData.data[0])
if getHypercallID(physical) == _KVM_HYPERCALL_VMEXIT {
bluepillGuestExit(c, context)
return
}
// Increment the fault count.
atomic.AddUint32(&c.faults, 1)
// For MMIO, the physical address is the first data item.
physical := uintptr(c.runData.data[0])
physical = uintptr(c.runData.data[0])
virtual, ok := handleBluepillFault(c.machine, physical, physicalRegions, _KVM_MEM_FLAGS_NONE)
if !ok {
c.die(bluepillArchContext(context), "invalid physical address")
+3
View File
@@ -26,6 +26,9 @@ type kvmOneReg struct {
addr uint64
}
// arm64HypercallMMIOBase is MMIO base address used to dispatch hypercalls.
var arm64HypercallMMIOBase uintptr
const KVM_NR_SPSR = 5
type userFpsimdState struct {
+10
View File
@@ -71,3 +71,13 @@ const (
_KVM_MEM_READONLY = uint32(1) << 1
_KVM_MEM_FLAGS_NONE = 0
)
// KVM hypercall list.
// Canonical list of hypercalls supported.
const (
// On amd64, it uses 'HLT' to leave the guest.
// Unlike amd64, arm64 can only uses mmio_exit/psci to leave the guest.
// _KVM_HYPERCALL_VMEXIT is only used on Arm64 for now.
_KVM_HYPERCALL_VMEXIT int = iota
_KVM_HYPERCALL_MAX
)
@@ -131,3 +131,10 @@ const (
_ESR_SEGV_PEMERR_L2 = 0xe
_ESR_SEGV_PEMERR_L3 = 0xf
)
// Arm64: MMIO base address used to dispatch hypercalls.
const (
// on Arm64, the MMIO address must be 64-bit aligned.
// Currently, we only need 1 hypercall: hypercall_vmexit.
_AARCH64_HYPERCALL_MMIO_SIZE = 1 << 3
)
@@ -159,6 +159,10 @@ func (c *vCPU) initArchState() error {
return err
}
// Use the address of the exception vector table as
// the MMIO address base.
arm64HypercallMMIOBase = toLocation
data = ring0.PsrDefaultSet | ring0.KernelFlagsSet
reg.id = _KVM_ARM64_REGS_PSTATE
if err := c.setOneRegister(&reg); err != nil {
+11 -3
View File
@@ -362,9 +362,17 @@ mmio_exit:
MOVD R1, CPU_LAZY_VFP(RSV_REG)
VFP_DISABLE
// MMIO_EXIT.
MOVD $0, R9
MOVD R0, 0xffff000000001000(R9)
// Trigger MMIO_EXIT/_KVM_HYPERCALL_VMEXIT.
//
// To keep it simple, I used the address of exception table as the
// MMIO base address, so that I can trigger a MMIO-EXIT by forcibly writing
// a read-only space.
// Also, the length is engough to match a sufficient number of hypercall ID.
// Then, in host user space, I can calculate this address to find out
// which hypercall.
MRS VBAR_EL1, R9
MOVD R0, 0x0(R9)
RET
// HaltAndResume halts execution and point the pointer to the resume function.