KVM
Classes | Macros | Typedefs | Enumerations | Functions | Variables
emulate-nested.c File Reference
#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_nested.h>
#include "hyp/include/hyp/adjust_pc.h"
#include "trace.h"
Include dependency graph for emulate-nested.c:

Go to the source code of this file.

Classes

struct  trap_bits
 
union  trap_config
 
struct  encoding_to_trap_config
 

Macros

#define MCB(id, ...)
 
#define CCC(id, fn)    [id - __COMPLEX_CONDITIONS__] = fn
 
#define TC_CGT_BITS   10
 
#define TC_FGT_BITS   4
 
#define TC_FGF_BITS   5
 
#define SR_RANGE_TRAP(sr_start, sr_end, trap_id)
 
#define SR_TRAP(sr, trap_id)   SR_RANGE_TRAP(sr, sr, trap_id)
 
#define SR_FGF(sr, g, b, p, f)
 
#define SR_FGT(sr, g, b, p)   SR_FGF(sr, g, b, p, __NO_FGF__)
 
#define sanitised_sys_reg(vcpu, reg)
 

Typedefs

typedef enum trap_behaviour(* complex_condition_check) (struct kvm_vcpu *)
 

Enumerations

enum  trap_behaviour { BEHAVE_HANDLE_LOCALLY = 0 , BEHAVE_FORWARD_READ = BIT(0) , BEHAVE_FORWARD_WRITE = BIT(1) , BEHAVE_FORWARD_ANY = BEHAVE_FORWARD_READ | BEHAVE_FORWARD_WRITE }
 
enum  cgt_group_id {
  __RESERVED__ , CGT_HCR_TID1 , CGT_HCR_TID2 , CGT_HCR_TID3 ,
  CGT_HCR_IMO , CGT_HCR_FMO , CGT_HCR_TIDCP , CGT_HCR_TACR ,
  CGT_HCR_TSW , CGT_HCR_TPC , CGT_HCR_TPU , CGT_HCR_TTLB ,
  CGT_HCR_TVM , CGT_HCR_TDZ , CGT_HCR_TRVM , CGT_HCR_TLOR ,
  CGT_HCR_TERR , CGT_HCR_APK , CGT_HCR_NV , CGT_HCR_NV_nNV2 ,
  CGT_HCR_NV1_nNV2 , CGT_HCR_AT , CGT_HCR_nFIEN , CGT_HCR_TID4 ,
  CGT_HCR_TICAB , CGT_HCR_TOCU , CGT_HCR_ENSCXT , CGT_HCR_TTLBIS ,
  CGT_HCR_TTLBOS , CGT_MDCR_TPMCR , CGT_MDCR_TPM , CGT_MDCR_TDE ,
  CGT_MDCR_TDA , CGT_MDCR_TDOSA , CGT_MDCR_TDRA , CGT_MDCR_E2PB ,
  CGT_MDCR_TPMS , CGT_MDCR_TTRF , CGT_MDCR_E2TB , CGT_MDCR_TDCC ,
  __MULTIPLE_CONTROL_BITS__ , CGT_HCR_IMO_FMO = __MULTIPLE_CONTROL_BITS__ , CGT_HCR_TID2_TID4 , CGT_HCR_TTLB_TTLBIS ,
  CGT_HCR_TTLB_TTLBOS , CGT_HCR_TVM_TRVM , CGT_HCR_TPU_TICAB , CGT_HCR_TPU_TOCU ,
  CGT_HCR_NV1_nNV2_ENSCXT , CGT_MDCR_TPM_TPMCR , CGT_MDCR_TDE_TDA , CGT_MDCR_TDE_TDOSA ,
  CGT_MDCR_TDE_TDRA , CGT_MDCR_TDCC_TDE_TDA , __COMPLEX_CONDITIONS__ , CGT_CNTHCTL_EL1PCTEN = __COMPLEX_CONDITIONS__ ,
  CGT_CNTHCTL_EL1PTEN , __NR_CGT_GROUP_IDS__
}
 
enum  fgt_group_id {
  __NO_FGT_GROUP__ , HFGxTR_GROUP , HDFGRTR_GROUP , HDFGWTR_GROUP ,
  HFGITR_GROUP , HAFGRTR_GROUP , __NR_FGT_GROUP_IDS__
}
 
enum  fg_filter_id { __NO_FGF__ , HCRX_FGTnXS , __NR_FG_FILTER_IDS__ }
 

Functions

static u64 get_sanitized_cnthctl (struct kvm_vcpu *vcpu)
 
static enum trap_behaviour check_cnthctl_el1pcten (struct kvm_vcpu *vcpu)
 
static enum trap_behaviour check_cnthctl_el1pten (struct kvm_vcpu *vcpu)
 
static DEFINE_XARRAY (sr_forward_xa)
 
static union trap_config get_trap_config (u32 sysreg)
 
static __init void print_nv_trap_error (const struct encoding_to_trap_config *tc, const char *type, int err)
 
