📄 simmagic.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. * */ /***************************************************************** * simmagic.c * * Interface between the OS view of the machine and the SimOS * device simulators. * * Created by: John Chapin, 05/95 * Revision history: * 06/95 (Dan Teodosiu) added interrupt subsystem support. * 06/95 (John Chapin) added register access, interrupt event codes * 06/95 (John Chapin) moved flash defines out, added universal I/O ops * 11/95 (John Chapin) added PPC version 2 support * 07/96 (Dan Teodosiu) complete OS/SimOS overhaul * 02/97 (Ben Werther) generalized number of devices per machine * ****************************************************************/#include "sim.h"#include <stdio.h>#include <sys/types.h>#include <sys/mman.h>#include <sys/file.h>#include <sys/signal.h>#ifndef __alpha#ifndef i386#include <sys/unistd.h>#include <sys/ioccom.h>#include <sys/filio.h>#include <netinet/in.h>#endif#endif#include <sys/time.h>#include <sys/uio.h>#include <unistd.h>#include <string.h>#ifdef sgi#include <netinet/if_ether.h>#endif#include <errno.h>#include <netdb.h>#include <stdlib.h>#include "syslimits.h"#include "simtypes.h"#include "checkpoint.h"#include "machine_params.h"#include "cpu_interface.h"#include "cpu_state.h"#include "sim_error.h"#include "addr_layout.h"#include "registry.h"#include "dma.h"#include "../../devices/disk/simos_interface.h"#include "remote_access.h"#include "simutil.h"#include "../../memsystems/flashlite/flash_interface.h"#include "../../memsystems/memsys.h"#include "simmagic.h"#include "hd.h"#include "console.h"#include "ethernet.h"#include "sips.h"#include "firewall.h"#include "startup.h"#include "machine_defs.h"#ifdef SUPPORT_LINUX#include "linux_init.h"#endif#ifdef TORNADO#include "simgizmo.h"#endif/* Cache counting stuff. The routines are in numa.c */#define IS_NUMA() (memsysVec.type == NUMA)uint64 MigRepGetHotPage(int memnum);uint64 MigRepGetInfo(unsigned long addr, int memnum, unsigned long countType, unsigned long countAddr);void MigRepSetInfo(unsigned long addr, int memnum, uint64 val, unsigned long countType, unsigned long countAddr);/* Control debugging info printout: 0=off, 1=on */#define DEBUG_MAGIC 0#define offsetof(t,m) ((int)&((t*)0)->m)int FPromUseFL;long initialBootTime; static CptCallback SimMagic_CheckpointCB;typedef struct MagicStatus { MagicRegister iPendingReg; /* 64b interrupt pending reg */ MagicRegister iTransReg; /* 64b int pending reg (transition-sensitive) */ MagicRegister iEnableMask; /* 64b interrupt enable mask */ unsigned char iBitTable[64]; /* IEC -> CPU intrBits map * Note: read/written in 64-bit * chunks so must be aligned */ MagicRegister IEChigh; /* current interrupt level (board) */ IEC ioSlotMap[SIM_MAXSLOTS]; /* slot -> IEC map */ IEC ioSlots[SIM_MAXSLOTS]; /* pending count for each slot */ int timerInterval; /* 0 => no timer interrupt on this CPU * > 0 => interrupt with specified * periodicity [us]. */ MagicRegister workerMask; /* mask bits for cell boundary */ MagicRegister workerMatch; /* match bits for cell id */} MagicStatus;MagicStatus mm[SIM_MAXCPUS]; /* MAGIC status for all nodes */DeviceToMachineStruct deviceToMachine; /* Device to machine mappings *//* * Save someone a bunch of debugging time if they use some of SGI compilers * that doesn't sign-extend correctly when optimization is turned on. */#define CHECK_FOR_COMPILER_BUG CheckForCompilerBug(0x80000000,(VA)0xffffffff80000000LL)static voidCheckForCompilerBug(uint addr, VA val){ VA vAddr = (VA)(Reg32_s)addr; /* Sign extend if needed */ if (vAddr != val) CPUError("Your compiler is broken\n");}#define CHECK_FOR_COMPILER_BUG2 \ CheckForCompilerBug2(0x80000000,(Reg)0xffffffff80000000LL)static voidCheckForCompilerBug2(Reg addr, Reg val){ Reg new = (Reg)(Reg32_s)addr; /* Sign extend if needed */ if (new != val) CPUWarning("CAREFUL: Your compiler is broken\n");}/**************************************************************************** * * Interrupt subsystem * ****************************************************************************//* recompute intrBits for the specified CPU. */voidrecompute_intr_bits(register int cpu){ MagicRegister pend; MagicRegister trans; int iechigh; int i; MagicRegister mask; ASSERT(!USE_MAGIC()); /* compute IEChigh = ffsb(pend) */ pend = mm[cpu].iPendingReg & mm[cpu].iEnableMask; if (pend == 0) { iechigh = 0; } else { for (iechigh = -1; pend >= (1<<8); pend >>= 8) iechigh += 8; for ( ; pend != 0; pend >>= 1) iechigh++; } mm[cpu].IEChigh = iechigh; /* compute cause bits */ trans = mm[cpu].iTransReg & mm[cpu].iEnableMask; CPUVec.intrBits[cpu] = 0; for(i=0, mask = 1; i < 64; i++, mask <<= 1) { if (trans & mask) { CPUVec.intrBits[cpu] |= (mm[cpu].iBitTable[i]<<2); } }#ifdef TORNADO /* XXX this may be broken now -- check! */ if ( mm[cpu].iPendingReg == 0x1 ) { CPUVec.intrBits[cpu] |= (CAUSE_IP4 >> CAUSE_IPSHIFT); } else if ( mm[cpu].iPendingReg ) { CPUVec.intrBits[cpu] |= (CAUSE_IP8 >> CAUSE_IPSHIFT); } else { CPUVec.intrBits[cpu] &= ~(CAUSE_IPMASK >> CAUSE_IPSHIFT); }#endif CPUVec.IntrBitsChanged(cpu);}voidRaiseIBit(int cpu, IEC code){ MagicRegister ibit = ((MagicRegister)1) << code; ASSERT(!USE_MAGIC()); if (!(mm[cpu].iPendingReg & ibit)) { /* 0->1 transition */#if (DEBUG_MAGIC == 1) LogEntry("RaiseIBit", cpu, "code=0x%x 0->1 transition\n", code);#endif mm[cpu].iPendingReg |= ibit; mm[cpu].iTransReg |= ibit; recompute_intr_bits(cpu); } else { /* no transition */#if (DEBUG_MAGIC == 1) LogEntry("RaiseIBit", cpu, "code=0x%x no transition\n", code);#endif }}voidClearIBit(int cpu, IEC code){ MagicRegister ibit = ((MagicRegister)1) << code; ASSERT(!USE_MAGIC()); if ((mm[cpu].iPendingReg & ibit)) { /* 1->0 transition */#if (DEBUG_MAGIC == 1) LogEntry("ClearIBit", cpu, "code=0x%x 1->0 transition\n", code);#endif mm[cpu].iPendingReg &= ~ibit; mm[cpu].iTransReg &= ~ibit; recompute_intr_bits(cpu); } else { /* no transition */#if (DEBUG_MAGIC == 1) LogEntry("ClearIBit", cpu, "code=0x%x no transition\n", code);#endif }}static voidRaiseSlot(int cpu, int slot){ ASSERT(0 <= cpu && cpu < TOTAL_CPUS); ASSERT(0 <= slot && slot < SIM_MAXSLOTS);#if (DEBUG_MAGIC == 1) LogEntry("RaiseSlot",cpu,"slot=%d prevVal=0x%x\n", slot, mm[cpu].ioSlots[slot]);#endif if (mm[cpu].ioSlots[slot]++ == 0) { /* Slot transitions 0->1, must raise interrupt bit */ if (USE_MAGIC()) { FlashliteRaiseSlot(cpu, slot); } else { RaiseIBit(cpu, mm[cpu].ioSlotMap[slot]); } }}voidClearSlot(int cpu, int slot){ register int slotval; ASSERT(0 <= cpu && cpu < TOTAL_CPUS); ASSERT(0 <= slot && slot < SIM_MAXSLOTS);#if (DEBUG_MAGIC == 1) LogEntry("ClearSlot",cpu,"slot=%d prevVal=0x%x\n", slot, mm[cpu].ioSlots[slot]);#endif slotval = --mm[cpu].ioSlots[slot]; if (slotval < 0) { /* this can occur if: console TX_INTR is * pending when a cell is rebooted. This gets cleared once * during cell initialization and again on the next GetIntrStatus * since flags in the simulated console device are still set. */ Sim_Warning("ClearSlot(%d, %d): slot value dropped below 0\n", cpu, slot); mm[cpu].ioSlots[slot] = 0; } else if (slotval == 0) { /* Slot transitions 1->0, must clear interrupt bit. */ if (USE_MAGIC()) { FlashliteClearSlot(cpu, slot); } else { ClearIBit(cpu, mm[cpu].ioSlotMap[slot]); } }}/* NOTE: can ack only an internal interrupt cause */intAckInternalInt(int n, IEC iec){ switch (iec) { case DEV_IEC_OSPC_LO: case DEV_IEC_OSPC_HI: /* ack SIPS (if any) */ sim_sips_ack(n, (iec == DEV_IEC_OSPC_LO)); return 0; case DEV_IEC_CLOCK: case DEV_IEC_IPI: case DEV_IEC_IPI1: case DEV_IEC_IPI2: /* just clear int */ ClearIBit(n, iec); return 0; default: return -1; }}/***************************************************************** * Migration-Replication support *****************************************************************/void MigRepStart(int cpu){ RaiseIBit(cpu, DEV_IEC_MIG_REP);}void MigRepEnd(int cpu){ ClearIBit(cpu, DEV_IEC_MIG_REP);}/**************************************************************************** * * Clock interrupt support * ****************************************************************************//* eventcallback hdr for clock timer */static EventCallbackHdr timerHdr[SIM_MAXCPUS];/* clock interrupt counter for stats */static uint clockIntrs;/* maintain last time timer was invoked so that we can checkpoint the correct timeleft. */static SimTime lastTimeout[SIM_MAXCPUS];/* timer callback: raise interrupt and enqueue yourself for next tick */static voidTimerCallback(int cpuNum, EventCallbackHdr *hdr, void *arg){ ASSERT(!USE_MAGIC()); /* if (CPUVec.drainEvents) { */ if (0) { /* eventqueue is being cleared, so figure out the timeleft so * next CPU model can restart the clock correctly */ CPUVec.clockStarted[cpuNum] = 0; SBase[cpuNum].clockTimeLeft = SBase[cpuNum].clockInterval - (CPUVec.CycleCount(cpuNum) - lastTimeout[cpuNum])/CPU_CLOCK; if (SBase[cpuNum].clockTimeLeft > SBase[cpuNum].clockInterval) SBase[cpuNum].clockTimeLeft = SBase[cpuNum].clockInterval; return; } lastTimeout[cpuNum] = CPUVec.CycleCount(cpuNum); clockIntrs++; RaiseIBit(cpuNum, DEV_IEC_CLOCK); CPUVec.IntrBitsChanged(cpuNum); EventDoCallback(cpuNum, TimerCallback, hdr, NULL, CPUVec.clockInterval[cpuNum] * CPU_CLOCK);}/* sets up the callback data and the first callback */voidInstallTimer(int cpuNum, unsigned int interval, unsigned int timeLeft){ ASSERT(!USE_MAGIC()); CPUVec.clockInterval[cpuNum] = interval; if (CPUVec.clockStarted[cpuNum]) EventCallbackRemove(&timerHdr[cpuNum]); CPUVec.clockStarted[cpuNum] = 1; EventDoCallback(cpuNum, TimerCallback, &timerHdr[cpuNum], NULL, timeLeft * CPU_CLOCK); SBase[cpuNum].clockInterval = CPUVec.clockInterval[cpuNum]; SBase[cpuNum].clockStarted = CPUVec.clockStarted[cpuNum];}/* called when restoring from a checkpoint */voidInstallTimers(void){ int i; for(i = 0; i < TOTAL_CPUS; i++) { if (SBase[i].clockStarted) { if (USE_MAGIC()) { FlashliteInstallTimer(i, SBase[i].clockInterval, SBase[i].clockTimeLeft); } else { InstallTimer(i, SBase[i].clockInterval, SBase[i].clockTimeLeft); } } }}/* called when checkpointing, so that timeLeft field can be updated. */voidTimerUpdateTimeLeft(void){ int cpuNum; for(cpuNum = 0; cpuNum < TOTAL_CPUS; cpuNum++) if (SBase[cpuNum].clockStarted) { SBase[cpuNum].clockTimeLeft = SBase[cpuNum].clockInterval - (CPUVec.CycleCount(cpuNum) - lastTimeout[cpuNum])/CPU_CLOCK; if (SBase[cpuNum].clockTimeLeft > SBase[cpuNum].clockInterval) SBase[cpuNum].clockTimeLeft = SBase[cpuNum].clockInterval; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -