2 * Copyright 2019 Google, Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "arch/arm/fastmodel/iris/thread_context.hh"
34 #include "iris/detail/IrisCppAdapter.h"
35 #include "iris/detail/IrisObjects.h"
36 #include "mem/fs_translating_port_proxy.hh"
37 #include "mem/se_translating_port_proxy.hh"
43 ThreadContext::initFromIrisInstance(const ResourceMap
&resources
)
46 call().perInstanceExecution_getState(_instId
, enabled
);
47 _status
= enabled
? Active
: Suspended
;
51 call().memory_getMemorySpaces(_instId
, memorySpaces
);
52 call().memory_getUsefulAddressTranslations(_instId
, translations
);
54 typedef ThreadContext Self
;
55 iris::EventSourceInfo evSrcInfo
;
57 client
.registerEventCallback
<Self
, &Self::breakpointHit
>(
58 this, "ec_IRIS_BREAKPOINT_HIT",
59 "Handle hitting a breakpoint", "Iris::ThreadContext");
60 call().event_getEventSource(_instId
, evSrcInfo
, "IRIS_BREAKPOINT_HIT");
61 call().eventStream_create(_instId
, breakpointEventStreamId
,
62 evSrcInfo
.evSrcId
, client
.getInstId());
64 for (auto it
= bps
.begin(); it
!= bps
.end(); it
++)
69 ThreadContext::extractResourceId(
70 const ResourceMap
&resources
, const std::string
&name
)
72 return resources
.at(name
).rscId
;
76 ThreadContext::extractResourceMap(
77 ResourceIds
&ids
, const ResourceMap
&resources
,
78 const IdxNameMap
&idx_names
)
80 for (const auto &idx_name
: idx_names
) {
81 int idx
= idx_name
.first
;
82 const std::string
&name
= idx_name
.second
;
84 if (idx
>= ids
.size())
85 ids
.resize(idx
+ 1, iris::IRIS_UINT64_MAX
);
87 ids
[idx
] = extractResourceId(resources
, name
);
92 ThreadContext::maintainStepping()
97 if (comInstEventQueue
.empty()) {
98 // Set to 0 to deactivate stepping.
99 call().step_setup(_instId
, 0, "instruction");
103 Tick next
= comInstEventQueue
.nextTick();
105 now
= getCurrentInstCount();
108 comInstEventQueue
.serviceEvents(now
);
109 // Start over now that comInstEventQueue has likely changed.
113 // Set to the number of instructions still to step through.
114 Tick remaining
= next
- now
;
115 call().step_setup(_instId
, remaining
, "instruction");
120 ThreadContext::BpInfoIt
121 ThreadContext::getOrAllocBp(Addr pc
)
123 auto pc_it
= bps
.find(pc
);
125 if (pc_it
!= bps
.end())
128 auto res
= bps
.emplace(std::make_pair(pc
, new BpInfo(pc
)));
129 panic_if(!res
.second
, "Inserting breakpoint failed.");
134 ThreadContext::installBp(BpInfoIt it
)
137 Addr pc
= it
->second
->pc
;
138 auto space_id
= getBpSpaceId(pc
);
139 call().breakpoint_set_code(_instId
, id
, pc
, space_id
, 0, true);
144 ThreadContext::uninstallBp(BpInfoIt it
)
146 call().breakpoint_delete(_instId
, it
->second
->id
);
147 it
->second
->clearId();
151 ThreadContext::delBp(BpInfoIt it
)
153 panic_if(!it
->second
->empty(),
154 "BP info still had events associated with it.");
156 if (it
->second
->validId())
163 ThreadContext::instanceRegistryChanged(
164 uint64_t esId
, const iris::IrisValueMap
&fields
, uint64_t time
,
165 uint64_t sInstId
, bool syncEc
, std::string
&error_message_out
)
167 const std::string
&event
= fields
.at("EVENT").getString();
168 const iris::InstanceId id
= fields
.at("INST_ID").getU64();
169 const std::string
&name
= fields
.at("INST_NAME").getString();
171 if (name
!= "component." + _irisPath
)
174 if (event
== "added")
176 else if (event
== "removed")
177 _instId
= iris::IRIS_UINT64_MAX
;
179 panic("Unrecognized event type %s", event
);
185 ThreadContext::phaseInitLeave(
186 uint64_t esId
, const iris::IrisValueMap
&fields
, uint64_t time
,
187 uint64_t sInstId
, bool syncEc
, std::string
&error_message_out
)
189 std::vector
<iris::ResourceInfo
> resources
;
190 call().resource_getList(_instId
, resources
);
192 ResourceMap resourceMap
;
193 for (auto &resource
: resources
)
194 resourceMap
[resource
.name
] = resource
;
196 initFromIrisInstance(resourceMap
);
202 ThreadContext::simulationTimeEvent(
203 uint64_t esId
, const iris::IrisValueMap
&fields
, uint64_t time
,
204 uint64_t sInstId
, bool syncEc
, std::string
&error_message_out
)
206 if (fields
.at("RUNNING").getAsBool()) {
207 // If this is just simulation time starting up, don't do anything.
211 // If simulation time has stopped for any reason, IRIS helpfully clears
212 // all stepping counters and we need to set them back. We might also need
213 // to service events based on the current number of executed instructions.
216 // Restart simulation time to make sure things progress once we give
218 call().simulationTime_run(iris::IrisInstIdSimulationEngine
);
224 ThreadContext::breakpointHit(
225 uint64_t esId
, const iris::IrisValueMap
&fields
, uint64_t time
,
226 uint64_t sInstId
, bool syncEc
, std::string
&error_message_out
)
228 Addr pc
= fields
.at("PC").getU64();
230 auto it
= getOrAllocBp(pc
);
232 auto e_it
= it
->second
->events
.begin();
233 while (e_it
!= it
->second
->events
.end()) {
235 // Advance e_it here since e might remove itself from the list.
243 ThreadContext::ThreadContext(
244 BaseCPU
*cpu
, int id
, System
*system
, ::BaseTLB
*dtb
, ::BaseTLB
*itb
,
245 iris::IrisConnectionInterface
*iris_if
, const std::string
&iris_path
) :
246 _cpu(cpu
), _threadId(id
), _system(system
), _dtb(dtb
), _itb(itb
),
247 _irisPath(iris_path
), vecRegs(TheISA::NumVecRegs
),
248 comInstEventQueue("instruction-based event queue"),
249 client(iris_if
, "client." + iris_path
)
251 iris::InstanceInfo info
;
252 auto ret_code
= noThrow().instanceRegistry_getInstanceInfoByName(
253 info
, "component." + iris_path
);
254 if (ret_code
== iris::E_ok
) {
255 // The iris instance registry already new about this path.
256 _instId
= info
.instId
;
258 // This path doesn't (yet) exist. Set the ID to something invalid.
259 _instId
= iris::IRIS_UINT64_MAX
;
262 typedef ThreadContext Self
;
263 iris::EventSourceInfo evSrcInfo
;
265 client
.registerEventCallback
<Self
, &Self::instanceRegistryChanged
>(
266 this, "ec_IRIS_INSTANCE_REGISTRY_CHANGED",
267 "Install the iris instance ID", "Iris::ThreadContext");
268 call().event_getEventSource(iris::IrisInstIdGlobalInstance
, evSrcInfo
,
269 "IRIS_INSTANCE_REGISTRY_CHANGED");
270 regEventStreamId
= iris::IRIS_UINT64_MAX
;
271 static const std::vector
<std::string
> fields
=
272 { "EVENT", "INST_ID", "INST_NAME" };
273 call().eventStream_create(iris::IrisInstIdGlobalInstance
, regEventStreamId
,
274 evSrcInfo
.evSrcId
, client
.getInstId(), &fields
);
276 client
.registerEventCallback
<Self
, &Self::phaseInitLeave
>(
277 this, "ec_IRIS_SIM_PHASE_INIT_LEAVE",
278 "Initialize register contexts", "Iris::ThreadContext");
279 call().event_getEventSource(iris::IrisInstIdSimulationEngine
, evSrcInfo
,
280 "IRIS_SIM_PHASE_INIT_LEAVE");
281 initEventStreamId
= iris::IRIS_UINT64_MAX
;
282 call().eventStream_create(
283 iris::IrisInstIdSimulationEngine
, initEventStreamId
,
284 evSrcInfo
.evSrcId
, client
.getInstId());
286 client
.registerEventCallback
<Self
, &Self::simulationTimeEvent
>(
287 this, "ec_IRIS_SIMULATION_TIME_EVENT",
288 "Handle simulation time stopping for breakpoints or stepping",
289 "Iris::ThreadContext");
290 call().event_getEventSource(iris::IrisInstIdSimulationEngine
, evSrcInfo
,
291 "IRIS_SIMULATION_TIME_EVENT");
292 timeEventStreamId
= iris::IRIS_UINT64_MAX
;
293 call().eventStream_create(
294 iris::IrisInstIdSimulationEngine
, timeEventStreamId
,
295 evSrcInfo
.evSrcId
, client
.getInstId());
297 breakpointEventStreamId
= iris::IRIS_UINT64_MAX
;
300 ThreadContext::~ThreadContext()
302 call().eventStream_destroy(
303 iris::IrisInstIdSimulationEngine
, initEventStreamId
);
304 initEventStreamId
= iris::IRIS_UINT64_MAX
;
305 client
.unregisterEventCallback("ec_IRIS_SIM_PHASE_INIT_LEAVE");
307 call().eventStream_destroy(
308 iris::IrisInstIdGlobalInstance
, regEventStreamId
);
309 regEventStreamId
= iris::IRIS_UINT64_MAX
;
310 client
.unregisterEventCallback("ec_IRIS_INSTANCE_REGISTRY_CHANGED");
312 call().eventStream_destroy(
313 iris::IrisInstIdGlobalInstance
, timeEventStreamId
);
314 timeEventStreamId
= iris::IRIS_UINT64_MAX
;
315 client
.unregisterEventCallback("ec_IRIS_SIMULATION_TIME_EVENT");
319 ThreadContext::schedule(PCEvent
*e
)
321 auto it
= getOrAllocBp(e
->pc());
322 it
->second
->events
.push_back(e
);
324 if (_instId
!= iris::IRIS_UINT64_MAX
&& !it
->second
->validId())
331 ThreadContext::remove(PCEvent
*e
)
333 auto it
= getOrAllocBp(e
->pc());
334 it
->second
->events
.remove(e
);
336 if (it
->second
->empty())
343 ThreadContext::translateAddress(Addr
&paddr
, iris::MemorySpaceId p_space
,
344 Addr vaddr
, iris::MemorySpaceId v_space
)
346 iris::MemoryAddressTranslationResult result
;
347 auto ret
= noThrow().memory_translateAddress(
348 _instId
, result
, v_space
, vaddr
, p_space
);
350 if (ret
!= iris::E_ok
) {
351 // Check if there was a legal translation between these two spaces.
352 // If so, something else went wrong.
353 for (auto &trans
: translations
)
354 if (trans
.inSpaceId
== v_space
&& trans
.outSpaceId
== p_space
)
357 panic("No legal translation IRIS address translation found.");
360 if (result
.address
.empty())
363 if (result
.address
.size() > 1) {
364 warn("Multiple mappings for address %#x.", vaddr
);
368 paddr
= result
.address
[0];
373 ThreadContext::scheduleInstCountEvent(Event
*event
, Tick count
)
375 Tick now
= getCurrentInstCount();
376 comInstEventQueue
.schedule(event
, count
);
378 call().simulationTime_stop(iris::IrisInstIdSimulationEngine
);
384 ThreadContext::descheduleInstCountEvent(Event
*event
)
386 comInstEventQueue
.deschedule(event
);
391 ThreadContext::getCurrentInstCount()
394 auto ret
= call().step_getStepCounterValue(_instId
, count
, "instruction");
395 panic_if(ret
!= iris::E_ok
, "Failed to get instruction count.");
400 ThreadContext::initMemProxies(::ThreadContext
*tc
)
403 assert(!physProxy
&& !virtProxy
);
404 physProxy
.reset(new PortProxy(_cpu
->getSendFunctional(),
405 _cpu
->cacheLineSize()));
406 virtProxy
.reset(new FSTranslatingPortProxy(tc
));
409 virtProxy
.reset(new SETranslatingPortProxy(
410 _cpu
->getSendFunctional(), getProcessPtr(),
411 SETranslatingPortProxy::NextPage
));
415 ThreadContext::Status
416 ThreadContext::status() const
422 ThreadContext::setStatus(Status new_status
)
424 if (new_status
== Active
) {
425 if (_status
!= Active
)
426 call().perInstanceExecution_setState(_instId
, true);
428 if (_status
== Active
)
429 call().perInstanceExecution_setState(_instId
, false);
431 _status
= new_status
;
435 ThreadContext::pcState() const
437 ArmISA::CPSR cpsr
= readMiscRegNoEffect(ArmISA::MISCREG_CPSR
);
441 pc
.nextThumb(pc
.thumb());
443 pc
.nextJazelle(cpsr
.j
);
444 pc
.aarch64(!cpsr
.width
);
445 pc
.nextAArch64(!cpsr
.width
);
446 pc
.illegalExec(false);
448 iris::ResourceReadResult result
;
449 call().resource_read(_instId
, result
, pcRscId
);
450 Addr addr
= result
.data
.at(0);
451 if (cpsr
.width
&& cpsr
.t
)
458 ThreadContext::pcState(const ArmISA::PCState
&val
)
462 ArmISA::CPSR cpsr
= readMiscRegNoEffect(ArmISA::MISCREG_CPSR
);
463 if (cpsr
.width
&& cpsr
.t
)
466 iris::ResourceWriteResult result
;
467 call().resource_write(_instId
, result
, pcRscId
, pc
);
471 ThreadContext::instAddr() const
473 return pcState().instAddr();
477 ThreadContext::nextInstAddr() const
479 return pcState().nextInstAddr();
483 ThreadContext::readMiscRegNoEffect(RegIndex misc_reg
) const
485 iris::ResourceReadResult result
;
486 call().resource_read(_instId
, result
, miscRegIds
.at(misc_reg
));
487 return result
.data
.at(0);
491 ThreadContext::setMiscRegNoEffect(RegIndex misc_reg
, const RegVal val
)
493 iris::ResourceWriteResult result
;
494 call().resource_write(_instId
, result
, miscRegIds
.at(misc_reg
), val
);
498 ThreadContext::readIntReg(RegIndex reg_idx
) const
500 ArmISA::CPSR cpsr
= readMiscRegNoEffect(ArmISA::MISCREG_CPSR
);
502 iris::ResourceReadResult result
;
504 call().resource_read(_instId
, result
, intReg32Ids
.at(reg_idx
));
506 call().resource_read(_instId
, result
, intReg64Ids
.at(reg_idx
));
507 return result
.data
.at(0);
511 ThreadContext::setIntReg(RegIndex reg_idx
, RegVal val
)
513 ArmISA::CPSR cpsr
= readMiscRegNoEffect(ArmISA::MISCREG_CPSR
);
515 iris::ResourceWriteResult result
;
517 call().resource_write(_instId
, result
, intReg32Ids
.at(reg_idx
), val
);
519 call().resource_write(_instId
, result
, intReg64Ids
.at(reg_idx
), val
);
522 const ArmISA::VecRegContainer
&
523 ThreadContext::readVecReg(const RegId
®_id
) const
525 const RegIndex idx
= reg_id
.index();
526 // Ignore accesses to registers which aren't architected. gem5 defines a
527 // few extra registers which it uses internally in the implementation of
528 // some instructions.
529 if (idx
>= vecRegIds
.size())
530 return vecRegs
.at(idx
);
531 ArmISA::VecRegContainer
®
= vecRegs
.at(idx
);
533 iris::ResourceReadResult result
;
534 call().resource_read(_instId
, result
, vecRegIds
.at(idx
));
535 size_t data_size
= result
.data
.size() * (sizeof(*result
.data
.data()));
536 size_t size
= std::min(data_size
, reg
.SIZE
);
537 memcpy(reg
.raw_ptr
<void>(), (void *)result
.data
.data(), size
);
542 const ArmISA::VecRegContainer
&
543 ThreadContext::readVecRegFlat(RegIndex idx
) const
545 return readVecReg(RegId(VecRegClass
, idx
));