mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Merge branch 'staging' of xenbits.xen.org:/home/xen/git/xen into staging
This commit is contained in:
commit
2c8d85bd15
9 files changed
+219
-90
No files matched your search
+25
-12
@@ -14,6 +14,7 @@
|
||||
#include <xen/init.h>
|
||||
#include <xen/device_tree.h>
|
||||
#include <xen/libfdt/libfdt.h>
|
||||
#include <xsm/xsm.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
static bool_t __init device_tree_node_matches(const void *fdt, int node,
|
||||
@@ -175,6 +176,17 @@ static void __init process_multiboot_node(const void *fdt, int node,
|
||||
const char *cmdline;
|
||||
int len;
|
||||
|
||||
prop = fdt_get_property(fdt, node, "reg", &len);
|
||||
if ( !prop )
|
||||
panic("node %s missing `reg' property\n", name);
|
||||
|
||||
if ( len < dt_cells_to_size(address_cells + size_cells) )
|
||||
panic("fdt: node `%s': `reg` property length is too short\n",
|
||||
name);
|
||||
|
||||
cell = (const __be32 *)prop->data;
|
||||
device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
|
||||
|
||||
if ( fdt_node_check_compatible(fdt, node, "xen,linux-zimage") == 0 ||
|
||||
fdt_node_check_compatible(fdt, node, "multiboot,kernel") == 0 )
|
||||
kind = BOOTMOD_KERNEL;
|
||||
@@ -186,7 +198,17 @@ static void __init process_multiboot_node(const void *fdt, int node,
|
||||
else
|
||||
kind = BOOTMOD_UNKNOWN;
|
||||
|
||||
/* Guess that first two unknown are kernel and ramdisk respectively. */
|
||||
/**
|
||||
* Guess the kind of these first two unknowns respectively:
|
||||
* (1) The first unknown must be kernel.
|
||||
* (2) Detect the XSM Magic from the 2nd unknown:
|
||||
* a. If it's XSM, set the kind as XSM, and that also means we
|
||||
* won't load ramdisk;
|
||||
* b. if it's not XSM, set the kind as ramdisk.
|
||||
* So if user want to load ramdisk, it must be the 2nd unknown.
|
||||
* We also detect the XSM Magic for the following unknowns,
|
||||
* then set its kind according to the return value of has_xsm_magic.
|
||||
*/
|
||||
if ( kind == BOOTMOD_UNKNOWN )
|
||||
{
|
||||
switch ( kind_guess++ )
|
||||
@@ -195,19 +217,10 @@ static void __init process_multiboot_node(const void *fdt, int node,
|
||||
case 1: kind = BOOTMOD_RAMDISK; break;
|
||||
default: break;
|
||||
}
|
||||
if ( kind_guess > 1 && has_xsm_magic(start) )
|
||||
kind = BOOTMOD_XSM;
|
||||
}
|
||||
|
||||
prop = fdt_get_property(fdt, node, "reg", &len);
|
||||
if ( !prop )
|
||||
panic("node %s missing `reg' property\n", name);
|
||||
|
||||
if ( len < dt_cells_to_size(address_cells + size_cells) )
|
||||
panic("fdt: node `%s': `reg` property length is too short\n",
|
||||
name);
|
||||
|
||||
cell = (const __be32 *)prop->data;
|
||||
device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
|
||||
|
||||
prop = fdt_get_property(fdt, node, "bootargs", &len);
|
||||
if ( prop )
|
||||
{
|
||||
|
||||
+25
-9
@@ -24,12 +24,19 @@
|
||||
#include <asm/mmio.h>
|
||||
|
||||
static int handle_read(const struct mmio_handler *handler, struct vcpu *v,
|
||||
mmio_info_t *info, register_t *r)
|
||||
mmio_info_t *info)
|
||||
{
|
||||
const struct hsr_dabt dabt = info->dabt;
|
||||
struct cpu_user_regs *regs = guest_cpu_user_regs();
|
||||
/*
|
||||
* Initialize to zero to avoid leaking data if there is an
|
||||
* implementation error in the emulation (such as not correctly
|
||||
* setting r).
|
||||
*/
|
||||
register_t r = 0;
|
||||
uint8_t size = (1 << dabt.size) * 8;
|
||||
|
||||
if ( !handler->ops->read(v, info, r, handler->priv) )
|
||||
if ( !handler->ops->read(v, info, &r, handler->priv) )
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -37,7 +44,7 @@ static int handle_read(const struct mmio_handler *handler, struct vcpu *v,
|
||||
* Note that we expect the read handler to have zeroed the bits
|
||||
* outside the requested access size.
|
||||
*/
|
||||
if ( dabt.sign && (*r & (1UL << (size - 1))) )
|
||||
if ( dabt.sign && (r & (1UL << (size - 1))) )
|
||||
{
|
||||
/*
|
||||
* We are relying on register_t using the same as
|
||||
@@ -45,21 +52,30 @@ static int handle_read(const struct mmio_handler *handler, struct vcpu *v,
|
||||
* code smaller.
|
||||
*/
|
||||
BUILD_BUG_ON(sizeof(register_t) != sizeof(unsigned long));
|
||||
*r |= (~0UL) << size;
|
||||
r |= (~0UL) << size;
|
||||
}
|
||||
|
||||
set_user_reg(regs, dabt.reg, r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_write(const struct mmio_handler *handler, struct vcpu *v,
|
||||
mmio_info_t *info)
|
||||
{
|
||||
const struct hsr_dabt dabt = info->dabt;
|
||||
struct cpu_user_regs *regs = guest_cpu_user_regs();
|
||||
|
||||
return handler->ops->write(v, info, get_user_reg(regs, dabt.reg),
|
||||
handler->priv);
|
||||
}
|
||||
|
||||
int handle_mmio(mmio_info_t *info)
|
||||
{
|
||||
struct vcpu *v = current;
|
||||
int i;
|
||||
const struct mmio_handler *handler = NULL;
|
||||
const struct vmmio *vmmio = &v->domain->arch.vmmio;
|
||||
struct hsr_dabt dabt = info->dabt;
|
||||
struct cpu_user_regs *regs = guest_cpu_user_regs();
|
||||
register_t *r = select_user_reg(regs, dabt.reg);
|
||||
|
||||
for ( i = 0; i < vmmio->num_entries; i++ )
|
||||
{
|
||||
@@ -74,9 +90,9 @@ int handle_mmio(mmio_info_t *info)
|
||||
return 0;
|
||||
|
||||
if ( info->dabt.write )
|
||||
return handler->ops->write(v, info, *r, handler->priv);
|
||||
return handle_write(handler, v, info);
|
||||
else
|
||||
return handle_read(handler, v, info, r);
|
||||
return handle_read(handler, v, info);
|
||||
}
|
||||
|
||||
void register_mmio_handler(struct domain *d,
|
||||
|
||||
+84
-42
@@ -149,7 +149,31 @@ static void print_xen_info(void)
|
||||
debug_build() ? 'y' : 'n', print_tainted(taint_str));
|
||||
}
|
||||
|
||||
register_t *select_user_reg(struct cpu_user_regs *regs, int reg)
|
||||
#ifdef CONFIG_ARM_32
|
||||
static inline bool_t is_zero_register(int reg)
|
||||
{
|
||||
/* There is no zero register for ARM32 */
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline bool_t is_zero_register(int reg)
|
||||
{
|
||||
/*
|
||||
* For store/load and sysreg instruction, the encoding 31 always
|
||||
* corresponds to {w,x}zr which is the zero register.
|
||||
*/
|
||||
return (reg == 31);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns a pointer to the given register value in regs, taking the
|
||||
* processor mode (CPSR) into account.
|
||||
*
|
||||
* Note that this function should not be used directly but via
|
||||
* {get,set}_user_reg.
|
||||
*/
|
||||
static register_t *select_user_reg(struct cpu_user_regs *regs, int reg)
|
||||
{
|
||||
BUG_ON( !guest_mode(regs) );
|
||||
|
||||
@@ -207,16 +231,31 @@ register_t *select_user_reg(struct cpu_user_regs *regs, int reg)
|
||||
}
|
||||
#undef REGOFFS
|
||||
#else
|
||||
/* In 64 bit the syndrome register contains the AArch64 register
|
||||
* number even if the trap was from AArch32 mode. Except that
|
||||
* AArch32 R15 (PC) is encoded as 0b11111.
|
||||
/*
|
||||
* On 64-bit the syndrome register contains the register index as
|
||||
* viewed in AArch64 state even if the trap was from AArch32 mode.
|
||||
*/
|
||||
if ( reg == 0x1f /* && is aarch32 guest */)
|
||||
return ®s->pc;
|
||||
BUG_ON(is_zero_register(reg)); /* Cannot be {w,x}zr */
|
||||
return ®s->x0 + reg;
|
||||
#endif
|
||||
}
|
||||
|
||||
register_t get_user_reg(struct cpu_user_regs *regs, int reg)
|
||||
{
|
||||
if ( is_zero_register(reg) )
|
||||
return 0;
|
||||
|
||||
return *select_user_reg(regs, reg);
|
||||
}
|
||||
|
||||
void set_user_reg(struct cpu_user_regs *regs, int reg, register_t value)
|
||||
{
|
||||
if ( is_zero_register(reg) )
|
||||
return;
|
||||
|
||||
*select_user_reg(regs, reg) = value;
|
||||
}
|
||||
|
||||
static const char *decode_fsc(uint32_t fsc, int *level)
|
||||
{
|
||||
const char *msg = NULL;
|
||||
@@ -1241,22 +1280,19 @@ static arm_hypercall_t arm_hypercall_table[] = {
|
||||
#ifndef NDEBUG
|
||||
static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
|
||||
{
|
||||
register_t *r;
|
||||
uint32_t reg;
|
||||
uint32_t domid = current->domain->domain_id;
|
||||
switch ( code ) {
|
||||
case 0xe0 ... 0xef:
|
||||
reg = code - 0xe0;
|
||||
r = select_user_reg(regs, reg);
|
||||
printk("DOM%d: R%d = 0x%"PRIregister" at 0x%"PRIvaddr"\n",
|
||||
domid, reg, *r, regs->pc);
|
||||
domid, reg, get_user_reg(regs, reg), regs->pc);
|
||||
break;
|
||||
case 0xfd:
|
||||
printk("DOM%d: Reached %"PRIvaddr"\n", domid, regs->pc);
|
||||
break;
|
||||
case 0xfe:
|
||||
r = select_user_reg(regs, 0);
|
||||
printk("%c", (char)(*r & 0xff));
|
||||
printk("%c", (char)(get_user_reg(regs, 0) & 0xff));
|
||||
break;
|
||||
case 0xff:
|
||||
printk("DOM%d: DEBUG\n", domid);
|
||||
@@ -1614,7 +1650,7 @@ static void advance_pc(struct cpu_user_regs *regs, const union hsr hsr)
|
||||
|
||||
/* Read as zero and write ignore */
|
||||
static void handle_raz_wi(struct cpu_user_regs *regs,
|
||||
register_t *reg,
|
||||
int regidx,
|
||||
bool_t read,
|
||||
const union hsr hsr,
|
||||
int min_el)
|
||||
@@ -1625,7 +1661,7 @@ static void handle_raz_wi(struct cpu_user_regs *regs,
|
||||
return inject_undef_exception(regs, hsr);
|
||||
|
||||
if ( read )
|
||||
*reg = 0;
|
||||
set_user_reg(regs, regidx, 0);
|
||||
/* else: write ignored */
|
||||
|
||||
advance_pc(regs, hsr);
|
||||
@@ -1633,7 +1669,7 @@ static void handle_raz_wi(struct cpu_user_regs *regs,
|
||||
|
||||
/* Write only as write ignore */
|
||||
static void handle_wo_wi(struct cpu_user_regs *regs,
|
||||
register_t *reg,
|
||||
int regidx,
|
||||
bool_t read,
|
||||
const union hsr hsr,
|
||||
int min_el)
|
||||
@@ -1652,7 +1688,7 @@ static void handle_wo_wi(struct cpu_user_regs *regs,
|
||||
|
||||
/* Read only as read as zero */
|
||||
static void handle_ro_raz(struct cpu_user_regs *regs,
|
||||
register_t *reg,
|
||||
int regidx,
|
||||
bool_t read,
|
||||
const union hsr hsr,
|
||||
int min_el)
|
||||
@@ -1666,7 +1702,7 @@ static void handle_ro_raz(struct cpu_user_regs *regs,
|
||||
return inject_undef_exception(regs, hsr);
|
||||
/* else: raz */
|
||||
|
||||
*reg = 0;
|
||||
set_user_reg(regs, regidx, 0);
|
||||
|
||||
advance_pc(regs, hsr);
|
||||
}
|
||||
@@ -1675,7 +1711,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
|
||||
const union hsr hsr)
|
||||
{
|
||||
const struct hsr_cp32 cp32 = hsr.cp32;
|
||||
register_t *r = select_user_reg(regs, cp32.reg);
|
||||
int regidx = cp32.reg;
|
||||
struct vcpu *v = current;
|
||||
|
||||
if ( !check_conditional_instr(regs, hsr) )
|
||||
@@ -1708,7 +1744,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
|
||||
if ( psr_mode_is_user(regs) )
|
||||
return inject_undef_exception(regs, hsr);
|
||||
if ( cp32.read )
|
||||
*r = v->arch.actlr;
|
||||
set_user_reg(regs, regidx, v->arch.actlr);
|
||||
break;
|
||||
|
||||
/*
|
||||
@@ -1740,13 +1776,13 @@ static void do_cp15_32(struct cpu_user_regs *regs,
|
||||
case HSR_CPREG32(PMUSERENR):
|
||||
/* RO at EL0. RAZ/WI at EL1 */
|
||||
if ( psr_mode_is_user(regs) )
|
||||
return handle_ro_raz(regs, r, cp32.read, hsr, 0);
|
||||
return handle_ro_raz(regs, regidx, cp32.read, hsr, 0);
|
||||
else
|
||||
return handle_raz_wi(regs, r, cp32.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
|
||||
case HSR_CPREG32(PMINTENSET):
|
||||
case HSR_CPREG32(PMINTENCLR):
|
||||
/* EL1 only, however MDCR_EL2.TPM==1 means EL0 may trap here also. */
|
||||
return handle_raz_wi(regs, r, cp32.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
|
||||
case HSR_CPREG32(PMCR):
|
||||
case HSR_CPREG32(PMCNTENSET):
|
||||
case HSR_CPREG32(PMCNTENCLR):
|
||||
@@ -1763,7 +1799,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
|
||||
* Accessible at EL0 only if PMUSERENR_EL0.EN is set. We
|
||||
* emulate that register as 0 above.
|
||||
*/
|
||||
return handle_raz_wi(regs, r, cp32.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
|
||||
|
||||
/*
|
||||
* HCR_EL2.TIDCP
|
||||
@@ -1866,7 +1902,7 @@ static void do_cp15_64(struct cpu_user_regs *regs,
|
||||
static void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr)
|
||||
{
|
||||
const struct hsr_cp32 cp32 = hsr.cp32;
|
||||
register_t *r = select_user_reg(regs, cp32.reg);
|
||||
int regidx = cp32.reg;
|
||||
struct domain *d = current->domain;
|
||||
|
||||
if ( !check_conditional_instr(regs, hsr) )
|
||||
@@ -1888,9 +1924,9 @@ static void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr)
|
||||
* DBGPRCR
|
||||
*/
|
||||
case HSR_CPREG32(DBGOSLAR):
|
||||
return handle_wo_wi(regs, r, cp32.read, hsr, 1);
|
||||
return handle_wo_wi(regs, regidx, cp32.read, hsr, 1);
|
||||
case HSR_CPREG32(DBGOSDLR):
|
||||
return handle_raz_wi(regs, r, cp32.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
|
||||
|
||||
/*
|
||||
* MDCR_EL2.TDA
|
||||
@@ -1915,6 +1951,9 @@ static void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr)
|
||||
* DBGOSECCR
|
||||
*/
|
||||
case HSR_CPREG32(DBGDIDR):
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
/*
|
||||
* Read-only register. Accessible by EL0 if DBGDSCRext.UDCCdis
|
||||
* is set to 0, which we emulated below.
|
||||
@@ -1928,23 +1967,26 @@ static void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr)
|
||||
* - Version: ARMv7 v7.1
|
||||
* - Variant and Revision bits match MDIR
|
||||
*/
|
||||
*r = (1 << 24) | (5 << 16);
|
||||
*r |= ((d->arch.vpidr >> 20) & 0xf) | (d->arch.vpidr & 0xf);
|
||||
val = (1 << 24) | (5 << 16);
|
||||
val |= ((d->arch.vpidr >> 20) & 0xf) | (d->arch.vpidr & 0xf);
|
||||
set_user_reg(regs, regidx, val);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case HSR_CPREG32(DBGDSCRINT):
|
||||
/*
|
||||
* Read-only register. Accessible by EL0 if DBGDSCRext.UDCCdis
|
||||
* is set to 0, which we emulated below.
|
||||
*/
|
||||
return handle_ro_raz(regs, r, cp32.read, hsr, 1);
|
||||
return handle_ro_raz(regs, regidx, cp32.read, hsr, 1);
|
||||
|
||||
case HSR_CPREG32(DBGDSCREXT):
|
||||
/*
|
||||
* Implement debug status and control register as RAZ/WI.
|
||||
* The OS won't use Hardware debug if MDBGen not set.
|
||||
*/
|
||||
return handle_raz_wi(regs, r, cp32.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
|
||||
|
||||
case HSR_CPREG32(DBGVCR):
|
||||
case HSR_CPREG32(DBGBVR0):
|
||||
@@ -1953,7 +1995,7 @@ static void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr)
|
||||
case HSR_CPREG32(DBGWCR0):
|
||||
case HSR_CPREG32(DBGBVR1):
|
||||
case HSR_CPREG32(DBGBCR1):
|
||||
return handle_raz_wi(regs, r, cp32.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
|
||||
|
||||
/*
|
||||
* CPTR_EL2.TTA
|
||||
@@ -2077,7 +2119,7 @@ static void do_cp(struct cpu_user_regs *regs, const union hsr hsr)
|
||||
static void do_sysreg(struct cpu_user_regs *regs,
|
||||
const union hsr hsr)
|
||||
{
|
||||
register_t *x = select_user_reg(regs, hsr.sysreg.reg);
|
||||
int regidx = hsr.sysreg.reg;
|
||||
struct vcpu *v = current;
|
||||
|
||||
switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
|
||||
@@ -2091,7 +2133,7 @@ static void do_sysreg(struct cpu_user_regs *regs,
|
||||
if ( psr_mode_is_user(regs) )
|
||||
return inject_undef_exception(regs, hsr);
|
||||
if ( hsr.sysreg.read )
|
||||
*x = v->arch.actlr;
|
||||
set_user_reg(regs, regidx, v->arch.actlr);
|
||||
break;
|
||||
|
||||
/*
|
||||
@@ -2100,7 +2142,7 @@ static void do_sysreg(struct cpu_user_regs *regs,
|
||||
* ARMv8 (DDI 0487A.d): D1-1508 Table D1-57
|
||||
*/
|
||||
case HSR_SYSREG_MDRAR_EL1:
|
||||
return handle_ro_raz(regs, x, hsr.sysreg.read, hsr, 1);
|
||||
return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
|
||||
/*
|
||||
* MDCR_EL2.TDOSA
|
||||
@@ -2112,9 +2154,9 @@ static void do_sysreg(struct cpu_user_regs *regs,
|
||||
* DBGPRCR_EL1
|
||||
*/
|
||||
case HSR_SYSREG_OSLAR_EL1:
|
||||
return handle_wo_wi(regs, x, hsr.sysreg.read, hsr, 1);
|
||||
return handle_wo_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
case HSR_SYSREG_OSDLR_EL1:
|
||||
return handle_raz_wi(regs, x, hsr.sysreg.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
|
||||
/*
|
||||
* MDCR_EL2.TDA
|
||||
@@ -2134,18 +2176,18 @@ static void do_sysreg(struct cpu_user_regs *regs,
|
||||
* DBGAUTHSTATUS_EL1
|
||||
*/
|
||||
case HSR_SYSREG_MDSCR_EL1:
|
||||
return handle_raz_wi(regs, x, hsr.sysreg.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
case HSR_SYSREG_MDCCSR_EL0:
|
||||
/*
|
||||
* Accessible at EL0 only if MDSCR_EL1.TDCC is set to 0. We emulate that
|
||||
* register as RAZ/WI above. So RO at both EL0 and EL1.
|
||||
*/
|
||||
return handle_ro_raz(regs, x, hsr.sysreg.read, hsr, 0);
|
||||
return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 0);
|
||||
HSR_SYSREG_DBG_CASES(DBGBVR):
|
||||
HSR_SYSREG_DBG_CASES(DBGBCR):
|
||||
HSR_SYSREG_DBG_CASES(DBGWVR):
|
||||
HSR_SYSREG_DBG_CASES(DBGWCR):
|
||||
return handle_raz_wi(regs, x, hsr.sysreg.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
|
||||
/*
|
||||
* MDCR_EL2.TPM
|
||||
@@ -2169,13 +2211,13 @@ static void do_sysreg(struct cpu_user_regs *regs,
|
||||
* Accessible from EL1 only, but if EL0 trap happens handle as
|
||||
* undef.
|
||||
*/
|
||||
return handle_raz_wi(regs, x, hsr.sysreg.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
case HSR_SYSREG_PMUSERENR_EL0:
|
||||
/* RO at EL0. RAZ/WI at EL1 */
|
||||
if ( psr_mode_is_user(regs) )
|
||||
return handle_ro_raz(regs, x, hsr.sysreg.read, hsr, 0);
|
||||
return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 0);
|
||||
else
|
||||
return handle_raz_wi(regs, x, hsr.sysreg.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
case HSR_SYSREG_PMCR_EL0:
|
||||
case HSR_SYSREG_PMCNTENSET_EL0:
|
||||
case HSR_SYSREG_PMCNTENCLR_EL0:
|
||||
@@ -2192,7 +2234,7 @@ static void do_sysreg(struct cpu_user_regs *regs,
|
||||
* Accessible at EL0 only if PMUSERENR_EL0.EN is set. We
|
||||
* emulate that register as 0 above.
|
||||
*/
|
||||
return handle_raz_wi(regs, x, hsr.sysreg.read, hsr, 1);
|
||||
return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
|
||||
/*
|
||||
* !CNTHCTL_EL2.EL1PCEN
|
||||
|
||||
@@ -1304,7 +1304,6 @@ static int vgic_v3_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr)
|
||||
{
|
||||
struct vcpu *v = current;
|
||||
struct hsr_sysreg sysreg = hsr.sysreg;
|
||||
register_t *r = select_user_reg(regs, sysreg.reg);
|
||||
|
||||
ASSERT (hsr.ec == HSR_EC_SYSREG);
|
||||
|
||||
@@ -1318,7 +1317,7 @@ static int vgic_v3_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr)
|
||||
case HSR_SYSREG_ICC_SGI1R_EL1:
|
||||
/* WO */
|
||||
if ( !sysreg.read )
|
||||
return vgic_v3_to_sgi(v, *r);
|
||||
return vgic_v3_to_sgi(v, get_user_reg(regs, sysreg.reg));
|
||||
else
|
||||
{
|
||||
gprintk(XENLOG_WARNING, "Reading SGI1R_EL1 - WO register\n");
|
||||
|
||||
+46
-13
@@ -249,32 +249,49 @@ static int vtimer_cntp_cval(struct cpu_user_regs *regs, uint64_t *r, int read)
|
||||
static int vtimer_emulate_cp32(struct cpu_user_regs *regs, union hsr hsr)
|
||||
{
|
||||
struct hsr_cp32 cp32 = hsr.cp32;
|
||||
uint32_t *r = (uint32_t *)select_user_reg(regs, cp32.reg);
|
||||
/*
|
||||
* Initialize to zero to avoid leaking data if there is an
|
||||
* implementation error in the emulation (such as not correctly
|
||||
* setting r).
|
||||
*/
|
||||
uint32_t r = 0;
|
||||
int res;
|
||||
|
||||
|
||||
if ( cp32.read )
|
||||
perfc_incr(vtimer_cp32_reads);
|
||||
else
|
||||
perfc_incr(vtimer_cp32_writes);
|
||||
|
||||
if ( !cp32.read )
|
||||
r = get_user_reg(regs, cp32.reg);
|
||||
|
||||
switch ( hsr.bits & HSR_CP32_REGS_MASK )
|
||||
{
|
||||
case HSR_CPREG32(CNTP_CTL):
|
||||
return vtimer_cntp_ctl(regs, r, cp32.read);
|
||||
res = vtimer_cntp_ctl(regs, &r, cp32.read);
|
||||
break;
|
||||
|
||||
case HSR_CPREG32(CNTP_TVAL):
|
||||
return vtimer_cntp_tval(regs, r, cp32.read);
|
||||
res = vtimer_cntp_tval(regs, &r, cp32.read);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( res && cp32.read )
|
||||
set_user_reg(regs, cp32.reg, r);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int vtimer_emulate_cp64(struct cpu_user_regs *regs, union hsr hsr)
|
||||
{
|
||||
struct hsr_cp64 cp64 = hsr.cp64;
|
||||
uint32_t *r1 = (uint32_t *)select_user_reg(regs, cp64.reg1);
|
||||
uint32_t *r2 = (uint32_t *)select_user_reg(regs, cp64.reg2);
|
||||
uint64_t x = (uint64_t)(*r1) | ((uint64_t)(*r2) << 32);
|
||||
uint32_t r1 = get_user_reg(regs, cp64.reg1);
|
||||
uint32_t r2 = get_user_reg(regs, cp64.reg2);
|
||||
uint64_t x = (uint64_t)r1 | ((uint64_t)r2 << 32);
|
||||
|
||||
if ( cp64.read )
|
||||
perfc_incr(vtimer_cp64_reads);
|
||||
@@ -294,8 +311,8 @@ static int vtimer_emulate_cp64(struct cpu_user_regs *regs, union hsr hsr)
|
||||
|
||||
if ( cp64.read )
|
||||
{
|
||||
*r1 = (uint32_t)(x & 0xffffffff);
|
||||
*r2 = (uint32_t)(x >> 32);
|
||||
set_user_reg(regs, cp64.reg1, x & 0xffffffff);
|
||||
set_user_reg(regs, cp64.reg2, x >> 32);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -311,14 +328,16 @@ static int vtimer_emulate_sysreg32(struct cpu_user_regs *regs, union hsr hsr,
|
||||
vtimer_sysreg32_fn_t fn)
|
||||
{
|
||||
struct hsr_sysreg sysreg = hsr.sysreg;
|
||||
register_t *x = select_user_reg(regs, sysreg.reg);
|
||||
uint32_t r = *x;
|
||||
uint32_t r = 0;
|
||||
int ret;
|
||||
|
||||
if ( !sysreg.read )
|
||||
r = get_user_reg(regs, sysreg.reg);
|
||||
|
||||
ret = fn(regs, &r, sysreg.read);
|
||||
|
||||
if ( ret && sysreg.read )
|
||||
*x = r;
|
||||
set_user_reg(regs, sysreg.reg, r);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -327,9 +346,23 @@ static int vtimer_emulate_sysreg64(struct cpu_user_regs *regs, union hsr hsr,
|
||||
vtimer_sysreg64_fn_t fn)
|
||||
{
|
||||
struct hsr_sysreg sysreg = hsr.sysreg;
|
||||
uint64_t *x = select_user_reg(regs, sysreg.reg);
|
||||
/*
|
||||
* Initialize to zero to avoid leaking data if there is an
|
||||
* implementation error in the emulation (such as not correctly
|
||||
* setting x).
|
||||
*/
|
||||
uint64_t x = 0;
|
||||
int ret;
|
||||
|
||||
return fn(regs, x, sysreg.read);
|
||||
if ( !sysreg.read )
|
||||
x = get_user_reg(regs, sysreg.reg);
|
||||
|
||||
ret = fn(regs, &x, sysreg.read);
|
||||
|
||||
if ( ret && sysreg.read )
|
||||
set_user_reg(regs, sysreg.reg, x);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vtimer_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr)
|
||||
|
||||
@@ -50,11 +50,8 @@
|
||||
|
||||
#define return_reg(v) ((v)->arch.cpu_info->guest_cpu_user_regs.r0)
|
||||
|
||||
/*
|
||||
* Returns a pointer to the given register value in regs, taking the
|
||||
* processor mode (CPSR) into account.
|
||||
*/
|
||||
extern register_t *select_user_reg(struct cpu_user_regs *regs, int reg);
|
||||
register_t get_user_reg(struct cpu_user_regs *regs, int reg);
|
||||
void set_user_reg(struct cpu_user_regs *regs, int reg, register_t val);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -760,6 +760,7 @@ extern int xsm_multiboot_policy_init(unsigned long *module_map,
|
||||
#ifdef CONFIG_HAS_DEVICE_TREE
|
||||
extern int xsm_dt_init(void);
|
||||
extern int xsm_dt_policy_init(void);
|
||||
extern bool has_xsm_magic(paddr_t);
|
||||
#endif
|
||||
|
||||
extern int register_xsm(struct xsm_operations *ops);
|
||||
@@ -786,7 +787,12 @@ static inline int xsm_dt_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool has_xsm_magic(paddr_t start)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_HAS_DEVICE_TREE */
|
||||
|
||||
#endif /* CONFIG_XSM */
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
|
||||
#ifdef CONFIG_XSM
|
||||
|
||||
#ifdef CONFIG_HAS_DEVICE_TREE
|
||||
#include <asm/setup.h>
|
||||
#endif
|
||||
|
||||
#define XSM_FRAMEWORK_VERSION "1.0.0"
|
||||
|
||||
struct xsm_operations *xsm_ops;
|
||||
@@ -109,6 +113,29 @@ int __init xsm_dt_init(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* has_xsm_magic - Check XSM Magic of the module header by phy address
|
||||
* A XSM module has a special header
|
||||
* ------------------------------------------------
|
||||
* uint magic | uint target_len | uchar target[8] |
|
||||
* 0xf97cff8c | 8 | "XenFlask" |
|
||||
* ------------------------------------------------
|
||||
* 0xf97cff8c is policy magic number (XSM_MAGIC).
|
||||
* Here we only check the "magic" of the module.
|
||||
*/
|
||||
bool __init has_xsm_magic(paddr_t start)
|
||||
{
|
||||
xsm_magic_t magic;
|
||||
|
||||
if ( XSM_MAGIC )
|
||||
{
|
||||
copy_from_paddr(&magic, start, sizeof(magic) );
|
||||
return ( magic == XSM_MAGIC );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
int register_xsm(struct xsm_operations *ops)
|
||||
|
||||
@@ -79,7 +79,6 @@ int __init xsm_dt_policy_init(void)
|
||||
{
|
||||
struct bootmodule *mod = boot_module_find_by_kind(BOOTMOD_XSM);
|
||||
paddr_t paddr, len;
|
||||
xsm_magic_t magic;
|
||||
|
||||
if ( !mod || !mod->size )
|
||||
return 0;
|
||||
@@ -87,12 +86,9 @@ int __init xsm_dt_policy_init(void)
|
||||
paddr = mod->start;
|
||||
len = mod->size;
|
||||
|
||||
copy_from_paddr(&magic, paddr, sizeof(magic));
|
||||
|
||||
if ( magic != XSM_MAGIC )
|
||||
if ( !has_xsm_magic(paddr) )
|
||||
{
|
||||
printk(XENLOG_ERR "xsm: Invalid magic for XSM blob got 0x%x "
|
||||
"expected 0x%x\n", magic, XSM_MAGIC);
|
||||
printk(XENLOG_ERR "xsm: Invalid magic for XSM blob\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||