target-arm queue:

* fix handling of execute-never bits in page table walks
  * tell kernel to initialize KVM GIC in realize function
  * fix handling of STM (user) with r15 in register list
  * ignore low bit of PC in M-profile exception return
  * fix linux-user get/set_tls syscalls on CPUs with TZ
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJVBs7oAAoJEDwlJe0UNgzeyFMP/Re3884RXnk5Mc9+57mwJOCh
 NjVOiNskvFWwSxmOBWK0Zestr1MWp9zsnr27dj6wu9EqIlSTLbknl8ttnHnHdSrj
 C21mD3H/1DXmQyIysHa3g61BQAuOU9UGgG8PSgK6z8IFM7x0+ntcyEzR8BL2qjHU
 9YyvENrmbbVaY8/YfvAdqs0d4mp6RVwzPrb/t35CkX0nI2rgGX+wNTsqH/UCIpNb
 eD1YeSaUJnaxODhZlZUcTR/D7wAzUmPtp7Le5qwMSH4jm6LTPSAQ2B5WFAfLodGO
 Tpb8sXUAAJymnLOjPchYACEH/tS+yLTN40aTYXgq/sc7b6uCwRvEfZzVjJ3cn6Cf
 ZEtP2ZwevzS2Uy17tfYs6fxgAdh07dB/lUif5lCg5tvlYa531HhH1uq0QplSxhDR
 /uXvl8Q/tAVXLnWDh0uydZ7NuqEv7P+25feL7sAT5I/VUWgYCs3RhwE1lU1JMwih
 yMKipD93bg+z7PqtOW/GHjIKyai7yTKhaVNS+BGZaqOIfqWSTFJ0NPFK0SK67kou
 +38OMHtORaAnKGFbkBnJQGVjHTgzWPol9r1KuVgsa5zZvhDtNGNhk0A0xLil/Qkh
 jwj1O5y+xtYI+JXIDucbcEySwL/RpzEOSKbd7OTsmTVNqhKqoomKUy5e0w/zG1v6
 RFuUdUzabLTzT3uqwL+I
 =uK1h
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150316' into staging

target-arm queue:
 * fix handling of execute-never bits in page table walks
 * tell kernel to initialize KVM GIC in realize function
 * fix handling of STM (user) with r15 in register list
 * ignore low bit of PC in M-profile exception return
 * fix linux-user get/set_tls syscalls on CPUs with TZ

# gpg: Signature made Mon Mar 16 12:39:04 2015 GMT using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20150316:
  linux-user: Access correct register for get/set_tls syscalls on ARM TZ CPUs
  target-arm: Ignore low bit of PC in M-profile exception return
  target-arm: Fix handling of STM (user) with r15 in register list
  hw/intc/arm_gic: Initialize the vgic in the realize function
  target-arm: get_phys_addr_lpae: more xn control
  target-arm: fix get_phys_addr_v6/SCTLR_AFE access check
  target-arm: convert check_ap to ap_to_rw_prot

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-03-16 13:56:10 +00:00
commit dcf848c478
5 changed files with 197 additions and 67 deletions

View file

@ -573,6 +573,13 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, 0, &numirqs, 1);
}
/* Tell the kernel to complete VGIC initialization now */
if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_CTRL,
KVM_DEV_ARM_VGIC_CTRL_INIT)) {
kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CTRL,
KVM_DEV_ARM_VGIC_CTRL_INIT, 0, 0, 1);
}
/* Distributor */
memory_region_init_reservation(&s->iomem, OBJECT(s),
"kvm-gic_dist", 0x1000);

View file

@ -29,7 +29,20 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls)
{
env->cp15.tpidrro_el[0] = newtls;
if (access_secure_reg(env)) {
env->cp15.tpidruro_s = newtls;
} else {
env->cp15.tpidrro_el[0] = newtls;
}
}
static inline target_ulong cpu_get_tls(CPUARMState *env)
{
if (access_secure_reg(env)) {
return env->cp15.tpidruro_s;
} else {
return env->cp15.tpidrro_el[0];
}
}
#endif

