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:
commit
dcf848c478
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user