This repository has been archived by the owner on Sep 7, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
/
BCMHostDongleInterface.py
247 lines (190 loc) · 8.99 KB
/
BCMHostDongleInterface.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# Legilimency - Memory Analysis Framework for iOS
# --------------------------------------
#
# Written and maintained by Gal Beniamini <[email protected]>
#
# Copyright 2017 Google Inc. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from defs import *
import struct
#The offset of the "rxd" field in the dma_info structure
RXD_OFFSET = 64
#The offset of the "nrxd" field in the dma_info structure
NRXD_OFFSET = 108
#The size of a 64-bit RX descriptor in the DMA descriptor chain
RX_DESC_SIZE = 16
#The offset of the rings_info_ptr field in the PCIe shared structure
RINGS_INFO_PTR_OFFSET = 12 * DWORD_SIZE
#The offset of the flow ring instance array in the PCIe object
FLOW_RINGS_OFFSET = 1328
#The size of a ring_mem entry in the ringmem array
RING_MEM_ENTRY_SIZE = 16
#The number of D2H/H2D rings (not including flow rings!)
NUM_RINGS = 5
#The number of D2H rings (not including flow rings!)
NUM_D2H_RINGS = 3
#The indices of each of the generic H2D/D2H rings (not including flow rings)
H2D_MSGRING_CONTROL_SUBMIT = 0
H2D_MSGRING_RXPOST_SUBMIT = 1
D2H_MSGRING_CONTROL_COMPLETE = 2
D2H_MSGRING_TX_COMPLETE = 3
D2H_MSGRING_RX_COMPLETE = 4
#The offsets of the AppleBCMWLANPCIeSubmissionRing instances for each H2D ring in the PCIe object
H2D_RING_OFFSETS = {H2D_MSGRING_CONTROL_SUBMIT : 1232,
H2D_MSGRING_RXPOST_SUBMIT : 1272}
#The offsets of the AppleBCMWLANPCIeCompletionRing instances for each D2H ring in the PCIe object
D2H_RING_OFFSETS = {D2H_MSGRING_CONTROL_COMPLETE : 1240,
D2H_MSGRING_TX_COMPLETE : 1288,
D2H_MSGRING_RX_COMPLETE : 1280}
#The types of indices present
H2D_WRITE = 0
H2D_READ = 1
D2H_WRITE = 2
D2H_READ = 3
#The hostaddr offsets for each type of index provided, within rings_info structure
INDEX_HOSTADDR_OFFSETS = {H2D_WRITE : 5 * DWORD_SIZE,
H2D_READ : 7 * DWORD_SIZE,
D2H_WRITE : 9 * DWORD_SIZE,
D2H_READ : 11 * DWORD_SIZE}
class BCMHostDongleInterface(object):
"""
This class allows inspection of the H2D/D2H communication between the BCM chip and the host.
"""
def __init__(self, bcmclient):
"""
Creates a new instance, using the underlying BCMClient to communicate with the Wi-Fi SoC.
"""
self.bcmclient = bcmclient
self.client = bcmclient.client
def dump_rx_descriptors(self, dma_object_addr):
"""
Dumps each RXD in the given DMA object.
"""
rxd = self.bcmclient.fw_read32(dma_object_addr + RXD_OFFSET)
nrxd = struct.unpack("<HH", struct.pack("<I", self.bcmclient.fw_read32(dma_object_addr + NRXD_OFFSET)))[0]
print "rxd: %X" % rxd
print "nrxd: %X" % nrxd
for i in range(0, nrxd):
print "desc[%d] : 0x%016X" % (i, self.bcmclient.fw_read64(rxd + RX_DESC_SIZE*i + QWORD_SIZE))
def get_pciedev_shared_t_addr(self):
"""
Returns the address of the pciedev_shared_t structure.
"""
return self.bcmclient.fw_read32(self.bcmclient.ram_offset + self.bcmclient.ram_size - DWORD_SIZE)
def dump_pcie_rings(self):
"""
Dumps the information about each of the PCIe rings.
"""
pciedev_shared_t_addr = self.bcmclient.fw_read32(self.bcmclient.ram_offset + self.bcmclient.ram_size - DWORD_SIZE)
rings_info_ptr = self.bcmclient.fw_read32(pciedev_shared_t_addr + RINGS_INFO_PTR_OFFSET)
ringmem_ptr = self.bcmclient.fw_read32(rings_info_ptr)
print "rings_info_ptr: %X" % rings_info_ptr
print "pciedev_shared_t_addr: 0x%08X" % pciedev_shared_t_addr
print "ringmem_ptr: %X" % ringmem_ptr
for i in range(0, NUM_RINGS):
ring_mem_entry = self.bcmclient.fw_read(ringmem_ptr + i * RING_MEM_ENTRY_SIZE)
(_, _, _, max_items, len_items, ringaddr) = struct.unpack("<HBBHHQ", ring_mem_entry)
ringaddr_ptr = ringmem_ptr + (i + 1) * RING_MEM_ENTRY_SIZE - QWORD_SIZE
ringaddr = self.bcmclient.fw_read64(ringaddr_ptr)
print "ring : %d" % i
print "max_items: %d, len_items: %d" % (max_items, len_items)
print "ringaddr_ptr: %X, ringaddr: %X " % (ringaddr_ptr, ringaddr)
def get_index_hostaddr(self, index_type):
"""
Returns the hostaddr (IO-Space address) of the index type provided
"""
pciedev_shared_t_addr = self.bcmclient.fw_read32(self.bcmclient.ram_offset + self.bcmclient.ram_size - DWORD_SIZE)
rings_info_ptr = self.bcmclient.fw_read32(pciedev_shared_t_addr + RINGS_INFO_PTR_OFFSET)
return self.bcmclient.fw_read32(rings_info_ptr + INDEX_HOSTADDR_OFFSETS[index_type])
def get_h2d_w_idx_hostaddr(self):
"""
Returns the address of the h2d_w_idx_hostaddr field in the rings_info_ptr
"""
return self.get_index_hostaddr(H2D_WRITE)
def get_h2d_r_idx_hostaddr(self):
"""
Returns the address of the h2d_r_idx_hostaddr field in the rings_info_ptr
"""
return self.get_index_hostaddr(H2D_READ)
def get_d2h_w_idx_hostaddr(self):
"""
Returns the address of the d2h_w_idx_hostaddr field in the rings_info_ptr
"""
return self.get_index_hostaddr(D2H_WRITE)
def get_d2h_r_idx_hostaddr(self):
"""
Returns the address of the d2h_r_idx_hostaddr field in the rings_info_ptr
"""
return self.get_index_hostaddr(D2H_READ)
def get_ring_instance(ring_index):
"""
Returns the ring instance for the corresponding ring index
"""
pcie_obj = self.bcmclient.get_pcie_obj()
if ring_index in H2D_RING_OFFSETS:
clazz = AppleBCMWLANPCIeSubmissionRing
off = H2D_RING_OFFSETS[ring_index]
elif ring_index in D2H_RING_OFFSETS:
clazz = AppleBCMWLANPCIeCompletionRing
off = D2H_RING_OFFSETS[ring_index]
else:
raise Exception("Invalid ring index: %d" % ring_index)
return clazz(self.client, self.client.read(pcie_obj + off), ring_index)
def get_h2d_msgring_control_submit_ring(self):
"""
Returns the AppleBCMWLANPCIeSubmissionRing instance for ring #0 (H2D_MSGRING_CONTROL_SUBMIT)
"""
return self.get_ring_instance(H2D_MSGRING_CONTROL_SUBMIT)
def get_h2d_msgring_rxpost_submit_ring(self):
"""
Returns the AppleBCMWLANPCIeSubmissionRing instance for ring #1 (H2D_MSGRING_RXPOST_SUBMIT)
"""
return self.get_ring_instance(H2D_MSGRING_RXPOST_SUBMIT)
def get_d2h_msgring_control_complete_ring(self):
"""
Returns the AppleBCMWLANPCIeCompletionRing instance for ring #2 (D2H_MSGRING_CONTROL_COMPLETE)
"""
return self.get_ring_instance(D2H_MSGRING_CONTROL_SUBMIT)
def get_d2h_msgring_tx_complete_ring(self):
"""
Returns the AppleBCMWLANPCIeCompletionRing instance for ring #3 (D2H_MSGRING_TX_COMPLETE)
"""
return self.get_ring_instance(D2H_MSGRING_TX_COMPLETE)
def get_d2h_msgring_rx_complete_ring(self):
"""
Returns the AppleBCMWLANPCIeCompletionRing instance for ring #4 (D2H_MSGRING_RX_COMPLETE)
"""
return self.get_ring_instance(D2H_MSGRING_RX_COMPLETE)
def get_flow_ring(self, flow_id):
"""
Returns the flow ring corresponding to the given flow ID
"""
pcie_obj = self.bcmclient.get_pcie_obj()
obj_addr = self.client.read64(pcie_obj + flow_id * QWORD_SIZE + FLOW_RINGS_OFFSET)
if obj_addr == 0:
return None
return AppleBCMWLANPCIeSubmissionRing(self.client, obj_addr, flow_id + NUM_D2H_RINGS)
def dump_submission_and_completion_rings(self):
"""
Dumps information about the submission and completion rings
"""
compl_rings = [self.get_d2h_msgring_control_complete_ring(),
self.get_d2h_msgring_tx_complete_ring(),
self.get_d2h_msgring_rx_complete_ring()]
subm_rings = [self.get_h2d_msgring_control_submit_ring(),
self.get_h2d_msgring_rxpost_submit_ring()]
for ring in (subm_rings + compl_rings):
print "Ring ID: %d" % ring.get_ring_id()
print "Ring Base Address: %016X" % ring.get_base_address()
print "Ring Element Size: %d" % ring.get_element_size()
print "Ring Index Pointer %016X" % ring.get_index_pointer()