From nobody Fri May 3 04:09:33 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1529500401537892.3862716513561; Wed, 20 Jun 2018 06:13:21 -0700 (PDT) Received: from localhost ([::1]:49560 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fVcvI-00006t-Jb for importer@patchew.org; Wed, 20 Jun 2018 09:13:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50365) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fVcol-0003Ms-U6 for qemu-devel@nongnu.org; Wed, 20 Jun 2018 09:06:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fVcoj-00052f-V0 for qemu-devel@nongnu.org; Wed, 20 Jun 2018 09:06:35 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:42842) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fVcof-0004vT-Ig; Wed, 20 Jun 2018 09:06:29 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVcoX-0001Vm-8P; Wed, 20 Jun 2018 14:06:21 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Wed, 20 Jun 2018 14:06:17 +0100 Message-Id: <20180620130619.11362-2-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620130619.11362-1-peter.maydell@linaro.org> References: <20180620130619.11362-1-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 1/3] tcg: Support MMU protection regions smaller than TARGET_PAGE_SIZE X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , Richard Henderson , patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add support for MMU protection regions that are smaller than TARGET_PAGE_SIZE. We do this by marking the TLB entry for those pages with a flag TLB_RECHECK. This flag causes us to always take the slow-path for accesses. In the slow path we can then special case them to always call tlb_fill() again, so we have the correct information for the exact address being accessed. This change allows us to handle reading and writing from small regions; we cannot deal with execution from the small region. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- accel/tcg/softmmu_template.h | 24 ++++--- include/exec/cpu-all.h | 5 +- accel/tcg/cputlb.c | 131 +++++++++++++++++++++++++++++------ 3 files changed, 130 insertions(+), 30 deletions(-) diff --git a/accel/tcg/softmmu_template.h b/accel/tcg/softmmu_template.h index 239ea6692b4..c47591c9709 100644 --- a/accel/tcg/softmmu_template.h +++ b/accel/tcg/softmmu_template.h @@ -98,10 +98,12 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env, size_t mmu_idx, size_t index, target_ulong addr, - uintptr_t retaddr) + uintptr_t retaddr, + bool recheck) { CPUIOTLBEntry *iotlbentry =3D &env->iotlb[mmu_idx][index]; - return io_readx(env, iotlbentry, mmu_idx, addr, retaddr, DATA_SIZE); + return io_readx(env, iotlbentry, mmu_idx, addr, retaddr, recheck, + DATA_SIZE); } #endif =20 @@ -138,7 +140,8 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_u= long addr, =20 /* ??? Note that the io helpers always read data in the target byte ordering. We should push the LE/BE request down into io. = */ - res =3D glue(io_read, SUFFIX)(env, mmu_idx, index, addr, retaddr); + res =3D glue(io_read, SUFFIX)(env, mmu_idx, index, addr, retaddr, + tlb_addr & TLB_RECHECK); res =3D TGT_LE(res); return res; } @@ -205,7 +208,8 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_u= long addr, =20 /* ??? Note that the io helpers always read data in the target byte ordering. We should push the LE/BE request down into io. = */ - res =3D glue(io_read, SUFFIX)(env, mmu_idx, index, addr, retaddr); + res =3D glue(io_read, SUFFIX)(env, mmu_idx, index, addr, retaddr, + tlb_addr & TLB_RECHECK); res =3D TGT_BE(res); return res; } @@ -259,10 +263,12 @@ static inline void glue(io_write, SUFFIX)(CPUArchStat= e *env, size_t mmu_idx, size_t index, DATA_TYPE val, target_ulong addr, - uintptr_t retaddr) + uintptr_t retaddr, + bool recheck) { CPUIOTLBEntry *iotlbentry =3D &env->iotlb[mmu_idx][index]; - return io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr, DATA_SI= ZE); + return io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr, + recheck, DATA_SIZE); } =20 void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, @@ -298,7 +304,8 @@ void helper_le_st_name(CPUArchState *env, target_ulong = addr, DATA_TYPE val, /* ??? Note that the io helpers always read data in the target byte ordering. We should push the LE/BE request down into io. = */ val =3D TGT_LE(val); - glue(io_write, SUFFIX)(env, mmu_idx, index, val, addr, retaddr); + glue(io_write, SUFFIX)(env, mmu_idx, index, val, addr, + retaddr, tlb_addr & TLB_RECHECK); return; } =20 @@ -375,7 +382,8 @@ void helper_be_st_name(CPUArchState *env, target_ulong = addr, DATA_TYPE val, /* ??? Note that the io helpers always read data in the target byte ordering. We should push the LE/BE request down into io. = */ val =3D TGT_BE(val); - glue(io_write, SUFFIX)(env, mmu_idx, index, val, addr, retaddr); + glue(io_write, SUFFIX)(env, mmu_idx, index, val, addr, retaddr, + tlb_addr & TLB_RECHECK); return; } =20 diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 7fa726b8e36..7338f57062f 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -330,11 +330,14 @@ CPUArchState *cpu_copy(CPUArchState *env); #define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS - 2)) /* Set if TLB entry is an IO callback. */ #define TLB_MMIO (1 << (TARGET_PAGE_BITS - 3)) +/* Set if TLB entry must have MMU lookup repeated for every access */ +#define TLB_RECHECK (1 << (TARGET_PAGE_BITS - 4)) =20 /* Use this mask to check interception with an alignment mask * in a TCG backend. */ -#define TLB_FLAGS_MASK (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO) +#define TLB_FLAGS_MASK (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \ + | TLB_RECHECK) =20 void dump_exec_info(FILE *f, fprintf_function cpu_fprintf); void dump_opcount_info(FILE *f, fprintf_function cpu_fprintf); diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 0a721bb9c40..d893452295f 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -621,27 +621,42 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ul= ong vaddr, target_ulong code_address; uintptr_t addend; CPUTLBEntry *te, *tv, tn; - hwaddr iotlb, xlat, sz; + hwaddr iotlb, xlat, sz, paddr_page; + target_ulong vaddr_page; unsigned vidx =3D env->vtlb_index++ % CPU_VTLB_SIZE; int asidx =3D cpu_asidx_from_attrs(cpu, attrs); =20 assert_cpu_is_self(cpu); - assert(size >=3D TARGET_PAGE_SIZE); - if (size !=3D TARGET_PAGE_SIZE) { - tlb_add_large_page(env, vaddr, size); - } =20 - sz =3D size; - section =3D address_space_translate_for_iotlb(cpu, asidx, paddr, &xlat= , &sz, - attrs, &prot); + if (size < TARGET_PAGE_SIZE) { + sz =3D TARGET_PAGE_SIZE; + } else { + if (size > TARGET_PAGE_SIZE) { + tlb_add_large_page(env, vaddr, size); + } + sz =3D size; + } + vaddr_page =3D vaddr & TARGET_PAGE_MASK; + paddr_page =3D paddr & TARGET_PAGE_MASK; + + section =3D address_space_translate_for_iotlb(cpu, asidx, paddr_page, + &xlat, &sz, attrs, &prot); assert(sz >=3D TARGET_PAGE_SIZE); =20 tlb_debug("vaddr=3D" TARGET_FMT_lx " paddr=3D0x" TARGET_FMT_plx " prot=3D%x idx=3D%d\n", vaddr, paddr, prot, mmu_idx); =20 - address =3D vaddr; - if (!memory_region_is_ram(section->mr) && !memory_region_is_romd(secti= on->mr)) { + address =3D vaddr_page; + if (size < TARGET_PAGE_SIZE) { + /* + * Slow-path the TLB entries; we will repeat the MMU check and TLB + * fill on every access. + */ + address |=3D TLB_RECHECK; + } + if (!memory_region_is_ram(section->mr) && + !memory_region_is_romd(section->mr)) { /* IO memory case */ address |=3D TLB_MMIO; addend =3D 0; @@ -651,10 +666,10 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ul= ong vaddr, } =20 code_address =3D address; - iotlb =3D memory_region_section_get_iotlb(cpu, section, vaddr, paddr, = xlat, - prot, &address); + iotlb =3D memory_region_section_get_iotlb(cpu, section, vaddr_page, + paddr_page, xlat, prot, &addre= ss); =20 - index =3D (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + index =3D (vaddr_page >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); te =3D &env->tlb_table[mmu_idx][index]; /* do not discard the translation in te, evict it into a victim tlb */ tv =3D &env->tlb_v_table[mmu_idx][vidx]; @@ -670,18 +685,18 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ul= ong vaddr, * TARGET_PAGE_BITS, and either * + the ram_addr_t of the page base of the target RAM (if NOTDIRTY o= r ROM) * + the offset within section->mr of the page base (otherwise) - * We subtract the vaddr (which is page aligned and thus won't + * We subtract the vaddr_page (which is page aligned and thus won't * disturb the low bits) to give an offset which can be added to the * (non-page-aligned) vaddr of the eventual memory access to get * the MemoryRegion offset for the access. Note that the vaddr we * subtract here is that of the page base, and not the same as the * vaddr we add back in io_readx()/io_writex()/get_page_addr_code(). */ - env->iotlb[mmu_idx][index].addr =3D iotlb - vaddr; + env->iotlb[mmu_idx][index].addr =3D iotlb - vaddr_page; env->iotlb[mmu_idx][index].attrs =3D attrs; =20 /* Now calculate the new entry */ - tn.addend =3D addend - vaddr; + tn.addend =3D addend - vaddr_page; if (prot & PAGE_READ) { tn.addr_read =3D address; } else { @@ -702,7 +717,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulon= g vaddr, tn.addr_write =3D address | TLB_MMIO; } else if (memory_region_is_ram(section->mr) && cpu_physical_memory_is_clean( - memory_region_get_ram_addr(section->mr) + xlat)) { + memory_region_get_ram_addr(section->mr) + xlat)) { tn.addr_write =3D address | TLB_NOTDIRTY; } else { tn.addr_write =3D address; @@ -775,7 +790,8 @@ static inline ram_addr_t qemu_ram_addr_from_host_nofail= (void *ptr) =20 static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, int mmu_idx, - target_ulong addr, uintptr_t retaddr, int size) + target_ulong addr, uintptr_t retaddr, + bool recheck, int size) { CPUState *cpu =3D ENV_GET_CPU(env); hwaddr mr_offset; @@ -785,6 +801,29 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEn= try *iotlbentry, bool locked =3D false; MemTxResult r; =20 + if (recheck) { + /* + * This is a TLB_RECHECK access, where the MMU protection + * covers a smaller range than a target page, and we must + * repeat the MMU check here. This tlb_fill() call might + * longjump out if this access should cause a guest exception. + */ + int index; + target_ulong tlb_addr; + + tlb_fill(cpu, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr); + + index =3D (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_addr =3D env->tlb_table[mmu_idx][index].addr_read; + if (!(tlb_addr & ~(TARGET_PAGE_MASK | TLB_RECHECK))) { + /* RAM access */ + uintptr_t haddr =3D addr + env->tlb_table[mmu_idx][index].adde= nd; + + return ldn_p((void *)haddr, size); + } + /* Fall through for handling IO accesses */ + } + section =3D iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); mr =3D section->mr; mr_offset =3D (iotlbentry->addr & TARGET_PAGE_MASK) + addr; @@ -819,7 +858,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEnt= ry *iotlbentry, static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, int mmu_idx, uint64_t val, target_ulong addr, - uintptr_t retaddr, int size) + uintptr_t retaddr, bool recheck, int size) { CPUState *cpu =3D ENV_GET_CPU(env); hwaddr mr_offset; @@ -828,6 +867,30 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry= *iotlbentry, bool locked =3D false; MemTxResult r; =20 + if (recheck) { + /* + * This is a TLB_RECHECK access, where the MMU protection + * covers a smaller range than a target page, and we must + * repeat the MMU check here. This tlb_fill() call might + * longjump out if this access should cause a guest exception. + */ + int index; + target_ulong tlb_addr; + + tlb_fill(cpu, addr, size, MMU_DATA_STORE, mmu_idx, retaddr); + + index =3D (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_addr =3D env->tlb_table[mmu_idx][index].addr_write; + if (!(tlb_addr & ~(TARGET_PAGE_MASK | TLB_RECHECK))) { + /* RAM access */ + uintptr_t haddr =3D addr + env->tlb_table[mmu_idx][index].adde= nd; + + stn_p((void *)haddr, size, val); + return; + } + /* Fall through for handling IO accesses */ + } + section =3D iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); mr =3D section->mr; mr_offset =3D (iotlbentry->addr & TARGET_PAGE_MASK) + addr; @@ -911,6 +974,32 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, t= arget_ulong addr) tlb_fill(ENV_GET_CPU(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0= ); } } + + if (unlikely(env->tlb_table[mmu_idx][index].addr_code & TLB_RECHECK)) { + /* + * This is a TLB_RECHECK access, where the MMU protection + * covers a smaller range than a target page, and we must + * repeat the MMU check here. This tlb_fill() call might + * longjump out if this access should cause a guest exception. + */ + int index; + target_ulong tlb_addr; + + tlb_fill(cpu, addr, 0, MMU_INST_FETCH, mmu_idx, 0); + + index =3D (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_addr =3D env->tlb_table[mmu_idx][index].addr_code; + if (!(tlb_addr & ~(TARGET_PAGE_MASK | TLB_RECHECK))) { + /* RAM access. We can't handle this, so for now just stop */ + cpu_abort(cpu, "Unable to handle guest executing from RAM with= in " + "a small MPU region at 0x" TARGET_FMT_lx, addr); + } + /* + * Fall through to handle IO accesses (which will almost certainly + * also result in failure) + */ + } + iotlbentry =3D &env->iotlb[mmu_idx][index]; section =3D iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); mr =3D section->mr; @@ -1019,8 +1108,8 @@ static void *atomic_mmu_lookup(CPUArchState *env, tar= get_ulong addr, tlb_addr =3D tlbe->addr_write & ~TLB_INVALID_MASK; } =20 - /* Notice an IO access */ - if (unlikely(tlb_addr & TLB_MMIO)) { + /* Notice an IO access or a needs-MMU-lookup access */ + if (unlikely(tlb_addr & (TLB_MMIO | TLB_RECHECK))) { /* There's really nothing that can be done to support this apart from stop-the-world. */ goto stop_the_world; --=20 2.17.1 From nobody Fri May 3 04:09:33 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1529500971294733.8272786593035; Wed, 20 Jun 2018 06:22:51 -0700 (PDT) Received: from localhost ([::1]:49634 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fVd4T-0000oZ-7u for importer@patchew.org; Wed, 20 Jun 2018 09:22:49 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55061) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fVd2P-000800-7X for qemu-devel@nongnu.org; Wed, 20 Jun 2018 09:20:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fVd2N-0002mq-S5 for qemu-devel@nongnu.org; Wed, 20 Jun 2018 09:20:41 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:42860) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fVd2K-0002jn-Q9; Wed, 20 Jun 2018 09:20:36 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVcoX-0001Vz-W7; Wed, 20 Jun 2018 14:06:21 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Wed, 20 Jun 2018 14:06:18 +0100 Message-Id: <20180620130619.11362-3-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620130619.11362-1-peter.maydell@linaro.org> References: <20180620130619.11362-1-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 2/3] target/arm: Set page (region) size in get_phys_addr_pmsav7() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , Richard Henderson , patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We want to handle small MPU region sizes for ARMv7M. To do this, make get_phys_addr_pmsav7() set the page size to the region size if it is less that TARGET_PAGE_SIZE, rather than working only in TARGET_PAGE_SIZE chunks. Since the core TCG code con't handle execution from small MPU regions, we strip the exec permission from them so that any execution attempts will cause an MPU exception, rather than allowing it to end up with a cpu_abort() in get_page_addr_code(). (The previous code's intention was to make any small page be treated as having no permissions, but unfortunately errors in the implementation meant that it didn't behave that way. It's possible that some binaries using small regions were accidentally working with our old behaviour and won't now.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 1248d84e6fa..a7edeb66633 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9596,6 +9596,7 @@ static inline bool m_is_system_region(CPUARMState *en= v, uint32_t address) static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_= idx, hwaddr *phys_ptr, int *prot, + target_ulong *page_size, ARMMMUFaultInfo *fi) { ARMCPU *cpu =3D arm_env_get_cpu(env); @@ -9603,6 +9604,7 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, ui= nt32_t address, bool is_user =3D regime_is_user(env, mmu_idx); =20 *phys_ptr =3D address; + *page_size =3D TARGET_PAGE_SIZE; *prot =3D 0; =20 if (regime_translation_disabled(env, mmu_idx) || @@ -9675,16 +9677,12 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, = uint32_t address, rsize++; } } - if (rsize < TARGET_PAGE_BITS) { - qemu_log_mask(LOG_UNIMP, - "DRSR[%d]: No support for MPU (sub)region si= ze of" - " %" PRIu32 " bytes. Minimum is %d.\n", - n, (1 << rsize), TARGET_PAGE_SIZE); - continue; - } if (srdis) { continue; } + if (rsize < TARGET_PAGE_BITS) { + *page_size =3D 1 << rsize; + } break; } =20 @@ -9765,6 +9763,17 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, u= int32_t address, =20 fi->type =3D ARMFault_Permission; fi->level =3D 1; + /* + * Core QEMU code can't handle execution from small pages yet, so + * don't try it. This way we'll get an MPU exception, rather than + * eventually causing QEMU to exit in get_page_addr_code(). + */ + if (*page_size < TARGET_PAGE_SIZE && (*prot & PAGE_EXEC)) { + qemu_log_mask(LOG_UNIMP, + "MPU: No support for execution from regions " + "smaller than 1K\n"); + *prot &=3D ~PAGE_EXEC; + } return !(*prot & (1 << access_type)); } =20 @@ -10334,7 +10343,7 @@ static bool get_phys_addr(CPUARMState *env, target_= ulong address, } else if (arm_feature(env, ARM_FEATURE_V7)) { /* PMSAv7 */ ret =3D get_phys_addr_pmsav7(env, address, access_type, mmu_id= x, - phys_ptr, prot, fi); + phys_ptr, prot, page_size, fi); } else { /* Pre-v7 MPU */ ret =3D get_phys_addr_pmsav5(env, address, access_type, mmu_id= x, @@ -10396,9 +10405,15 @@ bool arm_tlb_fill(CPUState *cs, vaddr address, core_to_arm_mmu_idx(env, mmu_idx), &phys_addr, &attrs, &prot, &page_size, fi, NULL); if (!ret) { - /* Map a single [sub]page. */ - phys_addr &=3D TARGET_PAGE_MASK; - address &=3D TARGET_PAGE_MASK; + /* + * Map a single [sub]page. Regions smaller than our declared + * target page size are handled specially, so for those we + * pass in the exact addresses. + */ + if (page_size >=3D TARGET_PAGE_SIZE) { + phys_addr &=3D TARGET_PAGE_MASK; + address &=3D TARGET_PAGE_MASK; + } tlb_set_page_with_attrs(cs, address, phys_addr, attrs, prot, mmu_idx, page_size); return 0; --=20 2.17.1 From nobody Fri May 3 04:09:33 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1529500272654456.0100304290564; Wed, 20 Jun 2018 06:11:12 -0700 (PDT) Received: from localhost ([::1]:49539 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fVctD-0006mY-Mr for importer@patchew.org; Wed, 20 Jun 2018 09:11:11 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50368) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fVcom-0003Mw-76 for qemu-devel@nongnu.org; Wed, 20 Jun 2018 09:06:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fVcok-000530-G4 for qemu-devel@nongnu.org; Wed, 20 Jun 2018 09:06:36 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:42842) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fVcog-0004vT-M9; Wed, 20 Jun 2018 09:06:30 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVcoY-0001WK-SU; Wed, 20 Jun 2018 14:06:22 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Wed, 20 Jun 2018 14:06:19 +0100 Message-Id: <20180620130619.11362-4-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620130619.11362-1-peter.maydell@linaro.org> References: <20180620130619.11362-1-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 3/3] target/arm: Handle small regions in get_phys_addr_pmsav8() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , Richard Henderson , patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Allow ARMv8M to handle small MPU and SAU region sizes, by making get_phys_add_pmsav8() set the page size to the 1 if the MPU or SAU region covers less than a TARGET_PAGE_SIZE. We choose to use a size of 1 because it makes no difference to the core code, and avoids having to track both the base and limit for SAU and MPU and then convert into an artificially restricted "page size" that the core code will then ignore. Since the core TCG code can't handle execution from small MPU regions, we strip the exec permission from them so that any execution attempts will cause an MPU exception, rather than allowing it to end up with a cpu_abort() in get_page_addr_code(). (The previous code's intention was to make any small page be treated as having no permissions, but unfortunately errors in the implementation meant that it didn't behave that way. It's possible that some binaries using small regions were accidentally working with our old behaviour and won't now.) We also retain an existing bug, where we ignored the possibility that the SAU region might not cover the entire page, in the case of executable regions. This is necessary because some currently-working guest code images rely on being able to execute from addresses which are covered by a page-sized MPU region but a smaller SAU region. We can remove this workaround if we ever support execution from small regions. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 78 ++++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index a7edeb66633..3c6a4c565b1 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -41,6 +41,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_u= long address, =20 /* Security attributes for an address, as returned by v8m_security_lookup.= */ typedef struct V8M_SAttributes { + bool subpage; /* true if these attrs don't cover the whole TARGET_PAGE= */ bool ns; bool nsc; uint8_t sregion; @@ -9804,6 +9805,8 @@ static void v8m_security_lookup(CPUARMState *env, uin= t32_t address, int r; bool idau_exempt =3D false, idau_ns =3D true, idau_nsc =3D true; int idau_region =3D IREGION_NOTVALID; + uint32_t addr_page_base =3D address & TARGET_PAGE_MASK; + uint32_t addr_page_limit =3D addr_page_base + (TARGET_PAGE_SIZE - 1); =20 if (cpu->idau) { IDAUInterfaceClass *iic =3D IDAU_INTERFACE_GET_CLASS(cpu->idau); @@ -9841,6 +9844,9 @@ static void v8m_security_lookup(CPUARMState *env, uin= t32_t address, uint32_t limit =3D env->sau.rlar[r] | 0x1f; =20 if (base <=3D address && limit >=3D address) { + if (base > addr_page_base || limit < addr_page_limit) { + sattrs->subpage =3D true; + } if (sattrs->srvalid) { /* If we hit in more than one region then we must = report * as Secure, not NS-Callable, with no valid region @@ -9880,13 +9886,16 @@ static void v8m_security_lookup(CPUARMState *env, u= int32_t address, static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, ARMMMUFaultInfo *fi, uint32_t *mr= egion) + int *prot, bool *is_subpage, + ARMMMUFaultInfo *fi, uint32_t *mregion) { /* Perform a PMSAv8 MPU lookup (without also doing the SAU check * that a full phys-to-virt translation does). * mregion is (if not NULL) set to the region number which matched, * or -1 if no region number is returned (MPU off, address did not * hit a region, address hit in multiple regions). + * We set is_subpage to true if the region hit doesn't cover the + * entire TARGET_PAGE the address is within. */ ARMCPU *cpu =3D arm_env_get_cpu(env); bool is_user =3D regime_is_user(env, mmu_idx); @@ -9894,7 +9903,10 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint= 32_t address, int n; int matchregion =3D -1; bool hit =3D false; + uint32_t addr_page_base =3D address & TARGET_PAGE_MASK; + uint32_t addr_page_limit =3D addr_page_base + (TARGET_PAGE_SIZE - 1); =20 + *is_subpage =3D false; *phys_ptr =3D address; *prot =3D 0; if (mregion) { @@ -9932,6 +9944,10 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint= 32_t address, continue; } =20 + if (base > addr_page_base || limit < addr_page_limit) { + *is_subpage =3D true; + } + if (hit) { /* Multiple regions match -- always a failure (unlike * PMSAv7 where highest-numbered-region wins) @@ -9943,23 +9959,6 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint= 32_t address, =20 matchregion =3D n; hit =3D true; - - if (base & ~TARGET_PAGE_MASK) { - qemu_log_mask(LOG_UNIMP, - "MPU_RBAR[%d]: No support for MPU region bas= e" - "address of 0x%" PRIx32 ". Minimum alignment= is " - "%d\n", - n, base, TARGET_PAGE_BITS); - continue; - } - if ((limit + 1) & ~TARGET_PAGE_MASK) { - qemu_log_mask(LOG_UNIMP, - "MPU_RBAR[%d]: No support for MPU region lim= it" - "address of 0x%" PRIx32 ". Minimum alignment= is " - "%d\n", - n, limit, TARGET_PAGE_BITS); - continue; - } } } =20 @@ -9995,6 +9994,18 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint= 32_t address, =20 fi->type =3D ARMFault_Permission; fi->level =3D 1; + /* + * Core QEMU code can't handle execution from small pages yet, so + * don't try it. This means any attempted execution will generate + * an MPU exception, rather than eventually causing QEMU to exit in + * get_page_addr_code(). + */ + if (*is_subpage && (*prot & PAGE_EXEC)) { + qemu_log_mask(LOG_UNIMP, + "MPU: No support for execution from regions " + "smaller than 1K\n"); + *prot &=3D ~PAGE_EXEC; + } return !(*prot & (1 << access_type)); } =20 @@ -10002,10 +10013,13 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, u= int32_t address, static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_= idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, ARMMMUFaultInfo *fi) + int *prot, target_ulong *page_size, + ARMMMUFaultInfo *fi) { uint32_t secure =3D regime_is_secure(env, mmu_idx); V8M_SAttributes sattrs =3D {}; + bool ret; + bool mpu_is_subpage; =20 if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { v8m_security_lookup(env, address, access_type, mmu_idx, &sattrs); @@ -10033,6 +10047,7 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, = uint32_t address, } else { fi->type =3D ARMFault_QEMU_SFault; } + *page_size =3D sattrs.subpage ? 1 : TARGET_PAGE_SIZE; *phys_ptr =3D address; *prot =3D 0; return true; @@ -10055,6 +10070,7 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, = uint32_t address, * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). */ fi->type =3D ARMFault_QEMU_SFault; + *page_size =3D sattrs.subpage ? 1 : TARGET_PAGE_SIZE; *phys_ptr =3D address; *prot =3D 0; return true; @@ -10062,8 +10078,22 @@ static bool get_phys_addr_pmsav8(CPUARMState *env,= uint32_t address, } } =20 - return pmsav8_mpu_lookup(env, address, access_type, mmu_idx, phys_ptr, - txattrs, prot, fi, NULL); + ret =3D pmsav8_mpu_lookup(env, address, access_type, mmu_idx, phys_ptr, + txattrs, prot, &mpu_is_subpage, fi, NULL); + /* + * TODO: this is a temporary hack to ignore the fact that the SAU regi= on + * is smaller than a page if this is an executable region. We never + * supported small MPU regions, but we did (accidentally) allow small + * SAU regions, and if we now made small SAU regions not be executable + * then this would break previously working guest code. We can't + * remove this until/unless we implement support for execution from + * small regions. + */ + if (*prot & PAGE_EXEC) { + sattrs.subpage =3D false; + } + *page_size =3D sattrs.subpage || mpu_is_subpage ? 1 : TARGET_PAGE_SIZE; + return ret; } =20 static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, @@ -10339,7 +10369,7 @@ static bool get_phys_addr(CPUARMState *env, target_= ulong address, if (arm_feature(env, ARM_FEATURE_V8)) { /* PMSAv8 */ ret =3D get_phys_addr_pmsav8(env, address, access_type, mmu_id= x, - phys_ptr, attrs, prot, fi); + phys_ptr, attrs, prot, page_size, f= i); } else if (arm_feature(env, ARM_FEATURE_V7)) { /* PMSAv7 */ ret =3D get_phys_addr_pmsav7(env, address, access_type, mmu_id= x, @@ -10757,6 +10787,7 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t = addr, uint32_t op) uint32_t mregion; bool targetpriv; bool targetsec =3D env->v7m.secure; + bool is_subpage; =20 /* Work out what the security state and privilege level we're * interested in is... @@ -10786,7 +10817,8 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t = addr, uint32_t op) if (arm_current_el(env) !=3D 0 || alt) { /* We can ignore the return value as prot is always set */ pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, - &phys_addr, &attrs, &prot, &fi, &mregion); + &phys_addr, &attrs, &prot, &is_subpage, + &fi, &mregion); if (mregion =3D=3D -1) { mrvalid =3D false; mregion =3D 0; --=20 2.17.1