int __init populate_nv_trap_config (void)
 
static enum trap_behaviour get_behaviour (struct kvm_vcpu *vcpu, const struct trap_bits *tb)
 
static enum trap_behaviour __compute_trap_behaviour (struct kvm_vcpu *vcpu, const enum cgt_group_id id, enum trap_behaviour b)
 
static enum trap_behaviour compute_trap_behaviour (struct kvm_vcpu *vcpu, const union trap_config tc)
 
static bool check_fgt_bit (u64 val, const union trap_config tc)
 
bool __check_nv_sr_forward (struct kvm_vcpu *vcpu)
 
static u64 kvm_check_illegal_exception_return (struct kvm_vcpu *vcpu, u64 spsr)
 
void kvm_emulate_nested_eret (struct kvm_vcpu *vcpu)
 
static void kvm_inject_el2_exception (struct kvm_vcpu *vcpu, u64 esr_el2, enum exception_type type)
 
static int kvm_inject_nested (struct kvm_vcpu *vcpu, u64 esr_el2, enum exception_type type)
 
int kvm_inject_nested_sync (struct kvm_vcpu *vcpu, u64 esr_el2)
 
int kvm_inject_nested_irq (struct kvm_vcpu *vcpu)
 

Variables

static const struct trap_bits coarse_trap_bits []
 
static enum cgt_group_idcoarse_control_combo []
 
static const complex_condition_check ccc []
 
static const struct encoding_to_trap_config encoding_to_cgt[] __initconst
 

Macro Definition Documentation

◆ CCC

#define CCC (   id,
  fn 
)     [id - __COMPLEX_CONDITIONS__] = fn

Definition at line 413 of file emulate-nested.c.

◆ MCB

#define MCB (   id,
  ... 
)
Value:
(const enum cgt_group_id[]){ \
__VA_ARGS__, __RESERVED__ \
}
cgt_group_id
@ __RESERVED__
@ __MULTIPLE_CONTROL_BITS__

Definition at line 350 of file emulate-nested.c.

◆ sanitised_sys_reg

#define sanitised_sys_reg (   vcpu,
  reg 
)
Value:
({ \
u64 __val; \
__val = __vcpu_sys_reg(vcpu, reg); \
__val &= ~__ ## reg ## _RES0; \
(__val); \
})

Definition at line 1900 of file emulate-nested.c.

◆ SR_FGF

#define SR_FGF (   sr,
  g,
  b,
  p,
 
)
Value:
{ \
.encoding = sr, \
.end = sr, \
.tc = { \
.fgt = g ## _GROUP, \
.bit = g ## _EL2_ ## b ## _SHIFT, \
.pol = p, \
.fgf = f, \
}, \
.line = __LINE__, \
}

Definition at line 1029 of file emulate-nested.c.

◆ SR_FGT

#define SR_FGT (   sr,
  g,
  b,
 
)    SR_FGF(sr, g, b, p, __NO_FGF__)

Definition at line 1042 of file emulate-nested.c.

◆ SR_RANGE_TRAP

#define SR_RANGE_TRAP (   sr_start,
  sr_end,
  trap_id 
)
Value:
{ \
.encoding = sr_start, \
.end = sr_end, \
.tc = { \
.cgt = trap_id, \
}, \
.line = __LINE__, \
}

Definition at line 457 of file emulate-nested.c.

◆ SR_TRAP

#define SR_TRAP (   sr,
  trap_id 
)    SR_RANGE_TRAP(sr, sr, trap_id)

Definition at line 467 of file emulate-nested.c.

◆ TC_CGT_BITS

#define TC_CGT_BITS   10

Definition at line 433 of file emulate-nested.c.

◆ TC_FGF_BITS

#define TC_FGF_BITS   5

Definition at line 435 of file emulate-nested.c.

◆ TC_FGT_BITS

#define TC_FGT_BITS   4

Definition at line 434 of file emulate-nested.c.

Typedef Documentation

◆ complex_condition_check

typedef enum trap_behaviour(* complex_condition_check) (struct kvm_vcpu *)

Definition at line 356 of file emulate-nested.c.

Enumeration Type Documentation

◆ cgt_group_id

