tru64.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 1,211 行 · 第 1/3 页
HH
1,211 行
TypedBufferArg<T> tgt(addr);#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__) tgt->f_type = 0;#else tgt->f_type = htog(host->f_type);#endif tgt->f_bsize = htog(host->f_bsize); tgt->f_blocks = htog(host->f_blocks); tgt->f_bfree = htog(host->f_bfree); tgt->f_bavail = htog(host->f_bavail); tgt->f_files = htog(host->f_files); tgt->f_ffree = htog(host->f_ffree); // Is this as string normally? memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); tgt.copyOut(mem); } /// The target system's hostname. static const char *hostname; /// Target getdirentries() handler. static SyscallReturn getdirentriesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { using namespace TheISA;#ifdef __CYGWIN__ panic("getdirent not implemented on cygwin!");#else int fd = process->sim_fd(tc->getSyscallArg(0)); Addr tgt_buf = tc->getSyscallArg(1); int tgt_nbytes = tc->getSyscallArg(2); Addr tgt_basep = tc->getSyscallArg(3); char * const host_buf = new char[tgt_nbytes]; // just pass basep through uninterpreted. TypedBufferArg<int64_t> basep(tgt_basep); basep.copyIn(tc->getMemPort()); long host_basep = (off_t)htog((int64_t)*basep); int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep); // check for error if (host_result < 0) { delete [] host_buf; return -errno; } // no error: copy results back to target space Addr tgt_buf_ptr = tgt_buf; char *host_buf_ptr = host_buf; char *host_buf_end = host_buf + host_result; while (host_buf_ptr < host_buf_end) { global_dirent *host_dp = (global_dirent *)host_buf_ptr; int namelen = strlen(host_dp->d_name); // Actual size includes padded string rounded up for alignment. // Subtract 256 for dummy char array in Tru64::dirent definition. // Add 1 to namelen for terminating null char. int tgt_bufsize = sizeof(Tru64::dirent) - 256 + roundUp(namelen+1, 8); TypedBufferArg<Tru64::dirent> tgt_dp(tgt_buf_ptr, tgt_bufsize); tgt_dp->d_ino = host_dp->d_ino; tgt_dp->d_reclen = tgt_bufsize; tgt_dp->d_namlen = namelen; strcpy(tgt_dp->d_name, host_dp->d_name); tgt_dp.copyOut(tc->getMemPort()); tgt_buf_ptr += tgt_bufsize; host_buf_ptr += host_dp->d_reclen; } delete [] host_buf; *basep = htog((int64_t)host_basep); basep.copyOut(tc->getMemPort()); return tgt_buf_ptr - tgt_buf;#endif } /// Target sigreturn() handler. static SyscallReturn sigreturnFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { using namespace TheISA; using TheISA::RegFile; TypedBufferArg<Tru64::sigcontext> sc(tc->getSyscallArg(0)); sc.copyIn(tc->getMemPort()); // Restore state from sigcontext structure. // Note that we'll advance PC <- NPC before the end of the cycle, // so we need to restore the desired PC into NPC. // The current regs->pc will get clobbered. tc->setNextPC(htog(sc->sc_pc)); for (int i = 0; i < 31; ++i) { tc->setIntReg(i, htog(sc->sc_regs[i])); tc->setFloatRegBits(i, htog(sc->sc_fpregs[i])); } tc->setMiscRegNoEffect(AlphaISA::MISCREG_FPCR, htog(sc->sc_fpcr)); return 0; } // // Mach syscalls -- identified by negated syscall numbers // /// Create a stack region for a thread. static SyscallReturn stack_createFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { using namespace TheISA; TypedBufferArg<Tru64::vm_stack> argp(tc->getSyscallArg(0)); argp.copyIn(tc->getMemPort()); int stack_size = gtoh(argp->rsize) + gtoh(argp->ysize) + gtoh(argp->gsize); // if the user chose an address, just let them have it. Otherwise // pick one for them. Addr stack_base = gtoh(argp->address); if (stack_base == 0) { stack_base = process->next_thread_stack_base; process->next_thread_stack_base -= stack_size; } Addr rounded_stack_base = roundDown(stack_base, VMPageSize); Addr rounded_stack_size = roundUp(stack_size, VMPageSize); DPRINTF(SyscallVerbose, "stack_create: allocating stack @ %#x size %#x " "(rounded from %#x, %#x)\n", rounded_stack_base, rounded_stack_size, stack_base, stack_size); // map memory process->pTable->allocate(rounded_stack_base, rounded_stack_size); argp->address = gtoh(rounded_stack_base); argp.copyOut(tc->getMemPort()); return 0; } /// NXM library version stamp. static const int NXM_LIB_VERSION = 301003; /// This call sets up the interface between the user and kernel /// schedulers by creating a shared-memory region. The shared memory /// region has several structs, some global, some per-RAD, some per-VP. static SyscallReturn nxm_task_initFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { using namespace std; using namespace TheISA; TypedBufferArg<Tru64::nxm_task_attr> attrp(tc->getSyscallArg(0)); TypedBufferArg<Addr> configptr_ptr(tc->getSyscallArg(1)); attrp.copyIn(tc->getMemPort()); if (gtoh(attrp->nxm_version) != NXM_LIB_VERSION) { cerr << "nxm_task_init: thread library version mismatch! " << "got " << attrp->nxm_version << ", expected " << NXM_LIB_VERSION << endl; abort(); } if (gtoh(attrp->flags) != Tru64::NXM_TASK_INIT_VP) { cerr << "nxm_task_init: bad flag value " << attrp->flags << " (expected " << Tru64::NXM_TASK_INIT_VP << ")" << endl; abort(); } Addr base_addr = 0x12000; // was 0x3f0000000LL; Addr cur_addr = base_addr; // next addresses to use // first comes the config_info struct Addr config_addr = cur_addr; cur_addr += sizeof(Tru64::nxm_config_info); // next comes the per-cpu state vector Addr slot_state_addr = cur_addr; int slot_state_size = process->numCpus() * sizeof(Tru64::nxm_slot_state_t); cur_addr += slot_state_size; // now the per-RAD state struct (we only support one RAD) cur_addr = 0x14000; // bump up addr for alignment Addr rad_state_addr = cur_addr; int rad_state_size = (sizeof(Tru64::nxm_shared) + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); cur_addr += rad_state_size; // now initialize a config_info struct and copy it out to user space TypedBufferArg<Tru64::nxm_config_info> config(config_addr); config->nxm_nslots_per_rad = htog(process->numCpus()); config->nxm_nrads = htog(1); // only one RAD in our system! config->nxm_slot_state = htog(slot_state_addr); config->nxm_rad[0] = htog(rad_state_addr); // initialize the slot_state array and copy it out TypedBufferArg<Tru64::nxm_slot_state_t> slot_state(slot_state_addr, slot_state_size); for (int i = 0; i < process->numCpus(); ++i) { // CPU 0 is bound to the calling process; all others are available // XXX this code should have an endian conversion, but I don't think // it works anyway slot_state[i] = (i == 0) ? Tru64::NXM_SLOT_BOUND : Tru64::NXM_SLOT_AVAIL; } // same for the per-RAD "shared" struct. Note that we need to // allocate extra bytes for the per-VP array which is embedded at // the end. TypedBufferArg<Tru64::nxm_shared> rad_state(rad_state_addr, rad_state_size); rad_state->nxm_callback = attrp->nxm_callback; rad_state->nxm_version = attrp->nxm_version; rad_state->nxm_uniq_offset = attrp->nxm_uniq_offset; for (int i = 0; i < process->numCpus(); ++i) { Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[i]; ssp->nxm_u.sigmask = htog(0); ssp->nxm_u.sig = htog(0); ssp->nxm_u.flags = htog(0); ssp->nxm_u.cancel_state = htog(0); ssp->nxm_u.nxm_ssig = 0; ssp->nxm_bits = htog(0); ssp->nxm_quantum = attrp->nxm_quantum; ssp->nxm_set_quantum = attrp->nxm_quantum; ssp->nxm_sysevent = htog(0); if (i == 0) { uint64_t uniq = tc->readMiscRegNoEffect(AlphaISA::MISCREG_UNIQ); ssp->nxm_u.pth_id = htog(uniq + gtoh(attrp->nxm_uniq_offset)); ssp->nxm_u.nxm_active = htog(uniq | 1); } else { ssp->nxm_u.pth_id = htog(0); ssp->nxm_u.nxm_active = htog(0); } } // // copy pointer to shared config area out to user // *configptr_ptr = htog(config_addr); // Register this as a valid address range with the process base_addr = roundDown(base_addr, VMPageSize); int size = cur_addr - base_addr; process->pTable->allocate(base_addr, roundUp(size, VMPageSize)); config.copyOut(tc->getMemPort()); slot_state.copyOut(tc->getMemPort()); rad_state.copyOut(tc->getMemPort()); configptr_ptr.copyOut(tc->getMemPort()); return 0; } /// Initialize thread context. static void init_thread_context(ThreadContext *tc, Tru64::nxm_thread_attr *attrp, uint64_t uniq_val) { using namespace TheISA; tc->clearArchRegs(); tc->setIntReg(TheISA::ArgumentReg[0], gtoh(attrp->registers.a0)); tc->setIntReg(27/*t12*/, gtoh(attrp->registers.pc)); tc->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp)); tc->setMiscRegNoEffect(AlphaISA::MISCREG_UNIQ, uniq_val); tc->setPC(gtoh(attrp->registers.pc)); tc->setNextPC(gtoh(attrp->registers.pc) + sizeof(TheISA::MachInst)); tc->activate(); } /// Create thread. static SyscallReturn nxm_thread_createFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { using namespace std; using namespace TheISA; TypedBufferArg<Tru64::nxm_thread_attr> attrp(tc->getSyscallArg(0)); TypedBufferArg<uint64_t> kidp(tc->getSyscallArg(1)); int thread_index = tc->getSyscallArg(2); // get attribute args attrp.copyIn(tc->getMemPort()); if (gtoh(attrp->version) != NXM_LIB_VERSION) { cerr << "nxm_thread_create: thread library version mismatch! " << "got " << attrp->version << ", expected " << NXM_LIB_VERSION << endl; abort(); } if (thread_index < 0 | thread_index > process->numCpus()) { cerr << "nxm_thread_create: bad thread index " << thread_index << endl; abort(); } // On a real machine, the per-RAD shared structure is in // shared memory, so both the user and kernel can get at it. // We don't have that luxury, so we just copy it in and then // back out again. int rad_state_size = (sizeof(Tru64::nxm_shared) + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); TypedBufferArg<Tru64::nxm_shared> rad_state(0x14000, rad_state_size); rad_state.copyIn(tc->getMemPort()); uint64_t uniq_val = gtoh(attrp->pthid) - gtoh(rad_state->nxm_uniq_offset); if (gtoh(attrp->type) == Tru64::NXM_TYPE_MANAGER) { // DEC pthreads seems to always create one of these (in // addition to N application threads), but we don't use it, // so don't bother creating it. // This is supposed to be a port number. Make something up. *kidp = htog(99); kidp.copyOut(tc->getMemPort()); return 0; } else if (gtoh(attrp->type) == Tru64::NXM_TYPE_VP) { // A real "virtual processor" kernel thread. Need to fork // this thread on another CPU. Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index]; if (gtoh(ssp->nxm_u.nxm_active) != 0) return (int) Tru64::KERN_NOT_RECEIVER; ssp->nxm_u.pth_id = attrp->pthid; ssp->nxm_u.nxm_active = htog(uniq_val | 1); rad_state.copyOut(tc->getMemPort()); Addr slot_state_addr = 0x12000 + sizeof(Tru64::nxm_config_info); int slot_state_size = process->numCpus() * sizeof(Tru64::nxm_slot_state_t); TypedBufferArg<Tru64::nxm_slot_state_t> slot_state(slot_state_addr, slot_state_size); slot_state.copyIn(tc->getMemPort()); if (slot_state[thread_index] != Tru64::NXM_SLOT_AVAIL) { cerr << "nxm_thread_createFunc: requested VP slot " << thread_index << " not available!" << endl; fatal(""); } // XXX This should have an endian conversion but I think this code // doesn't work anyway slot_state[thread_index] = Tru64::NXM_SLOT_BOUND; slot_state.copyOut(tc->getMemPort()); // Find a free simulator thread context. for (int i = 0; i < process->numCpus(); ++i) { ThreadContext *tc = process->threadContexts[i]; if (tc->status() == ThreadContext::Unallocated) { // inactive context... grab it init_thread_context(tc, attrp, uniq_val); // This is supposed to be a port number, but we'll try // and get away with just sticking the thread index // here. *kidp = htog(thread_index); kidp.copyOut(tc->getMemPort()); return 0; } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?