blob: 60fb8ed6dfcf4e391e509468ff0638d9c896f58c [file] [log] [blame]
Kristofer Jonssone56b6e42022-09-29 11:52:22 +02001#
2# SPDX-FileCopyrightText: Copyright 2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
3#
4# SPDX-License-Identifier: Apache-2.0
5#
6# Licensed under the Apache License, Version 2.0 (the License); you may
7# not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an AS IS BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19from .elf import *
20from .types import *
21import json
22import mmap
23import os
24from sys import stderr
25
26class InputInterface:
27 def readEventRecord(self) -> EventRecord_t:
28 ...
29
30class InputFile(InputInterface):
31 def __init__(self, fname):
32 self.file = open(fname, 'rb')
33
34 def readEventRecord(self):
35 data = self.file.read(EventRecord_t.SIZE)
36 if len(data) == 0:
37 raise EOFError
38
39 yield data
40
41class InputRingBuffer(InputInterface):
42 def __init__(self, elfFile):
43 from elftools.elf.elffile import ELFFile
44
45 with open(elfFile, 'rb') as f:
46 elf = ELFFile(f)
47 symbol = elfFindSymbol(elf, 'EventRecorderInfo')
48 elfInfo = EventRecorderInfo_t(elfGetData(elf, symbol.entry.st_value, symbol.entry.st_size))
49 memInfo = EventRecorderInfo_t(self.read(symbol.entry.st_value, symbol.entry.st_size))
50
51 # Validate EventRecorder info
52 if elfInfo.protocolType != memInfo.protocolType or \
53 elfInfo.protocolVersion != memInfo.protocolVersion or \
54 elfInfo.eventBuffer != memInfo.eventBuffer or \
55 elfInfo.eventStatus != memInfo.eventStatus:
56 raise Exception(f'EventRecorder info mismatch. elf={elfInfo}, mem={memInfo}')
57
58 self.info = elfInfo
59 status = EventStatus_t(self.read(self.info.eventStatus, EventStatus_t.SIZE))
60 self.timestamp = status.tsLast
61 self.recordIndex = status.recordIndex
62 self.overflow = 0
63
64 def readEventRecord(self):
65 # Read status and use timestamp to detect if there are new samples
66 status = EventStatus_t(self.read(self.info.eventStatus, EventStatus_t.SIZE))
67 if self.timestamp == status.tsLast:
68 return None
69
70 self.timestamp = status.tsLast
71
72 # Detect firmware reset
73 if self.recordIndex > status.recordIndex:
74 self.recordIndex = 0
75
76 # Detect of recordIndex has overflowed the ring buffer
77 if status.recordIndex - self.recordIndex > self.info.recordCount:
78 stderr.write('Warning: Ring buffer overflow\n')
79 self.overflow = self.overflow + 1
80 self.recordIndex = status.recordIndex
81
82 # Generate data for each event record
83 for i in range(self.recordIndex, status.recordIndex):
84 i = i % self.info.recordCount
85 yield self.read(self.info.eventBuffer + EventRecord_t.SIZE * i, EventRecord_t.SIZE)
86
87 self.recordIndex = status.recordIndex
88
89 def read(self, address, size) -> bytearray:
90 ...
91
92class InputDAPLink(InputRingBuffer):
93 def __init__(self, elfFile):
94 self._open()
95 super().__init__(elfFile)
96 self.target.reset()
97
98 def _open(self):
99 from pyocd.core.helpers import ConnectHelper
100
101 self.session = ConnectHelper.session_with_chosen_probe()
102 self.board = self.session.board
103 self.target = self.board.target
104
105 self.session.open()
106
107 def read(self, address, size):
108 from pyocd.core.exceptions import Error
109
110 for i in range(1000):
111 try:
112 return bytearray(self.target.read_memory_block8(address, size))
113 except Error:
114 pass
115
116class InputMem(InputRingBuffer):
117 def __init__(self, elfFile, jsonFile):
118 with open(jsonFile, 'r') as f:
119 jsonDoc = json.loads(f.read())
120
121 self.memoryMap = []
122 for memoryMap in jsonDoc['memoryMap']:
123 host = int(memoryMap['host'], 16)
124 device = int(memoryMap['device'], 16)
125 size = int(memoryMap['size'], 16)
126 self.memoryMap.append(DevMemDevice(host, device, size))
127
128 super().__init__(elfFile)
129
130 def read(self, device, size):
131 for memoryMap in self.memoryMap:
132 data = memoryMap.read(device, size)
133 if data:
134 return data
135
136 stderr.write(f'Warning: No mapping found for device address {hex(device)} size {size}.\n')
137 return None
138
139class DevMem:
140 def __init__(self, address, size):
141 self.base_address = address & ~(mmap.PAGESIZE - 1)
142 self.offset = address - self.base_address
143 self.size = size + self.offset
144
145 self.fd = os.open('/dev/mem', os.O_RDWR | os.O_SYNC)
146 self.mem = mmap.mmap(self.fd, self.size, mmap.MAP_SHARED, mmap.PROT_READ,
147 offset=self.base_address)
148
149 def __del__(self):
150 os.close(self.fd)
151
152 def read(self, offset, size):
153 self.mem.seek(self.offset + offset)
154
155 data = bytearray(size)
156 for i in range(size):
157 data[i] = self.mem.read_byte()
158
159 return data
160
161class DevMemDevice(DevMem):
162 def __init__(self, host, device, size):
163 super().__init__(host, size)
164
165 self.device = device
166 self.size = size
167
168 def read(self, device, size):
169 offset = device - self.device
170 if offset < 0 or (offset + size) > self.size:
171 return None
172
173 return super().read(offset, size)