Enumerator
__RESERVED__ 
CGT_HCR_TID1 
CGT_HCR_TID2 
CGT_HCR_TID3 
CGT_HCR_IMO 
CGT_HCR_FMO 
CGT_HCR_TIDCP 
CGT_HCR_TACR 
CGT_HCR_TSW 
CGT_HCR_TPC 
CGT_HCR_TPU 
CGT_HCR_TTLB 
CGT_HCR_TVM 
CGT_HCR_TDZ 
CGT_HCR_TRVM 
CGT_HCR_TLOR 
CGT_HCR_TERR 
CGT_HCR_APK 
CGT_HCR_NV 
CGT_HCR_NV_nNV2 
CGT_HCR_NV1_nNV2 
CGT_HCR_AT 
CGT_HCR_nFIEN 
CGT_HCR_TID4 
CGT_HCR_TICAB 
CGT_HCR_TOCU 
CGT_HCR_ENSCXT 
CGT_HCR_TTLBIS 
CGT_HCR_TTLBOS 
CGT_MDCR_TPMCR 
CGT_MDCR_TPM 
CGT_MDCR_TDE 
CGT_MDCR_TDA 
CGT_MDCR_TDOSA 
CGT_MDCR_TDRA 
CGT_MDCR_E2PB 
CGT_MDCR_TPMS 
CGT_MDCR_TTRF 
CGT_MDCR_E2TB 
CGT_MDCR_TDCC 
__MULTIPLE_CONTROL_BITS__ 
CGT_HCR_IMO_FMO 
CGT_HCR_TID2_TID4 
CGT_HCR_TTLB_TTLBIS 
CGT_HCR_TTLB_TTLBOS 
CGT_HCR_TVM_TRVM 
CGT_HCR_TPU_TICAB 
CGT_HCR_TPU_TOCU 
CGT_HCR_NV1_nNV2_ENSCXT 
CGT_MDCR_TPM_TPMCR 
CGT_MDCR_TDE_TDA 
CGT_MDCR_TDE_TDOSA 
CGT_MDCR_TDE_TDRA 
CGT_MDCR_TDCC_TDE_TDA 
__COMPLEX_CONDITIONS__ 
CGT_CNTHCTL_EL1PCTEN 
CGT_CNTHCTL_EL1PTEN 
__NR_CGT_GROUP_IDS__ 

Definition at line 32 of file emulate-nested.c.

32  {
33  /* Indicates no coarse trap control */
35 
36  /*
37  * The first batch of IDs denote coarse trapping that are used
38  * on their own instead of being part of a combination of
39  * trap controls.
40  */
58  CGT_HCR_NV,
61  CGT_HCR_AT,
69 
81 
82  /*
83  * Anything after this point is a combination of coarse trap
84  * controls, which must all be evaluated to decide what to do.
85  */
100 
101  /*
102  * Anything after this point requires a callback evaluating a
103  * complex trap condition. Ugly stuff.
104  */
108 
109  /* Must be last */
111 };
@ CGT_HCR_TTLBOS
@ CGT_HCR_TICAB
@ CGT_HCR_TID3
@ CGT_HCR_IMO_FMO
@ __COMPLEX_CONDITIONS__
@ CGT_HCR_TVM_TRVM
@ CGT_HCR_AT
@ CGT_MDCR_E2PB
@ CGT_HCR_TOCU
@ CGT_HCR_NV1_nNV2
@ CGT_MDCR_TDE
@ CGT_MDCR_TDCC_TDE_TDA
@ CGT_HCR_TPC
@ CGT_HCR_TID1
@ CGT_HCR_TPU
@ CGT_HCR_NV1_nNV2_ENSCXT
@ CGT_CNTHCTL_EL1PTEN
@ CGT_MDCR_TPM_TPMCR
@ CGT_HCR_TID4
@ CGT_MDCR_TDRA
@ CGT_MDCR_TDOSA
@ CGT_HCR_NV
@ CGT_HCR_TTLB_TTLBIS
@ CGT_MDCR_TDE_TDOSA
@ CGT_MDCR_TPMCR
@ CGT_HCR_TID2
@ CGT_HCR_TACR
@ CGT_MDCR_TTRF
@ CGT_MDCR_TDE_TDA
@ CGT_HCR_TLOR
@ CGT_MDCR_TDE_TDRA
@ CGT_HCR_TVM
@ CGT_MDCR_TDCC
@ CGT_HCR_nFIEN
@ CGT_HCR_TPU_TICAB
@ CGT_HCR_APK
@ CGT_HCR_FMO
@ CGT_HCR_TTLB
@ CGT_HCR_NV_nNV2
@ CGT_CNTHCTL_EL1PCTEN
@ CGT_HCR_TRVM
@ CGT_MDCR_TPMS
@ CGT_HCR_TID2_TID4
@ CGT_HCR_TPU_TOCU
@ CGT_HCR_TDZ
@ CGT_HCR_TTLBIS
@ CGT_HCR_TSW
@ CGT_HCR_IMO
@ CGT_MDCR_E2TB
@ CGT_HCR_TTLB_TTLBOS
@ CGT_MDCR_TDA
@ CGT_HCR_TERR
@ CGT_HCR_TIDCP
@ CGT_HCR_ENSCXT
@ __NR_CGT_GROUP_IDS__
@ CGT_MDCR_TPM

◆ fg_filter_id

Enumerator
__NO_FGF__ 
HCRX_FGTnXS 
__NR_FG_FILTER_IDS__ 

Definition at line 1021 of file emulate-nested.c.

1021  {
1022  __NO_FGF__,
1023  HCRX_FGTnXS,
1024 
1025  /* Must be last */
1027 };
@ __NO_FGF__
@ __NR_FG_FILTER_IDS__
@ HCRX_FGTnXS

