[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] xen: arm: fix guest register access.
# HG changeset patch # User Ian Campbell <ian.campbell@xxxxxxxxxx> # Date 1356004388 0 # Node ID 509e9737e241010a3547689368ac1b7cb131e33c # Parent 7420b8f2fa51d2f45b8224511d5dee1242e1a303 xen: arm: fix guest register access. We weren't taking the guest mode (CPSR) into account and would always access the user version of the registers. Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> Acked-by: Tim Deegan <tim@xxxxxxx> Committed-by: Ian Campbell <ian.campbell@xxxxxxxxxx> --- diff -r 7420b8f2fa51 -r 509e9737e241 xen/arch/arm/traps.c --- a/xen/arch/arm/traps.c Thu Dec 20 11:53:07 2012 +0000 +++ b/xen/arch/arm/traps.c Thu Dec 20 11:53:08 2012 +0000 @@ -73,6 +73,64 @@ static void print_xen_info(void) debug, print_tainted(taint_str)); } +uint32_t *select_user_reg(struct cpu_user_regs *regs, int reg) +{ + BUG_ON( guest_mode(regs) ); + + /* + * We rely heavily on the layout of cpu_user_regs to avoid having + * to handle all of the registers individually. Use BUILD_BUG_ON to + * ensure that things which expect are contiguous actually are. + */ +#define REGOFFS(R) offsetof(struct cpu_user_regs, R) + + switch ( reg ) { + case 0 ... 7: /* Unbanked registers */ + BUILD_BUG_ON(REGOFFS(r0) + 7*sizeof(uint32_t) != REGOFFS(r7)); + return ®s->r0 + reg; + case 8 ... 12: /* Register banked in FIQ mode */ + BUILD_BUG_ON(REGOFFS(r8_fiq) + 4*sizeof(uint32_t) != REGOFFS(r12_fiq)); + if ( fiq_mode(regs) ) + return ®s->r8_fiq + reg - 8; + else + return ®s->r8 + reg - 8; + case 13 ... 14: /* Banked SP + LR registers */ + BUILD_BUG_ON(REGOFFS(sp_fiq) + 1*sizeof(uint32_t) != REGOFFS(lr_fiq)); + BUILD_BUG_ON(REGOFFS(sp_irq) + 1*sizeof(uint32_t) != REGOFFS(lr_irq)); + BUILD_BUG_ON(REGOFFS(sp_svc) + 1*sizeof(uint32_t) != REGOFFS(lr_svc)); + BUILD_BUG_ON(REGOFFS(sp_abt) + 1*sizeof(uint32_t) != REGOFFS(lr_abt)); + BUILD_BUG_ON(REGOFFS(sp_und) + 1*sizeof(uint32_t) != REGOFFS(lr_und)); + switch ( regs->cpsr & PSR_MODE_MASK ) + { + case PSR_MODE_USR: + case PSR_MODE_SYS: /* Sys regs are the usr regs */ + if ( reg == 13 ) + return ®s->sp_usr; + else /* lr_usr == lr in a user frame */ + return ®s->lr; + case PSR_MODE_FIQ: + return ®s->sp_fiq + reg - 13; + case PSR_MODE_IRQ: + return ®s->sp_irq + reg - 13; + case PSR_MODE_SVC: + return ®s->sp_svc + reg - 13; + case PSR_MODE_ABT: + return ®s->sp_abt + reg - 13; + case PSR_MODE_UND: + return ®s->sp_und + reg - 13; + case PSR_MODE_MON: + case PSR_MODE_HYP: + default: + BUG(); + } + case 15: /* PC */ + return ®s->pc; + default: + BUG(); + } +#undef REGOFFS +} + static const char *decode_fsc(uint32_t fsc, int *level) { const char *msg = NULL; @@ -448,7 +506,7 @@ static void do_debug_trap(struct cpu_use switch ( code ) { case 0xe0 ... 0xef: reg = code - 0xe0; - r = ®s->r0 + reg; + r = select_user_reg(regs, reg); printk("DOM%d: R%d = %#010"PRIx32" at %#010"PRIx32"\n", domid, reg, *r, regs->pc); break; @@ -518,7 +576,7 @@ static void do_cp15_32(struct cpu_user_r union hsr hsr) { struct hsr_cp32 cp32 = hsr.cp32; - uint32_t *r = ®s->r0 + cp32.reg; + uint32_t *r = select_user_reg(regs, cp32.reg); if ( !cp32.ccvalid ) { dprintk(XENLOG_ERR, "cp_15(32): need to handle invalid condition codes\n"); diff -r 7420b8f2fa51 -r 509e9737e241 xen/arch/arm/vgic.c --- a/xen/arch/arm/vgic.c Thu Dec 20 11:53:07 2012 +0000 +++ b/xen/arch/arm/vgic.c Thu Dec 20 11:53:08 2012 +0000 @@ -160,7 +160,7 @@ static int vgic_distr_mmio_read(struct v { struct hsr_dabt dabt = info->dabt; struct cpu_user_regs *regs = guest_cpu_user_regs(); - uint32_t *r = ®s->r0 + dabt.reg; + uint32_t *r = select_user_reg(regs, dabt.reg); struct vgic_irq_rank *rank; int offset = (int)(info->gpa - VGIC_DISTR_BASE_ADDRESS); int gicd_reg = REG(offset); @@ -372,7 +372,7 @@ static int vgic_distr_mmio_write(struct { struct hsr_dabt dabt = info->dabt; struct cpu_user_regs *regs = guest_cpu_user_regs(); - uint32_t *r = ®s->r0 + dabt.reg; + uint32_t *r = select_user_reg(regs, dabt.reg); struct vgic_irq_rank *rank; int offset = (int)(info->gpa - VGIC_DISTR_BASE_ADDRESS); int gicd_reg = REG(offset); diff -r 7420b8f2fa51 -r 509e9737e241 xen/arch/arm/vpl011.c --- a/xen/arch/arm/vpl011.c Thu Dec 20 11:53:07 2012 +0000 +++ b/xen/arch/arm/vpl011.c Thu Dec 20 11:53:08 2012 +0000 @@ -92,7 +92,7 @@ static int uart0_mmio_read(struct vcpu * { struct hsr_dabt dabt = info->dabt; struct cpu_user_regs *regs = guest_cpu_user_regs(); - uint32_t *r = ®s->r0 + dabt.reg; + uint32_t *r = select_user_reg(regs, dabt.reg); int offset = (int)(info->gpa - UART0_START); switch ( offset ) @@ -114,7 +114,7 @@ static int uart0_mmio_write(struct vcpu { struct hsr_dabt dabt = info->dabt; struct cpu_user_regs *regs = guest_cpu_user_regs(); - uint32_t *r = ®s->r0 + dabt.reg; + uint32_t *r = select_user_reg(regs, dabt.reg); int offset = (int)(info->gpa - UART0_START); switch ( offset ) diff -r 7420b8f2fa51 -r 509e9737e241 xen/arch/arm/vtimer.c --- a/xen/arch/arm/vtimer.c Thu Dec 20 11:53:07 2012 +0000 +++ b/xen/arch/arm/vtimer.c Thu Dec 20 11:53:08 2012 +0000 @@ -22,6 +22,7 @@ #include <xen/timer.h> #include <xen/sched.h> #include <asm/gic.h> +#include <asm/regs.h> extern s_time_t ticks_to_ns(uint64_t ticks); extern uint64_t ns_to_ticks(s_time_t ns); @@ -49,7 +50,7 @@ static int vtimer_emulate_32(struct cpu_ { struct vcpu *v = current; struct hsr_cp32 cp32 = hsr.cp32; - uint32_t *r = ®s->r0 + cp32.reg; + uint32_t *r = select_user_reg(regs, cp32.reg); s_time_t now; switch ( hsr.bits & HSR_CP32_REGS_MASK ) @@ -101,8 +102,8 @@ static int vtimer_emulate_64(struct cpu_ { struct vcpu *v = current; struct hsr_cp64 cp64 = hsr.cp64; - uint32_t *r1 = ®s->r0 + cp64.reg1; - uint32_t *r2 = ®s->r0 + cp64.reg2; + uint32_t *r1 = select_user_reg(regs, cp64.reg1); + uint32_t *r2 = select_user_reg(regs, cp64.reg2); uint64_t ticks; s_time_t now; diff -r 7420b8f2fa51 -r 509e9737e241 xen/include/asm-arm/regs.h --- a/xen/include/asm-arm/regs.h Thu Dec 20 11:53:07 2012 +0000 +++ b/xen/include/asm-arm/regs.h Thu Dec 20 11:53:08 2012 +0000 @@ -30,6 +30,12 @@ #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 uint32_t *select_user_reg(struct cpu_user_regs *regs, int reg); + #endif /* __ARM_REGS_H__ */ /* * Local variables: _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |