$NetBSD$ --- decode-dimms.orig 2018-03-01 23:05:59.000000000 +0000 +++ decode-dimms @@ -42,8 +42,9 @@ use POSIX qw(ceil); use Fcntl qw(:DEFAULT :seek); use File::Basename; use vars qw($opt_html $opt_bodyonly $opt_side_by_side $opt_merge - $opt_igncheck $use_sysfs $use_hexdump $sbs_col_width - @vendors %decode_callback $revision @dimm $current %hexdump_cache); + $opt_igncheck $use_sysfs $use_hexdump $use_sysctl $sbs_col_width + @vendors %decode_callback $revision @dimm $current %hexdump_cache + %sysctl_cache); use constant LITTLEENDIAN => "little-endian"; use constant BIGENDIAN => "big-endian"; @@ -339,6 +340,7 @@ $revision = '20171205' ); $use_sysfs = -d '/sys/bus'; +$use_sysctl = 0; # We consider that no data was written to this area of the SPD EEPROM if # all bytes read 0x00 or all bytes read 0xff @@ -2250,6 +2252,26 @@ sub spd_sizes($) } } +# read data from a NetBSD (or equivalent) sysctl variable + +sub read_sysctl($) +{ + + # Look in the cache first + return @{$sysctl_cache{$_[0]}} if exists $sysctl_cache{$_[0]}; + + my $sysctl_var = sprintf("hw.%s.spd_data", $_[0]); + open(PIPE, "-|", "sysctl -r $sysctl_var") + or die "Cannot read sysctl variable $sysctl_var"; + sysread(PIPE, my $eeprom, 512); # XXX Assumed maximum size! XXX + close PIPE or die "sysctl returned $?"; + my @bytes = unpack("C*", $eeprom); + + # Cache the data for later use + $hexdump_cache{$_[0]} = \@bytes; + return @bytes; +} + # Read bytes from SPD-EEPROM # Note: offset must be a multiple of 16! sub readspd($$$) @@ -2259,6 +2281,9 @@ sub readspd($$$) if ($use_hexdump) { @bytes = read_hexdump($dimm_i); return @bytes[$offset..($offset + $size - 1)]; + } elsif ($use_sysctl) { + @bytes = read_sysctl($dimm_i); + return @bytes[$offset..($offset + $size - 1)]; } elsif ($use_sysfs) { # Kernel 2.6 with sysfs sysopen(HANDLE, "$dimm_i/eeprom", O_RDONLY) @@ -2335,7 +2360,7 @@ sub check_crc($) # Parse command-line foreach (@ARGV) { if ($_ eq '-h' || $_ eq '--help') { - print "Usage: $0 [-c] [-f [-b]] [-x|-X file [files..]]\n", + print "Usage: $0 [-c] [-f [-b]] [-x|-X|-s file [files..]]\n", " $0 -h\n\n", " -f, --format Print nice html output\n", " -b, --bodyonly Don't print html header\n", @@ -2349,6 +2374,8 @@ foreach (@ARGV) { " -x, Read data from hexdump files\n", " -X, Same as -x except treat multibyte hex\n", " data as little endian\n", + " -s, Use NetBSD-compatible sysctl(8) to obtain\n", + " EEPROM data\n", " -h, --help Display this usage summary\n"; print <<"EOF"; @@ -2393,13 +2420,20 @@ EOF $use_hexdump = LITTLEENDIAN; next; } + if ($_ eq '-s') { + if (-x "/sbin/sysctl") { + $use_sysctl = 1; + } else { die "No /sbin/sysctl available for -s"; } + next; + } if (m/^-/) { print STDERR "Unrecognized option $_\n"; exit; } - push @dimm, { eeprom => basename($_), file => $_ } if $use_hexdump; + push @dimm, { eeprom => basename($_), file => $_ } + if ($use_sysctl || $use_hexdump); } # Default values @@ -2477,7 +2511,7 @@ sub get_dimm_list # * chk_spd: The checksum or CRC value found in the EEPROM # * chk_calc: The checksum or CRC computed from the EEPROM data # Keys are added over time. -@dimm = get_dimm_list() unless $use_hexdump; +@dimm = get_dimm_list() unless ($use_sysctl || $use_hexdump); for my $i (0 .. $#dimm) { my @bytes = readspd(0, 128, $dimm[$i]->{file}); @@ -2529,7 +2563,7 @@ for $current (0 .. $#dimm) { printl("Decoding EEPROM", $dimm[$current]->{eeprom}); } - if (!$use_hexdump) { + if (!$use_hexdump && !$use_sysctl) { if ($dimm[$current]->{file} =~ /-([\da-f]+)$/i) { my $dimm_num = hex($1) - 0x50 + 1; if ($dimm_num >= 1 && $dimm_num <= 8) {