From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:51747) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R0HUm-0001yF-Ch for qemu-devel@nongnu.org; Sun, 04 Sep 2011 14:32:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1R0HUi-0008T5-Q7 for qemu-devel@nongnu.org; Sun, 04 Sep 2011 14:32:40 -0400 Received: from mail-qy0-f173.google.com ([209.85.216.173]:38938) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R0HUi-0008T1-H6 for qemu-devel@nongnu.org; Sun, 04 Sep 2011 14:32:36 -0400 Received: by qyk31 with SMTP id 31so1559876qyk.4 for ; Sun, 04 Sep 2011 11:32:36 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <1314909960-31738-30-git-send-email-jcmvbkbc@gmail.com> References: <1314909960-31738-1-git-send-email-jcmvbkbc@gmail.com> <1314909960-31738-30-git-send-email-jcmvbkbc@gmail.com> From: Blue Swirl Date: Sun, 4 Sep 2011 18:32:16 +0000 Message-ID: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH v4 29/32] target-xtensa: implement memory protection options List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Max Filippov Cc: qemu-devel@nongnu.org On Thu, Sep 1, 2011 at 8:45 PM, Max Filippov wrote: > - TLB opcode group; > - region protection option (ISA, 4.6.3); > - region translation option (ISA, 4.6.4); > - MMU option (ISA, 4.6.5). > > Cache control attribute bits are not used by this implementation. > > Signed-off-by: Max Filippov > --- > =C2=A0target-xtensa/cpu.h =C2=A0 =C2=A0 =C2=A0 | =C2=A0 56 ++++++++- > =C2=A0target-xtensa/helper.c =C2=A0 =C2=A0| =C2=A0340 +++++++++++++++++++= +++++++++++++++++++++++++- > =C2=A0target-xtensa/helpers.h =C2=A0 | =C2=A0 =C2=A07 + > =C2=A0target-xtensa/op_helper.c | =C2=A0301 +++++++++++++++++++++++++++++= ++++++++++- > =C2=A0target-xtensa/translate.c | =C2=A0 91 ++++++++++++- > =C2=A05 files changed, 782 insertions(+), 13 deletions(-) > > diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h > index 93e17d1..05948f1 100644 > --- a/target-xtensa/cpu.h > +++ b/target-xtensa/cpu.h > @@ -114,6 +114,10 @@ enum { > =C2=A0 =C2=A0 SCOMPARE1 =3D 12, > =C2=A0 =C2=A0 WINDOW_BASE =3D 72, > =C2=A0 =C2=A0 WINDOW_START =3D 73, > + =C2=A0 =C2=A0PTEVADDR =3D 83, > + =C2=A0 =C2=A0RASID =3D 90, > + =C2=A0 =C2=A0ITLBCFG =3D 91, > + =C2=A0 =C2=A0DTLBCFG =3D 92, > =C2=A0 =C2=A0 EPC1 =3D 177, > =C2=A0 =C2=A0 DEPC =3D 192, > =C2=A0 =C2=A0 EPS2 =3D 194, > @@ -154,6 +158,9 @@ enum { > =C2=A0#define MAX_NLEVEL 6 > =C2=A0#define MAX_NNMI 1 > =C2=A0#define MAX_NCCOMPARE 3 > +#define MAX_TLB_WAY_SIZE 8 > + > +#define REGION_PAGE_MASK 0xe0000000 > > =C2=A0enum { > =C2=A0 =C2=A0 /* Static vectors */ > @@ -214,6 +221,21 @@ typedef enum { > =C2=A0 =C2=A0 INTTYPE_MAX > =C2=A0} interrupt_type; > > +typedef struct xtensa_tlb_entry { > + =C2=A0 =C2=A0uint32_t vaddr; > + =C2=A0 =C2=A0uint32_t paddr; > + =C2=A0 =C2=A0uint8_t asid; > + =C2=A0 =C2=A0uint8_t attr; > + =C2=A0 =C2=A0bool variable; > +} xtensa_tlb_entry; > + > +typedef struct xtensa_tlb { > + =C2=A0 =C2=A0unsigned nways; > + =C2=A0 =C2=A0const unsigned way_size[10]; > + =C2=A0 =C2=A0bool varway56; > + =C2=A0 =C2=A0unsigned nrefillentries; > +} xtensa_tlb; > + > =C2=A0typedef struct XtensaGdbReg { > =C2=A0 =C2=A0 int targno; > =C2=A0 =C2=A0 int type; > @@ -248,6 +270,9 @@ typedef struct XtensaConfig { > =C2=A0 =C2=A0 unsigned nccompare; > =C2=A0 =C2=A0 uint32_t timerint[MAX_NCCOMPARE]; > =C2=A0 =C2=A0 uint32_t clock_freq_khz; > + > + =C2=A0 =C2=A0xtensa_tlb itlb; > + =C2=A0 =C2=A0xtensa_tlb dtlb; > =C2=A0} XtensaConfig; > > =C2=A0typedef struct CPUXtensaState { > @@ -258,6 +283,10 @@ typedef struct CPUXtensaState { > =C2=A0 =C2=A0 uint32_t uregs[256]; > =C2=A0 =C2=A0 uint32_t phys_regs[MAX_NAREG]; > > + =C2=A0 =C2=A0xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE]; > + =C2=A0 =C2=A0xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE]; > + =C2=A0 =C2=A0unsigned autorefill_idx; > + > =C2=A0 =C2=A0 int pending_irq_level; /* level of last raised IRQ */ > =C2=A0 =C2=A0 void **irq_inputs; > =C2=A0 =C2=A0 QEMUTimer *ccompare_timer; > @@ -287,12 +316,29 @@ int cpu_xtensa_signal_handler(int host_signum, void= *pinfo, void *puc); > =C2=A0void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf); > =C2=A0void xtensa_sync_window_from_phys(CPUState *env); > =C2=A0void xtensa_sync_phys_from_window(CPUState *env); > +uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32= _t way); > +void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *vpn, uint32_t wi, uint32_t *ei); > +int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *_wi, uint32_t *_ei, uint8_t *_ring= ); > +void xtensa_tlb_set_entry(CPUState *env, bool dtlb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned wi, unsigned ei, uint32_t vpn, uint= 32_t pte); > +int xtensa_get_physical_addr(CPUState *env, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t vaddr, int is_write, int mmu_idx, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *paddr, uint32_t *page_size, unsign= ed *access); > + > > =C2=A0#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) > > +static inline bool xtensa_option_bits_enabled(const XtensaConfig *config= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t opt) > +{ > + =C2=A0 =C2=A0return (config->options & opt) !=3D 0; > +} > + > =C2=A0static inline bool xtensa_option_enabled(const XtensaConfig *config= , int opt) > =C2=A0{ > - =C2=A0 =C2=A0return (config->options & XTENSA_OPTION_BIT(opt)) !=3D 0; > + =C2=A0 =C2=A0return xtensa_option_bits_enabled(config, XTENSA_OPTION_BI= T(opt)); > =C2=A0} > > =C2=A0static inline int xtensa_get_cintlevel(const CPUState *env) > @@ -323,6 +369,14 @@ static inline int xtensa_get_cring(const CPUState *e= nv) > =C2=A0 =C2=A0 } > =C2=A0} > > +static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUState *env, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bool dtlb, unsigned wi, unsigned ei) > +{ > + =C2=A0 =C2=A0return dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->dtlb[wi] + ei : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->itlb[wi] + ei; > +} > + > =C2=A0/* MMU modes definitions */ > =C2=A0#define MMU_MODE0_SUFFIX _ring0 > =C2=A0#define MMU_MODE1_SUFFIX _ring1 > diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c > index 487847c..00571e8 100644 > --- a/target-xtensa/helper.c > +++ b/target-xtensa/helper.c > @@ -38,6 +38,8 @@ > =C2=A0 =C2=A0 =C2=A0 =C2=A0 a1, a2, a3, a4, a5, a6) \ > =C2=A0 =C2=A0 { .targno =3D (_targno), .type =3D (typ), .group =3D (_grou= p) }, > > +static void reset_mmu(CPUState *env); > + > =C2=A0void cpu_reset(CPUXtensaState *env) > =C2=A0{ > =C2=A0 =C2=A0 env->exception_taken =3D 0; > @@ -48,6 +50,7 @@ void cpu_reset(CPUXtensaState *env) > =C2=A0 =C2=A0 env->sregs[VECBASE] =3D env->config->vecbase; > > =C2=A0 =C2=A0 env->pending_irq_level =3D 0; > + =C2=A0 =C2=A0reset_mmu(env); > =C2=A0} > > =C2=A0static const XtensaConfig core_config[] =3D { > @@ -150,7 +153,19 @@ void xtensa_cpu_list(FILE *f, fprintf_function cpu_f= printf) > > =C2=A0target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ul= ong addr) > =C2=A0{ > - =C2=A0 =C2=A0return addr; > + =C2=A0 =C2=A0uint32_t paddr; > + =C2=A0 =C2=A0uint32_t page_size; > + =C2=A0 =C2=A0unsigned access; > + > + =C2=A0 =C2=A0if (0 =3D=3D xtensa_get_physical_addr(env, addr, 0, 0, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&paddr, &page_si= ze, &access)) { This order in comparison looks alien. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return paddr; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0if (0 =3D=3D xtensa_get_physical_addr(env, addr, 2, 0, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&paddr, &page_si= ze, &access)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return paddr; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0return ~0; > =C2=A0} > > =C2=A0static uint32_t relocated_vector(CPUState *env, uint32_t vector) > @@ -255,3 +270,326 @@ void do_interrupt(CPUState *env) > =C2=A0 =C2=A0 } > =C2=A0 =C2=A0 check_interrupts(env); > =C2=A0} > + > +static void reset_tlb_mmu_all_ways(CPUState *env, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0const xtensa_tlb *tlb, xtensa_tlb_entry entr= y[][MAX_TLB_WAY_SIZE]) > +{ > + =C2=A0 =C2=A0unsigned wi, ei; > + > + =C2=A0 =C2=A0for (wi =3D 0; wi < tlb->nways; ++wi) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0for (ei =3D 0; ei < tlb->way_size[wi]; ++ei)= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[wi][ei].asid =3D 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[wi][ei].variable =3D tru= e; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > +} > + > +static void reset_tlb_mmu_ways56(CPUState *env, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0const xtensa_tlb *tlb, xtensa_tlb_entry entr= y[][MAX_TLB_WAY_SIZE]) > +{ > + =C2=A0 =C2=A0if (!tlb->varway56) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0static const xtensa_tlb_entry way5[] =3D { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.vaddr =3D 0xd00= 00000, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.paddr =3D 0, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.asid =3D 1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.attr =3D 7, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.variable =3D fa= lse, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}, { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.vaddr =3D 0xd80= 00000, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.paddr =3D 0, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.asid =3D 1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.attr =3D 3, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.variable =3D fa= lse, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0static const xtensa_tlb_entry way6[] =3D { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.vaddr =3D 0xe00= 00000, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.paddr =3D 0xf00= 00000, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.asid =3D 1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.attr =3D 7, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.variable =3D fa= lse, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}, { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.vaddr =3D 0xf00= 00000, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.paddr =3D 0xf00= 00000, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.asid =3D 1, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.attr =3D 3, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.variable =3D fa= lse, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0}; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0memcpy(entry[5], way5, sizeof(way5)); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0memcpy(entry[6], way6, sizeof(way6)); > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t ei; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0for (ei =3D 0; ei < 8; ++ei) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[6][ei].vaddr =3D ei << 2= 9; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[6][ei].paddr =3D ei << 2= 9; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[6][ei].asid =3D 1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[6][ei].attr =3D 2; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > +} > + > +static void reset_tlb_region_way0(CPUState *env, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) > +{ > + =C2=A0 =C2=A0unsigned ei; > + > + =C2=A0 =C2=A0for (ei =3D 0; ei < 8; ++ei) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[0][ei].vaddr =3D ei << 29; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[0][ei].paddr =3D ei << 29; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[0][ei].asid =3D 1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[0][ei].attr =3D 2; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0entry[0][ei].variable =3D true; > + =C2=A0 =C2=A0} > +} > + > +static void reset_mmu(CPUState *env) > +{ > + =C2=A0 =C2=A0if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU))= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->sregs[RASID] =3D 0x04030201; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->sregs[ITLBCFG] =3D 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->sregs[DTLBCFG] =3D 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->autorefill_idx =3D 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0reset_tlb_mmu_all_ways(env, &env->config->it= lb, env->itlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0reset_tlb_mmu_all_ways(env, &env->config->dt= lb, env->dtlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0reset_tlb_mmu_ways56(env, &env->config->itlb= , env->itlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0reset_tlb_mmu_ways56(env, &env->config->dtlb= , env->dtlb); > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0reset_tlb_region_way0(env, env->itlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0reset_tlb_region_way0(env, env->dtlb); > + =C2=A0 =C2=A0} > +} > + > +static unsigned get_ring(const CPUState *env, uint8_t asid) > +{ > + =C2=A0 =C2=A0unsigned i; > + =C2=A0 =C2=A0for (i =3D 0; i < 4; ++i) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (((env->sregs[RASID] >> i * 8) & 0xff) = =3D=3D asid) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return i; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0return 0xff; > +} > + > +/*! > + * Lookup xtensa TLB for the given virtual address. > + * See ISA, 4.6.2.2 > + * > + * \param _wi: [out] way index > + * \param _ei: [out] entry index > + * \param _ring: [out] access ring > + * \return 0 if ok, exception cause code otherwise > + */ > +int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *_wi, uint32_t *_ei, uint8_t *_ring= ) Underscores. > +{ > + =C2=A0 =C2=A0const xtensa_tlb *tlb =3D dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0&env->config->dtlb : &env->config->itlb; > + =C2=A0 =C2=A0const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] =3D dtlb= ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->dtlb : env->itlb; > + > + =C2=A0 =C2=A0int nhits =3D 0; > + =C2=A0 =C2=A0unsigned wi; > + > + =C2=A0 =C2=A0for (wi =3D 0; wi < tlb->nways; ++wi) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t vpn; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t ei; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0split_tlb_entry_spec_way(env, addr, dtlb, &v= pn, wi, &ei); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (entry[wi][ei].vaddr =3D=3D vpn && entry[= wi][ei].asid) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned ring =3D get_ring(env= , entry[wi][ei].asid); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (ring < 4) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (++nhits > 1)= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0re= turn dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0LOAD_STORE_TLB_MULTI_HIT_CAUSE : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0INST_TLB_MULTI_HIT_CAUSE; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*_wi =3D wi; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*_ei =3D ei; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*_ring =3D ring; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0return nhits ? 0 : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0(dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB= _MISS_CAUSE); > +} > + > +/*! > + * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask. > + * See ISA, 4.6.5.10 > + */ > +static unsigned mmu_attr_to_access(uint32_t attr) > +{ > + =C2=A0 =C2=A0unsigned access =3D 0; > + =C2=A0 =C2=A0if (attr < 12) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0access |=3D PAGE_READ; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (attr & 0x1) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0access |=3D PAGE_EXEC; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (attr & 0x2) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0access |=3D PAGE_WRITE; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} else if (attr =3D=3D 13) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0access |=3D PAGE_READ | PAGE_WRITE; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0return access; > +} > + > +/*! > + * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask. > + * See ISA, 4.6.3.3 > + */ > +static unsigned region_attr_to_access(uint32_t attr) > +{ > + =C2=A0 =C2=A0unsigned access =3D 0; > + =C2=A0 =C2=A0if ((attr < 6 && attr !=3D 3) || attr =3D=3D 14) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0access |=3D PAGE_READ | PAGE_WRITE; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0if (attr > 0 && attr < 6) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0access |=3D PAGE_EXEC; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0return access; > +} > + > +static bool is_access_granted(unsigned access, int is_write) > +{ > + =C2=A0 =C2=A0switch (is_write) { > + =C2=A0 =C2=A0case 0: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return access & PAGE_READ; > + > + =C2=A0 =C2=A0case 1: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return access & PAGE_WRITE; > + > + =C2=A0 =C2=A0case 2: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return access & PAGE_EXEC; > + > + =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0; > + =C2=A0 =C2=A0} > +} > + > +static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *wi, uint32_t *ei, uint8_t *ring); > + > +static int get_physical_addr_mmu(CPUState *env, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t vaddr, int is_write, int mmu_idx, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *paddr, uint32_t *page_size, unsign= ed *access) > +{ > + =C2=A0 =C2=A0bool dtlb =3D is_write !=3D 2; > + =C2=A0 =C2=A0uint32_t wi; > + =C2=A0 =C2=A0uint32_t ei; > + =C2=A0 =C2=A0uint8_t ring; > + =C2=A0 =C2=A0int ret =3D xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, = &ring); > + > + =C2=A0 =C2=A0if ((ret =3D=3D INST_TLB_MISS_CAUSE || ret =3D=3D LOAD_STO= RE_TLB_MISS_CAUSE) && > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(mmu_idx !=3D 0 || ((vaddr ^ e= nv->sregs[PTEVADDR]) & 0xffc00000)) && > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0autorefill_mmu(env, vaddr, dtl= b, &wi, &ei, &ring) =3D=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D 0; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0if (ret !=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return ret; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0const xtensa_tlb_entry *entry =3D > + =C2=A0 =C2=A0 =C2=A0 =C2=A0xtensa_tlb_get_entry(env, dtlb, wi, ei); > + > + =C2=A0 =C2=A0if (ring < mmu_idx) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0LOAD_STORE_PRIVILEGE_CAUSE : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0INST_FETCH_PRIVILEGE_CAUSE; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0*access =3D mmu_attr_to_access(entry->attr); > + =C2=A0 =C2=A0if (!is_access_granted(*access, is_write)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(is_write ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 STORE_PROHIBITED_CAUSE : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 LOAD_PROHIBITED_CAUSE) : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0INST_FETCH_PROHIBITED_CAUSE; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0*paddr =3D entry->paddr | (vaddr & ~xtensa_tlb_get_addr_ma= sk(env, dtlb, wi)); > + =C2=A0 =C2=A0*page_size =3D ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + = 1; > + > + =C2=A0 =C2=A0return 0; > +} > + > +static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *wi, uint32_t *ei, uint8_t *ring) > +{ > + =C2=A0 =C2=A0uint32_t paddr; > + =C2=A0 =C2=A0uint32_t page_size; > + =C2=A0 =C2=A0unsigned access; > + =C2=A0 =C2=A0uint32_t pt_vaddr =3D > + =C2=A0 =C2=A0 =C2=A0 =C2=A0(env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xf= ffffffc; > + =C2=A0 =C2=A0int ret =3D get_physical_addr_mmu(env, pt_vaddr, 0, 0, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&paddr, &page_size, &access); > + > + =C2=A0 =C2=A0qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vaddr, ret ? ~0 : paddr); > + > + =C2=A0 =C2=A0if (ret =3D=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t vpn; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t pte =3D ldl_phys(paddr); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*ring =3D (pte >> 4) & 0x3; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*wi =3D (++env->autorefill_idx) & 0x3; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0split_tlb_entry_spec_way(env, vaddr, dtlb, &= vpn, *wi, ei); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0xtensa_tlb_set_entry(env, dtlb, *wi, *ei, vp= n, pte); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_log("%s: autorefill(%08x): %08x -> %08x= \n", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0__func__, vaddr,= vpn, pte); > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0return ret; > +} > + > +static int get_physical_addr_region(CPUState *env, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t vaddr, int is_write, int mmu_idx, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *paddr, uint32_t *page_size, unsign= ed *access) > +{ > + =C2=A0 =C2=A0bool dtlb =3D is_write !=3D 2; > + =C2=A0 =C2=A0uint32_t wi =3D 0; > + =C2=A0 =C2=A0uint32_t ei =3D (vaddr >> 29) & 0x7; > + =C2=A0 =C2=A0const xtensa_tlb_entry *entry =3D > + =C2=A0 =C2=A0 =C2=A0 =C2=A0xtensa_tlb_get_entry(env, dtlb, wi, ei); > + > + =C2=A0 =C2=A0*access =3D region_attr_to_access(entry->attr); > + =C2=A0 =C2=A0if (!is_access_granted(*access, is_write)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(is_write ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 STORE_PROHIBITED_CAUSE : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 LOAD_PROHIBITED_CAUSE) : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0INST_FETCH_PROHIBITED_CAUSE; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0*paddr =3D entry->paddr | (vaddr & ~REGION_PAGE_MASK); > + =C2=A0 =C2=A0*page_size =3D ~REGION_PAGE_MASK + 1; > + > + =C2=A0 =C2=A0return 0; > +} > + > +/*! > + * Convert virtual address to physical addr. > + * MMU may issue pagewalk and change xtensa autorefill TLB way entry. > + * > + * \return 0 if ok, exception cause code otherwise > + */ > +int xtensa_get_physical_addr(CPUState *env, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t vaddr, int is_write, int mmu_idx, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *paddr, uint32_t *page_size, unsign= ed *access) > +{ > + =C2=A0 =C2=A0if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU))= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return get_physical_addr_mmu(env, vaddr, is_= write, mmu_idx, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0paddr, page_size= , access); > + =C2=A0 =C2=A0} else if (xtensa_option_bits_enabled(env->config, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0XTENSA_OPTION_BI= T(XTENSA_OPTION_REGION_PROTECTION) | > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0XTENSA_OPTION_BI= T(XTENSA_OPTION_REGION_TRANSLATION))) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return get_physical_addr_region(env, vaddr, = is_write, mmu_idx, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0paddr, page_size= , access); > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*paddr =3D vaddr; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*page_size =3D TARGET_PAGE_SIZE; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*access =3D PAGE_READ | PAGE_WRITE | PAGE_EX= EC; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0; > + =C2=A0 =C2=A0} > +} > diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h > index 28689c3..09ab332 100644 > --- a/target-xtensa/helpers.h > +++ b/target-xtensa/helpers.h > @@ -22,4 +22,11 @@ DEF_HELPER_2(timer_irq, void, i32, i32) > =C2=A0DEF_HELPER_1(advance_ccount, void, i32) > =C2=A0DEF_HELPER_1(check_interrupts, void, env) > > +DEF_HELPER_1(wsr_rasid, void, i32) > +DEF_HELPER_2(rtlb0, i32, i32, i32) > +DEF_HELPER_2(rtlb1, i32, i32, i32) > +DEF_HELPER_2(itlb, void, i32, i32) > +DEF_HELPER_2(ptlb, i32, i32, i32) > +DEF_HELPER_3(wtlb, void, i32, i32, i32) > + > =C2=A0#include "def-helper.h" > diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c > index fcec506..6a9c886 100644 > --- a/target-xtensa/op_helper.c > +++ b/target-xtensa/op_helper.c > @@ -70,13 +70,32 @@ static void do_unaligned_access(target_ulong addr, in= t is_write, int is_user, > =C2=A0 =C2=A0 } > =C2=A0} > > -void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retadd= r) > +void tlb_fill(target_ulong vaddr, int is_write, int mmu_idx, void *retad= dr) > =C2=A0{ > - =C2=A0 =C2=A0tlb_set_page(cpu_single_env, > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0addr & ~(TARGET_PAGE_SIZE - 1)= , > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0addr & ~(TARGET_PAGE_SIZE - 1)= , > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0PAGE_READ | PAGE_WRITE | PAGE_= EXEC, > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mmu_idx, TARGET_PAGE_SIZE); > + =C2=A0 =C2=A0CPUState *saved_env =3D env; > + > + =C2=A0 =C2=A0env =3D cpu_single_env; > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t paddr; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t page_size; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned access; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0int ret =3D xtensa_get_physical_addr(env, va= ddr, is_write, mmu_idx, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&paddr, &page_si= ze, &access); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_log("%s(%08x, %d, %d) -> %08x, ret =3D = %d\n", __func__, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vaddr, is_write,= mmu_idx, paddr, ret); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (ret =3D=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tlb_set_page(env, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0va= ddr & TARGET_PAGE_MASK, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pa= ddr & TARGET_PAGE_MASK, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ac= cess, mmu_idx, page_size); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0do_restore_state(retaddr); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0HELPER(exception_cause_vaddr)(= env->pc, ret, vaddr); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0env =3D saved_env; > =C2=A0} > > =C2=A0void HELPER(exception)(uint32_t excp) > @@ -377,3 +396,273 @@ void HELPER(check_interrupts)(CPUState *env) > =C2=A0{ > =C2=A0 =C2=A0 check_interrupts(env); > =C2=A0} > + > +void HELPER(wsr_rasid)(uint32_t v) > +{ > + =C2=A0 =C2=A0v =3D (v & 0xffffff00) | 0x1; > + =C2=A0 =C2=A0if (v !=3D env->sregs[RASID]) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->sregs[RASID] =3D v; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0tlb_flush(env, 1); > + =C2=A0 =C2=A0} > +} > + > +static uint32_t get_page_size(const CPUState *env, bool dtlb, uint32_t w= ay) > +{ > + =C2=A0 =C2=A0uint32_t tlbcfg =3D env->sregs[dtlb ? DTLBCFG : ITLBCFG]; > + > + =C2=A0 =C2=A0switch (way) { > + =C2=A0 =C2=A0case 4: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return (tlbcfg >> 16) & 0x3; > + > + =C2=A0 =C2=A0case 5: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return (tlbcfg >> 20) & 0x1; > + > + =C2=A0 =C2=A0case 6: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return (tlbcfg >> 24) & 0x1; > + > + =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0; > + =C2=A0 =C2=A0} > +} > + > +/*! > + * Get bit mask for the virtual address bits translated by the TLB way > + */ > +uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32= _t way) > +{ > + =C2=A0 =C2=A0if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU))= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bool varway56 =3D dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->dtlb.varway56 : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->itlb.varway56; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0switch (way) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case 4: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0xfff00000 << get_page_= size(env, dtlb, way) * 2; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case 5: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (varway56) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0xf800000= 0 << get_page_size(env, dtlb, way); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0xf800000= 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case 6: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (varway56) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0xf000000= 0 << (1 - get_page_size(env, dtlb, way)); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0xf000000= 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0xfffff000; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return REGION_PAGE_MASK; > + =C2=A0 =C2=A0} > +} > + > +/*! > + * Get bit mask for the 'VPN without index' field. > + * See ISA, 4.6.5.6, data format for RxTLB0 > + */ > +static uint32_t get_vpn_mask(const CPUState *env, bool dtlb, uint32_t wa= y) > +{ > + =C2=A0 =C2=A0if (way < 4) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bool is32 =3D (dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->dtl= b.nrefillentries : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->itl= b.nrefillentries) =3D=3D 32; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return is32 ? 0xffff8000 : 0xffffc000; > + =C2=A0 =C2=A0} else if (way =3D=3D 4) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return xtensa_tlb_get_addr_mask(env, dtlb, w= ay) << 2; > + =C2=A0 =C2=A0} else if (way <=3D 6) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t mask =3D xtensa_tlb_get_addr_mask(e= nv, dtlb, way); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bool varway56 =3D dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->dtlb.varway56 : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->itlb.varway56; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (varway56) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return mask << (way =3D=3D 5 ?= 2 : 3); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return mask << 1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0xfffff000; > + =C2=A0 =C2=A0} > +} > + > +/*! > + * Split virtual address into VPN (with index) and entry index > + * for the given TLB way > + */ > +void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *vpn, uint32_t wi, uint32_t *ei) > +{ > + =C2=A0 =C2=A0bool varway56 =3D dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->dtlb.varway56 : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->itlb.varway56; > + > + =C2=A0 =C2=A0if (!dtlb) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0wi &=3D 7; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0if (wi < 4) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bool is32 =3D (dtlb ? > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->dtl= b.nrefillentries : > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0env->config->itl= b.nrefillentries) =3D=3D 32; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*ei =3D (v >> 12) & (is32 ? 0x7 : 0x3); > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0switch (wi) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case 4: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t eibase = =3D 20 + get_page_size(env, dtlb, wi) * 2; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*ei =3D (v >> ei= base) & 0x3; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case 5: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (varway56) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t eibase = =3D 27 + get_page_size(env, dtlb, wi); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*ei =3D (v >> ei= base) & 0x3; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*ei =3D (v >> 27= ) & 0x1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case 6: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (varway56) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t eibase = =3D 29 - get_page_size(env, dtlb, wi); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*ei =3D (v >> ei= base) & 0x7; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*ei =3D (v >> 28= ) & 0x1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*ei =3D 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0*vpn =3D v & xtensa_tlb_get_addr_mask(env, dtlb, wi); > +} > + > +/*! > + * Split TLB address into TLB way, entry index and VPN (with index). > + * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format > + */ > +static void split_tlb_entry_spec(uint32_t v, bool dtlb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *vpn, uint32_t *wi, uint32_t *ei) > +{ > + =C2=A0 =C2=A0if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU))= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*wi =3D v & (dtlb ? 0xf : 0x7); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0split_tlb_entry_spec_way(env, v, dtlb, vpn, = *wi, ei); > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*vpn =3D v & REGION_PAGE_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*wi =3D 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*ei =3D (v >> 29) & 0x7; > + =C2=A0 =C2=A0} > +} > + > +static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *= _wi) > +{ > + =C2=A0 =C2=A0uint32_t vpn; > + =C2=A0 =C2=A0uint32_t wi; > + =C2=A0 =C2=A0uint32_t ei; > + > + =C2=A0 =C2=A0split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei); > + =C2=A0 =C2=A0if (_wi) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*_wi =3D wi; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0return xtensa_tlb_get_entry(env, dtlb, wi, ei); > +} > + > +uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb) > +{ > + =C2=A0 =C2=A0if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU))= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t wi; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0const xtensa_tlb_entry *entry =3D get_tlb_en= try(v, dtlb, &wi); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return (entry->vaddr & get_vpn_mask(env, dtl= b, wi)) | entry->asid; > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return v & REGION_PAGE_MASK; > + =C2=A0 =C2=A0} > +} > + > +uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb) > +{ > + =C2=A0 =C2=A0const xtensa_tlb_entry *entry =3D get_tlb_entry(v, dtlb, N= ULL); > + =C2=A0 =C2=A0return entry->paddr | entry->attr; > +} > + > +void HELPER(itlb)(uint32_t v, uint32_t dtlb) > +{ > + =C2=A0 =C2=A0if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU))= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t wi; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0xtensa_tlb_entry *entry =3D get_tlb_entry(v,= dtlb, &wi); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (entry->variable && entry->asid) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tlb_flush_page(env, entry->vad= dr); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry->asid =3D 0; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > +} > + > +uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb) > +{ > + =C2=A0 =C2=A0if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU))= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t wi; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t ei; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t ring; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0int res =3D xtensa_tlb_lookup(env, v, dtlb, = &wi, &ei, &ring); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0switch (res) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case 0: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (ring >=3D xtensa_get_ring(= env)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (v & 0xff= fff000) | wi | (dtlb ? 0x10 : 0x8); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case INST_TLB_MULTI_HIT_CAUSE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case LOAD_STORE_TLB_MULTI_HIT_CAUSE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0HELPER(exception_cause_vaddr)(= env->pc, res, v); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0; > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return (v & REGION_PAGE_MASK) | 0x1; > + =C2=A0 =C2=A0} > +} > + > +void xtensa_tlb_set_entry(CPUState *env, bool dtlb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned wi, unsigned ei, uint32_t vpn, uint= 32_t pte) > +{ > + =C2=A0 =C2=A0xtensa_tlb_entry *entry =3D xtensa_tlb_get_entry(env, dtlb= , wi, ei); > + > + =C2=A0 =C2=A0if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU))= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (entry->variable) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (entry->asid) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tlb_flush_page(e= nv, entry->vaddr); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry->vaddr =3D vpn; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry->paddr =3D pte & xtensa_= tlb_get_addr_mask(env, dtlb, wi); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry->asid =3D (env->sregs[RA= SID] >> ((pte >> 1) & 0x18)) & 0xff; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry->attr =3D pte & 0xf; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_log("%s %d, %d, %d trying= to set immutable entry\n", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0__= func__, dtlb, wi, ei); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0tlb_flush_page(env, entry->vaddr); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (xtensa_option_enabled(env->config, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0XT= ENSA_OPTION_REGION_TRANSLATION)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0entry->paddr =3D pte & REGION_= PAGE_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0entry->attr =3D pte & 0xf; > + =C2=A0 =C2=A0} > +} > + > +void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb) > +{ > + =C2=A0 =C2=A0uint32_t vpn; > + =C2=A0 =C2=A0uint32_t wi; > + =C2=A0 =C2=A0uint32_t ei; > + =C2=A0 =C2=A0split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei); > + =C2=A0 =C2=A0xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p); > +} > diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c > index 3b21bc4..731f04f 100644 > --- a/target-xtensa/translate.c > +++ b/target-xtensa/translate.c > @@ -80,6 +80,10 @@ static const char * const sregnames[256] =3D { > =C2=A0 =C2=A0 [SCOMPARE1] =3D "SCOMPARE1", > =C2=A0 =C2=A0 [WINDOW_BASE] =3D "WINDOW_BASE", > =C2=A0 =C2=A0 [WINDOW_START] =3D "WINDOW_START", > + =C2=A0 =C2=A0[PTEVADDR] =3D "PTEVADDR", > + =C2=A0 =C2=A0[RASID] =3D "RASID", > + =C2=A0 =C2=A0[ITLBCFG] =3D "ITLBCFG", > + =C2=A0 =C2=A0[DTLBCFG] =3D "DTLBCFG", > =C2=A0 =C2=A0 [EPC1] =3D "EPC1", > =C2=A0 =C2=A0 [EPC1 + 1] =3D "EPC2", > =C2=A0 =C2=A0 [EPC1 + 2] =3D "EPC3", > @@ -161,6 +165,11 @@ void xtensa_translate_init(void) > =C2=A0#include "helpers.h" > =C2=A0} > > +static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt) > +{ > + =C2=A0 =C2=A0return xtensa_option_bits_enabled(dc->config, opt); > +} > + > =C2=A0static inline bool option_enabled(DisasContext *dc, int opt) > =C2=A0{ > =C2=A0 =C2=A0 return xtensa_option_enabled(dc->config, opt); > @@ -379,11 +388,19 @@ static void gen_rsr_ccount(DisasContext *dc, TCGv_i= 32 d, uint32_t sr) > =C2=A0 =C2=A0 tcg_gen_mov_i32(d, cpu_SR[sr]); > =C2=A0} > > +static void gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr) > +{ > + =C2=A0 =C2=A0tcg_gen_shri_i32(d, cpu_SR[EXCVADDR], 10); > + =C2=A0 =C2=A0tcg_gen_or_i32(d, d, cpu_SR[sr]); > + =C2=A0 =C2=A0tcg_gen_andi_i32(d, d, 0xfffffffc); > +} > + > =C2=A0static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) > =C2=A0{ > =C2=A0 =C2=A0 static void (* const rsr_handler[256])(DisasContext *dc, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 TCGv_i32 d, uint32_t sr) =3D { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 [CCOUNT] =3D gen_rsr_ccount, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0[PTEVADDR] =3D gen_rsr_ptevaddr, > =C2=A0 =C2=A0 }; > > =C2=A0 =C2=A0 if (sregnames[sr]) { > @@ -436,6 +453,23 @@ static void gen_wsr_windowstart(DisasContext *dc, ui= nt32_t sr, TCGv_i32 v) > =C2=A0 =C2=A0 reset_used_window(dc); > =C2=A0} > > +static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v) > +{ > + =C2=A0 =C2=A0tcg_gen_andi_i32(cpu_SR[sr], v, 0xffc00000); > +} > + > +static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v) > +{ > + =C2=A0 =C2=A0gen_helper_wsr_rasid(v); > + =C2=A0 =C2=A0/* This can change tb->flags, so exit tb */ > + =C2=A0 =C2=A0gen_jumpi_check_loop_end(dc, -1); > +} > + > +static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v) > +{ > + =C2=A0 =C2=A0tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000); > +} > + > =C2=A0static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 = v) > =C2=A0{ > =C2=A0 =C2=A0 tcg_gen_andi_i32(cpu_SR[sr], v, > @@ -505,6 +539,10 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, T= CGv_i32 s) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 [LITBASE] =3D gen_wsr_litbase, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 [WINDOW_BASE] =3D gen_wsr_windowbase, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 [WINDOW_START] =3D gen_wsr_windowstart, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0[PTEVADDR] =3D gen_wsr_ptevaddr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0[RASID] =3D gen_wsr_rasid, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0[ITLBCFG] =3D gen_wsr_tlbcfg, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0[DTLBCFG] =3D gen_wsr_tlbcfg, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 [INTSET] =3D gen_wsr_intset, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 [INTCLEAR] =3D gen_wsr_intclear, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 [INTENABLE] =3D gen_wsr_intenable, > @@ -585,14 +623,16 @@ static void gen_window_check3(DisasContext *dc, uns= igned r1, unsigned r2, > > =C2=A0static void disas_xtensa_insn(DisasContext *dc) > =C2=A0{ > -#define HAS_OPTION(opt) do { \ > - =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!option_enabled(dc, opt)) { \ > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_log("Option %d is not ena= bled %s:%d\n", \ > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(o= pt), __FILE__, __LINE__); \ > +#define HAS_OPTION_BITS(opt) do { \ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!option_bits_enabled(dc, opt)) { \ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_log("Option is not enable= d %s:%d\n", \ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0__= FILE__, __LINE__); \ > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto invalid_opcode; \ > =C2=A0 =C2=A0 =C2=A0 =C2=A0 } \ > =C2=A0 =C2=A0 } while (0) > > +#define HAS_OPTION(opt) HAS_OPTION_BITS(XTENSA_OPTION_BIT(opt)) > + > =C2=A0#define TBD() qemu_log("TBD(pc =3D %08x): %s:%d\n", dc->pc, __FILE_= _, __LINE__) > =C2=A0#define RESERVED() do { \ > =C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_log("RESERVED(pc =3D %08x, %02x%02x%02x)= : %s:%d\n", \ > @@ -1055,7 +1095,48 @@ static void disas_xtensa_insn(DisasContext *dc) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break; > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case 5: /*TLB*/ > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TBD(); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0HAS_OPTION_BITS( > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0XTENSA_OPTION_BIT(XTENSA_OPTION_MMU) | > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION)); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gen_check_privil= ege(dc); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gen_window_check= 2(dc, RRR_S, RRR_T); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TC= Gv_i32 dtlb =3D tcg_const_i32((RRR_R & 8) !=3D 0); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sw= itch (RRR_R & 7) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ca= se 3: /*RITLB0*/ /*RDTLB0*/ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0gen_helper_rtlb0(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0break; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ca= se 4: /*IITLB*/ /*IDTLB*/ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0gen_helper_itlb(cpu_R[RRR_S], dtlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0/* This could change memory mapping, so exit tb */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0gen_jumpi_check_loop_end(dc, -1); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0break; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ca= se 5: /*PITLB*/ /*PDTLB*/ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0tcg_gen_movi_i32(cpu_pc, dc->pc); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0gen_helper_ptlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0break; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ca= se 6: /*WITLB*/ /*WDTLB*/ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0gen_helper_wtlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0/* This could change memory mapping, so exit tb */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0gen_jumpi_check_loop_end(dc, -1); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0break; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ca= se 7: /*RITLB1*/ /*RDTLB1*/ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0gen_helper_rtlb1(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0break; > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0de= fault: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0tcg_temp_free(dtlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0RESERVED(); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tc= g_temp_free(dtlb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break; > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 case 6: /*RT0*/ > -- > 1.7.6 > > >