3 # Script for editing APCB binaries, such as injecting SPDs and GPIO
9 from collections
import namedtuple
12 GPIO_MAGIC
= bytes
.fromhex('fadeddad' * 3)
13 SPD_MAGIC
= bytes
.fromhex('f005ba110000')
14 EMPTY_SPD
= b
'\x00' * 512
16 spd_ssp_struct_fmt
= '??B?IIBBBxIIBBBx'
17 spd_ssp_struct
= namedtuple(
18 'spd_ssp_struct', 'SpdValid, DimmPresent, \
19 PageAddress, NvDimmPresent, \
20 DramManufacturersIDCode, Address, \
21 SpdMuxPresent, MuxI2CAddress, MuxChannel, \
22 Technology, Package, SocketNumber, \
23 ChannelNumber, DimmNumber')
27 parser
= argparse
.ArgumentParser(description
='Inject SPDs and SPD GPIO \
28 selection pins into APCB binaries')
32 type=argparse
.FileType('rb'),
34 help='APCB input file')
38 type=argparse
.FileType('wb'),
40 help='APCB output file')
43 type=argparse
.FileType('rb'),
44 help='SPD input file for channel 0, dimm 0')
47 type=argparse
.FileType('rb'),
48 help='SPD input file for channel 0, dimm 1')
51 type=argparse
.FileType('rb'),
52 help='SPD input file for channel 1, dimm 0')
55 type=argparse
.FileType('rb'),
56 help='SPD input file for channel 1, dimm 1')
60 help='SPD input file is hex encoded, binary otherwise')
62 '--strip_manufacturer_information',
64 help='Strip all manufacturer information from SPD')
70 help='Board ID GPIO 0: NUMBER IO_MUX BANK_CTRL')
76 help='Board ID GPIO 1: NUMBER IO_MUX BANK_CTRL')
82 help='Board ID GPIO 2: NUMBER IO_MUX BANK_CTRL')
88 help='Board ID GPIO 3: NUMBER IO_MUX BANK_CTRL')
89 return parser
.parse_args()
94 for b
in data
[:16] + data
[17:]:
95 sum = (sum + b
) & 0xff
96 return (0x100 - sum) & 0xff
99 def inject(orig
, insert
, offset
):
100 return b
''.join([orig
[:offset
], insert
, orig
[offset
+ len(insert
):]])
106 print("Reading input APCB from %s" % (args
.apcb_in
.name
))
108 apcb
= args
.apcb_in
.read()
110 orig_apcb_len
= len(apcb
)
112 gpio_offset
= apcb
.find(GPIO_MAGIC
)
113 assert gpio_offset
> 0, "GPIO magic number not found"
114 print('GPIO magic number found at offset 0x%x' % gpio_offset
)
115 gpio_array
= (args
.board_id_gpio0
+ args
.board_id_gpio1
+
116 args
.board_id_gpio2
+ args
.board_id_gpio3
)
117 print('Writing SPD GPIO array %s' % gpio_array
)
118 apcb
= inject(apcb
, pack('BBBBBBBBBBBB', *gpio_array
), gpio_offset
)
122 spd_offset
= apcb
.find(SPD_MAGIC
, spd_offset
)
126 spd_ssp_offset
= spd_offset
- calcsize(spd_ssp_struct_fmt
)
127 spd_ssp_bytes
= apcb
[spd_ssp_offset
:spd_offset
]
128 spd_ssp
= spd_ssp_struct
._make
(
129 unpack(spd_ssp_struct_fmt
, spd_ssp_bytes
))
131 assert spd_ssp
.DimmNumber
>= 0 and spd_ssp
.DimmNumber
<= 1, \
132 "Unexpected dimm number found in APCB"
133 assert spd_ssp
.ChannelNumber
>= 0 and spd_ssp
.ChannelNumber
<= 1, \
134 "Unexpected channel number found in APCB"
136 print("Found SPD magic number with channel %d and dimm %d "
137 "at offset 0x%x" % (spd_ssp
.ChannelNumber
, spd_ssp
.DimmNumber
,
140 dimm_channel
= (spd_ssp
.ChannelNumber
, spd_ssp
.DimmNumber
)
142 if dimm_channel
== (0, 0) and args
.spd_0_0
:
143 spd
= args
.spd_0_0
.read()
144 elif dimm_channel
== (0, 1) and args
.spd_0_1
:
145 spd
= args
.spd_0_1
.read()
146 elif dimm_channel
== (1, 0) and args
.spd_1_0
:
147 spd
= args
.spd_1_0
.read()
148 elif dimm_channel
== (1, 1) and args
.spd_1_1
:
149 spd
= args
.spd_1_0
.read()
154 spd
= re
.sub(r
'#.*', '', spd
)
155 spd
= re
.sub(r
'\s+', '', spd
)
156 spd
= bytes
.fromhex(spd
)
158 assert len(spd
) == 512, \
159 "Expected SPD to be 512 bytes, got %d" % len(spd
)
161 if args
.strip_manufacturer_information
:
162 print("Stripping manufacturer information from SPD")
163 spd
= spd
[0:320] + b
'\x00'*64 + spd
[320+64:]
165 assert len(spd
) == 512, \
166 "Error while stripping SPD manufacurer information"
168 print("Enabling channel %d, dimm %d and injecting SPD" %
169 (spd_ssp
.ChannelNumber
, spd_ssp
.DimmNumber
))
170 spd_ssp
= spd_ssp
._replace
(SpdValid
=True, DimmPresent
=True)
173 print("Disabling channel %d, dimm %d and clearing SPD" %
174 (spd_ssp
.ChannelNumber
, spd_ssp
.DimmNumber
))
175 spd_ssp
= spd_ssp
._replace
(SpdValid
=False, DimmPresent
=False)
178 apcb
= inject(apcb
, pack(spd_ssp_struct_fmt
, *spd_ssp
), spd_ssp_offset
)
179 apcb
= inject(apcb
, spd
, spd_offset
)
183 print("Fixing checksum and writing to %s" % (args
.apcb_out
.name
))
185 apcb
= inject(apcb
, bytes([chksum(apcb
)]), 16)
187 assert chksum(apcb
) == apcb
[16], "Checksum is invalid"
188 assert orig_apcb_len
== len(apcb
), \
189 "The size of the APCB binary changed, this should not happen."
191 args
.apcb_out
.write(apcb
)
194 if __name__
== "__main__":