◆ fgt_group_id

Enumerator
__NO_FGT_GROUP__ 
HFGxTR_GROUP 
HDFGRTR_GROUP 
HDFGWTR_GROUP 
HFGITR_GROUP 
HAFGRTR_GROUP 
__NR_FGT_GROUP_IDS__ 

Definition at line 1009 of file emulate-nested.c.

1009  {
1011  HFGxTR_GROUP,
1012  HDFGRTR_GROUP,
1013  HDFGWTR_GROUP,
1014  HFGITR_GROUP,
1015  HAFGRTR_GROUP,
1016 
1017  /* Must be last */
1019 };
@ HDFGWTR_GROUP
@ HFGxTR_GROUP
@ __NO_FGT_GROUP__
@ HDFGRTR_GROUP
@ HFGITR_GROUP
@ HAFGRTR_GROUP
@ __NR_FGT_GROUP_IDS__

◆ trap_behaviour

Enumerator
BEHAVE_HANDLE_LOCALLY 
BEHAVE_FORWARD_READ 
BEHAVE_FORWARD_WRITE 
BEHAVE_FORWARD_ANY 

Definition at line 17 of file emulate-nested.c.

17  {
19  BEHAVE_FORWARD_READ = BIT(0),
20  BEHAVE_FORWARD_WRITE = BIT(1),
22 };
@ BEHAVE_HANDLE_LOCALLY
@ BEHAVE_FORWARD_ANY
@ BEHAVE_FORWARD_WRITE
@ BEHAVE_FORWARD_READ

Function Documentation

◆ __check_nv_sr_forward()

bool __check_nv_sr_forward ( struct kvm_vcpu *  vcpu)

Definition at line 1908 of file emulate-nested.c.

1909 {
1910  union trap_config tc;
1911  enum trap_behaviour b;
1912  bool is_read;
1913  u32 sysreg;
1914  u64 esr, val;
1915 
1916  if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
1917  return false;
1918 
1919  esr = kvm_vcpu_get_esr(vcpu);
1920  sysreg = esr_sys64_to_sysreg(esr);
1921  is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
1922 
1923  tc = get_trap_config(sysreg);
1924 
1925  /*
1926  * A value of 0 for the whole entry means that we know nothing
1927  * for this sysreg, and that it cannot be re-injected into the
1928  * nested hypervisor. In this situation, let's cut it short.
1929  *
1930  * Note that ultimately, we could also make use of the xarray
1931  * to store the index of the sysreg in the local descriptor
1932  * array, avoiding another search... Hint, hint...
1933  */
1934  if (!tc.val)
1935  return false;
1936 
1937  switch ((enum fgt_group_id)tc.fgt) {
1938  case __NO_FGT_GROUP__:
1939  break;
1940 
1941  case HFGxTR_GROUP:
1942  if (is_read)
1943  val = sanitised_sys_reg(vcpu, HFGRTR_EL2);
1944  else
1945  val = sanitised_sys_reg(vcpu, HFGWTR_EL2);
1946  break;
1947 
1948  case HDFGRTR_GROUP:
1949  case HDFGWTR_GROUP:
1950  if (is_read)
1951  val = sanitised_sys_reg(vcpu, HDFGRTR_EL2);
1952  else
1953  val = sanitised_sys_reg(vcpu, HDFGWTR_EL2);
1954  break;
1955 
1956  case HAFGRTR_GROUP:
1957  val = sanitised_sys_reg(vcpu, HAFGRTR_EL2);
1958  break;
1959 
1960  case HFGITR_GROUP:
1961  val = sanitised_sys_reg(vcpu, HFGITR_EL2);
1962  switch (tc.fgf) {
1963  u64 tmp;
1964 
1965  case __NO_FGF__:
1966  break;
1967 
1968  case HCRX_FGTnXS:
1969  tmp = sanitised_sys_reg(vcpu, HCRX_EL2);
1970  if (tmp & HCRX_EL2_FGTnXS)
1971  tc.fgt = __NO_FGT_GROUP__;
1972  }
1973  break;
1974 
1975  case __NR_FGT_GROUP_IDS__:
1976  /* Something is really wrong, bail out */
1977  WARN_ONCE(1, "__NR_FGT_GROUP_IDS__");
1978  return false;
1979  }
1980 
1981  if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(val, tc))
1982  goto inject;
1983 
1984  b = compute_trap_behaviour(vcpu, tc);
1985 
1986  if (((b & BEHAVE_FORWARD_READ) && is_read) ||
1987  ((b & BEHAVE_FORWARD_WRITE) && !is_read))
1988  goto inject;
1989 
1990  return false;
1991 
1992 inject:
1993  trace_kvm_forward_sysreg_trap(vcpu, sysreg, is_read);
1994 
1995  kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu));
1996  return true;
1997 }
trap_behaviour
#define sanitised_sys_reg(vcpu, reg)
fgt_group_id
static enum trap_behaviour compute_trap_behaviour(struct kvm_vcpu *vcpu, const union trap_config tc)
static union trap_config get_trap_config(u32 sysreg)
static bool check_fgt_bit(u64 val, const union trap_config tc)
int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ __compute_trap_behaviour()