View file

@ -566,7 +566,7 @@ do_kernel_trap(CPUARMState *env)
end_exclusive();
break;
case 0xffff0fe0: /* __kernel_get_tls */
env->regs[0] = env->cp15.tpidrro_el[0];
env->regs[0] = cpu_get_tls(env);
break;
case 0xffff0f60: /* __kernel_cmpxchg64 */
arm_kernel_cmpxchg64_helper(env);

View file

@ -4334,6 +4334,16 @@ static void do_v7m_exception_exit(CPUARMState *env)
env->regs[12] = v7m_pop(env);
env->regs[14] = v7m_pop(env);
env->regs[15] = v7m_pop(env);
if (env->regs[15] & 1) {
qemu_log_mask(LOG_GUEST_ERROR,
"M profile return from interrupt with misaligned "
"PC is UNPREDICTABLE\n");
/* Actual hardware seems to ignore the lsbit, and there are several
* RTOSes out there which incorrectly assume the r15 in the stack
* frame should be a Thumb-style "lsbit indicates ARM/Thumb" value.
*/
env->regs[15] &= ~1U;
}
xpsr = v7m_pop(env);
xpsr_write(env, xpsr, 0xfffffdff);
/* Undo stack alignment. */
@ -4903,34 +4913,28 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
}
}
/* Check section/page access permissions.
Returns the page protection flags, or zero if the access is not
permitted. */
static inline int check_ap(CPUARMState *env, ARMMMUIdx mmu_idx,
int ap, int domain_prot,
int access_type)
/* Translate section/page access permissions to page
* R/W protection flags
*
* @env: CPUARMState
* @mmu_idx: MMU index indicating required translation regime
* @ap: The 3-bit access permissions (AP[2:0])
* @domain_prot: The 2-bit domain access permissions
*/
static inline int ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx,
int ap, int domain_prot)
{
int prot_ro;
bool is_user = regime_is_user(env, mmu_idx);
if (domain_prot == 3) {
return PAGE_READ | PAGE_WRITE;
}
if (access_type == 1) {
prot_ro = 0;
} else {
prot_ro = PAGE_READ;
}
switch (ap) {
case 0:
if (arm_feature(env, ARM_FEATURE_V7)) {
return 0;
}
if (access_type == 1) {
return 0;
}
switch (regime_sctlr(env, mmu_idx) & (SCTLR_S | SCTLR_R)) {
case SCTLR_S:
return is_user ? 0 : PAGE_READ;
@ -4943,7 +4947,7 @@ static inline int check_ap(CPUARMState *env, ARMMMUIdx mmu_idx,
return is_user ? 0 : PAGE_READ | PAGE_WRITE;
case 2:
if (is_user) {
return prot_ro;
return PAGE_READ;
} else {
return PAGE_READ | PAGE_WRITE;
}
@ -4952,19 +4956,128 @@ static inline int check_ap(CPUARMState *env, ARMMMUIdx mmu_idx,
case 4: /* Reserved. */
return 0;
case 5:
return is_user ? 0 : prot_ro;
return is_user ? 0 : PAGE_READ;
case 6:
return prot_ro;
return PAGE_READ;
case 7:
if (!arm_feature(env, ARM_FEATURE_V6K)) {
return 0;
}
return prot_ro;
return PAGE_READ;
default:
abort();
g_assert_not_reached();
}
}
/* Translate section/page access permissions to page
* R/W protection flags.
*
* @ap: The 2-bit simple AP (AP[2:1])
* @is_user: TRUE if accessing from PL0
*/
static inline int simple_ap_to_rw_prot_is_user(int ap, bool is_user)
{
switch (ap) {
case 0:
return is_user ? 0 : PAGE_READ | PAGE_WRITE;
case 1:
return PAGE_READ | PAGE_WRITE;
case 2:
return is_user ? 0 : PAGE_READ;
case 3:
return PAGE_READ;
default:
g_assert_not_reached();
}
}
static inline int
simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap)
{
return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx));
}
/* Translate section/page access permissions to protection flags
*
* @env: CPUARMState
* @mmu_idx: MMU index indicating required translation regime
* @is_aa64: TRUE if AArch64
* @ap: The 2-bit simple AP (AP[2:1])
* @ns: NS (non-secure) bit
* @xn: XN (execute-never) bit
* @pxn: PXN (privileged execute-never) bit
*/
static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64,
int ap, int ns, int xn, int pxn)
{
bool is_user = regime_is_user(env, mmu_idx);
int prot_rw, user_rw;
bool have_wxn;
int wxn = 0;
assert(mmu_idx != ARMMMUIdx_S2NS);
user_rw = simple_ap_to_rw_prot_is_user(ap, true);
if (is_user) {
prot_rw = user_rw;
} else {
prot_rw = simple_ap_to_rw_prot_is_user(ap, false);
}
if (ns && arm_is_secure(env) && (env->cp15.scr_el3 & SCR_SIF)) {
return prot_rw;
}
/* TODO have_wxn should be replaced with
* ARM_FEATURE_V8 || (ARM_FEATURE_V7 && ARM_FEATURE_EL2)
* when ARM_FEATURE_EL2 starts getting set. For now we assume all LPAE
* compatible processors have EL2, which is required for [U]WXN.
*/
have_wxn = arm_feature(env, ARM_FEATURE_LPAE);
if (have_wxn) {
wxn = regime_sctlr(env, mmu_idx) & SCTLR_WXN;
}
if (is_aa64) {
switch (regime_el(env, mmu_idx)) {
case 1:
if (!is_user) {
xn = pxn || (user_rw & PAGE_WRITE);
}
break;
case 2:
case 3:
break;
}
} else if (arm_feature(env, ARM_FEATURE_V7)) {
switch (regime_el(env, mmu_idx)) {
case 1:
case 3:
if (is_user) {
xn = xn || !(user_rw & PAGE_READ);
} else {
int uwxn = 0;
if (have_wxn) {
uwxn = regime_sctlr(env, mmu_idx) & SCTLR_UWXN;
}
xn = xn || !(prot_rw & PAGE_READ) || pxn ||
(uwxn && (user_rw & PAGE_WRITE));
}
break;
case 2:
break;
}
} else {
xn = wxn = 0;
}
if (xn || (wxn && (prot_rw & PAGE_WRITE))) {
return prot_rw;
}
return prot_rw | PAGE_EXEC;
}
static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx,
uint32_t *table, uint32_t address)
{
@ -5083,12 +5196,12 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type,
}
code = 15;
}
*prot = check_ap(env, mmu_idx, ap, domain_prot, access_type);
if (!*prot) {
*prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot);
*prot |= *prot ? PAGE_EXEC : 0;
if (!(*prot & (1 << access_type))) {
/* Access permission fault. */
goto do_fault;
}
*prot |= PAGE_EXEC;
*phys_ptr = phys_addr;
return 0;
do_fault:
@ -5197,21 +5310,25 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
if (xn && access_type == 2)
goto do_fault;
/* The simplified model uses AP[0] as an access control bit. */
if ((regime_sctlr(env, mmu_idx) & SCTLR_AFE)
&& (ap & 1) == 0) {
/* Access flag fault. */
code = (code == 15) ? 6 : 3;
goto do_fault;
if (arm_feature(env, ARM_FEATURE_V6K) &&
(regime_sctlr(env, mmu_idx) & SCTLR_AFE)) {
/* The simplified model uses AP[0] as an access control bit. */
if ((ap & 1) == 0) {
/* Access flag fault. */
code = (code == 15) ? 6 : 3;
goto do_fault;
}
*prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1);
} else {
*prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot);
}
*prot = check_ap(env, mmu_idx, ap, domain_prot, access_type);
if (!*prot) {
if (*prot && !xn) {
*prot |= PAGE_EXEC;
}
if (!(*prot & (1 << access_type))) {
/* Access permission fault. */
goto do_fault;
}
if (!xn) {
*prot |= PAGE_EXEC;
}
}
*phys_ptr = phys_addr;
return 0;
@ -5249,8 +5366,8 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
int32_t granule_sz = 9;
int32_t va_size = 32;
int32_t tbi = 0;
bool is_user;
TCR *tcr = regime_tcr(env, mmu_idx);
int ap, ns, xn, pxn;
/* TODO:
* This code assumes we're either a 64-bit EL1 or a 32-bit PL1;
@ -5411,7 +5528,7 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
if (extract32(tableattrs, 2, 1)) {
attrs &= ~(1 << 4);
}
/* Since we're always in the Non-secure state, NSTable is ignored. */
attrs |= extract32(tableattrs, 4, 1) << 3; /* NS */
break;
}
/* Here descaddr is the final physical address, and attributes
@ -5422,31 +5539,18 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
/* Access flag */
goto do_fault;
}
ap = extract32(attrs, 4, 2);
ns = extract32(attrs, 3, 1);
xn = extract32(attrs, 12, 1);
pxn = extract32(attrs, 11, 1);
*prot = get_S1prot(env, mmu_idx, va_size == 64, ap, ns, xn, pxn);
fault_type = permission_fault;
is_user = regime_is_user(env, mmu_idx);
if (is_user && !(attrs & (1 << 4))) {
/* Unprivileged access not enabled */
if (!(*prot & (1 << access_type))) {
goto do_fault;
}
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
if ((arm_feature(env, ARM_FEATURE_V8) && is_user && (attrs & (1 << 12))) ||
(!arm_feature(env, ARM_FEATURE_V8) && (attrs & (1 << 12))) ||
(!is_user && (attrs & (1 << 11)))) {
/* XN/UXN or PXN. Since we only implement EL0/EL1 we unconditionally
* treat XN/UXN as UXN for v8.
*/
if (access_type == 2) {
goto do_fault;
}
*prot &= ~PAGE_EXEC;
}
if (attrs & (1 << 5)) {
/* Write access forbidden */
if (access_type == 1) {
goto do_fault;
}
*prot &= ~PAGE_WRITE;
}
*phys_ptr = descaddr;
*page_size_ptr = page_size;

View file

@ -8859,17 +8859,23 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
case 0x08:
case 0x09:
{
int j, n, user, loaded_base;
int j, n, loaded_base;
bool exc_return = false;
bool is_load = extract32(insn, 20, 1);
bool user = false;
TCGv_i32 loaded_var;
/* load/store multiple words */
/* XXX: store correct base if write back */
user = 0;
if (insn & (1 << 22)) {
/* LDM (user), LDM (exception return) and STM (user) */
if (IS_USER(s))
goto illegal_op; /* only usable in supervisor mode */
if ((insn & (1 << 15)) == 0)
user = 1;
if (is_load && extract32(insn, 15, 1)) {
exc_return = true;
} else {
user = true;
}
}
rn = (insn >> 16) & 0xf;
addr = load_reg(s, rn);
@ -8903,7 +8909,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
j = 0;
for(i=0;i<16;i++) {
if (insn & (1 << i)) {
if (insn & (1 << 20)) {
if (is_load) {
/* load */
tmp = tcg_temp_new_i32();
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
@ -8968,7 +8974,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
if (loaded_base) {
store_reg(s, rn, loaded_var);
}
if ((insn & (1 << 22)) && !user) {
if (exc_return) {
/* Restore CPSR from SPSR. */
tmp = load_cpu_field(spsr);
gen_set_cpsr(tmp, CPSR_ERET_MASK);