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

📄 mem_control.c

📁 一个用在mips体系结构中的操作系统
💻 C
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees *    of Leland Stanford Junior University. *  * This file is part of the SimOS distribution.  * See LICENSE file for terms of the license.  * *//**************************************************************** * mem_control.c *  * Author: $Author: bosch $ * Date:   $Date: 1998/02/10 00:30:41 $ *****************************************************************//* include the sim stuff first so we don't expand our macros in their code */#include <stdio.h>#include <unistd.h>#include "simmisc.h"#include "embra.h"#include "mem_control.h"#include "qc.h"#include "cache.h"#include "debug.h"#include "driver.h"#include "cp0.h"#include "clock.h"#include "main_run.h"#include "tc_coherence.h"#include "stats.h"#include "callout.h"#include "main_run.h"#include "tc.h"#include "annotations.h"PA mem_translate( int cpuNum, VA vAddr ){  PA pAddr;  int status;#ifdef wrongl_place    /*   * This is definitively not the right place to do this.    * As a matter of fact, we should get rid of sim_misc.first....   * altogether.    * (bugnion)   */    /* Should I enter the debugger?  -- Since this is done in Periodic_Callout,*/  /* This is really just to handle cpus in the prom slave loop */  if( sim_misc.first_cpu_into_debugger != -1 ) {	 Embra_Collect_Processes_For_Debug(cpuNum);  }#endif  /* Since this is the start of a basic block, we are not in the delay slot */   status = Em_TranslateVirtual( cpuNum, vAddr, &pAddr, ACT_IREAD);  if( status == BACKDOOR_CODE ) {     /* Assume this is a call. Execute it on the real CPU. This      * assumes all backdoor calls take less than 4 arguments.       */     /* If we are counting time for the translator, stop */     STAT_TIMER_STOP( trans_timer );     /* Set this global ONLY for backdoor calls where we don't want to */     /* force a cpuNum parameter */     /*     curr_cpu = cpuNum; */     curEmp = &EMP[cpuNum];     STAT_INC( backdoor_calls );     if( !EMP[cpuNum].outOfSlaveLoop ) {        /* This CPU has not been kicked yet -- it's in the PROM */        uint launchAddr = (uint)sim_misc.launchAddr[cpuNum];        if( !embra.MPinUP )           if(!launchAddr) sginap(20); /* XXX ??? */        /* Get master's cycle count */        EMP[cpuNum].cycleCount = EMP[0].cycleCount;        /* Make time go foward */        EMP[cpuNum].cycleCountdown = 0;        /* XXX - non-backdoor address is launch, backdoor address is call */        if( IS_BACKDOOR( launchAddr ) ) {           int64 result;           /* Do call */           result = ((int64 (*)(int,int,int,int))launchAddr)              ( sim_misc.launchArg[cpuNum][0],                sim_misc.launchArg[cpuNum][1],                sim_misc.launchArg[cpuNum][2],                sim_misc.launchArg[cpuNum][3] );           if( result == SLAVELOOP_CONTINUE ) {              /* signal init function done */              sim_misc.launchAddr[cpuNum] = 0;              /* clear so will be 0 if not set up on next call */              sim_misc.launchArg[cpuNum][0] = 0;	      sim_misc.launchArg[cpuNum][1] = 0;	      sim_misc.launchArg[cpuNum][2] = 0;	      sim_misc.launchArg[cpuNum][3] = 0;              CPUPut("Slave %d returning to launch wait\n",cpuNum );           }        } else {           if( launchAddr != 0 ) {              /* Start emulation */              CPUWarning("Launch slave PC 0x%x\n", launchAddr);              /* Note we set PC to RA before returning from here */              EMP[cpuNum].R[31] = launchAddr;              EMP[cpuNum].cpuStatus = cpu_running;              EMP[cpuNum].R[REG_A0] = sim_misc.launchArg[cpuNum][0];              EMP[cpuNum].R[REG_A1] = sim_misc.launchArg[cpuNum][1];              EMP[cpuNum].R[REG_A2] = sim_misc.launchArg[cpuNum][2];              EMP[cpuNum].R[REG_A3] = sim_misc.launchArg[cpuNum][3];              EMP[cpuNum].outOfSlaveLoop = 1;           }         }     } else {        /* Not a Prom call, just do it */        int64 bdoorRetval;        ASSERT(pAddr < 0x80000000);        bdoorRetval = ((int64 (*)(int,int,int,int))pAddr)           (EMP[cpuNum].R[REG_A0],            EMP[cpuNum].R[REG_A1],            EMP[cpuNum].R[REG_A2],            EMP[cpuNum].R[REG_A3]);        EMP[cpuNum].R[2] = bdoorRetval >> 32;        EMP[cpuNum].R[3] = bdoorRetval & 0xffffffff;     }     ASSERT( embra.emode == EMBRA_PAGE ||embra.sequential || EMP[cpuNum].outTC );     EMP[cpuNum].PC = EMP[cpuNum].R[31];     ASSERT( (EMP[cpuNum].PC & 0x3) == 0 );     if (embra.MPinUP) {        /* NOTE: to get things to boot we need to do a CX after the */        /* slave loop.  */        if( !EMP[cpuNum].outOfSlaveLoop ) {           EMP[cpuNum].jumpPC = (uint)continue_run_without_chaining;           ReenterTC_CX( &EMP[cpuNum] );           ASSERT(0);           /* NOT REACHED */        }     }     ReenterTC( &EMP[cpuNum] );     /* NOT REACHED */  }  if( status == EXCEPTION_CODE ) {     ReenterTC(&EMP[cpuNum]);     ASSERT(0);     /* NOT REACHED */     return 0;  }  return pAddr;#ifdef gone  return PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum), pAddr);#endif}static int debugOnWatchpoint[SIM_MAXCPUS];/* called on miss in Quickcheck and Physarray  * In virtual quickcheck mode we first have to check * the physical quickcheck in phys_mem_ref */MA  mem_ref( VA vAddr, EmVQCMemState new_state, int cpuNum ){   int prevTCGenNumber = tcGenNumber;   PA pAddr;   int status;   Em_accesstype act;   MA retval;   exceptionDuringBackdoor = FALSE;   if( VQC_INST(new_state) ) {      vAddr = IN_BD(EMP[cpuNum].PC)?CLEAR_BD(EMP[cpuNum].PC)+INST_SIZE:         EMP[cpuNum].PC;      act = ACT_IREAD;   } else {      act = VQC_EXCL( new_state ) ? ACT_DWRITE : ACT_DREAD;   }   /* In cache mode, PQC missed, in page mode, mmu reloc missed */   STAT_PQC(new_state);   status = Em_TranslateVirtual( cpuNum, vAddr, &pAddr, act );   /*    * I guess that we could check even if the translation fails, but    * it's overall faster to do it this way    */   if (status==NORMAL_CODE && annWatchpoints == TRUE) {      if (VQC_SHARED(new_state)) {         EmbraAnnExec(cpuNum,AnnFMLookup(vAddr, ANNFM_LD_TYPE),ANNFM_LD_TYPE);      }      if (VQC_EXCL(new_state)) {         EmbraAnnExec(cpuNum,AnnFMLookup(vAddr, ANNFM_ST_TYPE),ANNFM_ST_TYPE);      }   }   if( status == NORMAL_CODE ) {      /* NOTE: this code detects the case where we write code and then */      /* jump to it.  In that case we need to downgrade the code so we */      /* can detect future writes.  This detection occurs here and in */      /* pc_tc_lookup depending on whether we detect the condition when */      /* we jump to the code, or if we are executing inside a */      /* traslation */      if( embra.emode == EMBRA_PAGE ) {         if( VQC_EXCL( new_state ) ) {            if( EmbraTCCoherenceCheck( cpuNum, vAddr,pAddr, pAddr+8 ) ) {               CPUWarning("Flushing the TC in mem_ref:1 (TC coherence) PC=0x%llx vAddr=0x%llx \n",                          (Reg64)EMP[cpuNum].PC, (Reg64)vAddr);               ReenterTC( &EMP[cpuNum] );               /* NOT REACHED */            }         }#ifdef EMBRA_USE_QC64         if( VQC_INST( new_state )) {            /* Downgrade page to read/execute so we can detect */            /* writes to it */             qc_downgrade( cpuNum, vAddr, new_state );         }#else         if( VQC_INST( new_state ) &&              (IS_MMU_PROT_WRITE(EMP[cpuNum].mmu[PAGE_NUMBER(vAddr)]) ) ) {            /* Downgrade page to read/execute so we can detect */            /* writes to it */             qc_downgrade( cpuNum, vAddr, new_state );         }#endif         /* This returns to callout.s */         return PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum), pAddr);      } else {         /* ASSERT(embra.emode == EMBRA_CACHE); */         /* If we are doing cache simulation, make the reference */         if( NUM_CPUS(M_FROM_CPU(cpuNum)) == 1 ) {            UPCache_Ref( cpuNum, pAddr, vAddr, new_state );         } else {            if( embra.MPinUP ) {               MPinUPCache_Ref( cpuNum, pAddr, vAddr, new_state );            } else {               MPCache_Ref( cpuNum, pAddr, vAddr, new_state );            }         }         if( VQC_INST( new_state )){            if (embra.useVQC){               if (VQC_EXCL(EMP[cpuNum].qc_v[ADDR2SLINE(vAddr)])) {                  /* Downgrade page to read/execute so we can detect */                  /* writes to it */                   qc_downgrade( cpuNum, vAddr, new_state );                }            } else {              /* !useVQC */#ifdef EMBRA_USE_QC64               if (1) { /* alway safe to do in QC64 */#else               if (IS_MMU_PROT_WRITE(EMP[cpuNum].mmu[PAGE_NUMBER(vAddr)]) )  {#endif                  /* Downgrade page to read/execute so we can detect */                  /* writes to it */                   qc_downgrade( cpuNum, vAddr, new_state );               }            }         }         /* This maintains a data structure which allows us to determine */         /* if we are writing to a page which has code in it which we are */         /* exectuing.  If such a conflict occurs, we flush the TC and */         /* ReenterTC with the pc value */         /* This is conservative because most stores are not doubles */            if( VQC_EXCL( new_state ) ) {               if( EmbraTCCoherenceCheck( cpuNum, vAddr,pAddr, pAddr+8 ) ) {                  CPUWarning("Flushing the TC in mem_ref:2 (TC coherence) PC=0x%llx vAddr=0x%llx \n",                             (Reg64)EMP[cpuNum].PC, (Reg64)vAddr);                  ReenterTC( &EMP[cpuNum] );                  /* NOT REACHED */               }            }                 /* And return Zero indicating rewind the QC */         if( embra.sequential ) {            /* No need to rewind in               MPinUP, if line is stolen               during stall, access               still suceeds, but sc fails */            return PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum), pAddr);         } else {            return 0;         }      }   }   else if (status == BACKDOOR_CODE) {      if (tcGenNumber != prevTCGenNumber) {         /*          * the TC was flushed during the badoor data addressed function          * at this point, the RT register has already been set,           * so we simply reenter the TC.           * Caveat: we better NOT be in a BD.           */         if (!exceptionDuringBackdoor) {             CPUPrint("EMBRA: %10lld cpu=%d TC flushed on backdoor ref (ok) \n",                     (uint64) EmbraCpuCycleCount(cpuNum),cpuNum);            ASSERT( !IN_BD(EMP[cpuNum].PC));            EMP[cpuNum].PC += INST_SIZE;            EMP[cpuNum].cycleCountdown--;         } else {            ASSERT( !(EMP[cpuNum].CP0[C0_CAUSE] & CAUSE_BD));            EMP[cpuNum].CP0[C0_EPC] += INST_SIZE;                  /* Don't reexecute on return */         }         ReenterTC(&EMP[cpuNum]);      }      exceptionDuringBackdoor = FALSE;      /*       * XXX this cast is very important and makes sense.        */            return (MA)pAddr;   }              else {      if (status != EXCEPTION_CODE) {          CPUWarning("PROBABLY a user-levle SIGSEGV! stats=0x%x when 0x%x (EXCEPTION_CODE) expected.cpu=%d vAddr=0x%x  \n",                    status,EXCEPTION_CODE,cpuNum,vAddr);         Em_EXCEPTION(cpuNum, (act==ACT_IREAD) ? EXC_IBE : EXC_DBE, 0);         ReenterTC( &EMP[cpuNum] );         /* NOT REACHED */         return 0;      }      ASSERT( status == EXCEPTION_CODE );      ReenterTC( &EMP[cpuNum] );      /* NOT REACHED */      return 0;   }}/* ***************************************************** * EmbraTCCoherenceCheck * *****************************************************/ static int just_flushed;static VA last_pc;static PA last_pAddr;int EmbraTCCoherenceCheck(int cpuNum, VA vAddr, PA pAddr, PA end){   if (TCcoherence_check(PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum), pAddr),                         PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum), end))) {            if( just_flushed ) {         /* This catches and disallows an infinite loop case */         /* The problem is that the kernel writes say the UTLB miss */         /* handler, then flushed the cache.  The cache flush looks */         /* like a self-writing line because we just flushed from */         /* the write.  We special case this by checking for vAddr */         /* == 0 */         if( (EMP[cpuNum].PC == last_pc) && (pAddr == last_pAddr) &&             vAddr ) {             CPUWarning("SELF-WRITING  LINE code PA 0x%x VA 0x%x vPC 0x%x pPC 0x%x\n",                        pAddr, vAddr, EMP[cpuNum].PC,                       K0_TO_PHYS_REMAP(non_excepting_tv(cpuNum,                                                         EMP[cpuNum].PC),                                        cpuNum) );          }          return 0;       }            /* This doesn't add appreciable cost, so always maintain it */      em_stats.icache_coherence++;      /*        CPUWarning("Write to code PA 0x%x VA 0x%x PC 0x%x\n",        pAddr, vAddr, EMP[cpuNum].PC );        */      /* Kernel text is overwritten (ex. UTLB miss handler) */      Clear_Translation_State(TCFLUSH_ALL );      last_pc = EMP[cpuNum].PC;      last_pAddr = pAddr;      just_flushed = 1;      if( IN_BD( EMP[cpuNum].PC ) ) {         EMP[cpuNum].PC = CLEAR_BD( EMP[cpuNum].PC );         EMP[cpuNum].PC -= INST_SIZE;      }      ASSERT( (EMP[cpuNum].PC & 0x3) == 0 );#if 0      CPUWarning("TCcoherence_check_code detected conflict at pc=0x%llx. \n",                 (Reg64)EMP[cpuNum].PC);#endif      return 1;   } else {       just_flushed = 0;      return 0;   }}      

⌨️ 快捷键说明

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