e22b300591206f76704f30fa48e915c501c4cec7
[gem5.git] / src / arch / arm / fastmodel / iris / thread_context.cc
1 /*
2 * Copyright 2019 Google, Inc.
3 *
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.
14 *
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.
26 *
27 * Authors: Gabe Black
28 */
29
30 #include "arch/arm/fastmodel/iris/thread_context.hh"
31
32 #include <utility>
33
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"
38
39 namespace Iris
40 {
41
42 void
43 ThreadContext::initFromIrisInstance(const ResourceMap &resources)
44 {
45 bool enabled = false;
46 call().perInstanceExecution_getState(_instId, enabled);
47 _status = enabled ? Active : Suspended;
48
49 suspend();
50
51 call().memory_getMemorySpaces(_instId, memorySpaces);
52 call().memory_getUsefulAddressTranslations(_instId, translations);
53
54 typedef ThreadContext Self;
55 iris::EventSourceInfo evSrcInfo;
56
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());
63
64 for (auto it = bps.begin(); it != bps.end(); it++)
65 installBp(it);
66 }
67
68 iris::ResourceId
69 ThreadContext::extractResourceId(
70 const ResourceMap &resources, const std::string &name)
71 {
72 return resources.at(name).rscId;
73 }
74
75 void
76 ThreadContext::extractResourceMap(
77 ResourceIds &ids, const ResourceMap &resources,
78 const IdxNameMap &idx_names)
79 {
80 for (const auto &idx_name: idx_names) {
81 int idx = idx_name.first;
82 const std::string &name = idx_name.second;
83
84 if (idx >= ids.size())
85 ids.resize(idx + 1, iris::IRIS_UINT64_MAX);
86
87 ids[idx] = extractResourceId(resources, name);
88 }
89 }
90
91 void
92 ThreadContext::maintainStepping()
93 {
94 Tick now = 0;
95
96 while (true) {
97 if (comInstEventQueue.empty()) {
98 // Set to 0 to deactivate stepping.
99 call().step_setup(_instId, 0, "instruction");
100 break;
101 }
102
103 Tick next = comInstEventQueue.nextTick();
104 if (!now)
105 now = getCurrentInstCount();
106
107 if (next <= now) {
108 comInstEventQueue.serviceEvents(now);
109 // Start over now that comInstEventQueue has likely changed.
110 continue;
111 }
112
113 // Set to the number of instructions still to step through.
114 Tick remaining = next - now;
115 call().step_setup(_instId, remaining, "instruction");
116 break;
117 }
118 }
119
120 ThreadContext::BpInfoIt
121 ThreadContext::getOrAllocBp(Addr pc)
122 {
123 auto pc_it = bps.find(pc);
124
125 if (pc_it != bps.end())
126 return pc_it;
127
128 auto res = bps.emplace(std::make_pair(pc, new BpInfo(pc)));
129 panic_if(!res.second, "Inserting breakpoint failed.");
130 return res.first;
131 }
132
133 void
134 ThreadContext::installBp(BpInfoIt it)
135 {
136 BpId id;
137 Addr pc = it->second->pc;
138 auto space_id = getBpSpaceId(pc);
139 call().breakpoint_set_code(_instId, id, pc, space_id, 0, true);
140 it->second->id = id;
141 }
142
143 void
144 ThreadContext::uninstallBp(BpInfoIt it)
145 {
146 call().breakpoint_delete(_instId, it->second->id);
147 it->second->clearId();
148 }
149
150 void
151 ThreadContext::delBp(BpInfoIt it)
152 {
153 panic_if(!it->second->empty(),
154 "BP info still had events associated with it.");
155
156 if (it->second->validId())
157 uninstallBp(it);
158
159 bps.erase(it);
160 }
161
162 iris::IrisErrorCode
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)
166 {
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();
170
171 if (name != "component." + _irisPath)
172 return iris::E_ok;
173
174 if (event == "added")
175 _instId = id;
176 else if (event == "removed")
177 _instId = iris::IRIS_UINT64_MAX;
178 else
179 panic("Unrecognized event type %s", event);
180
181 return iris::E_ok;
182 }
183
184 iris::IrisErrorCode
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)
188 {
189 std::vector<iris::ResourceInfo> resources;
190 call().resource_getList(_instId, resources);
191
192 ResourceMap resourceMap;
193 for (auto &resource: resources)
194 resourceMap[resource.name] = resource;
195
196 initFromIrisInstance(resourceMap);
197
198 return iris::E_ok;
199 }
200
201 iris::IrisErrorCode
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)
205 {
206 if (fields.at("RUNNING").getAsBool()) {
207 // If this is just simulation time starting up, don't do anything.
208 return iris::E_ok;
209 }
210
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.
214 maintainStepping();
215
216 // Restart simulation time to make sure things progress once we give
217 // control back.
218 call().simulationTime_run(iris::IrisInstIdSimulationEngine);
219
220 return iris::E_ok;
221 }
222
223 iris::IrisErrorCode
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)
227 {
228 Addr pc = fields.at("PC").getU64();
229
230 auto it = getOrAllocBp(pc);
231
232 auto e_it = it->second->events.begin();
233 while (e_it != it->second->events.end()) {
234 PCEvent *e = *e_it;
235 // Advance e_it here since e might remove itself from the list.
236 e_it++;
237 e->process(this);
238 }
239
240 return iris::E_ok;
241 }
242
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)
250 {
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;
257 } else {
258 // This path doesn't (yet) exist. Set the ID to something invalid.
259 _instId = iris::IRIS_UINT64_MAX;
260 }
261
262 typedef ThreadContext Self;
263 iris::EventSourceInfo evSrcInfo;
264
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);
275
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());
285
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());
296
297 breakpointEventStreamId = iris::IRIS_UINT64_MAX;
298 }
299
300 ThreadContext::~ThreadContext()
301 {
302 call().eventStream_destroy(
303 iris::IrisInstIdSimulationEngine, initEventStreamId);
304 initEventStreamId = iris::IRIS_UINT64_MAX;
305 client.unregisterEventCallback("ec_IRIS_SIM_PHASE_INIT_LEAVE");
306
307 call().eventStream_destroy(
308 iris::IrisInstIdGlobalInstance, regEventStreamId);
309 regEventStreamId = iris::IRIS_UINT64_MAX;
310 client.unregisterEventCallback("ec_IRIS_INSTANCE_REGISTRY_CHANGED");
311
312 call().eventStream_destroy(
313 iris::IrisInstIdGlobalInstance, timeEventStreamId);
314 timeEventStreamId = iris::IRIS_UINT64_MAX;
315 client.unregisterEventCallback("ec_IRIS_SIMULATION_TIME_EVENT");
316 }
317
318 bool
319 ThreadContext::schedule(PCEvent *e)
320 {
321 auto it = getOrAllocBp(e->pc());
322 it->second->events.push_back(e);
323
324 if (_instId != iris::IRIS_UINT64_MAX && !it->second->validId())
325 installBp(it);
326
327 return true;
328 }
329
330 bool
331 ThreadContext::remove(PCEvent *e)
332 {
333 auto it = getOrAllocBp(e->pc());
334 it->second->events.remove(e);
335
336 if (it->second->empty())
337 delBp(it);
338
339 return true;
340 }
341
342 bool
343 ThreadContext::translateAddress(Addr &paddr, iris::MemorySpaceId p_space,
344 Addr vaddr, iris::MemorySpaceId v_space)
345 {
346 iris::MemoryAddressTranslationResult result;
347 auto ret = noThrow().memory_translateAddress(
348 _instId, result, v_space, vaddr, p_space);
349
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)
355 return false;
356
357 panic("No legal translation IRIS address translation found.");
358 }
359
360 if (result.address.empty())
361 return false;
362
363 if (result.address.size() > 1) {
364 warn("Multiple mappings for address %#x.", vaddr);
365 return false;
366 }
367
368 paddr = result.address[0];
369 return true;
370 }
371
372 void
373 ThreadContext::scheduleInstCountEvent(Event *event, Tick count)
374 {
375 Tick now = getCurrentInstCount();
376 comInstEventQueue.schedule(event, count);
377 if (count <= now)
378 call().simulationTime_stop(iris::IrisInstIdSimulationEngine);
379 else
380 maintainStepping();
381 }
382
383 void
384 ThreadContext::descheduleInstCountEvent(Event *event)
385 {
386 comInstEventQueue.deschedule(event);
387 maintainStepping();
388 }
389
390 Tick
391 ThreadContext::getCurrentInstCount()
392 {
393 uint64_t count;
394 auto ret = call().step_getStepCounterValue(_instId, count, "instruction");
395 panic_if(ret != iris::E_ok, "Failed to get instruction count.");
396 return count;
397 }
398
399 void
400 ThreadContext::initMemProxies(::ThreadContext *tc)
401 {
402 if (FullSystem) {
403 assert(!physProxy && !virtProxy);
404 physProxy.reset(new PortProxy(_cpu->getSendFunctional(),
405 _cpu->cacheLineSize()));
406 virtProxy.reset(new FSTranslatingPortProxy(tc));
407 } else {
408 assert(!virtProxy);
409 virtProxy.reset(new SETranslatingPortProxy(
410 _cpu->getSendFunctional(), getProcessPtr(),
411 SETranslatingPortProxy::NextPage));
412 }
413 }
414
415 ThreadContext::Status
416 ThreadContext::status() const
417 {
418 return _status;
419 }
420
421 void
422 ThreadContext::setStatus(Status new_status)
423 {
424 if (new_status == Active) {
425 if (_status != Active)
426 call().perInstanceExecution_setState(_instId, true);
427 } else {
428 if (_status == Active)
429 call().perInstanceExecution_setState(_instId, false);
430 }
431 _status = new_status;
432 }
433
434 ArmISA::PCState
435 ThreadContext::pcState() const
436 {
437 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
438 ArmISA::PCState pc;
439
440 pc.thumb(cpsr.t);
441 pc.nextThumb(pc.thumb());
442 pc.jazelle(cpsr.j);
443 pc.nextJazelle(cpsr.j);
444 pc.aarch64(!cpsr.width);
445 pc.nextAArch64(!cpsr.width);
446 pc.illegalExec(false);
447
448 iris::ResourceReadResult result;
449 call().resource_read(_instId, result, pcRscId);
450 Addr addr = result.data.at(0);
451 if (cpsr.width && cpsr.t)
452 addr = addr & ~0x1;
453 pc.set(addr);
454
455 return pc;
456 }
457 void
458 ThreadContext::pcState(const ArmISA::PCState &val)
459 {
460 Addr pc = val.pc();
461
462 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
463 if (cpsr.width && cpsr.t)
464 pc = pc | 0x1;
465
466 iris::ResourceWriteResult result;
467 call().resource_write(_instId, result, pcRscId, pc);
468 }
469
470 Addr
471 ThreadContext::instAddr() const
472 {
473 return pcState().instAddr();
474 }
475
476 Addr
477 ThreadContext::nextInstAddr() const
478 {
479 return pcState().nextInstAddr();
480 }
481
482 RegVal
483 ThreadContext::readMiscRegNoEffect(RegIndex misc_reg) const
484 {
485 iris::ResourceReadResult result;
486 call().resource_read(_instId, result, miscRegIds.at(misc_reg));
487 return result.data.at(0);
488 }
489
490 void
491 ThreadContext::setMiscRegNoEffect(RegIndex misc_reg, const RegVal val)
492 {
493 iris::ResourceWriteResult result;
494 call().resource_write(_instId, result, miscRegIds.at(misc_reg), val);
495 }
496
497 RegVal
498 ThreadContext::readIntReg(RegIndex reg_idx) const
499 {
500 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
501
502 iris::ResourceReadResult result;
503 if (cpsr.width)
504 call().resource_read(_instId, result, intReg32Ids.at(reg_idx));
505 else
506 call().resource_read(_instId, result, intReg64Ids.at(reg_idx));
507 return result.data.at(0);
508 }
509
510 void
511 ThreadContext::setIntReg(RegIndex reg_idx, RegVal val)
512 {
513 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
514
515 iris::ResourceWriteResult result;
516 if (cpsr.width)
517 call().resource_write(_instId, result, intReg32Ids.at(reg_idx), val);
518 else
519 call().resource_write(_instId, result, intReg64Ids.at(reg_idx), val);
520 }
521
522 const ArmISA::VecRegContainer &
523 ThreadContext::readVecReg(const RegId &reg_id) const
524 {
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 &reg = vecRegs.at(idx);
532
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);
538
539 return reg;
540 }
541
542 const ArmISA::VecRegContainer &
543 ThreadContext::readVecRegFlat(RegIndex idx) const
544 {
545 return readVecReg(RegId(VecRegClass, idx));
546 }
547
548 } // namespace Iris