⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 r4k_cp0.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
      case CBIT_UPDATE:         if (IS_R10000(P)) {            break; /* fall thru to error, doesn't work on R10000 */         }      case CBIT_NONCOHERENT:      case CBIT_EXCLUSIVE:      case CBIT_EXCLUSIVE_WRITE:      {         Reg64 offset = XKPHYS_ONE_PAGE_OFFSET(vAddr);         if (XKPHYS_INVALID_OFFSET(offset)) goto addrErr;         *pAddr = offset;         /* XXX - NEED TO ACCESS FLAVOR */         return SUCCESS;      }      case CBIT_UNCACHED:      case CBIT_UNCACHED_ACCEL:      {         uint flavor = XKPHYS_UNCACHED_FLAVOR(vAddr);         Reg64 offset = XKPHYS_FOUR_PAGE_OFFSET(vAddr);         if (XKPHYS_INVALID_OFFSET(offset)) goto addrErr;         if (!IS_R10000(P) && (flavor != 0)) goto addrErr;         *pAddr = offset;         *tlbFlavor = TLB_UNCACHED;         if (cache_algorithm == CBIT_UNCACHED_ACCEL) {            *tlbFlavor |= TLB_ACCELERATED;         }         return SUCCESS;      }      default:         /* invalid cache alogrithm fall thru to error */         break;      }      goto addrErr;   } else if (region == 1) {      /* Supervisor region - only available in 64bit mode */      if (IN_32BIT_MODE(P) || ((sr_reg & SR_KSU_USR) && !IS_KERNEL_MODE(P)) ||           HAS_BAD_VADDR_BITS(vAddr)) goto addrErr;      if (IS_R10000(P) && !(sr_reg & SR_SX)) goto addrErr;      /* Fall thru to TLB lookup */#endif   }    /* Check TLB */    VPN2 = GET_VPN2(vAddr);    tlbIndex = TLBLookup(P, region, VPN2, myASID);    if (tlbIndex) {      int szEntry;       /* We have a matching VPN and ASID - see if it is valid */      tlbIndex--;      szEntry = P->tlbEntrySize[tlbIndex];      /* Which lo register? */      if (vAddr & PgSz[szEntry].loBit)         lo_reg = P->tlbEntry[tlbIndex].Lo1;      else         lo_reg = P->tlbEntry[tlbIndex].Lo0;            if (IS_VALID(lo_reg)) {         /* Check if the page is dirty or we are reading */         if ( IS_DIRTY(lo_reg) || !(writing)) {            /* Everything is cool - form the address */#ifdef notdef  /* For performance, disable this check by default */            int cache_algorithm = GET_CACHE_ALGOR(lo_reg);                        if (!((cache_algorithm == CBIT_EXCLUSIVE) ||                   (cache_algorithm == CBIT_EXCLUSIVE_WRITE))) {               CPUWarning("Unsupported TLB cache algorithm (%d) for address 0x%llx by cpu %d at PC 0x%llx\n",                          cache_algorithm,  (uint64)vAddr, P->myNum, (uint64)P->PC);            }#endif                        /*              * XXX TO_DO non-cacheable support eventualy support table              * which has 8 modes.             * if (!IS_CACHEABLE(lo_reg){             *  *tlbFlavor = TLB_UNCACHED;             * }             */            *pAddr = (((GET_PFN(lo_reg)&SZ2MASK(szEntry))*4*1024) |                       (vAddr & PgSz[szEntry].offset_mask));                        return SUCCESS;         } else {                         /* TLB MODIFICATION */            /* Page is not dirty and we want to write */            /* Set up the CTxt register !!! */            /* EPC set up in EXCEPTION, badVaddr and context */            /* stored in macro */                        if (isPrefetch) return FAILURE;                        contextReg.tc_data = P->CP0[C0_CTXT];            contextReg.s32.tc_badvpn = VPN2;                        xcontextReg.tc_data = P->CP0[C0_XCTXT];            xcontextReg.s64.tc_region = region;#ifndef BIG_BIT_FIELD_BROKEN            xcontextReg.s64.tc_badvpn = VPN2;#else            xcontextReg.s64.tc_badvpn_hi3 = VPN2>>28;            xcontextReg.s64.tc_badvpn_lo28 = VPN2;#endif            tlbhi = (((Reg)region << TLBHI_REGIONSHIFT) |                      (VPN2 << TLBHI_VPN2SHIFT)  |                      ((Reg)myASID << TLBHI_PIDSHIFT)) ;            RECORD_EXCEPTION(P, EXC_MOD, E_VEC, vAddr,                              tlbhi,contextReg.tc_data,                             xcontextReg.tc_data);            return FAILURE;         }      } else {   /* TLB INVALID */         if (isPrefetch) return FAILURE;         contextReg.tc_data = P->CP0[C0_CTXT];         contextReg.s32.tc_badvpn = VPN2;                  xcontextReg.tc_data = P->CP0[C0_XCTXT];         xcontextReg.s64.tc_region = region;#ifndef BIG_BIT_FIELD_BROKEN         xcontextReg.s64.tc_badvpn = VPN2;#else         xcontextReg.s64.tc_badvpn_hi3 = VPN2>>28;         xcontextReg.s64.tc_badvpn_lo28 = VPN2;#endif                  tlbhi = (((Reg)region << TLBHI_REGIONSHIFT) |                   (VPN2 << TLBHI_VPN2SHIFT)  |                   ((Reg)myASID << TLBHI_PIDSHIFT)) ;                  RECORD_EXCEPTION(P, (writing ? EXC_WMISS : EXC_RMISS),E_VEC,                          vAddr,tlbhi,contextReg.tc_data,                          xcontextReg.tc_data);         return FAILURE;      }    }    /* TLB REFILL      * Since there were no matching VPN2s, there is a TLB refill exception.     * First put the VPN2 and ASID of the non-matching address in Hi.     * The BadVAddr and Context registers also need to be set.         * 1.) set TLBL or TLBS(store only) code in cause register     * use EPC and BD bit in cause reg, inst or load, or store.     * 2.) BadVAddr, Context, XContect and EntryHi hold the vAddr     * that failed. Entry HI also has ASID. EPC pts to last instruction     * take care of branches.     */    if (isPrefetch) return FAILURE;    contextReg.tc_data = P->CP0[C0_CTXT];    contextReg.s32.tc_badvpn = VPN2;    xcontextReg.tc_data = P->CP0[C0_XCTXT];    xcontextReg.s64.tc_region = region;#ifndef BIG_BIT_FIELD_BROKEN    xcontextReg.s64.tc_badvpn = VPN2;#else    xcontextReg.s64.tc_badvpn_hi3 = VPN2>>28;    xcontextReg.s64.tc_badvpn_lo28 = VPN2;#endif     tlbhi = (((Reg)region << TLBHI_REGIONSHIFT) |                      (VPN2 << TLBHI_VPN2SHIFT)  |                      ((Reg)myASID << TLBHI_PIDSHIFT)) ;    if (isIfetch) {        ITLB_MISS_EVENT(MipsyReadTime(P->myNum), P->myNum, vAddr);    } else {        DTLB_MISS_EVENT(MipsyReadTime(P->myNum), P->myNum, P->PC, vAddr);    }    if (sr_reg & SR_EXL) {        RECORD_EXCEPTION(P, (writing ? EXC_WMISS : EXC_RMISS),E_VEC,vAddr,                        tlbhi,contextReg.tc_data,                              xcontextReg.tc_data);    } else {           if (((region == 0) && (sr_reg & SR_UX)) ||           ((region == 3) && (sr_reg & SR_KX)) ||           ((region == 1) && (sr_reg & SR_SX))) {          /* Should pass XUT_VEC to RECORD below, but this isn't              currently used. */       }       RECORD_UTLBEXCEPTION(P, writing ? EXC_WMISS : EXC_RMISS,                             UT_VEC, vAddr, tlbhi, contextReg.tc_data,                             xcontextReg.tc_data);    }        return FAILURE;    addrErr:    if (isPrefetch) return FAILURE;    /* Illegal address - generate an address error */        RECORD_EXCEPTION(P, (writing ? EXC_WADE : EXC_RADE), E_VEC,                     vAddr,P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]);    return FAILURE;    bdoor:    {      SimMagic_accesstype a;            if (!IS_KERNEL_MODE(P)) {         CPUWarning("Accessing bdoor while not in kernel mode (PC %#x RA %#x)\n",                    P->PC, P->R[REG_RA]);      }            a = SimMagic_kseg1_accesstype(vAddr);            if (a == SIMMAGIC_UNCACHED) {         *tlbFlavor = TLB_UNCACHED;         *pAddr = vAddr;      } else if (a == SIMMAGIC_UNCACHED_ACCELERATED) {         *tlbFlavor = TLB_UNCACHED|TLB_ACCELERATED;         *pAddr = vAddr;      } else {         uint flag;         /* a == SIMMAGIC_DIRECT */                  if (!RegistryIsInRange(vAddr, bdoorAddr, &flag)) {            /* Raise an address error on a bad backdoor address. */            if (!isPrefetch) {               CPUWarning("MIPSY: Bad bdoor reference to 0x%x from %#x RA %#x\n",                           vAddr, P->PC, P->R[31]);               /* ASSERT(0); */               RECORD_EXCEPTION(P, (writing ? EXC_WADE : EXC_RADE), E_VEC,                                vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT],                                P->CP0[C0_CTXT]);            }            return FAILURE;         }         if (flag & REG_DATA) {            *tlbFlavor = TLB_BDOOR_DATA;         } else {            ASSERT(flag & REG_FUNC);            *tlbFlavor = TLB_BDOOR_FUNC;         }                   SIM_DEBUG(('b', "MIPSY: CPU %d Translated %#x to %#x (%s) at pc %#x\n",                     P->myNum, vAddr, pAddr, (flag & REG_DATA)?"data":"func", P->PC));      }    }       return  SUCCESS;}/* a version of TranslateVirtual intended to be called from the debugger. */Result TranslateVirtualNoSideeffect(CPUState *P, VA vAddr, PA *pAddr){   unsigned       tlbIndex;   int            myASID;   Reg64          lo_reg;   int             region = GET_REGION(vAddr);   if (region==2) {      *pAddr = XKPHYS_FOUR_PAGE_OFFSET(vAddr);      return SUCCESS;   }   if (region==3 && vAddr >= CKSEG0_START_ADDR) {       if (IS_KSEG0(vAddr)) {         *pAddr = K0_TO_PHYS(vAddr);          return SUCCESS;      }   }   /* fall through and cover 32-bit cases. */      if (!IS_KUSEG(vAddr)) {      if (IS_KSEG1(vAddr)) { #ifdef __alpha         return FAILURE;#else          void *dat;         uint flag;         *pAddr = (PA)RegistryGetSimFunction(vAddr);         if (*pAddr) {            SIM_DEBUG(('b', "BDOOR: CPU %d found func %#x at 0x%x (PC %#x RA %#x\n",                   P->myNum, *pAddr, vAddr, P->PC, P->R[REG_RA]));            return SUCCESS;         }         /* backdoor access */         if (!RegistryIsInRange(vAddr,&dat, &flag) ||             !(flag & REG_DATA)) {            /* Raise an address error on a bad backdoor address. */            return FAILURE;         }         *pAddr = (PA) dat;         return SUCCESS;#endif /* __alpha */      } else if (IS_KSEG0(vAddr)) {         *pAddr = K0_TO_PHYS(vAddr);         return SUCCESS;      }      /* KSEG2 references will fall through and be translated normally */   }      /* Check TLB */   myASID = GET_ASID(P->CP0[C0_TLBHI]);      tlbIndex = TLBLookup(P, region, GET_VPN2(vAddr) , myASID);      if (tlbIndex) {      int sz;      /* We have a matching VPN and ASID - see if it is valid */      tlbIndex--;      sz = P->tlbEntrySize[tlbIndex];      /* Which lo register? */      if (vAddr & PgSz[sz].loBit)         lo_reg = P->tlbEntry[tlbIndex].Lo1;      else         lo_reg = P->tlbEntry[tlbIndex].Lo0;            if (IS_VALID(lo_reg)) {         *pAddr =  (((GET_PFN(lo_reg)&SZ2MASK(sz))*4*1024) |                     (vAddr & PgSz[sz].offset_mask));         return SUCCESS;      }      /* fall through to failure case if not valid */   }   /* OK, let's resort to calling tcl for help */   *pAddr = TclTranslateVirtual(P->myNum, vAddr);   if (*pAddr) {      return SUCCESS;   }   return FAILURE;}  /***************************************************************** * ProbeTLB - * Probe TLB for a matching entry. The Index register is loaded  * with the address of the TLB entry whose contents match the  * contents of the Hi register. If no TLB entry matches, the  * high order bit of the Index register is set.  *  * What to do when there are multiple matches was not specified, * so I'm leaving after the first match. * R4000 CHANGED >> No changes. *****************************************************************/static voidProbeTLB(CPUState *P){   int idx;   idx = TLBLookup(P,  GET_REGION(P->CP0[C0_TLBHI]),                    GET_VPN2(P->CP0[C0_TLBHI]),                    GET_ASID(P->CP0[C0_TLBHI]));   if (idx) {      /* We matched */      P->CP0[C0_INX] = (idx - 1) << TLBINX_INXSHIFT;      return;   }      /* Probe Miss */   P->CP0[C0_INX] = 0x80000000;   return;}/***************************************************************** * ReadTLBEntry - * The Hi, Lo0, and Lo1 registers are loaded with the contents  * of the TLB entry pointed at by the contents of the TLB Index * register. The results are unspecified if the contents or Index * are greater than the number of TLB entries. * R4000 CHANGED >> G(global) bit from TLB is written into both the lo0 and lo1 * registers. Entry HI and EntryLo registers are loaded with contents * of the TLB entry pointedt at by the index register. As is the  * PgMsk register.  if index > numtlbentries, undefined behavior.   *****************************************************************/static void ReadTLBEntry(CPUState *P){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -