| | 1224 | # Returns the (total, used) number of bytes in the EEPROM, |
| | 1225 | # assuming it is an SPD EEPROM. |
| | 1226 | sub spd_sizes($) |
| | 1227 | { |
| | 1228 | my $bytes = shift; |
| | 1229 | |
| | 1230 | if ($bytes->[2] >= 9) { |
| | 1231 | # For FB-DIMM and newer, decode number of bytes written |
| | 1232 | my $spd_len = ($bytes->[0] >> 4) & 7; |
| | 1233 | my $size = 64 << ($bytes->[0] & 15); |
| | 1234 | if ($spd_len == 0) { |
| | 1235 | return ($size, 128); |
| | 1236 | } elsif ($spd_len == 1) { |
| | 1237 | return ($size, 176); |
| | 1238 | } elsif ($spd_len == 2) { |
| | 1239 | return ($size, 256); |
| | 1240 | } else { |
| | 1241 | return (64, 64); |
| | 1242 | } |
| | 1243 | } else { |
| | 1244 | my $size; |
| | 1245 | if ($bytes->[1] <= 14) { |
| | 1246 | $size = 1 << $bytes->[1]; |
| | 1247 | } elsif ($bytes->[1] == 0) { |
| | 1248 | $size = "RFU"; |
| | 1249 | } else { $size = "ERROR!" } |
| | 1250 | |
| | 1251 | return ($size, ($bytes->[0] < 64) ? 64 : $bytes->[0]); |
| | 1252 | } |
| | 1253 | } |
| | 1254 | |
| | 1281 | # Calculate and verify checksum of first 63 bytes |
| | 1282 | sub checksum($) |
| | 1283 | { |
| | 1284 | my $bytes = shift; |
| | 1285 | my $dimm_checksum = 0; |
| | 1286 | local $_; |
| | 1287 | |
| | 1288 | $dimm_checksum += $bytes->[$_] foreach (0 .. 62); |
| | 1289 | $dimm_checksum &= 0xff; |
| | 1290 | |
| | 1291 | return ("EEPROM Checksum of bytes 0-62", |
| | 1292 | ($bytes->[63] == $dimm_checksum) ? 1 : 0, |
| | 1293 | sprintf('0x%02X', $bytes->[63]), |
| | 1294 | sprintf('0x%02X', $dimm_checksum)); |
| | 1295 | } |
| | 1296 | |
| | 1297 | # Calculate and verify CRC |
| | 1298 | sub check_crc($) |
| | 1299 | { |
| | 1300 | my $bytes = shift; |
| | 1301 | my $crc = 0; |
| | 1302 | my $crc_cover = $bytes->[0] & 0x80 ? 116 : 125; |
| | 1303 | my $crc_ptr = 0; |
| | 1304 | my $crc_bit; |
| | 1305 | |
| | 1306 | while ($crc_ptr <= $crc_cover) { |
| | 1307 | $crc = $crc ^ ($bytes->[$crc_ptr] << 8); |
| | 1308 | for ($crc_bit = 0; $crc_bit < 8; $crc_bit++) { |
| | 1309 | if ($crc & 0x8000) { |
| | 1310 | $crc = ($crc << 1) ^ 0x1021; |
| | 1311 | } else { |
| | 1312 | $crc = $crc << 1 |
| | 1313 | } |
| | 1314 | } |
| | 1315 | $crc_ptr++; |
| | 1316 | } |
| | 1317 | $crc &= 0xffff; |
| | 1318 | |
| | 1319 | my $dimm_crc = ($bytes->[127] << 8) | $bytes->[126]; |
| | 1320 | return ("EEPROM CRC of bytes 0-$crc_cover", |
| | 1321 | ($dimm_crc == $crc) ? 1 : 0, |
| | 1322 | sprintf("0x%04X", $dimm_crc), |
| | 1323 | sprintf("0x%04X", $crc)); |
| | 1324 | } |
| | 1325 | |
| 1336 | | my $dimm_checksum = 0; |
| 1337 | | $dimm_checksum += $bytes[$_] foreach (0 .. 62); |
| 1338 | | $dimm_checksum &= 0xff; |
| 1339 | | |
| 1340 | | next unless $bytes[63] == $dimm_checksum || $opt_igncheck; |
| | 1412 | my ($spd_size, $spd_used) = spd_sizes(\@bytes); |
| | 1413 | my ($l, $chk_valid, $chk_spd, $chk_calc); |
| | 1414 | if ($bytes[2] < 9) { |
| | 1415 | ($l, $chk_valid, $chk_spd, $chk_calc) = |
| | 1416 | checksum(\@bytes); |
| | 1417 | } else { |
| | 1418 | ($l, $chk_valid, $chk_spd, $chk_calc) = |
| | 1419 | check_crc(\@bytes); |
| | 1420 | } |
| | 1421 | |
| | 1422 | next unless $chk_valid || $opt_igncheck; |
| 1361 | | my $l = "EEPROM Checksum of bytes 0-62"; |
| 1362 | | printl $l, ($bytes[63] == $dimm_checksum ? |
| 1363 | | sprintf("OK (0x%.2X)", $bytes[63]): |
| 1364 | | sprintf("Bad\n(found 0x%.2X, calculated 0x%.2X)\n", |
| 1365 | | $bytes[63], $dimm_checksum)); |
| | 1443 | printl $l, ($chk_valid ? |
| | 1444 | sprintf("OK (%s)", $chk_calc) : |
| | 1445 | sprintf("Bad\n(found %s, calculated %s)\n", |
| | 1446 | $chk_spd, $chk_calc)); |
| 1394 | | if ($bytes[2] == 1) { $type = "FPM DRAM"; } |
| 1395 | | elsif ($bytes[2] == 2) { $type = "EDO"; } |
| 1396 | | elsif ($bytes[2] == 3) { $type = "Pipelined Nibble"; } |
| 1397 | | elsif ($bytes[2] == 4) { $type = "SDR SDRAM"; } |
| 1398 | | elsif ($bytes[2] == 5) { $type = "Multiplexed ROM"; } |
| 1399 | | elsif ($bytes[2] == 6) { $type = "DDR SGRAM"; } |
| 1400 | | elsif ($bytes[2] == 7) { $type = "DDR SDRAM"; } |
| 1401 | | elsif ($bytes[2] == 8) { $type = "DDR2 SDRAM"; } |
| | 1470 | my @type_list = ( |
| | 1471 | "Reserved", "FPM DRAM", # 0, 1 |
| | 1472 | "EDO", "Pipelined Nibble", # 2, 3 |
| | 1473 | "SDR SDRAM", "Multiplexed ROM", # 4, 5 |
| | 1474 | "DDR SGRAM", "DDR SDRAM", # 6, 7 |
| | 1475 | "DDR2 SDRAM", "FB-DIMM", # 8, 9 |
| | 1476 | "FB-DIMM Probe", "DDR3 SDRAM", # 10, 11 |
| | 1477 | ); |
| | 1478 | if ($bytes[2] < @type_list) { |
| | 1479 | $type = $type_list[$bytes[2]]; |
| | 1480 | } |