aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mvp/mvpkm/worldswitch.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mvp/mvpkm/worldswitch.h')
-rw-r--r--arch/arm/mvp/mvpkm/worldswitch.h381
1 files changed, 381 insertions, 0 deletions
diff --git a/arch/arm/mvp/mvpkm/worldswitch.h b/arch/arm/mvp/mvpkm/worldswitch.h
new file mode 100644
index 0000000..785f2cd
--- /dev/null
+++ b/arch/arm/mvp/mvpkm/worldswitch.h
@@ -0,0 +1,381 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Definition of the world switch page
+ *
+ * Two pages are maintained to facilitate switching from the vmx to
+ * the monitor - a data and code page. The data page contains:
+ * - the necessary information about itself (its MPN, KVA, ...)
+ * - the saved register file of the other world (including some cp15 regs)
+ * - some information about the monitor's address space (the monVA member)
+ * that needed right after the w.s before any communication channels
+ * could have been established
+ * - a world switch related L2 table of the monitor -- this could be
+ * elsewhere.
+ *
+ * The code page contains:
+ * - the actual switching code that saves/restores the registers
+ *
+ * The world switch data page is mapped into the user, kernel, and the monitor
+ * address spaces. In case of the user and monitor spaces the global variable
+ * wsp points to the world switch page (in the vmx and the monitor
+ * respectively). The kernel address of the world switch page is saved on
+ * the page itself: wspHKVA.
+ *
+ * The kernel virtual address for both code and data pages is mapped into
+ * the monitor's space temporarily at the time of the actual switch. This is
+ * needed to provide a stable code and data page while the L1 page table
+ * base is changing. As the monitor does not need the world switch data page
+ * at its KVA for its internal operation, that map is severed right after the
+ * switching to the monitor and re-established before switching back.
+ */
+#ifndef _WORLDSWITCH_H
+#define _WORLDSWITCH_H
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+/**
+ * @brief Area for saving the monitor/kernel register files.
+ *
+ * The order of the registers in this structure was designed to
+ * facilitate the organization of the switching code. For example
+ * all Supervisor Mode registers are grouped together allowing the
+ * @code
+ * switch to svc,
+ * stm old svc regs
+ * ldm new svc regs
+ * @endcode
+ * code to work using a single base register for both the store and
+ * load area.
+ */
+#define MAX_REGISTER_SAVE_SIZE 464
+
+#ifndef __ASSEMBLER__
+typedef struct {
+ uint32 kSPSR_svc;
+ uint32 kr13_svc;
+ uint32 kr14_svc;
+ uint32 mSPSR_svc;
+ uint32 mR13_svc;
+ uint32 mR14_svc;
+
+ uint32 kSPSR_abt;
+ uint32 kr13_abt;
+ uint32 kr14_abt;
+ uint32 mSPSR_abt;
+ uint32 mR13_abt;
+ uint32 mR14_abt;
+
+ uint32 kSPSR_und;
+ uint32 kr13_und;
+ uint32 kr14_und;
+ uint32 mSPSR_und;
+ uint32 mR13_und;
+ uint32 mR14_und;
+
+ uint32 kSPSR_irq;
+ uint32 kr13_irq;
+ uint32 kr14_irq;
+ uint32 mSPSR_irq;
+ uint32 mR13_irq;
+ uint32 mR14_irq;
+
+ uint32 kSPSR_fiq;
+ uint32 kr8_fiq;
+ uint32 kr9_fiq;
+ uint32 kr10_fiq;
+ uint32 kr11_fiq;
+ uint32 kr12_fiq;
+ uint32 kr13_fiq;
+ uint32 kr14_fiq;
+ uint32 mSPSR_fiq;
+ uint32 mR8_fiq;
+ uint32 mR9_fiq;
+ uint32 mR10_fiq;
+ uint32 mR11_fiq;
+ uint32 mR12_fiq;
+ uint32 mR13_fiq;
+ uint32 mR14_fiq;
+} BankedRegisterSave;
+
+/**
+ * @brief Registers for monitor execution context.
+ */
+typedef struct {
+ uint32 mCPSR;
+ uint32 mR1;
+ uint32 mR4;
+ uint32 mR5;
+ uint32 mR6;
+ uint32 mR7;
+ uint32 mR8;
+ uint32 mR9;
+ uint32 mR10;
+ uint32 mR11;
+ uint32 mSP;
+ uint32 mLR; // =mPC
+} MonitorRegisterSave;
+
+/**
+ * @brief LPV monitor register save/restore.
+ */
+typedef struct {
+ uint32 kR2; // =kCPSR
+ uint32 kR4;
+ uint32 kR5;
+ uint32 kR6;
+ uint32 kR7;
+ uint32 kR8;
+ uint32 kR9;
+ uint32 kR10;
+ uint32 kR11;
+ uint32 kR13;
+ uint32 kR14; // =kPC
+
+ BankedRegisterSave bankedRegs;
+
+ uint32 kCtrlReg;
+ uint32 kTTBR0;
+ uint32 kDACR;
+ uint32 kASID;
+ uint32 kTIDUserRW;
+ uint32 kTIDUserRO;
+ uint32 kTIDPrivRW;
+ uint32 kCSSELR;
+ uint32 kPMNCIntEn;
+ uint32 kPMNCCCCNT;
+ uint32 kPMNCOvFlag;
+ uint32 kOpEnabled;
+ uint32 mCtrlReg;
+ uint32 mTTBR0;
+ uint32 mASID;
+ uint32 mTIDUserRW;
+ uint32 mTIDUserRO;
+ uint32 mTIDPrivRW;
+ uint32 mCSSELR;
+
+ MonitorRegisterSave monRegs;
+} RegisterSaveLPV;
+
+/**
+ * @brief VE monitor register save/restore.
+ */
+typedef struct {
+ uint32 mHTTBR;
+
+ uint32 kR3;
+ uint32 kR4;
+ uint32 kR5;
+ uint32 kR6;
+ uint32 kR7;
+ uint32 kR8;
+ uint32 kR9;
+ uint32 kR10;
+ uint32 kR11;
+ uint32 kR12;
+ uint32 kCPSR;
+ uint32 kRet;
+
+ BankedRegisterSave bankedRegs;
+
+ uint32 kCSSELR;
+ uint32 kCtrlReg;
+ uint32 kTTBR0[2];
+ uint32 kTTBR1[2];
+ uint32 kTTBRC;
+ uint32 kDACR;
+ uint32 kDFSR;
+ uint32 kIFSR;
+ uint32 kAuxDFSR;
+ uint32 kAuxIFSR;
+ uint32 kDFAR;
+ uint32 kIFAR;
+ uint32 kPAR[2];
+ uint32 kPRRR;
+ uint32 kNMRR;
+ uint32 kASID;
+ uint32 kTIDUserRW;
+ uint32 kTIDUserRO;
+ uint32 kTIDPrivRW;
+ uint32 mCSSELR;
+ uint32 mCtrlReg;
+ uint32 mTTBR0[2];
+ uint32 mTTBR1[2];
+ uint32 mTTBRC;
+ uint32 mDACR;
+ uint32 mDFSR;
+ uint32 mIFSR;
+ uint32 mAuxDFSR;
+ uint32 mAuxIFSR;
+ uint32 mDFAR;
+ uint32 mIFAR;
+ uint32 mPAR[2];
+ uint32 mPRRR;
+ uint32 mNMRR;
+ uint32 mASID;
+ uint32 mTIDUserRW;
+ uint32 mTIDUserRO;
+ uint32 mTIDPrivRW;
+
+ uint32 mHCR;
+ uint32 mHDCR;
+ uint32 mHCPTR;
+ uint32 mHSTR;
+ uint32 mVTTBR[2];
+ uint32 mVTCR;
+
+ MonitorRegisterSave monRegs;
+} RegisterSaveVE;
+
+typedef union {
+ unsigned char reserve_space[MAX_REGISTER_SAVE_SIZE];
+ RegisterSaveLPV lpv;
+ RegisterSaveVE ve;
+} RegisterSave;
+
+MY_ASSERTS(REGSAVE,
+ ASSERT_ON_COMPILE(sizeof(RegisterSave) == MAX_REGISTER_SAVE_SIZE);
+)
+
+/**
+ * @brief Area for saving the monitor/kernel VFP state.
+ */
+typedef struct VFPSave {
+ uint32 fpexc, fpscr, fpinst, fpinst2, cpacr, fpexc_;
+
+ uint64 fpregs[32]; // Hardware requires that this must be 8-byte (64-bit)
+ // aligned, however the SaveVFP/LoadVFP code does not
+ // align its pointer before accessing so we don't have
+ // an 'aligned(8)' attribute here. However, the
+ // alignment is checked via asserts in SetupMonitor()
+ // where it initializes the contents.
+
+ // So if the preceding uint32's are changed and fpregs[]
+ // is no longer 8-byte aligned, the assert will fire.
+ // Then the uint32's will have to be fixed AND THE CODE
+ // in SaveVFP/LoadVFP will have to be CHANGED EQUALLY to
+ // compensate, as simply padding the uint32's (or
+ // sticking an aligned(8) attribute here) will leave the
+ // this structure mismatched with the code.
+
+} VFPSave __attribute__((aligned(8)));
+ // Keep the aligned(8) attribute here though so the
+ // VFPSave structures begin on an 8-byte boundary.
+
+typedef struct WorldSwitchPage WorldSwitchPage;
+typedef void (SwitchToMonitor)(RegisterSave *regSave);
+typedef void (SwitchToUser)(RegisterSave *regSaveEnd);
+
+#include "atomic.h"
+#include "monva_common.h"
+#include "mksck_shared.h"
+
+struct WorldSwitchPage {
+ uint32 mvpkmVersion; ///< The version number of mvpkm
+
+ HKVA wspHKVA; ///< host kernel virtual address of this page
+ ARM_L1D wspKVAL1D; ///< The l1D entry at the above location
+
+ SwitchToMonitor*switchToMonitor;///< entrypoint of the switching function
+ SwitchToUser *switchToUser; ///< ditto
+
+ MonVA monVA; ///< monitor virtual address space description
+ union {
+ ARM_L2D monAttribL2D; ///< {S,TEX,CB} attributes for monitor mappings (LPV)
+ ARM_MemAttrNormal memAttr; ///< Normal memory attributes for monitor (VE)
+ };
+
+ MonitorType monType; ///< the type of the monitor. Used by mvpkm
+ _Bool allowInts; ///< true: monitor runs with ints enabled as much as possible (normal)
+ ///< false: monitor runs with ints blocked as much as possible (debug)
+
+ struct {
+ uint64 switchedAt64; ///< approx time CP15 TSC was set to...
+ uint32 switchedAtTSC; ///< CP15 TSC value on entry from monitor
+ uint32 tscToRate64Mult; ///< multiplier to convert TSC_READ()s to our RATE64s
+ uint32 tscToRate64Shift; ///< shift to convert TSC_READ()s to our RATE64s
+ };
+
+ struct {
+ AtmUInt32 hostActions; ///< actions for monitor on instruction boundary
+ Mksck_VmId guestId; ///< vmId of the monitor page
+ };
+
+ struct { ///< Mksck attributes needed by Mksck_WspRelease()
+ uint32 critSecCount; ///< if >0 the monitor is in critical section
+ ///< and expects to regain control
+ _Bool isPageMapped[MKSCK_MAX_SHARES]; ///< host mksckPages known to the monitor
+ _Bool guestPageMapped;///< the guest Mksck page has been mapped in MVA space
+ uint32 isOpened; ///< bitfield indicating which mkscks
+ ///< are open on the guest's mksckPage.
+ /* Note that isOpened is per VM not per VCPU. Also note
+ * that this and other bitfields in the MksckPage structure
+ * limit the number of sockets to 32.
+ */
+ };
+
+#define WSP_PARAMS_SIZE 512
+ uint8 params_[WSP_PARAMS_SIZE]; ///< opaque worldswitch call parameters
+
+ RegisterSave regSave; ///< Save area for the worldswitch code below
+ VFPSave hostVFP; ///< Save areas for monitor/kernel VFP state
+ VFPSave monVFP;
+
+__attribute__((aligned(ARM_L2PT_COARSE_SIZE)))
+ ARM_L2D wspDoubleMap[ARM_L2PT_COARSE_ENTRIES]; ///< maps worldswitch page at its HKVA
+ uint8 secondHalfPadding[ARM_L2PT_COARSE_SIZE];
+};
+
+/*
+ * These asserts duplicate the assert at the beginning of SetL1L2esc.
+ */
+MY_ASSERTS(WSP,
+ ASSERT_ON_COMPILE(offsetof(struct WorldSwitchPage, wspDoubleMap) %
+ ARM_L2PT_COARSE_SIZE == 0);
+)
+
+extern void SaveVFP(VFPSave *);
+extern void LoadVFP(VFPSave *);
+
+#define SWITCH_VFP_TO_MONITOR \
+ do { \
+ SaveVFP(&wsp->hostVFP); \
+ LoadVFP(&wsp->monVFP); \
+ } while(0)
+
+#define SWITCH_VFP_TO_HOST \
+ do { \
+ SaveVFP(&wsp->monVFP); \
+ LoadVFP(&wsp->hostVFP); \
+ } while(0)
+
+#endif /// __ASSEMBLER__
+
+#define OFFSETOF_KR3_REGSAVE_VE_WSP 616
+
+#endif /// _WORLDSWITCH_H