static enum trap_behaviour __compute_trap_behaviour ( struct kvm_vcpu *  vcpu,
const enum cgt_group_id  id,
enum trap_behaviour  b 
)
static

Definition at line 1760 of file emulate-nested.c.

1864 {
1865  switch (id) {
1866  const enum cgt_group_id *cgids;
1867 
1869  if (likely(id != __RESERVED__))
1870  b |= get_behaviour(vcpu, &coarse_trap_bits[id]);
1871  break;
1873  /* Yes, this is recursive. Don't do anything stupid. */
1875  for (int i = 0; cgids[i] != __RESERVED__; i++)
1876  b |= __compute_trap_behaviour(vcpu, cgids[i], b);
1877  break;
1878  default:
1879  if (ARRAY_SIZE(ccc))
1880  b |= ccc[id - __COMPLEX_CONDITIONS__](vcpu);
1881  break;
1882  }
1883 
1884  return b;
1885 }
static const complex_condition_check ccc[]
static const struct trap_bits coarse_trap_bits[]
static enum cgt_group_id * coarse_control_combo[]
static enum trap_behaviour __compute_trap_behaviour(struct kvm_vcpu *vcpu, const enum cgt_group_id id, enum trap_behaviour b)
static enum trap_behaviour get_behaviour(struct kvm_vcpu *vcpu, const struct trap_bits *tb)
Here is the call graph for this function:

◆ check_cnthctl_el1pcten()

static enum trap_behaviour check_cnthctl_el1pcten ( struct kvm_vcpu *  vcpu)
static

Definition at line 387 of file emulate-nested.c.

398 {
399  if (get_sanitized_cnthctl(vcpu) & (CNTHCTL_EL1PCTEN << 10))
400  return BEHAVE_HANDLE_LOCALLY;
401 
402  return BEHAVE_FORWARD_ANY;
403 }
static u64 get_sanitized_cnthctl(struct kvm_vcpu *vcpu)

◆ check_cnthctl_el1pten()

static enum trap_behaviour check_cnthctl_el1pten ( struct kvm_vcpu *  vcpu)
static

Definition at line 387 of file emulate-nested.c.

406 {
407  if (get_sanitized_cnthctl(vcpu) & (CNTHCTL_EL1PCEN << 10))
408  return BEHAVE_HANDLE_LOCALLY;
409 
410  return BEHAVE_FORWARD_ANY;
411 }

◆ check_fgt_bit()

static bool check_fgt_bit ( u64  val,
const union trap_config  tc 
)
static

Definition at line 1895 of file emulate-nested.c.

1896 {
1897  return ((val >> tc.bit) & 1) == tc.pol;
1898 }
unsigned long bit
unsigned long pol
Here is the caller graph for this function:

◆ compute_trap_behaviour()

static enum trap_behaviour compute_trap_behaviour ( struct kvm_vcpu *  vcpu,
const union trap_config  tc 
)
static

Definition at line 1760 of file emulate-nested.c.

1889 {
1891 
1892  return __compute_trap_behaviour(vcpu, tc.cgt, b);
1893 }
unsigned long cgt
Here is the caller graph for this function:

◆ DEFINE_XARRAY()

static DEFINE_XARRAY ( sr_forward_xa  )
static

◆ get_behaviour()

static enum trap_behaviour get_behaviour ( struct kvm_vcpu *  vcpu,
const struct trap_bits tb 
)
static

Definition at line 1760 of file emulate-nested.c.

1850 {
1852  u64 val;
1853 
1854  val = __vcpu_sys_reg(vcpu, tb->index);
1855  if ((val & tb->mask) == tb->value)
1856  b |= tb->behaviour;
1857 
1858  return b;
1859 }
enum trap_behaviour behaviour
enum vcpu_sysreg index
const u64 value
const u64 mask

◆ get_sanitized_cnthctl()

static u64 get_sanitized_cnthctl ( struct kvm_vcpu *  vcpu)
static

Definition at line 387 of file emulate-nested.c.

388 {
389  u64 val = __vcpu_sys_reg(vcpu, CNTHCTL_EL2);
390 
391  if (!vcpu_el2_e2h_is_set(vcpu))
392  val = (val & (CNTHCTL_EL1PCEN | CNTHCTL_EL1PCTEN)) << 10;
393 
394  return val & ((CNTHCTL_EL1PCEN | CNTHCTL_EL1PCTEN) << 10);
395 }

◆ get_trap_config()

static union trap_config get_trap_config ( u32  sysreg)
static

Definition at line 1044 of file emulate-nested.c.

1739 {
1740  return (union trap_config) {
1741  .val = xa_to_value(xa_load(&sr_forward_xa, sysreg)),
1742  };
1743 }
Here is the caller graph for this function:

