mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Merge pull request #2711 from lubinszARM:pr_mmio
PiperOrigin-RevId: 315812219
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(®); err != nil {
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user