mirror of
https://github.com/qca/qca-swiss-army-knife.git
synced 2026-01-27 17:07:18 +01:00
scripts: ath10k: add ath10k-fwencoder and ath10k-bdencoder
Scripts for handling ath10k firmware image container format.
This commit is contained in:
parent
41b194534b
commit
b2b06517bb
2 changed files with 1128 additions and 0 deletions
277
tools/scripts/ath10k/ath10k-bdencoder
Executable file
277
tools/scripts/ath10k/ath10k-bdencoder
Executable file
|
|
@ -0,0 +1,277 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (c) 2015 Qualcomm Atheros, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
import struct
|
||||
import ctypes
|
||||
import sys
|
||||
import os.path
|
||||
from optparse import OptionParser
|
||||
import json
|
||||
|
||||
MAX_BUF_LEN = 200000
|
||||
ATH10K_BOARD_SIGNATURE = "QCA-ATH10K-BOARD"
|
||||
|
||||
DEFAULT_BD_API = 2
|
||||
DEFAULT_BOARD_FILE = 'board-%d.bin' % DEFAULT_BD_API
|
||||
DEFAULT_JSON_FILE = 'board-%d.json' % DEFAULT_BD_API
|
||||
TYPE_LENGTH_SIZE = 8
|
||||
|
||||
ATH10K_BD_IE_BOARD = 0
|
||||
|
||||
ATH10K_BD_IE_BOARD_NAME = 0
|
||||
ATH10K_BD_IE_BOARD_DATA = 1
|
||||
|
||||
|
||||
def padding_needed(len):
|
||||
if len % 4 != 0:
|
||||
return 4 - len % 4
|
||||
return 0
|
||||
|
||||
|
||||
def add_ie(buf, offset, id, value):
|
||||
length = len(value)
|
||||
padding_len = padding_needed(length)
|
||||
length = length + padding_len
|
||||
|
||||
padding = ctypes.create_string_buffer(padding_len)
|
||||
|
||||
for i in range(padding_len):
|
||||
struct.pack_into('<B', padding, i, 0x6d)
|
||||
|
||||
fmt = '<2i%ds%ds' % (len(value), padding_len)
|
||||
struct.pack_into(fmt, buf, offset, id, len(value), value, padding.raw)
|
||||
offset = offset + TYPE_LENGTH_SIZE + len(value) + padding_len
|
||||
|
||||
return offset
|
||||
|
||||
|
||||
class BoardContainer:
|
||||
|
||||
def create_board(self, filename, names):
|
||||
if os.path.getsize(filename) > MAX_BUF_LEN:
|
||||
print "file %s is too large, maximum size is %d" % (filename,
|
||||
MAX_BUF_LEN)
|
||||
return -1
|
||||
|
||||
buf = ctypes.create_string_buffer(MAX_BUF_LEN)
|
||||
offset = 0
|
||||
|
||||
# add name IEs
|
||||
for name in names:
|
||||
offset = add_ie(buf, offset, ATH10K_BD_IE_BOARD_NAME, str(name))
|
||||
|
||||
# add data IEs
|
||||
f = open(filename, 'rb')
|
||||
data = f.read()
|
||||
offset = add_ie(buf, offset, ATH10K_BD_IE_BOARD_DATA, data)
|
||||
f.close()
|
||||
|
||||
# return the full IE including padding
|
||||
return buf[:offset]
|
||||
|
||||
def pack_boards(self, mapping):
|
||||
for board in mapping:
|
||||
filename = board['data']
|
||||
payload = self.create_board(filename, board['names'])
|
||||
|
||||
self.buf_len = add_ie(self.buf, self.buf_len,
|
||||
ATH10K_BD_IE_BOARD, payload)
|
||||
|
||||
def create_single_bin(self, name):
|
||||
fd = open(name, 'wb')
|
||||
fd.write(self.buf.raw[0:self.buf_len])
|
||||
fd.close()
|
||||
print "board binary file '%s' is created" % name
|
||||
|
||||
def add_signature(self, signature):
|
||||
signature = signature + '\0'
|
||||
length = len(signature)
|
||||
pad_len = padding_needed(length)
|
||||
length = length + pad_len
|
||||
|
||||
padding = ctypes.create_string_buffer(pad_len)
|
||||
|
||||
for i in range(pad_len):
|
||||
struct.pack_into('<B', padding, i, 0x6d)
|
||||
|
||||
fmt = '<%ds%ds' % (len(signature), pad_len)
|
||||
struct.pack_into(fmt, self.buf, self.buf_len, signature, padding.raw)
|
||||
self.buf_len = self.buf_len + length
|
||||
self.sig_len = length # signature length includes null byte+padding
|
||||
|
||||
def open(self, name):
|
||||
f = open(name, 'rb')
|
||||
self.buf = f.read()
|
||||
f.close()
|
||||
self.buf_len = len(self.buf)
|
||||
|
||||
offset = 0
|
||||
self.boards = []
|
||||
|
||||
fmt = '<%dsb' % (len(ATH10K_BOARD_SIGNATURE))
|
||||
(signature, null) = struct.unpack_from(fmt, self.buf, offset)
|
||||
|
||||
if signature != ATH10K_BOARD_SIGNATURE or null != 0:
|
||||
print "invalid signature found in %s" % name
|
||||
return 1
|
||||
|
||||
offset = offset + self.sig_len
|
||||
i = 0
|
||||
|
||||
# FIXME: this supports only ATH10K_BD_IE_BOARD for now, needs
|
||||
# to refactored to support more IEs
|
||||
|
||||
# looping main IEs
|
||||
while offset < self.buf_len:
|
||||
(ie_id, ie_len) = struct.unpack_from('<2i', self.buf, offset)
|
||||
offset = offset + TYPE_LENGTH_SIZE
|
||||
|
||||
if offset + ie_len > self.buf_len:
|
||||
print 'Error: Buffer too short (%d + %d > %d)' % (offset,
|
||||
ie_len,
|
||||
self.buf_len)
|
||||
return 1
|
||||
|
||||
# skip if an unknown IE
|
||||
if ie_id != ATH10K_BD_IE_BOARD:
|
||||
offset = offset + ie_len + padding_needed(ie_len)
|
||||
continue
|
||||
|
||||
board = {}
|
||||
board['names'] = []
|
||||
|
||||
# looping board IEs
|
||||
while ie_len > 0:
|
||||
(board_ie_id, board_ie_len) = struct.unpack_from('<2i',
|
||||
self.buf,
|
||||
offset)
|
||||
offset = offset + TYPE_LENGTH_SIZE
|
||||
|
||||
if board_ie_len > ie_len:
|
||||
print 'Error: board_ie_len too big (%d > %d)' % (board_ie_len, ie_len)
|
||||
return 1
|
||||
|
||||
if board_ie_id == ATH10K_BD_IE_BOARD_NAME:
|
||||
fmt = '<%ds' % board_ie_len
|
||||
(name, ) = struct.unpack_from(fmt, self.buf, offset)
|
||||
board['names'].append(name)
|
||||
elif board_ie_id == ATH10K_BD_IE_BOARD_DATA:
|
||||
fmt = '<%ds' % board_ie_len
|
||||
(board_data, ) = struct.unpack_from(fmt, self.buf, offset)
|
||||
board['data'] = board_data
|
||||
|
||||
offset = offset + board_ie_len + padding_needed(board_ie_len)
|
||||
ie_len = ie_len - TYPE_LENGTH_SIZE - board_ie_len - padding_needed(board_ie_len)
|
||||
|
||||
self.boards.append(board)
|
||||
i = i + 1
|
||||
|
||||
def __init__(self):
|
||||
self.buf = ctypes.create_string_buffer(MAX_BUF_LEN)
|
||||
self.buf_len = 0
|
||||
|
||||
self.add_signature(ATH10K_BOARD_SIGNATURE)
|
||||
|
||||
|
||||
def extract(options, args):
|
||||
if len(args) != 1:
|
||||
print "Error: extract option requires input filename\n"
|
||||
usage()
|
||||
return 1
|
||||
|
||||
cont = BoardContainer()
|
||||
cont.open(args[0])
|
||||
|
||||
mapping = []
|
||||
|
||||
for board in cont.boards:
|
||||
filename = board['names'][0] + '.bin'
|
||||
|
||||
b = {}
|
||||
b['names'] = board['names']
|
||||
b['data'] = filename
|
||||
mapping.append(b)
|
||||
|
||||
f = open(filename, 'w')
|
||||
f.write(board['data'])
|
||||
f.close()
|
||||
|
||||
print "%s created size: %d" % (filename, len(board['data']))
|
||||
|
||||
filename = DEFAULT_JSON_FILE
|
||||
f = open(filename, 'w')
|
||||
f.write(json.dumps(mapping))
|
||||
f.close()
|
||||
|
||||
print "%s created" % (filename)
|
||||
|
||||
|
||||
def create(options):
|
||||
|
||||
mapping_file = options.create
|
||||
|
||||
if options.output:
|
||||
output = options.output
|
||||
else:
|
||||
output = DEFAULT_BOARD_FILE
|
||||
|
||||
cont = BoardContainer()
|
||||
|
||||
if not os.path.exists(mapping_file):
|
||||
print 'mapping file %s not found' % (mapping_file)
|
||||
return
|
||||
|
||||
f = open(mapping_file, 'r')
|
||||
mapping = json.loads(f.read())
|
||||
cont.pack_boards(mapping)
|
||||
f.close()
|
||||
|
||||
cont.create_single_bin(output)
|
||||
|
||||
|
||||
def usage():
|
||||
print "Usage:"
|
||||
print "ath10k-board-encoder <-c or --create> <optional -o or --output> <FILE>"
|
||||
print "ath10k-board-encoder <-e or --extract> <FILE>"
|
||||
|
||||
|
||||
def main():
|
||||
parser = OptionParser()
|
||||
|
||||
parser.add_option("-c", "--create", dest="create",
|
||||
help='Create single board binary for ath10k from '
|
||||
'mapping file')
|
||||
parser.add_option("-e", "--extract", action="store_true", dest="extract",
|
||||
help='extract board file from encoded single binary')
|
||||
parser.add_option("-o", "--output", action="store", type="string",
|
||||
dest="output", help='Name of output file')
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.create:
|
||||
try:
|
||||
return create(options)
|
||||
except Exception as e:
|
||||
print 'Create failed: %s' % e
|
||||
sys.exit(2)
|
||||
elif options.extract:
|
||||
return extract(options, args)
|
||||
else:
|
||||
return usage()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
851
tools/scripts/ath10k/ath10k-fwencoder
Executable file
851
tools/scripts/ath10k/ath10k-fwencoder
Executable file
|
|
@ -0,0 +1,851 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import ctypes
|
||||
import struct
|
||||
import optparse
|
||||
import time
|
||||
import math
|
||||
import logging
|
||||
import sys
|
||||
import os.path
|
||||
import traceback
|
||||
import binascii
|
||||
|
||||
DEFAULT_FW_API_VERSION = 4
|
||||
|
||||
ATH10K_SIGNATURE = "QCA-ATH10K"
|
||||
MAX_LEN = 2000000
|
||||
|
||||
ATH10K_FW_IE_FW_VERSION = 0
|
||||
ATH10K_FW_IE_TIMESTAMP = 1
|
||||
ATH10K_FW_IE_FEATURES = 2
|
||||
ATH10K_FW_IE_FW_IMAGE = 3
|
||||
ATH10K_FW_IE_OTP_IMAGE = 4
|
||||
ATH10K_FW_IE_WMI_OP_VERSION = 5
|
||||
ATH10K_FW_IE_HTT_OP_VERSION = 6
|
||||
ATH10K_FW_IE_FW_CODE_SWAP_IMAGE = 7
|
||||
|
||||
# enum ath10k_fw_features from ath10k/core.h
|
||||
ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0
|
||||
ATH10K_FW_FEATURE_WMI_10X = 1
|
||||
ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2
|
||||
ATH10K_FW_FEATURE_NO_P2P = 3
|
||||
ATH10K_FW_FEATURE_WMI_10_2 = 4
|
||||
ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5
|
||||
ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6
|
||||
ATH10K_FW_FEATURE_IGNORE_OTP_RESULT = 7
|
||||
ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING = 8
|
||||
ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9
|
||||
ATH10K_FW_FEATURE_RAW_MODE_SUPPORT = 10
|
||||
ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA = 11
|
||||
ATH10K_FW_FEATURE_MFP_SUPPORT = 12
|
||||
ATH10K_FW_FEATURE_MAX = 13
|
||||
|
||||
feature_map = {
|
||||
'ext-wmi-mgmt-rx': ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX,
|
||||
'wmi-10x': ATH10K_FW_FEATURE_WMI_10X,
|
||||
'wmi-mgmt-tx': ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
|
||||
'no-p2p': ATH10K_FW_FEATURE_NO_P2P,
|
||||
'wmi-10-2': ATH10K_FW_FEATURE_WMI_10_2,
|
||||
'multi-vif-ps': ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,
|
||||
'wowlan': ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
|
||||
'ignore-otp-result': ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
|
||||
'no-nwifi-decap-4addr-padding':
|
||||
ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
|
||||
'skip-clock-init': ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
|
||||
'raw-mode': ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,
|
||||
'adaptive-cca': ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA,
|
||||
'mfp-support': ATH10K_FW_FEATURE_MFP_SUPPORT
|
||||
}
|
||||
|
||||
# from enum ath10k_fw_wmi_op_version in ath10k/hw.h
|
||||
ATH10K_FW_WMI_OP_VERSION_UNSET = 0
|
||||
ATH10K_FW_WMI_OP_VERSION_MAIN = 1
|
||||
ATH10K_FW_WMI_OP_VERSION_10_1 = 2
|
||||
ATH10K_FW_WMI_OP_VERSION_10_2 = 3
|
||||
ATH10K_FW_WMI_OP_VERSION_TLV = 4
|
||||
ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5
|
||||
ATH10K_FW_WMI_OP_VERSION_10_4 = 6
|
||||
|
||||
wmi_op_version_map = {
|
||||
'unset': ATH10K_FW_WMI_OP_VERSION_UNSET,
|
||||
'main': ATH10K_FW_WMI_OP_VERSION_MAIN,
|
||||
'10.1': ATH10K_FW_WMI_OP_VERSION_10_1,
|
||||
'10.2': ATH10K_FW_WMI_OP_VERSION_10_2,
|
||||
'tlv': ATH10K_FW_WMI_OP_VERSION_TLV,
|
||||
'10.2.4': ATH10K_FW_WMI_OP_VERSION_10_2_4,
|
||||
'10.4': ATH10K_FW_WMI_OP_VERSION_10_4,
|
||||
}
|
||||
|
||||
|
||||
# from enum ath10k_fw_wmi_op_version in ath10k/hw.h
|
||||
ATH10K_FW_HTT_OP_VERSION_UNSET = 0
|
||||
ATH10K_FW_HTT_OP_VERSION_MAIN = 1
|
||||
ATH10K_FW_HTT_OP_VERSION_10_1 = 2
|
||||
ATH10K_FW_HTT_OP_VERSION_TLV = 3
|
||||
ATH10K_FW_HTT_OP_VERSION_10_4 = 4
|
||||
|
||||
htt_op_version_map = {
|
||||
'unset': ATH10K_FW_HTT_OP_VERSION_UNSET,
|
||||
'main': ATH10K_FW_HTT_OP_VERSION_MAIN,
|
||||
'10.1': ATH10K_FW_HTT_OP_VERSION_10_1,
|
||||
'tlv': ATH10K_FW_HTT_OP_VERSION_TLV,
|
||||
'10.4': ATH10K_FW_HTT_OP_VERSION_10_4,
|
||||
}
|
||||
|
||||
ETHTOOL_FWVERS_LEN = 32
|
||||
|
||||
# global variables
|
||||
logger = None
|
||||
|
||||
|
||||
class FWEncoderError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_output_name(fw_api=None):
|
||||
if fw_api != None:
|
||||
api = fw_api
|
||||
else:
|
||||
api = DEFAULT_FW_API_VERSION
|
||||
|
||||
return 'firmware-%s.bin' % api
|
||||
|
||||
|
||||
class FirmwareContainer:
|
||||
|
||||
def add_element(self, type_id, value):
|
||||
length = len(value)
|
||||
padding_len = padding_needed(length)
|
||||
length = length + padding_len
|
||||
|
||||
padding = ctypes.create_string_buffer(padding_len)
|
||||
|
||||
for i in range(padding_len):
|
||||
struct.pack_into('<B', padding, i, 0x77)
|
||||
|
||||
logger.debug('adding id %d len(value) %d'
|
||||
'padding_len %d' % (type_id,
|
||||
len(value),
|
||||
padding_len))
|
||||
fmt = '<ii%ds%ds' % (len(value), padding_len)
|
||||
struct.pack_into(fmt, self.buf, self.buf_len, type_id, len(value),
|
||||
value, padding.raw)
|
||||
self.buf_len = self.buf_len + 4 + 4 + len(value) + padding_len
|
||||
|
||||
def add_u32(self, type_id, value):
|
||||
if not type(value) is int:
|
||||
raise FWEncoderError('u32 IE %d is not int: %s' %
|
||||
(type_id, str(value)))
|
||||
|
||||
buf = ctypes.create_string_buffer(4)
|
||||
struct.pack_into("<i", buf, 0, value)
|
||||
self.add_element(type_id, buf.raw)
|
||||
|
||||
def read_u32(self, type_id):
|
||||
(val,) = struct.unpack_from("<i", self.elements[type_id])
|
||||
return val
|
||||
|
||||
def add_bitmap(self, ie, enabled, maximum):
|
||||
|
||||
if (max(enabled) >= maximum):
|
||||
logger.error("bitmap %d out of maximum (%d >= %d)" % \
|
||||
(ie, max(enabled), maximum))
|
||||
return
|
||||
|
||||
bytes = [0] * maximum
|
||||
|
||||
for i in range(maximum):
|
||||
if i not in enabled:
|
||||
continue
|
||||
|
||||
max_set = i
|
||||
index = i / 8
|
||||
bit = i % 8
|
||||
bytes[index] = bytes[index] | (1 << bit)
|
||||
|
||||
# remove trailing null bits away, that changing only
|
||||
# maximum doesn't affect created binary size
|
||||
length = int(math.ceil(max_set / float(8)))
|
||||
bytes = bytes[:length]
|
||||
|
||||
buf = ctypes.create_string_buffer(length)
|
||||
|
||||
for index in range(length):
|
||||
struct.pack_into('<B', buf, index, bytes[index])
|
||||
|
||||
self.add_element(ie, buf.raw)
|
||||
|
||||
def read_bitmap(self, ie):
|
||||
buf = self.elements[ie]
|
||||
length = len(buf)
|
||||
|
||||
bits = []
|
||||
|
||||
for index in range(length):
|
||||
val = struct.unpack_from('<B', buf, index)[0]
|
||||
|
||||
for bit in range(8):
|
||||
if val & 0x1:
|
||||
bits.append(index * 8 + bit)
|
||||
|
||||
val = val >> 1
|
||||
|
||||
return bits
|
||||
|
||||
def set_signature(self, signature):
|
||||
self.signature = signature
|
||||
self.signature_len = len(signature)
|
||||
|
||||
# include the null byte
|
||||
length = len(signature) + 1
|
||||
|
||||
padding_len = padding_needed(length)
|
||||
|
||||
length = length + padding_len
|
||||
|
||||
padding = ctypes.create_string_buffer(padding_len)
|
||||
|
||||
for i in range(padding_len):
|
||||
struct.pack_into('<B', padding, i, 0x77)
|
||||
|
||||
fmt = '<%dsb%ds' % (len(signature), padding_len)
|
||||
struct.pack_into(fmt, self.buf, 0, signature, 0, padding.raw)
|
||||
self.buf_len = length
|
||||
|
||||
def write(self, name):
|
||||
f = open(name, 'wb')
|
||||
f.write(self.buf.raw[:self.buf_len])
|
||||
f.close()
|
||||
|
||||
return self.buf_len
|
||||
|
||||
def open(self, name):
|
||||
f = open(name, 'rb')
|
||||
self.buf = f.read()
|
||||
self.buf_len = len(self.buf)
|
||||
f.close()
|
||||
|
||||
offset = 0
|
||||
|
||||
fmt = '<%dsb' % (self.signature_len)
|
||||
(signature, null) = struct.unpack_from(fmt, self.buf, offset)
|
||||
offset = offset + self.signature_len + 1
|
||||
|
||||
if signature != self.signature or null != 0:
|
||||
logger.error("Invalid signature!")
|
||||
return False
|
||||
|
||||
offset = self.signature_len + 1
|
||||
offset = offset + padding_needed(offset)
|
||||
|
||||
self.elements = {}
|
||||
|
||||
while offset + 4 + 4 < self.buf_len:
|
||||
(type_id, length) = struct.unpack_from("<ii", self.buf, offset)
|
||||
offset = offset + 4 + 4
|
||||
|
||||
if offset + length > self.buf_len:
|
||||
logger.error("Buffer too short")
|
||||
return
|
||||
|
||||
fmt = '<%ds' % length
|
||||
(payload,) = struct.unpack_from(fmt, self.buf, offset)
|
||||
offset = offset + length
|
||||
offset = offset + padding_needed(offset)
|
||||
|
||||
self.elements[type_id] = payload
|
||||
|
||||
return True
|
||||
|
||||
def __init__(self, signature):
|
||||
self.buf = ctypes.create_string_buffer(MAX_LEN)
|
||||
self.buf_len = 0
|
||||
|
||||
self.set_signature(signature)
|
||||
|
||||
|
||||
class Ath10kFirmwareContainer(object):
|
||||
def _load_file(self, name):
|
||||
if os.path.getsize(name) > MAX_LEN:
|
||||
raise FWEncoderError('file %s is too large, maximum size is %d' %
|
||||
(name, MAX_LEN))
|
||||
|
||||
f = open(name, 'rb')
|
||||
buf = f.read()
|
||||
f.close()
|
||||
|
||||
return buf
|
||||
|
||||
def set_fw_code_swap_image(self, fw_code_swap_image_name):
|
||||
self.fw_code_swap_image = self._load_file(fw_code_swap_image_name)
|
||||
|
||||
def get_fw_code_swap_image(self):
|
||||
return self.fw_code_swap_image
|
||||
|
||||
def set_htt_op_version(self, htt_op_version):
|
||||
s = htt_op_version
|
||||
|
||||
# convert the string to integer
|
||||
if s in htt_op_version_map:
|
||||
version = htt_op_version_map[s]
|
||||
elif is_int(s):
|
||||
version = s
|
||||
else:
|
||||
print 'Error: Invalid HTT OP version: %s' % s
|
||||
return 1
|
||||
|
||||
self.htt_op_version = version
|
||||
|
||||
def get_htt_op_version(self):
|
||||
version = self.htt_op_version
|
||||
|
||||
# find value from the dict
|
||||
try:
|
||||
name = [key for key, value in htt_op_version_map.iteritems()
|
||||
if value == version][0]
|
||||
except IndexError:
|
||||
name = str(version)
|
||||
|
||||
return name
|
||||
|
||||
def set_wmi_op_version(self, wmi_op_version):
|
||||
s = wmi_op_version
|
||||
|
||||
# convert the string to integer
|
||||
if s in wmi_op_version_map:
|
||||
version = wmi_op_version_map[s]
|
||||
elif is_int(s):
|
||||
version = s
|
||||
else:
|
||||
print 'Error: Invalid WMI OP version: %s' % s
|
||||
return 1
|
||||
|
||||
self.wmi_op_version = version
|
||||
|
||||
def get_wmi_op_version(self):
|
||||
version = self.wmi_op_version
|
||||
|
||||
# find value from the dict
|
||||
try:
|
||||
name = [key for key, value in wmi_op_version_map.iteritems()
|
||||
if value == version][0]
|
||||
except IndexError:
|
||||
name = str(version)
|
||||
|
||||
return name
|
||||
|
||||
def set_features(self, features):
|
||||
self.features = features.split(',')
|
||||
|
||||
enabled = []
|
||||
for capa in self.features:
|
||||
if capa not in feature_map:
|
||||
print "Error: '%s' not found from the feature map" % capa
|
||||
return 1
|
||||
|
||||
enabled.append(feature_map[capa])
|
||||
|
||||
self.features_bitmap = enabled
|
||||
|
||||
def get_features(self):
|
||||
s = ""
|
||||
|
||||
if self.features_bitmap == None:
|
||||
return None
|
||||
|
||||
for capa in self.features_bitmap:
|
||||
# find value from the dict
|
||||
try:
|
||||
name = [key for key, value in feature_map.iteritems()
|
||||
if value == capa][0]
|
||||
except IndexError:
|
||||
name = str(capa)
|
||||
|
||||
s = s + name + ","
|
||||
|
||||
# strip last comma
|
||||
if len(s) > 0:
|
||||
s = s[:-1]
|
||||
|
||||
return s
|
||||
|
||||
def set_fw_image(self, fw_image_name):
|
||||
self.fw_image = self._load_file(fw_image_name)
|
||||
|
||||
def get_fw_image(self):
|
||||
return self.fw_image
|
||||
|
||||
def set_otp_image(self, otp_image_name):
|
||||
self.otp_image = self._load_file(otp_image_name)
|
||||
|
||||
def get_otp_image(self):
|
||||
return self.otp_image
|
||||
|
||||
def set_timestamp(self, timestamp):
|
||||
self.timestamp = int(timestamp)
|
||||
|
||||
def get_timestamp(self):
|
||||
return self.timestamp
|
||||
|
||||
def get_timestamp_as_iso8601(self):
|
||||
if self.timestamp == None:
|
||||
return None
|
||||
|
||||
return time.strftime('%Y-%m-%d %H:%M:%S',
|
||||
time.localtime(self.timestamp))
|
||||
|
||||
def set_fw_version(self, fw_version):
|
||||
self.fw_version = fw_version
|
||||
# reserve one byte for null
|
||||
if len(self.fw_version) > ETHTOOL_FWVERS_LEN - 1:
|
||||
print 'Firmware version string too long: %d' % (len(self.fw_version))
|
||||
return 1
|
||||
|
||||
def get_fw_version(self):
|
||||
return self.fw_version
|
||||
|
||||
def load(self, filename):
|
||||
c = FirmwareContainer(ATH10K_SIGNATURE)
|
||||
c.open(filename)
|
||||
|
||||
self.file = c.buf
|
||||
|
||||
for e in c.elements:
|
||||
if e == ATH10K_FW_IE_FW_VERSION:
|
||||
self.fw_version = c.elements[e]
|
||||
elif e == ATH10K_FW_IE_TIMESTAMP:
|
||||
self.timestamp = c.read_u32(e)
|
||||
elif e == ATH10K_FW_IE_OTP_IMAGE:
|
||||
self.otp_image = c.elements[e]
|
||||
elif e == ATH10K_FW_IE_FW_IMAGE:
|
||||
self.fw_image = c.elements[e]
|
||||
elif e == ATH10K_FW_IE_FEATURES:
|
||||
self.features_bitmap = c.read_bitmap(ATH10K_FW_IE_FEATURES)
|
||||
elif e == ATH10K_FW_IE_WMI_OP_VERSION:
|
||||
self.wmi_op_version = c.read_u32(ATH10K_FW_IE_WMI_OP_VERSION)
|
||||
elif e == ATH10K_FW_IE_HTT_OP_VERSION:
|
||||
self.htt_op_version = c.read_u32(ATH10K_FW_IE_HTT_OP_VERSION)
|
||||
elif e == ATH10K_FW_IE_FW_CODE_SWAP_IMAGE:
|
||||
self.fw_code_swap_image = c.elements[e]
|
||||
else:
|
||||
print "Unknown IE: ", e
|
||||
|
||||
def save(self, filename):
|
||||
self.container = FirmwareContainer(ATH10K_SIGNATURE)
|
||||
|
||||
if self.fw_version:
|
||||
self.container.add_element(ATH10K_FW_IE_FW_VERSION,
|
||||
self.fw_version)
|
||||
if self.timestamp:
|
||||
self.container.add_u32(ATH10K_FW_IE_TIMESTAMP, self.timestamp)
|
||||
|
||||
# FIXME: otp should be after fw_image but that breaks the
|
||||
# current tests
|
||||
if self.otp_image:
|
||||
self.container.add_element(ATH10K_FW_IE_OTP_IMAGE, self.otp_image)
|
||||
|
||||
if self.fw_image:
|
||||
self.container.add_element(ATH10K_FW_IE_FW_IMAGE, self.fw_image)
|
||||
|
||||
# FIXME: features should be before fw_image but that breaks
|
||||
# the current tests
|
||||
if self.features_bitmap:
|
||||
self.container.add_bitmap(ATH10K_FW_IE_FEATURES,
|
||||
self.features_bitmap,
|
||||
ATH10K_FW_FEATURE_MAX)
|
||||
|
||||
if self.wmi_op_version:
|
||||
self.container.add_u32(ATH10K_FW_IE_WMI_OP_VERSION, self.wmi_op_version)
|
||||
|
||||
if self.htt_op_version:
|
||||
self.container.add_u32(ATH10K_FW_IE_HTT_OP_VERSION,
|
||||
self.htt_op_version)
|
||||
|
||||
if self.fw_code_swap_image:
|
||||
self.container.add_element(ATH10K_FW_IE_FW_CODE_SWAP_IMAGE,
|
||||
self.fw_code_swap_image)
|
||||
|
||||
return self.container.write(filename)
|
||||
|
||||
def __init__(self):
|
||||
self.fw_version = None
|
||||
self.timestamp = None
|
||||
self.features = None
|
||||
self.features_bitmap = None
|
||||
self.fw_image = None
|
||||
self.otp_image = None
|
||||
self.wmi_op_version = None
|
||||
self.htt_op_version = None
|
||||
self.fw_code_swap_image = None
|
||||
|
||||
|
||||
# to workaround annoying python feature of returning negative hex values
|
||||
def hex32(val):
|
||||
return val & 0xffffffff
|
||||
|
||||
|
||||
# match with kernel crc32_le(0, buf, buf_len) implementation
|
||||
def _crc32(buf):
|
||||
return hex32(~(hex32(binascii.crc32(buf, 0xffffffff))))
|
||||
|
||||
|
||||
def padding_needed(length):
|
||||
if length % 4 != 0:
|
||||
return 4 - length % 4
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def is_int(val):
|
||||
try:
|
||||
int(val)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def write_file(filename, buf):
|
||||
f = open(filename, 'w')
|
||||
f.write(buf)
|
||||
f.close
|
||||
|
||||
|
||||
def info(options, args):
|
||||
|
||||
if len(args) != 1:
|
||||
print 'Filename missing'
|
||||
return 1
|
||||
|
||||
filename = args[0]
|
||||
|
||||
c = Ath10kFirmwareContainer()
|
||||
c.load(filename)
|
||||
|
||||
s = ''
|
||||
|
||||
s = s + 'FileSize: %s\n' % (len(c.file))
|
||||
s = s + 'FileCRC32: %08x\n' % (_crc32(c.file))
|
||||
|
||||
if c.get_fw_version():
|
||||
s = s + 'FirmwareVersion: %s\n' % (c.get_fw_version())
|
||||
|
||||
if c.get_timestamp():
|
||||
s = s + 'Timestamp: %s\n' % (c.get_timestamp_as_iso8601())
|
||||
|
||||
if c.get_features():
|
||||
s = s + 'Features: %s\n' % (c.get_features())
|
||||
|
||||
if c.get_fw_image():
|
||||
s = s + 'FirmwareImageSize: %s\n' % (len(c.get_fw_image()))
|
||||
s = s + 'FirmwareImageCRC32: %08x\n' % (_crc32(c.get_fw_image()))
|
||||
|
||||
if c.get_otp_image():
|
||||
s = s + 'OTPImageSize: %s\n' % (len(c.get_otp_image()))
|
||||
s = s + 'OTPImageCRC32: %08x\n' % (_crc32(c.get_otp_image()))
|
||||
|
||||
if c.get_wmi_op_version():
|
||||
s = s + 'WMIOpVersion: %s\n' % (c.get_wmi_op_version())
|
||||
|
||||
if c.get_htt_op_version():
|
||||
s = s + 'HTTOpVersion: %s\n' % (c.get_htt_op_version())
|
||||
|
||||
if c.get_fw_code_swap_image():
|
||||
s = s + 'FirmwareCodeSwapImageSize: %s\n' % (len(c.get_fw_code_swap_image()))
|
||||
s = s + 'FirmwareCodeSwapImageCRC32: %08x\n' % (_crc32(c.get_fw_code_swap_image()))
|
||||
|
||||
print s.strip()
|
||||
|
||||
|
||||
def dump(options, args):
|
||||
|
||||
if len(args) != 1:
|
||||
print 'Filename missing'
|
||||
return 1
|
||||
|
||||
filename = args[0]
|
||||
|
||||
c = Ath10kFirmwareContainer()
|
||||
c.load(filename)
|
||||
|
||||
print "ath10k-fwencoder --create \\"
|
||||
|
||||
if c.get_fw_version():
|
||||
print "--firmware-version=%s \\" % c.get_fw_version()
|
||||
|
||||
if c.get_timestamp() and options.show_timestamp:
|
||||
print "--timestamp=%u \\" % c.get_timestamp()
|
||||
|
||||
if c.get_features():
|
||||
print "--features=%s \\" % c.get_features()
|
||||
|
||||
if c.get_fw_image():
|
||||
name = "athwlan.bin"
|
||||
print "--firmware=%s \\" % name
|
||||
|
||||
if c.get_otp_image():
|
||||
name = "otp.bin"
|
||||
print "--otp=%s \\" % name
|
||||
|
||||
if c.get_wmi_op_version():
|
||||
print '--set-wmi-op-version=%s \\' % c.get_wmi_op_version()
|
||||
|
||||
if c.get_htt_op_version():
|
||||
print '--set-htt-op-version=%s \\' % (c.get_htt_op_version())
|
||||
|
||||
if c.get_fw_code_swap_image():
|
||||
name = "athwlan.codeswap.bin"
|
||||
print "--firmware-codeswap=%s \\" % name
|
||||
|
||||
print
|
||||
|
||||
|
||||
def extract(options, args):
|
||||
|
||||
if len(args) != 1:
|
||||
print 'Filename missing'
|
||||
return 1
|
||||
|
||||
filename = args[0]
|
||||
|
||||
c = Ath10kFirmwareContainer()
|
||||
c.load(filename)
|
||||
|
||||
if c.get_fw_image():
|
||||
name = "athwlan.bin"
|
||||
write_file(name, c.get_fw_image())
|
||||
print '%s extracted: %d B' % (name, len(c.get_fw_image()))
|
||||
|
||||
if c.get_otp_image():
|
||||
name = "otp.bin"
|
||||
write_file(name, c.get_otp_image())
|
||||
print '%s extracted: %d B' % (name, len(c.get_otp_image()))
|
||||
|
||||
if c.get_fw_code_swap_image():
|
||||
name = "athwlan.codeswap.bin"
|
||||
write_file(name, c.get_fw_code_swap_image())
|
||||
print '%s extracted: %d B' % (name, len(c.get_fw_code_swap_image()))
|
||||
|
||||
print
|
||||
|
||||
|
||||
def modify(options, args):
|
||||
if len(args) != 1:
|
||||
print 'Filename missing'
|
||||
return 1
|
||||
|
||||
filename = args[0]
|
||||
|
||||
c = Ath10kFirmwareContainer()
|
||||
c.load(filename)
|
||||
|
||||
if options.firmware_version:
|
||||
c.set_fw_version(options.firmware_version)
|
||||
|
||||
if options.timestamp:
|
||||
stamp = str(int(options.timestamp))
|
||||
else:
|
||||
# if no timestamp provided use the current time so that the
|
||||
# timestamp shows the time of last modication
|
||||
stamp = int(time.time())
|
||||
|
||||
c.set_timestamp(stamp)
|
||||
|
||||
if options.otp:
|
||||
c.set_otp_image(options.otp)
|
||||
|
||||
if options.fw:
|
||||
c.set_fw_image(options.fw)
|
||||
|
||||
if options.features:
|
||||
c.set_features(options.features)
|
||||
|
||||
if options.wmi_op_version:
|
||||
c.set_wmi_op_version(options.wmi_op_version)
|
||||
|
||||
if options.htt_op_version:
|
||||
c.set_htt_op_version(options.htt_op_version)
|
||||
|
||||
if options.fw_codeswap:
|
||||
c.set_fw_code_swap_image(options.fw_codeswap)
|
||||
|
||||
file_len = c.save(filename)
|
||||
|
||||
print '%s modified: %d B' % (filename, file_len)
|
||||
|
||||
|
||||
def create(options):
|
||||
output = get_output_name(options.fw_api)
|
||||
|
||||
if options.output:
|
||||
output = options.output
|
||||
|
||||
c = Ath10kFirmwareContainer()
|
||||
|
||||
if options.firmware_version:
|
||||
c.set_fw_version(options.firmware_version)
|
||||
|
||||
# always add a timestamp
|
||||
if options.timestamp:
|
||||
stamp = int(options.timestamp)
|
||||
else:
|
||||
stamp = int(time.time())
|
||||
|
||||
c.set_timestamp(stamp)
|
||||
|
||||
if options.otp:
|
||||
c.set_otp_image(options.otp)
|
||||
|
||||
if options.fw:
|
||||
c.set_fw_image(options.fw)
|
||||
|
||||
if options.features:
|
||||
c.set_features(options.features)
|
||||
|
||||
if options.wmi_op_version:
|
||||
c.set_wmi_op_version(options.wmi_op_version)
|
||||
|
||||
if options.htt_op_version:
|
||||
c.set_htt_op_version(options.htt_op_version)
|
||||
|
||||
if options.fw_codeswap:
|
||||
c.set_fw_code_swap_image(options.fw_codeswap)
|
||||
|
||||
file_len = c.save(output)
|
||||
|
||||
print '%s created: %d B' % (output, file_len)
|
||||
|
||||
|
||||
def cmd_crc32(options, args):
|
||||
if len(args) != 1:
|
||||
print 'Filename missing'
|
||||
return 1
|
||||
|
||||
filename = args[0]
|
||||
|
||||
f = open(filename, 'r')
|
||||
buf = f.read()
|
||||
print '%08x' % (_crc32(buf))
|
||||
f.close()
|
||||
|
||||
|
||||
def main():
|
||||
global logger
|
||||
|
||||
logger = logging.getLogger('ath10k-fwencoder')
|
||||
logging.basicConfig(format='%(levelname)s: %(message)s')
|
||||
|
||||
parser = optparse.OptionParser()
|
||||
|
||||
# actions
|
||||
parser.add_option("-c", "--create", action="store_true", dest="create",
|
||||
help='Create container file '
|
||||
'for ath10k (%s)' % get_output_name())
|
||||
parser.add_option("-D", "--dump-cmdline", action="store_true", dest="dump",
|
||||
help='Show the cmdline used to create '
|
||||
'this container file')
|
||||
parser.add_option('--dump', action='store_true', dest='dump',
|
||||
help='Same as --dump-cmdline '
|
||||
'(for backwards compatibility)')
|
||||
parser.add_option("-e", "--extract", action="store_true", dest="extract",
|
||||
help='Extract binary files from the container file '
|
||||
'and dump cmdline as well')
|
||||
parser.add_option("--info", action="store_true", dest="info",
|
||||
help='Show information about the container file')
|
||||
parser.add_option("--modify", action="store_true", dest="modify",
|
||||
help='Modify the container file')
|
||||
parser.add_option('--crc32', action='store_true', dest='crc32',
|
||||
help='Count crc32 checksum for a file')
|
||||
|
||||
# parameters
|
||||
parser.add_option("-o", "--output", action="store", type="string",
|
||||
dest="output", help='Name of output file')
|
||||
|
||||
# FW IEs, only use long style of option names!
|
||||
parser.add_option("--otp", action="store", type="string",
|
||||
dest="otp",
|
||||
help='Name of otp.bin file')
|
||||
parser.add_option("--firmware", action="store", type="string",
|
||||
dest="fw",
|
||||
help='Name of athwlan.bin file')
|
||||
parser.add_option("--firmware-version", action="store",
|
||||
type="string", dest="firmware_version",
|
||||
help='Firmware version string to be used')
|
||||
parser.add_option("--timestamp", action="store",
|
||||
type="string", dest="timestamp",
|
||||
help='Timestamp to be used (seconds)')
|
||||
|
||||
parser.add_option("--features", action="store",
|
||||
type="string", dest="features",
|
||||
help='feature bits to be enabled: %s' %
|
||||
feature_map.keys())
|
||||
parser.add_option("--set-wmi-op-version", action="store",
|
||||
type="string", dest="wmi_op_version",
|
||||
help='WMI op interface version: %s' %
|
||||
wmi_op_version_map.keys())
|
||||
parser.add_option("--set-fw-api", action="store",
|
||||
type="string", dest="fw_api",
|
||||
help='Set firmware API used in creating the name for '
|
||||
'output file (Default: %s)' %
|
||||
DEFAULT_FW_API_VERSION)
|
||||
parser.add_option("--set-htt-op-version", action="store",
|
||||
type="string", dest="htt_op_version",
|
||||
help='HTT op interface version: %s' %
|
||||
htt_op_version_map.keys())
|
||||
parser.add_option("--firmware-codeswap", action="store", type="string",
|
||||
dest="fw_codeswap",
|
||||
help='Name of athwlan.codeswap.bin file')
|
||||
|
||||
# debug etc
|
||||
parser.add_option('--show-timestamp', action='store_true',
|
||||
dest='show_timestamp',
|
||||
help='Show timestamp in --dump-cmdline action. '
|
||||
'It is not shown by default so that the timestamp would be correct')
|
||||
parser.add_option('-d', '--debug', action='store_true', dest='debug',
|
||||
help='Enable debug messages')
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.debug:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
if options.create:
|
||||
try:
|
||||
return create(options)
|
||||
except FWEncoderError as e:
|
||||
print 'Create failed: %s' % e
|
||||
sys.exit(2)
|
||||
except Exception as e:
|
||||
print 'Create failed: %s' % e
|
||||
traceback.print_exc()
|
||||
sys.exit(3)
|
||||
elif options.dump:
|
||||
return dump(options, args)
|
||||
elif options.extract:
|
||||
return extract(options, args)
|
||||
elif options.info:
|
||||
return info(options, args)
|
||||
elif options.modify:
|
||||
return modify(options, args)
|
||||
elif options.crc32:
|
||||
return cmd_crc32(options, args)
|
||||
else:
|
||||
print 'Action command missing'
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Reference in a new issue