◆ kvm_check_illegal_exception_return()

static u64 kvm_check_illegal_exception_return ( struct kvm_vcpu *  vcpu,
u64  spsr 
)
static

Definition at line 1999 of file emulate-nested.c.

2000 {
2001  u64 mode = spsr & PSR_MODE_MASK;
2002 
2003  /*
2004  * Possible causes for an Illegal Exception Return from EL2:
2005  * - trying to return to EL3
2006  * - trying to return to an illegal M value
2007  * - trying to return to a 32bit EL
2008  * - trying to return to EL1 with HCR_EL2.TGE set
2009  */
2010  if (mode == PSR_MODE_EL3t || mode == PSR_MODE_EL3h ||
2011  mode == 0b00001 || (mode & BIT(1)) ||
2012  (spsr & PSR_MODE32_BIT) ||
2013  (vcpu_el2_tge_is_set(vcpu) && (mode == PSR_MODE_EL1t ||
2014  mode == PSR_MODE_EL1h))) {
2015  /*
2016  * The guest is playing with our nerves. Preserve EL, SP,
2017  * masks, flags from the existing PSTATE, and set IL.
2018  * The HW will then generate an Illegal State Exception
2019  * immediately after ERET.
2020  */
2021  spsr = *vcpu_cpsr(vcpu);
2022 
2023  spsr &= (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT |
2024  PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT |
2025  PSR_MODE_MASK | PSR_MODE32_BIT);
2026  spsr |= PSR_IL_BIT;
2027  }
2028 
2029  return spsr;
2030 }
Here is the caller graph for this function:

◆ kvm_emulate_nested_eret()

void kvm_emulate_nested_eret ( struct kvm_vcpu *  vcpu)

Definition at line 2032 of file emulate-nested.c.

2033 {
2034  u64 spsr, elr, mode;
2035  bool direct_eret;
2036 
2037  /*
2038  * Going through the whole put/load motions is a waste of time
2039  * if this is a VHE guest hypervisor returning to its own
2040  * userspace, or the hypervisor performing a local exception
2041  * return. No need to save/restore registers, no need to
2042  * switch S2 MMU. Just do the canonical ERET.
2043  */
2044  spsr = vcpu_read_sys_reg(vcpu, SPSR_EL2);
2045  spsr = kvm_check_illegal_exception_return(vcpu, spsr);
2046 
2047  mode = spsr & (PSR_MODE_MASK | PSR_MODE32_BIT);
2048 
2049  direct_eret = (mode == PSR_MODE_EL0t &&
2050  vcpu_el2_e2h_is_set(vcpu) &&
2051  vcpu_el2_tge_is_set(vcpu));
2052  direct_eret |= (mode == PSR_MODE_EL2h || mode == PSR_MODE_EL2t);
2053 
2054  if (direct_eret) {
2055  *vcpu_pc(vcpu) = vcpu_read_sys_reg(vcpu, ELR_EL2);
2056  *vcpu_cpsr(vcpu) = spsr;
2057  trace_kvm_nested_eret(vcpu, *vcpu_pc(vcpu), spsr);
2058  return;
2059  }
2060 
2061  preempt_disable();
2062  kvm_arch_vcpu_put(vcpu);
2063 
2064  elr = __vcpu_sys_reg(vcpu, ELR_EL2);
2065 
2066  trace_kvm_nested_eret(vcpu, elr, spsr);
2067 
2068  /*
2069  * Note that the current exception level is always the virtual EL2,
2070  * since we set HCR_EL2.NV bit only when entering the virtual EL2.
2071  */
2072  *vcpu_pc(vcpu) = elr;
2073  *vcpu_cpsr(vcpu) = spsr;
2074 
2075  kvm_arch_vcpu_load(vcpu, smp_processor_id());
2076  preempt_enable();
2077 }
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
Definition: arm.c:472
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
Definition: arm.c:426
static u64 kvm_check_illegal_exception_return(struct kvm_vcpu *vcpu, u64 spsr)
u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
Definition: sys_regs.c:128
Here is the call graph for this function:
Here is the caller graph for this function:

◆ kvm_inject_el2_exception()

static void kvm_inject_el2_exception ( struct kvm_vcpu *  vcpu,
u64  esr_el2,
enum exception_type  type 
)
static

Definition at line 2079 of file emulate-nested.c.

2081 {
2082  trace_kvm_inject_nested_exception(vcpu, esr_el2, type);
2083 
2084  switch (type) {
2085  case except_type_sync:
2086  kvm_pend_exception(vcpu, EXCEPT_AA64_EL2_SYNC);
2087  vcpu_write_sys_reg(vcpu, esr_el2, ESR_EL2);
2088  break;
2089  case except_type_irq:
2090  kvm_pend_exception(vcpu, EXCEPT_AA64_EL2_IRQ);
2091  break;
2092  default:
2093  WARN_ONCE(1, "Unsupported EL2 exception injection %d\n", type);
2094  }
2095 }
void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
Definition: sys_regs.c:172
Here is the call graph for this function:
Here is the caller graph for this function:

