# Linux Kernel Module Cheat

##### 24.22.6.3. gem5 `ExecContext`

`ExecContext` gets used in gem5 instruction definitions, e.g.:

    build/ARM/arch/arm/generated/exec-ns.cc.inc

contains:

        Fault Mul::execute(
            ExecContext *xc, Trace::InstRecord *traceData) const

It contains methods to allow interacting with CPU state from inside instruction execution, notably reading and writing from/to registers.

For example, the ARM `mul` instruction uses `ExecContext` to read the input operands, multiply them, and write to the output:

        Fault Mul::execute(
            ExecContext *xc, Trace::InstRecord *traceData) const
        {
            Fault fault = NoFault;
            uint64_t resTemp = 0;
            resTemp = resTemp;
            uint32_t OptCondCodesNZ = 0;
            uint32_t OptCondCodesC = 0;
            uint32_t OptCondCodesV = 0;
            uint32_t Reg0 = 0;
            uint32_t Reg1 = 0;
            uint32_t Reg2 = 0;

            OptCondCodesNZ = xc->readCCRegOperand(this, 0);
            OptCondCodesC = xc->readCCRegOperand(this, 1);
            OptCondCodesV = xc->readCCRegOperand(this, 2);
            Reg1 =
                ((reg1 == PCReg) ? readPC(xc) : xc->readIntRegOperand(this, 3));
            Reg2 =
                ((reg2 == PCReg) ? readPC(xc) : xc->readIntRegOperand(this, 4));

            if (testPredicate(OptCondCodesNZ, OptCondCodesC, OptCondCodesV, condCode)/*auto*/)
            {
                Reg0 = resTemp = Reg1 * Reg2;;
                if (fault == NoFault) {
                    {
                        uint32_t final_val = Reg0;
                        ((reg0 == PCReg) ? setNextPC(xc, Reg0) : xc->setIntRegOperand(this, 0, Reg0));
                        if (traceData) { traceData->setData(final_val); }
                    };
                }
            } else {
                xc->setPredicate(false);
            }

            return fault;
        }

`ExecContext` is however basically just a wrapper that forwards to other classes that actually contain the data in a microarchitectural neutral manner. For example, in `SimpleExecContext`:

        /** Reads an integer register. */
        RegVal
        readIntRegOperand(const StaticInst *si, int idx) override
        {
            numIntRegReads++;
            const RegId& reg = si->srcRegIdx(idx);
            assert(reg.isIntReg());
            return thread->readIntReg(reg.index());
        }

So we see that this just does some register position bookkeeping needed for instruction execution, but the actual data comes from `SimpleThread::readIntReg`, which is a specialization of gem5 `ThreadContext`.

`ExecContext` is a fully virtual class. The hierarchy is:

- `ExecContext`

  - `SimpleExecContext`

  - `Minor::MinorExecContext`

  - `BaseDynInst`

    - `BaseO3DynInst`

If we follow `SimpleExecContext` creation for example, we see:

    class BaseSimpleCPU : public BaseCPU
    {
        std::vector<SimpleExecContext*> threadInfo;

and:

    BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
        : BaseCPU(p),
          curThread(0),
          branchPred(p->branchPred),
          traceData(NULL),
          inst(),
          _status(Idle)
    {
        SimpleThread *thread;

        for (unsigned i = 0; i < numThreads; i++) {
            if (FullSystem) {
                thread = new SimpleThread(this, i, p->system,
                                          p->itb, p->dtb, p->isa[i]);
            } else {
                thread = new SimpleThread(this, i, p->system, p->workload[i],
                                          p->itb, p->dtb, p->isa[i]);
            }
            threadInfo.push_back(new SimpleExecContext(this, thread));
            ThreadContext *tc = thread->getTC();
            threadContexts.push_back(tc);
        }

therefore there is one `ExecContext` for each `ThreadContext`, and each `ExecContext` knows about its own `ThreadContext`.

This makes sense, since each `ThreadContext` represents one CPU register set, and therefore needs a separate `ExecContext` which allows instruction implementations to access those registers.

- gem5 <code>ExecContext::readIntRegOperand</code> register resolution