◆ kvm_inject_nested()

static int kvm_inject_nested ( struct kvm_vcpu *  vcpu,
u64  esr_el2,
enum exception_type  type 
)
static

Definition at line 2101 of file emulate-nested.c.

2103 {
2104  u64 pstate, mode;
2105  bool direct_inject;
2106 
2107  if (!vcpu_has_nv(vcpu)) {
2108  kvm_err("Unexpected call to %s for the non-nesting configuration\n",
2109  __func__);
2110  return -EINVAL;
2111  }
2112 
2113  /*
2114  * As for ERET, we can avoid doing too much on the injection path by
2115  * checking that we either took the exception from a VHE host
2116  * userspace or from vEL2. In these cases, there is no change in
2117  * translation regime (or anything else), so let's do as little as
2118  * possible.
2119  */
2120  pstate = *vcpu_cpsr(vcpu);
2121  mode = pstate & (PSR_MODE_MASK | PSR_MODE32_BIT);
2122 
2123  direct_inject = (mode == PSR_MODE_EL0t &&
2124  vcpu_el2_e2h_is_set(vcpu) &&
2125  vcpu_el2_tge_is_set(vcpu));
2126  direct_inject |= (mode == PSR_MODE_EL2h || mode == PSR_MODE_EL2t);
2127 
2128  if (direct_inject) {
2129  kvm_inject_el2_exception(vcpu, esr_el2, type);
2130  return 1;
2131  }
2132 
2133  preempt_disable();
2134 
2135  /*
2136  * We may have an exception or PC update in the EL0/EL1 context.
2137  * Commit it before entering EL2.
2138  */
2139  __kvm_adjust_pc(vcpu);
2140 
2141  kvm_arch_vcpu_put(vcpu);
2142 
2143  kvm_inject_el2_exception(vcpu, esr_el2, type);
2144 
2145  /*
2146  * A hard requirement is that a switch between EL1 and EL2
2147  * contexts has to happen between a put/load, so that we can
2148  * pick the correct timer and interrupt configuration, among
2149  * other things.
2150  *
2151  * Make sure the exception actually took place before we load
2152  * the new context.
2153  */
2154  __kvm_adjust_pc(vcpu);
2155 
2156  kvm_arch_vcpu_load(vcpu, smp_processor_id());
2157  preempt_enable();
2158 
2159  return 1;
2160 }
static void kvm_inject_el2_exception(struct kvm_vcpu *vcpu, u64 esr_el2, enum exception_type type)
void __kvm_adjust_pc(struct kvm_vcpu *vcpu)
Definition: exception.c:365
Here is the call graph for this function:
Here is the caller graph for this function:

◆ kvm_inject_nested_irq()

int kvm_inject_nested_irq ( struct kvm_vcpu *  vcpu)

Definition at line 2167 of file emulate-nested.c.

2168 {
2169  /*
2170  * Do not inject an irq if the:
2171  * - Current exception level is EL2, and
2172  * - virtual HCR_EL2.TGE == 0
2173  * - virtual HCR_EL2.IMO == 0
2174  *
2175  * See Table D1-17 "Physical interrupt target and masking when EL3 is
2176  * not implemented and EL2 is implemented" in ARM DDI 0487C.a.
2177  */
2178 
2179  if (vcpu_is_el2(vcpu) && !vcpu_el2_tge_is_set(vcpu) &&
2180  !(__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_IMO))
2181  return 1;
2182 
2183  /* esr_el2 value doesn't matter for exits due to irqs. */
2184  return kvm_inject_nested(vcpu, 0, except_type_irq);
2185 }
static int kvm_inject_nested(struct kvm_vcpu *vcpu, u64 esr_el2, enum exception_type type)

◆ kvm_inject_nested_sync()

int kvm_inject_nested_sync ( struct kvm_vcpu *  vcpu,
u64  esr_el2 
)

Definition at line 2162 of file emulate-nested.c.

2163 {
2164  return kvm_inject_nested(vcpu, esr_el2, except_type_sync);
2165 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ populate_nv_trap_config()

int __init populate_nv_trap_config ( void  )

Definition at line 1760 of file emulate-nested.c.

1761 {
1762  int ret = 0;
1763 
1764  BUILD_BUG_ON(sizeof(union trap_config) != sizeof(void *));
1765  BUILD_BUG_ON(__NR_CGT_GROUP_IDS__ > BIT(TC_CGT_BITS));
1766  BUILD_BUG_ON(__NR_FGT_GROUP_IDS__ > BIT(TC_FGT_BITS));
1767  BUILD_BUG_ON(__NR_FG_FILTER_IDS__ > BIT(TC_FGF_BITS));
1768 
1769  for (int i = 0; i < ARRAY_SIZE(encoding_to_cgt); i++) {
1770  const struct encoding_to_trap_config *cgt = &encoding_to_cgt[i];
1771  void *prev;
1772 
1773  if (cgt->tc.val & BIT(63)) {
1774  kvm_err("CGT[%d] has MBZ bit set\n", i);
1775  ret = -EINVAL;
1776  }
1777 
1778  if (cgt->encoding != cgt->end) {
1779  prev = xa_store_range(&sr_forward_xa,
1780  cgt->encoding, cgt->end,
1781  xa_mk_value(cgt->tc.val),
1782  GFP_KERNEL);
1783  } else {
1784  prev = xa_store(&sr_forward_xa, cgt->encoding,
1785  xa_mk_value(cgt->tc.val), GFP_KERNEL);
1786  if (prev && !xa_is_err(prev)) {
1787  ret = -EINVAL;
1788  print_nv_trap_error(cgt, "Duplicate CGT", ret);
1789  }
1790  }
1791 
1792  if (xa_is_err(prev)) {
1793  ret = xa_err(prev);
1794  print_nv_trap_error(cgt, "Failed CGT insertion", ret);
1795  }
1796  }
1797 
1798  kvm_info("nv: %ld coarse grained trap handlers\n",
1799  ARRAY_SIZE(encoding_to_cgt));
1800 
1801  if (!cpus_have_final_cap(ARM64_HAS_FGT))
1802  goto check_mcb;
1803 
1804  for (int i = 0; i < ARRAY_SIZE(encoding_to_fgt); i++) {
1805  const struct encoding_to_trap_config *fgt = &encoding_to_fgt[i];
1806  union trap_config tc;
1807 
1808  if (fgt->tc.fgt >= __NR_FGT_GROUP_IDS__) {
1809  ret = -EINVAL;
1810  print_nv_trap_error(fgt, "Invalid FGT", ret);
1811  }
1812 
1813  tc = get_trap_config(fgt->encoding);
1814 
1815  if (tc.fgt) {
1816  ret = -EINVAL;
1817  print_nv_trap_error(fgt, "Duplicate FGT", ret);
1818  }
1819 
1820  tc.val |= fgt->tc.val;
1821  xa_store(&sr_forward_xa, fgt->encoding,
1822  xa_mk_value(tc.val), GFP_KERNEL);
1823  }
1824 
1825  kvm_info("nv: %ld fine grained trap handlers\n",
1826  ARRAY_SIZE(encoding_to_fgt));
1827 
1828 check_mcb:
1829  for (int id = __MULTIPLE_CONTROL_BITS__; id < __COMPLEX_CONDITIONS__; id++) {
1830  const enum cgt_group_id *cgids;
1831 
1833 
1834  for (int i = 0; cgids[i] != __RESERVED__; i++) {
1835  if (cgids[i] >= __MULTIPLE_CONTROL_BITS__) {
1836  kvm_err("Recursive MCB %d/%d\n", id, cgids[i]);
1837  ret = -EINVAL;
1838  }
1839  }
1840  }
1841 
1842  if (ret)
1843  xa_destroy(&sr_forward_xa);
1844 
1845  return ret;
1846 }
#define TC_FGF_BITS
static __init void print_nv_trap_error(const struct encoding_to_trap_config *tc, const char *type, int err)
#define TC_FGT_BITS
#define TC_CGT_BITS
const union trap_config tc
unsigned long fgt
Here is the caller graph for this function:

◆ print_nv_trap_error()

static __init void print_nv_trap_error ( const struct encoding_to_trap_config tc,
const char *  type,
int  err 
)
static

Definition at line 1745 of file emulate-nested.c.

1747 {
1748  kvm_err("%s line %d encoding range "
1749  "(%d, %d, %d, %d, %d) - (%d, %d, %d, %d, %d) (err=%d)\n",
1750  type, tc->line,
1751  sys_reg_Op0(tc->encoding), sys_reg_Op1(tc->encoding),
1752  sys_reg_CRn(tc->encoding), sys_reg_CRm(tc->encoding),
1753  sys_reg_Op2(tc->encoding),
1754  sys_reg_Op0(tc->end), sys_reg_Op1(tc->end),
1755  sys_reg_CRn(tc->end), sys_reg_CRm(tc->end),
1756  sys_reg_Op2(tc->end),
1757  err);
1758 }
const unsigned int line
Here is the caller graph for this function:

Variable Documentation

◆ __initconst

const struct encoding_to_trap_config encoding_to_fgt [] __initconst
static

Definition at line 476 of file emulate-nested.c.

◆ ccc

const complex_condition_check ccc[]
static
Initial value:
= {
}
static enum trap_behaviour check_cnthctl_el1pcten(struct kvm_vcpu *vcpu)
static enum trap_behaviour check_cnthctl_el1pten(struct kvm_vcpu *vcpu)
#define CCC(id, fn)

Definition at line 416 of file emulate-nested.c.

◆ coarse_control_combo

enum cgt_group_id* coarse_control_combo[]
static

◆ coarse_trap_bits

const struct trap_bits coarse_trap_bits[]
static

Definition at line 1 of file emulate-nested.c.