* [PATCH] Read SPD data from a hexdump (take 2)
@ 2008-03-16 21:33 Trent Piepho
[not found] ` <Pine.LNX.4.58.0803161427360.20723-13q4cmjDBaTP3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
0 siblings, 1 reply; 11+ messages in thread
From: Trent Piepho @ 2008-03-16 21:33 UTC (permalink / raw)
To: i2c list
This is updated version of the previous patch. I realized that I used four
space indent in the last one. I changed it to 8, and then mode the hexdump
reading code to another function as it was getting too indented. Also, it
can now understand the format of "eeprog".
This adds a "-x" option to decode_dimms.pl, which lets one supply a list of
file names to read SPD data from. It can parse various hexdump formats,
such as the output from i2cdump and the util-linux and Busybox hexdump
progams run on a sysfs eeprom file.
Useful for decoding SPD data that you cut and pasted from a manufacturer's
website or from a DIMM installed on an embeded system that does not have
perl/etc, but does have a serial console with busybox.
-----
--- i2c-tools/eeprom/decode-dimms.pl.orig 2008-03-16 14:19:21.000000000 -0700
+++ i2c-tools/eeprom/decode-dimms.pl 2008-03-16 14:27:15.000000000 -0700
@@ -46,7 +46,7 @@
use strict;
use POSIX;
use Fcntl qw(:DEFAULT :seek);
-use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs
+use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs $use_hexdump
@vendors %decode_callback $revision);
$revision = '$Revision: 5089 $ ($Date: 2008-01-04 08:34:36 -0800 (Fri, 04 Jan 2008) $)';
@@ -1081,10 +1081,51 @@
printl $l, $temp;
}
+# Read various hex dump style formats: hexdump, hexdump -C, i2cdump, eeprog
+# note that normal 'hexdump' format on a little-endian system byte-swaps
+# words, using hexdump -C is better.
+sub readhexdump ($) {
+ my $addr = 0;
+ my $repstart = 0;
+ my @bytes;
+
+ open F, '<', $_[0] or die "Unable to open: $_[0]";
+ while(<F>) {
+ chomp;
+ if(/^\*$/) {
+ $repstart = $addr;
+ next;
+ }
+ /^(?:0000 )?([a-fA-F\d]{2,7}):? ((:?[a-fA-F\d]{4}\s*){8}|(:?[a-fA-F\d]{2}\s*){16})/ ||
+ /^(?:0000 )?([a-fA-F\d]{2,7}):?\s*$/ or die "Can't parse data";
+ $addr = hex $1;
+ if ($repstart) {
+ @bytes[$repstart .. ($addr-1)] = ($bytes[$repstart-1]) x ($addr-$repstart);
+ $repstart = 0;
+ }
+ last unless defined $2;
+ foreach (split(/\s+/, $2)) {
+ if(/^(..)(..)$/) {
+ $bytes[$addr++] = hex($1);
+ $bytes[$addr++] = hex($2);
+ } elsif(/^(..)$/) {
+ $bytes[$addr++] = hex($1);
+ } else {
+ print "Can't parse hex word '$_'\n";
+ }
+ }
+ }
+ close F;
+ return @bytes;
+}
+
sub readspd64 ($$) { # reads 64 bytes from SPD-EEPROM
my ($offset, $dimm_i) = @_;
my @bytes;
- if ($use_sysfs) {
+ if ($use_hexdump) {
+ @bytes = readhexdump($dimm_i);
+ return @bytes[$offset..($offset+63)];
+ } elsif ($use_sysfs) {
# Kernel 2.6 with sysfs
sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY)
or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom";
@@ -1103,20 +1144,25 @@
return @bytes;
}
+my @dimm_list;
+
for (@ARGV) {
if (/-h/) {
- print "Usage: $0 [-c] [-f [-b]]\n",
+ print "Usage: $0 [-c] [-f [-b]] [-x file [files..]]\n",
" $0 -h\n\n",
" -f, --format print nice html output\n",
" -b, --bodyonly don't print html header\n",
" (useful for postprocessing the output)\n",
" -c, --checksum decode completely even if checksum fails\n",
+ " -x, Read data from hexdump files\n",
" -h, --help display this usage summary\n";
exit;
}
$opt_html = 1 if (/-f/);
$opt_bodyonly = 1 if (/-b/);
$opt_igncheck = 1 if (/-c/);
+ $use_hexdump = 1 if(/-x/);
+ push @dimm_list, $_ if($use_hexdump && !/^-[fbcx]$/);
}
$opt_body = $opt_html && ! $opt_bodyonly;
@@ -1136,21 +1182,24 @@
my $dimm_count=0;
-my @dimm_list;
my $dir;
-if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
-else { $dir = '/proc/sys/dev/sensors'; }
-if (-d $dir) {
- @dimm_list = split(/\s+/, `ls $dir`);
-} elsif (! -d '/sys/module/eeprom') {
- print "No EEPROM found, are you sure the eeprom module is loaded?\n";
- exit;
+
+if (!$use_hexdump) {
+ if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
+ else { $dir = '/proc/sys/dev/sensors'; }
+ if (-d $dir) {
+ @dimm_list = split(/\s+/, `ls $dir`);
+ } elsif (! -d '/sys/module/eeprom') {
+ print "No EEPROM found, are you sure the eeprom module is loaded?\n";
+ exit;
+ }
}
for my $i ( 0 .. $#dimm_list ) {
$_=$dimm_list[$i];
if (($use_sysfs && /^\d+-\d+$/)
- || (!$use_sysfs && /^eeprom-/)) {
+ || (!$use_sysfs&& /^eeprom-/)
+ || $use_hexdump) {
my @bytes = readspd64(0, $dimm_list[$i]);
my $dimm_checksum = 0;
$dimm_checksum += $bytes[$_] foreach (0 .. 62);
@@ -1160,15 +1209,18 @@
$dimm_count++;
print "<b><u>" if $opt_html;
- printl2 "\n\nDecoding EEPROM", ($use_sysfs ?
+ printl2 "\n\nDecoding EEPROM",
+ $use_hexdump ? $dimm_list[$i] : ($use_sysfs ?
"/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" :
"/proc/sys/dev/sensors/$dimm_list[$i]");
print "</u></b>" if $opt_html;
print "<table border=1>\n" if $opt_html;
- if (($use_sysfs && /^[^-]+-([^-]+)$/)
- || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
- my $dimm_num=$1 - 49;
- printl "Guessing DIMM is in", "bank $dimm_num";
+ if (!$use_hexdump) {
+ if (($use_sysfs && /^[^-]+-([^-]+)$/)
+ || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
+ my $dimm_num=$1 - 49;
+ printl "Guessing DIMM is in", "bank $dimm_num";
+ }
}
# Decode first 3 bytes (0-2)
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <Pine.LNX.4.58.0803161427360.20723-13q4cmjDBaTP3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
@ 2008-03-20 11:33 ` Jean Delvare
[not found] ` <20080320123315.648911cd-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-03-22 14:02 ` Jean Delvare
1 sibling, 1 reply; 11+ messages in thread
From: Jean Delvare @ 2008-03-20 11:33 UTC (permalink / raw)
To: Trent Piepho; +Cc: i2c list
Hi Trent,
On Sun, 16 Mar 2008 14:33:23 -0700 (PDT), Trent Piepho wrote:
> This is updated version of the previous patch. I realized that I used four
> space indent in the last one. I changed it to 8, and then mode the hexdump
> reading code to another function as it was getting too indented. Also, it
> can now understand the format of "eeprog".
>
> This adds a "-x" option to decode_dimms.pl, which lets one supply a list of
> file names to read SPD data from. It can parse various hexdump formats,
> such as the output from i2cdump and the util-linux and Busybox hexdump
> progams run on a sysfs eeprom file.
>
> Useful for decoding SPD data that you cut and pasted from a manufacturer's
> website or from a DIMM installed on an embeded system that does not have
> perl/etc, but does have a serial console with busybox.
FYI, we already have a way to achieve this, using the i2c-stub kernel
driver and the standard i2c tools. For simple cases, the
i2c-stub-from-dump helper script (in the i2c-tools SVN repository [1])
automates almost everything. That's what I used to test your new DDR2
timing decoding code, as my workstation doesn't have DDR2 memory.
The main drawback compared to your approach is that one needs root
access to the development system, but in practice I doubt that this is
a problem. The advantage is that it works without any change to the
application (e.g. decode-dimms) so all applications are supported right
away.
i2c-stub-from-dump is currently limited in the dump format it supports
(it only takes byte and word dumps from i2cdump) but extending it to
support more dump formats would be trivial. We could even extend it to
support binary input.
[1] http://www.lm-sensors.org/browser/i2c-tools/trunk/stub
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <20080320123315.648911cd-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
@ 2008-03-20 14:59 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803200733220.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
0 siblings, 1 reply; 11+ messages in thread
From: Trent Piepho @ 2008-03-20 14:59 UTC (permalink / raw)
To: Jean Delvare; +Cc: i2c list
On Thu, 20 Mar 2008, Jean Delvare wrote:
> Hi Trent,
>
> On Sun, 16 Mar 2008 14:33:23 -0700 (PDT), Trent Piepho wrote:
> > This is updated version of the previous patch. I realized that I used four
> > space indent in the last one. I changed it to 8, and then mode the hexdump
> > reading code to another function as it was getting too indented. Also, it
> > can now understand the format of "eeprog".
> >
> > This adds a "-x" option to decode_dimms.pl, which lets one supply a list of
> > file names to read SPD data from. It can parse various hexdump formats,
> > such as the output from i2cdump and the util-linux and Busybox hexdump
> > progams run on a sysfs eeprom file.
> >
> > Useful for decoding SPD data that you cut and pasted from a manufacturer's
> > website or from a DIMM installed on an embeded system that does not have
> > perl/etc, but does have a serial console with busybox.
>
> FYI, we already have a way to achieve this, using the i2c-stub kernel
> driver and the standard i2c tools. For simple cases, the
> i2c-stub-from-dump helper script (in the i2c-tools SVN repository [1])
> automates almost everything. That's what I used to test your new DDR2
> timing decoding code, as my workstation doesn't have DDR2 memory.
>
> The main drawback compared to your approach is that one needs root
> access to the development system, but in practice I doubt that this is
> a problem. The advantage is that it works without any change to the
> application (e.g. decode-dimms) so all applications are supported right
> away.
It's also seriously inconvenient to have to compile and install a kernel
module just to decode some SPD data. You can also only decode one file at
a time, since you can only load a single i2c-stub module. It also requires
one to be running Linux, a new enough kernel that has i2c-stub, and have
the kernel source if your distribution didn't come with i2c-stub (we have
people using Linux vmware images that aren't loaded with all this extra
stuff). And there is no way to _not_ decode all the other DIMMs you have
in your system at the same time as one of files you want to inspect.
And of course one needs root access. Doesn't that seem a little
ridiculous, that one needs to be root to decode a spd data file? I can
hear the windows developers mocking me already. "I can't decode SDP data
with your lunix tools because I need root access? That's stupid! My
windows tools for decoding spd don't need to be run as administrator! Do
you need to be root to uncompress zip files?"
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <Pine.LNX.4.58.0803200733220.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
@ 2008-03-20 16:58 ` Jean Delvare
0 siblings, 0 replies; 11+ messages in thread
From: Jean Delvare @ 2008-03-20 16:58 UTC (permalink / raw)
To: Trent Piepho; +Cc: i2c list
On Thu, 20 Mar 2008 07:59:37 -0700 (PDT), Trent Piepho wrote:
> On Thu, 20 Mar 2008, Jean Delvare wrote:
> > FYI, we already have a way to achieve this, using the i2c-stub kernel
> > driver and the standard i2c tools. For simple cases, the
> > i2c-stub-from-dump helper script (in the i2c-tools SVN repository [1])
> > automates almost everything. That's what I used to test your new DDR2
> > timing decoding code, as my workstation doesn't have DDR2 memory.
> >
> > The main drawback compared to your approach is that one needs root
> > access to the development system, but in practice I doubt that this is
> > a problem. The advantage is that it works without any change to the
> > application (e.g. decode-dimms) so all applications are supported right
> > away.
>
> It's also seriously inconvenient to have to compile and install a kernel
> module just to decode some SPD data. You can also only decode one file at
> a time, since you can only load a single i2c-stub module.
In fact you can decode up to 8 files at once (since kernel 2.6.24), as
i2c-stub can create up to 10 virtual devices (could be increased if
needed) and the eeprom driver attaches to devices at addresses
0x50-0x57. We could also create more than one I2C adapter in i2c-stub
if needed.
> It also requires
> one to be running Linux, a new enough kernel that has i2c-stub, and have
> the kernel source if your distribution didn't come with i2c-stub (we have
> people using Linux vmware images that aren't loaded with all this extra
> stuff). And there is no way to _not_ decode all the other DIMMs you have
> in your system at the same time as one of files you want to inspect.
You can unload the on-board SMBus adapter driver, that's what I did to
test your DDR2 decoding patch. This might not be an option if there are
other chips on the SMBus and you can't live without them, though.
>
> And of course one needs root access. Doesn't that seem a little
> ridiculous, that one needs to be root to decode a spd data file? I can
> hear the windows developers mocking me already. "I can't decode SDP data
> with your lunix tools because I need root access? That's stupid! My
> windows tools for decoding spd don't need to be run as administrator! Do
> you need to be root to uncompress zip files?"
I fail to see what Windows developers [1] have to do in the picture.
Either the requirement to be root for this operation is acceptable to
us in practice, or it is not. If it isn't, we fix it, for example by
applying the patch you submitted. What people NOT using the code in
question think about its usage requirements, I couldn't care less.
I didn't mean to suggest that your patch was not welcome. I was only
mentioning an alternative which is already implemented, for your
information (thus the leading "FYI" in my reply.) Of course i2c-stub is
not perfect for the job, it was not designed for it. i2c-stub was
designed to allow I2C device emulation at kernel level. Using it for a
purely user-space job as I suggested is a side use.
--
Jean Delvare
[1] Especially when your Windows developer friend is most probably
always logged as Administrator anyway because there are so many things
that don't work properly as a regular user ;)
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <Pine.LNX.4.58.0803161427360.20723-13q4cmjDBaTP3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-20 11:33 ` Jean Delvare
@ 2008-03-22 14:02 ` Jean Delvare
[not found] ` <20080322150222.2a8ccc60-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
1 sibling, 1 reply; 11+ messages in thread
From: Jean Delvare @ 2008-03-22 14:02 UTC (permalink / raw)
To: Trent Piepho; +Cc: i2c list
Hi Trent,
On Sun, 16 Mar 2008 14:33:23 -0700 (PDT), Trent Piepho wrote:
> This is updated version of the previous patch. I realized that I used four
> space indent in the last one. I changed it to 8, and then mode the hexdump
> reading code to another function as it was getting too indented. Also, it
> can now understand the format of "eeprog".
>
> This adds a "-x" option to decode_dimms.pl, which lets one supply a list of
> file names to read SPD data from. It can parse various hexdump formats,
> such as the output from i2cdump and the util-linux and Busybox hexdump
> progams run on a sysfs eeprom file.
>
> Useful for decoding SPD data that you cut and pasted from a manufacturer's
> website or from a DIMM installed on an embeded system that does not have
> perl/etc, but does have a serial console with busybox.
Sounds like a good idea. Review:
>
> -----
> --- i2c-tools/eeprom/decode-dimms.pl.orig 2008-03-16 14:19:21.000000000 -0700
> +++ i2c-tools/eeprom/decode-dimms.pl 2008-03-16 14:27:15.000000000 -0700
> @@ -46,7 +46,7 @@
> use strict;
> use POSIX;
> use Fcntl qw(:DEFAULT :seek);
> -use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs
> +use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs $use_hexdump
> @vendors %decode_callback $revision);
>
> $revision = '$Revision: 5089 $ ($Date: 2008-01-04 08:34:36 -0800 (Fri, 04 Jan 2008) $)';
> @@ -1081,10 +1081,51 @@
> printl $l, $temp;
> }
>
> +# Read various hex dump style formats: hexdump, hexdump -C, i2cdump, eeprog
Space instead of tab after the colon.
> +# note that normal 'hexdump' format on a little-endian system byte-swaps
> +# words, using hexdump -C is better.
The function below chokes on the header line of i2cdump output:
<file>
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 80 08 08 0e 0b 60 48 00 05 50 60 02 82 04 04 00 ?????`H.?P`????.
10: ...
</file>
Can't parse data at eeprom/decode-dimms.pl line 1119, <F> line 1.
Of course I can delete this first line from the file and then it works,
but it would be better if the function could simply ignore this header
line.
> +sub readhexdump ($) {
Coding style: opening curly brace goes on the next line. I'd also
suggest renaming the function to read_hexdump.
> + my $addr = 0;
> + my $repstart = 0;
> + my @bytes;
> +
> + open F, '<', $_[0] or die "Unable to open: $_[0]";
> + while(<F>) {
Coding style: space after while.
> + chomp;
> + if(/^\*$/) {
Coding style: space after if, and again several times below.
> + $repstart = $addr;
> + next;
> + }
> + /^(?:0000 )?([a-fA-F\d]{2,7}):? ((:?[a-fA-F\d]{4}\s*){8}|(:?[a-fA-F\d]{2}\s*){16})/ ||
> + /^(?:0000 )?([a-fA-F\d]{2,7}):?\s*$/ or die "Can't parse data";
You could use the /i regexp modifier so that you don't have to specify
both a-f and A-F each time.
> + $addr = hex $1;
> + if ($repstart) {
> + @bytes[$repstart .. ($addr-1)] = ($bytes[$repstart-1]) x ($addr-$repstart);
You repeat the same byte for all the omitted block... this isn't how I
read man hexdump(1). As I understand it, you are supposed to repeat the
last line, not the last byte.
Alternatively you could drop support for this special format, which
doesn't make much sense for a 256-byte EEPROM if you ask me. And in
practice the only cases where it could happen is for rows of 0x00s or
0xffs - it doesn't make a difference if you omit them completely.
> + $repstart = 0;
> + }
> + last unless defined $2;
> + foreach (split(/\s+/, $2)) {
> + if(/^(..)(..)$/) {
> + $bytes[$addr++] = hex($1);
> + $bytes[$addr++] = hex($2);
I'm unsure if we want to support this ambiguous format. You assume
big-endian byte order here. Even though you document it in the comment
above, users might not read the source code and so might feed the
script with little-endian byte order data and get noise out of the
script.
> + } elsif(/^(..)$/) {
> + $bytes[$addr++] = hex($1);
> + } else {
> + print "Can't parse hex word '$_'\n";
I fail to see how this could ever happen.
> + }
> + }
> + }
> + close F;
> + return @bytes;
> +}
> +
> sub readspd64 ($$) { # reads 64 bytes from SPD-EEPROM
> my ($offset, $dimm_i) = @_;
> my @bytes;
> - if ($use_sysfs) {
> + if ($use_hexdump) {
> + @bytes = readhexdump($dimm_i);
> + return @bytes[$offset..($offset+63)];
> + } elsif ($use_sysfs) {
> # Kernel 2.6 with sysfs
> sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY)
> or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom";
> @@ -1103,20 +1144,25 @@
> return @bytes;
> }
>
> +my @dimm_list;
This one probably deserves being moved to the use vars declaration
above.
> +
> for (@ARGV) {
> if (/-h/) {
> - print "Usage: $0 [-c] [-f [-b]]\n",
> + print "Usage: $0 [-c] [-f [-b]] [-x file [files..]]\n",
> " $0 -h\n\n",
> " -f, --format print nice html output\n",
> " -b, --bodyonly don't print html header\n",
> " (useful for postprocessing the output)\n",
> " -c, --checksum decode completely even if checksum fails\n",
> + " -x, Read data from hexdump files\n",
> " -h, --help display this usage summary\n";
> exit;
> }
> $opt_html = 1 if (/-f/);
> $opt_bodyonly = 1 if (/-b/);
> $opt_igncheck = 1 if (/-c/);
> + $use_hexdump = 1 if(/-x/);
> + push @dimm_list, $_ if($use_hexdump && !/^-[fbcx]$/);
In anticipation of more options being added in the future, I'd
use !/^-/ instead. Your variant above also fails if long options are
used.
> }
> $opt_body = $opt_html && ! $opt_bodyonly;
>
> @@ -1136,21 +1182,24 @@
>
>
> my $dimm_count=0;
> -my @dimm_list;
> my $dir;
> -if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
> -else { $dir = '/proc/sys/dev/sensors'; }
> -if (-d $dir) {
> - @dimm_list = split(/\s+/, `ls $dir`);
> -} elsif (! -d '/sys/module/eeprom') {
> - print "No EEPROM found, are you sure the eeprom module is loaded?\n";
> - exit;
> +
> +if (!$use_hexdump) {
> + if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
> + else { $dir = '/proc/sys/dev/sensors'; }
> + if (-d $dir) {
> + @dimm_list = split(/\s+/, `ls $dir`);
> + } elsif (! -d '/sys/module/eeprom') {
> + print "No EEPROM found, are you sure the eeprom module is loaded?\n";
> + exit;
> + }
> }
>
> for my $i ( 0 .. $#dimm_list ) {
> $_=$dimm_list[$i];
> if (($use_sysfs && /^\d+-\d+$/)
> - || (!$use_sysfs && /^eeprom-/)) {
> + || (!$use_sysfs&& /^eeprom-/)
Coding style: space before &&.
> + || $use_hexdump) {
> my @bytes = readspd64(0, $dimm_list[$i]);
> my $dimm_checksum = 0;
> $dimm_checksum += $bytes[$_] foreach (0 .. 62);
> @@ -1160,15 +1209,18 @@
> $dimm_count++;
>
> print "<b><u>" if $opt_html;
> - printl2 "\n\nDecoding EEPROM", ($use_sysfs ?
> + printl2 "\n\nDecoding EEPROM",
> + $use_hexdump ? $dimm_list[$i] : ($use_sysfs ?
> "/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" :
> "/proc/sys/dev/sensors/$dimm_list[$i]");
> print "</u></b>" if $opt_html;
> print "<table border=1>\n" if $opt_html;
> - if (($use_sysfs && /^[^-]+-([^-]+)$/)
> - || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
> - my $dimm_num=$1 - 49;
> - printl "Guessing DIMM is in", "bank $dimm_num";
> + if (!$use_hexdump) {
> + if (($use_sysfs && /^[^-]+-([^-]+)$/)
> + || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
> + my $dimm_num=$1 - 49;
> + printl "Guessing DIMM is in", "bank $dimm_num";
> + }
> }
>
> # Decode first 3 bytes (0-2)
Please provide an updated patch and I'll commit it.
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <20080322150222.2a8ccc60-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
@ 2008-03-22 21:46 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803221346450.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
0 siblings, 1 reply; 11+ messages in thread
From: Trent Piepho @ 2008-03-22 21:46 UTC (permalink / raw)
To: Jean Delvare; +Cc: i2c list
On Sat, 22 Mar 2008, Jean Delvare wrote:
> The function below chokes on the header line of i2cdump output:
>
> <file>
> 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
> 00: 80 08 08 0e 0b 60 48 00 05 50 60 02 82 04 04 00 ?????`H.?P`????.
> 10: ...
> </file>
>
> Can't parse data at eeprom/decode-dimms.pl line 1119, <F> line 1.
>
> Of course I can delete this first line from the file and then it works,
> but it would be better if the function could simply ignore this header
> line.
[...]
> You repeat the same byte for all the omitted block... this isn't how I
> read man hexdump(1). As I understand it, you are supposed to repeat the
> last line, not the last byte.
>
> Alternatively you could drop support for this special format, which
> doesn't make much sense for a 256-byte EEPROM if you ask me. And in
> practice the only cases where it could happen is for rows of 0x00s or
> 0xffs - it doesn't make a difference if you omit them completely.
I've added code to ignore header lines. The code to parse the repeat line
syntax is there for the same reason: hexdump produces that syntax when you
run it on an eeprom file. Not parsing it requires editing the hexdumps by
hand, which is a lot more trouble than just deleting a one line header.
As far as I can tell, hexdump and od only produce the line repeat when
every byte in the line is the same, so repeating the last byte vs the last
16 bytes is effectively the same. My goal wasn't to code some complex
"perfect" hex dump parser, but just to work correctly on the formats one
typically has at hand.
> You could use the /i regexp modifier so that you don't have to specify
> both a-f and A-F each time.
Good idea.
> > + foreach (split(/\s+/, $2)) {
> > + if(/^(..)(..)$/) {
> > + $bytes[$addr++] = hex($1);
> > + $bytes[$addr++] = hex($2);
>
> I'm unsure if we want to support this ambiguous format. You assume
> big-endian byte order here. Even though you document it in the comment
> above, users might not read the source code and so might feed the
> script with little-endian byte order data and get noise out of the
> script.
I've added some better documentation to the help output. It's the default
format of "hexdump" and I'm not sure if old versions of busybox can produce
the -C format when compiled with certain options. I think if you turn on
hexdump but not od, you get a limited version that can't do everything.
> > + } elsif(/^(..)$/) {
> > + $bytes[$addr++] = hex($1);
> > + } else {
> > + print "Can't parse hex word '$_'\n";
>
> I fail to see how this could ever happen.
It was just defensive programming. In case my regexs to parse the line
were less than perfect, maybe it would get caught here.
> > $opt_html = 1 if (/-f/);
> > $opt_bodyonly = 1 if (/-b/);
> > $opt_igncheck = 1 if (/-c/);
> > + $use_hexdump = 1 if(/-x/);
> > + push @dimm_list, $_ if($use_hexdump && !/^-[fbcx]$/);
>
> In anticipation of more options being added in the future, I'd
> use !/^-/ instead. Your variant above also fails if long options are
> used.
Fixed. Note that all the option regexes should be changed to something
like '/^-?-f/'. Otherwise a filename like hys72d32500gr-7-b will trigger
the $opt_bodyonly option. (that's a real example, I named my eeprom dumps
after the part number, but in caps)
---------------------------------------------------------------------------
This adds a "-x" option to decode_dimms.pl, which lets one supply a list of
file names to read SPD data from. It can parse various hexdump formats,
such as the output from i2cdump and the util-linux and Busybox hexdump
progams run on a sysfs eeprom file.
Useful for decoding SPD data that you cut and pasted from a manufacturer's
website or from a DIMM installed on an embeded system that does not have
perl/etc, but does have a serial console with busybox.
---
Index: eeprom/decode-dimms.pl
===================================================================
--- eeprom/decode-dimms.pl (revision 5156)
+++ eeprom/decode-dimms.pl (working copy)
@@ -46,8 +46,8 @@
use strict;
use POSIX;
use Fcntl qw(:DEFAULT :seek);
-use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs
- @vendors %decode_callback $revision);
+use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs $use_hexdump
+ @vendors %decode_callback $revision @dimm_list);
$revision = '$Revision$ ($Date$)';
$revision =~ s/\$\w+: (.*?) \$/$1/g;
@@ -1100,10 +1100,59 @@
printl $l, $temp;
}
+# Read various hex dump style formats: hexdump, hexdump -C, i2cdump, eeprog
+# note that normal 'hexdump' format on a little-endian system byte-swaps
+# words, using hexdump -C is better.
+sub read_hexdump ($)
+{
+ my $addr = 0;
+ my $repstart = 0;
+ my @bytes;
+ my $header = 1;
+
+ open F, '<', $_[0] or die "Unable to open: $_[0]";
+ while (<F>) {
+ my $ok = 1;
+
+ chomp;
+ if (/^\*$/) {
+ $repstart = $addr;
+ next;
+ }
+ /^(?:0000 )?([a-f\d]{2,7}):? ((:?[a-f\d]{4}\s*){8}|(:?[a-f\d]{2}\s*){16})/i ||
+ /^(?:0000 )?([a-f\d]{2,7}):?\s*$/i or $ok = 0;
+ next if (!$ok && $header); # skip leading unparsed lines
+
+ $ok or die "Unable to parse input";
+ $header = 0;
+
+ $addr = hex $1;
+ if ($repstart) {
+ @bytes[$repstart .. ($addr-1)] = ($bytes[$repstart-1]) x ($addr-$repstart);
+ $repstart = 0;
+ }
+ last unless defined $2;
+ foreach (split(/\s+/, $2)) {
+ if (/^(..)(..)$/) {
+ $bytes[$addr++] = hex($1);
+ $bytes[$addr++] = hex($2);
+ } else {
+ /^(..)$/;
+ $bytes[$addr++] = hex($1);
+ }
+ }
+ }
+ close F;
+ return @bytes;
+}
+
sub readspd64 ($$) { # reads 64 bytes from SPD-EEPROM
my ($offset, $dimm_i) = @_;
my @bytes;
- if ($use_sysfs) {
+ if ($use_hexdump) {
+ @bytes = read_hexdump($dimm_i);
+ return @bytes[$offset..($offset+63)];
+ } elsif ($use_sysfs) {
# Kernel 2.6 with sysfs
sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY)
or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom";
@@ -1123,19 +1172,29 @@
}
for (@ARGV) {
- if (/-h/) {
- print "Usage: $0 [-c] [-f [-b]]\n",
+ if (/^-?-h/) {
+ print "Usage: $0 [-c] [-f [-b]] [-x file [files..]]\n",
" $0 -h\n\n",
" -f, --format print nice html output\n",
" -b, --bodyonly don't print html header\n",
" (useful for postprocessing the output)\n",
" -c, --checksum decode completely even if checksum fails\n",
+ " -x, Read data from hexdump files\n",
" -h, --help display this usage summary\n";
+ print <<"EOF";
+
+Hexdumps can be the output from hexdump, hexdump -C, i2cdump, eeprog and
+likely many other progams producing hex dumps of one kind or another. Note
+that the default output of "hexdump" will be byte-swapped on little-endian
+systems. It is better to use "hexdump -C", which is not ambiguous.
+EOF
exit;
}
- $opt_html = 1 if (/-f/);
- $opt_bodyonly = 1 if (/-b/);
- $opt_igncheck = 1 if (/-c/);
+ $opt_html = 1 if (/^-?-f/);
+ $opt_bodyonly = 1 if (/^-?-b/);
+ $opt_igncheck = 1 if (/^-?-c/);
+ $use_hexdump = 1 if (/^-x/);
+ push @dimm_list, $_ if ($use_hexdump && !/^-/);
}
$opt_body = $opt_html && ! $opt_bodyonly;
@@ -1155,21 +1214,23 @@
my $dimm_count = 0;
-my @dimm_list;
my $dir;
-if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
-else { $dir = '/proc/sys/dev/sensors'; }
-if (-d $dir) {
- @dimm_list = split(/\s+/, `ls $dir`);
-} elsif (! -d '/sys/module/eeprom') {
- print "No EEPROM found, are you sure the eeprom module is loaded?\n";
- exit;
+if (!$use_hexdump) {
+ if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
+ else { $dir = '/proc/sys/dev/sensors'; }
+ if (-d $dir) {
+ @dimm_list = split(/\s+/, `ls $dir`);
+ } elsif (! -d '/sys/module/eeprom') {
+ print "No EEPROM found, are you sure the eeprom module is loaded?\n";
+ exit;
+ }
}
for my $i ( 0 .. $#dimm_list ) {
$_ = $dimm_list[$i];
if (($use_sysfs && /^\d+-\d+$/)
- || (!$use_sysfs && /^eeprom-/)) {
+ || (!$use_sysfs && /^eeprom-/)
+ || $use_hexdump) {
my @bytes = readspd64(0, $dimm_list[$i]);
my $dimm_checksum = 0;
$dimm_checksum += $bytes[$_] foreach (0 .. 62);
@@ -1179,15 +1240,18 @@
$dimm_count++;
print "<b><u>" if $opt_html;
- printl2 "\n\nDecoding EEPROM", ($use_sysfs ?
+ printl2 "\n\nDecoding EEPROM",
+ $use_hexdump ? $dimm_list[$i] : ($use_sysfs ?
"/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" :
"/proc/sys/dev/sensors/$dimm_list[$i]");
print "</u></b>" if $opt_html;
print "<table border=1>\n" if $opt_html;
- if (($use_sysfs && /^[^-]+-([^-]+)$/)
- || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
- my $dimm_num = $1 - 49;
- printl "Guessing DIMM is in", "bank $dimm_num";
+ if (!$use_hexdump) {
+ if (($use_sysfs && /^[^-]+-([^-]+)$/)
+ || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
+ my $dimm_num = $1 - 49;
+ printl "Guessing DIMM is in", "bank $dimm_num";
+ }
}
# Decode first 3 bytes (0-2)
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <Pine.LNX.4.58.0803221346450.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
@ 2008-03-22 23:59 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803221654220.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-23 12:05 ` Jean Delvare
1 sibling, 1 reply; 11+ messages in thread
From: Trent Piepho @ 2008-03-22 23:59 UTC (permalink / raw)
To: Jean Delvare; +Cc: i2c list
The regex for parsing hexdump -C was wrong. I remember fixing that before,
so I think some old code got in these patches. It's a real pain to deal
with a stack of outstanding patches with svn and merge against conflicts
from upstream.
This adds a "-x" option to decode_dimms.pl, which lets one supply a list of
file names to read SPD data from. It can parse various hexdump formats,
such as the output from i2cdump and the util-linux and Busybox hexdump
progams run on a sysfs eeprom file.
Useful for decoding SPD data that you cut and pasted from a manufacturer's
website or from a DIMM installed on an embeded system that does not have
perl/etc, but does have a serial console with busybox.
---
Index: eeprom/decode-dimms.pl
===================================================================
--- eeprom/decode-dimms.pl (revision 5156)
+++ eeprom/decode-dimms.pl (working copy)
@@ -46,8 +46,8 @@
use strict;
use POSIX;
use Fcntl qw(:DEFAULT :seek);
-use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs
- @vendors %decode_callback $revision);
+use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs $use_hexdump
+ @vendors %decode_callback $revision @dimm_list);
$revision = '$Revision$ ($Date$)';
$revision =~ s/\$\w+: (.*?) \$/$1/g;
@@ -1100,10 +1100,60 @@
printl $l, $temp;
}
+# Read various hex dump style formats: hexdump, hexdump -C, i2cdump, eeprog
+# note that normal 'hexdump' format on a little-endian system byte-swaps
+# words, using hexdump -C is better.
+sub read_hexdump ($)
+{
+ my $addr = 0;
+ my $repstart = 0;
+ my @bytes;
+ my $header = 1;
+
+ open F, '<', $_[0] or die "Unable to open: $_[0]";
+ while (<F>) {
+ my $ok = 1;
+
+ chomp;
+ if (/^\*$/) {
+ $repstart = $addr;
+ next;
+ }
+ /^(?:0000 )?([a-f\d]{2,8}):?\s+((:?[a-f\d]{4}\s*){8}|(:?[a-f\d]{2}\s*){16})/i ||
+ /^(?:0000 )?([a-f\d]{2,8}):?\s*$/i or $ok = 0;
+ next if (!$ok && $header); # skip leading unparsed lines
+
+ $ok or die "Unable to parse input";
+ $header = 0;
+
+ $addr = hex $1;
+ if ($repstart) {
+ @bytes[$repstart .. ($addr-1)] = ($bytes[$repstart-1]) x ($addr-$repstart);
+ $repstart = 0;
+ }
+ last unless defined $2;
+ foreach (split(/\s+/, $2)) {
+ if (/^(..)(..)$/) {
+ $bytes[$addr++] = hex($1);
+ $bytes[$addr++] = hex($2);
+ } else {
+ /^(..)$/;
+ $bytes[$addr++] = hex($1);
+ }
+ }
+ }
+ close F;
+ $header and die "Unable to parse any data from hexdump '$_[0]'";
+ return @bytes;
+}
+
sub readspd64 ($$) { # reads 64 bytes from SPD-EEPROM
my ($offset, $dimm_i) = @_;
my @bytes;
- if ($use_sysfs) {
+ if ($use_hexdump) {
+ @bytes = read_hexdump($dimm_i);
+ return @bytes[$offset..($offset+63)];
+ } elsif ($use_sysfs) {
# Kernel 2.6 with sysfs
sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY)
or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom";
@@ -1123,19 +1173,29 @@
}
for (@ARGV) {
- if (/-h/) {
- print "Usage: $0 [-c] [-f [-b]]\n",
+ if (/^-?-h/) {
+ print "Usage: $0 [-c] [-f [-b]] [-x file [files..]]\n",
" $0 -h\n\n",
" -f, --format print nice html output\n",
" -b, --bodyonly don't print html header\n",
" (useful for postprocessing the output)\n",
" -c, --checksum decode completely even if checksum fails\n",
+ " -x, Read data from hexdump files\n",
" -h, --help display this usage summary\n";
+ print <<"EOF";
+
+Hexdumps can be the output from hexdump, hexdump -C, i2cdump, eeprog and
+likely many other progams producing hex dumps of one kind or another. Note
+that the default output of "hexdump" will be byte-swapped on little-endian
+systems. It is better to use "hexdump -C", which is not ambiguous.
+EOF
exit;
}
- $opt_html = 1 if (/-f/);
- $opt_bodyonly = 1 if (/-b/);
- $opt_igncheck = 1 if (/-c/);
+ $opt_html = 1 if (/^-?-f/);
+ $opt_bodyonly = 1 if (/^-?-b/);
+ $opt_igncheck = 1 if (/^-?-c/);
+ $use_hexdump = 1 if (/^-x/);
+ push @dimm_list, $_ if ($use_hexdump && !/^-/);
}
$opt_body = $opt_html && ! $opt_bodyonly;
@@ -1155,21 +1215,23 @@
my $dimm_count = 0;
-my @dimm_list;
my $dir;
-if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
-else { $dir = '/proc/sys/dev/sensors'; }
-if (-d $dir) {
- @dimm_list = split(/\s+/, `ls $dir`);
-} elsif (! -d '/sys/module/eeprom') {
- print "No EEPROM found, are you sure the eeprom module is loaded?\n";
- exit;
+if (!$use_hexdump) {
+ if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
+ else { $dir = '/proc/sys/dev/sensors'; }
+ if (-d $dir) {
+ @dimm_list = split(/\s+/, `ls $dir`);
+ } elsif (! -d '/sys/module/eeprom') {
+ print "No EEPROM found, are you sure the eeprom module is loaded?\n";
+ exit;
+ }
}
for my $i ( 0 .. $#dimm_list ) {
$_ = $dimm_list[$i];
if (($use_sysfs && /^\d+-\d+$/)
- || (!$use_sysfs && /^eeprom-/)) {
+ || (!$use_sysfs && /^eeprom-/)
+ || $use_hexdump) {
my @bytes = readspd64(0, $dimm_list[$i]);
my $dimm_checksum = 0;
$dimm_checksum += $bytes[$_] foreach (0 .. 62);
@@ -1179,15 +1241,18 @@
$dimm_count++;
print "<b><u>" if $opt_html;
- printl2 "\n\nDecoding EEPROM", ($use_sysfs ?
+ printl2 "\n\nDecoding EEPROM",
+ $use_hexdump ? $dimm_list[$i] : ($use_sysfs ?
"/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" :
"/proc/sys/dev/sensors/$dimm_list[$i]");
print "</u></b>" if $opt_html;
print "<table border=1>\n" if $opt_html;
- if (($use_sysfs && /^[^-]+-([^-]+)$/)
- || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
- my $dimm_num = $1 - 49;
- printl "Guessing DIMM is in", "bank $dimm_num";
+ if (!$use_hexdump) {
+ if (($use_sysfs && /^[^-]+-([^-]+)$/)
+ || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
+ my $dimm_num = $1 - 49;
+ printl "Guessing DIMM is in", "bank $dimm_num";
+ }
}
# Decode first 3 bytes (0-2)
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <Pine.LNX.4.58.0803221346450.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-22 23:59 ` Trent Piepho
@ 2008-03-23 12:05 ` Jean Delvare
[not found] ` <20080323130547.538eed81-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
1 sibling, 1 reply; 11+ messages in thread
From: Jean Delvare @ 2008-03-23 12:05 UTC (permalink / raw)
To: Trent Piepho; +Cc: i2c list
Hi Trent,
On Sat, 22 Mar 2008 14:46:43 -0700 (PDT), Trent Piepho wrote:
> On Sat, 22 Mar 2008, Jean Delvare wrote:
> > You repeat the same byte for all the omitted block... this isn't how I
> > read man hexdump(1). As I understand it, you are supposed to repeat the
> > last line, not the last byte.
> >
> > Alternatively you could drop support for this special format, which
> > doesn't make much sense for a 256-byte EEPROM if you ask me. And in
> > practice the only cases where it could happen is for rows of 0x00s or
> > 0xffs - it doesn't make a difference if you omit them completely.
>
> I've added code to ignore header lines. The code to parse the repeat line
> syntax is there for the same reason: hexdump produces that syntax when you
> run it on an eeprom file. Not parsing it requires editing the hexdumps by
> hand, which is a lot more trouble than just deleting a one line header.
Maybe I did not express myself clearly enough. I didn't mean to stop
supporting the special "compact" format by choking on it, but by
simply ignoring the "*" line as you do for i2cdump's header line (and
filling the @bytes array with zeroes, which would be presumably simpler
than what you did.)
> As far as I can tell, hexdump and od only produce the line repeat when
> every byte in the line is the same, so repeating the last byte vs the last
> 16 bytes is effectively the same.
Your assumption is incorrect. You can test it easily:
khali@hyperion:~> dd if=/dev/random of=random16.bin bs=16 count=1
1+0 records in
1+0 records out
16 bytes (16 B) copied, 6.5427e-05 s, 245 kB/s
khali@hyperion:~> hexdump random16.bin
0000000 9d89 66d7 d2a5 9118 86b9 85c6 9454 cc8e
0000010
khali@hyperion:~> cat random16.bin random16.bin random16.bin random16.bin > random64.bin
khali@hyperion:~> hexdump random64.bin
0000000 9d89 66d7 d2a5 9118 86b9 85c6 9454 cc8e
*
0000040
khali@hyperion:~> od -x random64.bin
0000000 9d89 66d7 d2a5 9118 86b9 85c6 9454 cc8e
*
0000100
khali@hyperion:~>
And I agree that it doesn't make much sense (at least when od's -w
option isn't used) but that's the way it is.
> My goal wasn't to code some complex
> "perfect" hex dump parser, but just to work correctly on the formats one
> typically has at hand.
Fine with me, but either implement the "repeat" mode properly (it
shouldn't be that difficult), or don't implement it at all.
Implementing it in a way which doesn't match what hexdump and od output
doesn't make any sense to me.
> > (...)
> > I'm unsure if we want to support this ambiguous format. You assume
> > big-endian byte order here. Even though you document it in the comment
> > above, users might not read the source code and so might feed the
> > script with little-endian byte order data and get noise out of the
> > script.
>
> I've added some better documentation to the help output. It's the default
Good start, but I'd go further and warn the user at runtime when
parsing hexdumps using this format. For example:
Warning: Assuming hexdump uses big-endian byte order
> > (...)
> > In anticipation of more options being added in the future, I'd
> > use !/^-/ instead. Your variant above also fails if long options are
> > used.
>
> Fixed. Note that all the option regexes should be changed to something
> like '/^-?-f/'. Otherwise a filename like hys72d32500gr-7-b will trigger
> the $opt_bodyonly option. (that's a real example, I named my eeprom dumps
> after the part number, but in caps)
You are correct. Even better would be to explicitly match the short and
long options. I'll fix that later.
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <Pine.LNX.4.58.0803221654220.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
@ 2008-03-23 13:36 ` Jean Delvare
0 siblings, 0 replies; 11+ messages in thread
From: Jean Delvare @ 2008-03-23 13:36 UTC (permalink / raw)
To: Trent Piepho; +Cc: i2c list
Hi Trent,
On Sat, 22 Mar 2008 16:59:05 -0700 (PDT), Trent Piepho wrote:
> The regex for parsing hexdump -C was wrong. I remember fixing that before,
> so I think some old code got in these patches. It's a real pain to deal
> with a stack of outstanding patches with svn and merge against conflicts
> from upstream.
Sorry about that, I should have delayed my cleanups until this patch
was merged, my bad.
>
>
> This adds a "-x" option to decode_dimms.pl, which lets one supply a list of
> file names to read SPD data from. It can parse various hexdump formats,
> such as the output from i2cdump and the util-linux and Busybox hexdump
> progams run on a sysfs eeprom file.
>
> Useful for decoding SPD data that you cut and pasted from a manufacturer's
> website or from a DIMM installed on an embeded system that does not have
> perl/etc, but does have a serial console with busybox.
>
> ---
> Index: eeprom/decode-dimms.pl
> ===================================================================
> --- eeprom/decode-dimms.pl (revision 5156)
> +++ eeprom/decode-dimms.pl (working copy)
> @@ -46,8 +46,8 @@
> use strict;
> use POSIX;
> use Fcntl qw(:DEFAULT :seek);
> -use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs
> - @vendors %decode_callback $revision);
> +use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs $use_hexdump
> + @vendors %decode_callback $revision @dimm_list);
>
> $revision = '$Revision$ ($Date$)';
> $revision =~ s/\$\w+: (.*?) \$/$1/g;
> @@ -1100,10 +1100,60 @@
> printl $l, $temp;
> }
>
> +# Read various hex dump style formats: hexdump, hexdump -C, i2cdump, eeprog
> +# note that normal 'hexdump' format on a little-endian system byte-swaps
> +# words, using hexdump -C is better.
> +sub read_hexdump ($)
> +{
> + my $addr = 0;
> + my $repstart = 0;
> + my @bytes;
> + my $header = 1;
> +
> + open F, '<', $_[0] or die "Unable to open: $_[0]";
> + while (<F>) {
> + my $ok = 1;
> +
> + chomp;
> + if (/^\*$/) {
> + $repstart = $addr;
> + next;
> + }
> + /^(?:0000 )?([a-f\d]{2,8}):?\s+((:?[a-f\d]{4}\s*){8}|(:?[a-f\d]{2}\s*){16})/i ||
> + /^(?:0000 )?([a-f\d]{2,8}):?\s*$/i or $ok = 0;
> + next if (!$ok && $header); # skip leading unparsed lines
I think you can do without $ok, just check for defined $1? Or use a
more standard if (m//) {} construct.
> +
> + $ok or die "Unable to parse input";
> + $header = 0;
> +
> + $addr = hex $1;
> + if ($repstart) {
> + @bytes[$repstart .. ($addr-1)] = ($bytes[$repstart-1]) x ($addr-$repstart);
As said in my other reply, this doesn't match what hexdump and od
output.
> + $repstart = 0;
> + }
> + last unless defined $2;
> + foreach (split(/\s+/, $2)) {
> + if (/^(..)(..)$/) {
> + $bytes[$addr++] = hex($1);
> + $bytes[$addr++] = hex($2);
> + } else {
> + /^(..)$/;
> + $bytes[$addr++] = hex($1);
Why not just
$bytes[$addr++] = hex;
?
> + }
> + }
> + }
> + close F;
> + $header and die "Unable to parse any data from hexdump '$_[0]'";
> + return @bytes;
> +}
> +
> sub readspd64 ($$) { # reads 64 bytes from SPD-EEPROM
> my ($offset, $dimm_i) = @_;
> my @bytes;
> - if ($use_sysfs) {
> + if ($use_hexdump) {
> + @bytes = read_hexdump($dimm_i);
> + return @bytes[$offset..($offset+63)];
> + } elsif ($use_sysfs) {
> # Kernel 2.6 with sysfs
> sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY)
> or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom";
> @@ -1123,19 +1173,29 @@
> }
>
> for (@ARGV) {
> - if (/-h/) {
> - print "Usage: $0 [-c] [-f [-b]]\n",
> + if (/^-?-h/) {
> + print "Usage: $0 [-c] [-f [-b]] [-x file [files..]]\n",
> " $0 -h\n\n",
> " -f, --format print nice html output\n",
> " -b, --bodyonly don't print html header\n",
> " (useful for postprocessing the output)\n",
> " -c, --checksum decode completely even if checksum fails\n",
> + " -x, Read data from hexdump files\n",
> " -h, --help display this usage summary\n";
> + print <<"EOF";
> +
> +Hexdumps can be the output from hexdump, hexdump -C, i2cdump, eeprog and
> +likely many other progams producing hex dumps of one kind or another. Note
> +that the default output of "hexdump" will be byte-swapped on little-endian
> +systems. It is better to use "hexdump -C", which is not ambiguous.
Maybe state more explicitly that such little-endian dumps are not
supported?
> +EOF
> exit;
> }
> - $opt_html = 1 if (/-f/);
> - $opt_bodyonly = 1 if (/-b/);
> - $opt_igncheck = 1 if (/-c/);
> + $opt_html = 1 if (/^-?-f/);
> + $opt_bodyonly = 1 if (/^-?-b/);
> + $opt_igncheck = 1 if (/^-?-c/);
> + $use_hexdump = 1 if (/^-x/);
> + push @dimm_list, $_ if ($use_hexdump && !/^-/);
> }
> $opt_body = $opt_html && ! $opt_bodyonly;
>
> @@ -1155,21 +1215,23 @@
>
>
> my $dimm_count = 0;
> -my @dimm_list;
> my $dir;
> -if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
> -else { $dir = '/proc/sys/dev/sensors'; }
> -if (-d $dir) {
> - @dimm_list = split(/\s+/, `ls $dir`);
> -} elsif (! -d '/sys/module/eeprom') {
> - print "No EEPROM found, are you sure the eeprom module is loaded?\n";
> - exit;
> +if (!$use_hexdump) {
> + if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
> + else { $dir = '/proc/sys/dev/sensors'; }
> + if (-d $dir) {
> + @dimm_list = split(/\s+/, `ls $dir`);
> + } elsif (! -d '/sys/module/eeprom') {
> + print "No EEPROM found, are you sure the eeprom module is loaded?\n";
> + exit;
> + }
> }
>
> for my $i ( 0 .. $#dimm_list ) {
> $_ = $dimm_list[$i];
> if (($use_sysfs && /^\d+-\d+$/)
> - || (!$use_sysfs && /^eeprom-/)) {
> + || (!$use_sysfs && /^eeprom-/)
> + || $use_hexdump) {
> my @bytes = readspd64(0, $dimm_list[$i]);
> my $dimm_checksum = 0;
> $dimm_checksum += $bytes[$_] foreach (0 .. 62);
> @@ -1179,15 +1241,18 @@
> $dimm_count++;
>
> print "<b><u>" if $opt_html;
> - printl2 "\n\nDecoding EEPROM", ($use_sysfs ?
> + printl2 "\n\nDecoding EEPROM",
> + $use_hexdump ? $dimm_list[$i] : ($use_sysfs ?
> "/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" :
> "/proc/sys/dev/sensors/$dimm_list[$i]");
> print "</u></b>" if $opt_html;
> print "<table border=1>\n" if $opt_html;
> - if (($use_sysfs && /^[^-]+-([^-]+)$/)
> - || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
> - my $dimm_num = $1 - 49;
> - printl "Guessing DIMM is in", "bank $dimm_num";
> + if (!$use_hexdump) {
> + if (($use_sysfs && /^[^-]+-([^-]+)$/)
> + || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
> + my $dimm_num = $1 - 49;
> + printl "Guessing DIMM is in", "bank $dimm_num";
> + }
> }
>
> # Decode first 3 bytes (0-2)
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <20080323130547.538eed81-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
@ 2008-03-23 20:46 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803231252590.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
0 siblings, 1 reply; 11+ messages in thread
From: Trent Piepho @ 2008-03-23 20:46 UTC (permalink / raw)
To: Jean Delvare; +Cc: i2c list
On Sun, 23 Mar 2008, Jean Delvare wrote:
> Hi Trent,
>
> On Sat, 22 Mar 2008 14:46:43 -0700 (PDT), Trent Piepho wrote:
> > On Sat, 22 Mar 2008, Jean Delvare wrote:
> > > You repeat the same byte for all the omitted block... this isn't how I
> > > read man hexdump(1). As I understand it, you are supposed to repeat the
> > > last line, not the last byte.
> > >
> > > Alternatively you could drop support for this special format, which
> > > doesn't make much sense for a 256-byte EEPROM if you ask me. And in
> > > practice the only cases where it could happen is for rows of 0x00s or
> > > 0xffs - it doesn't make a difference if you omit them completely.
> >
> > I've added code to ignore header lines. The code to parse the repeat line
> > syntax is there for the same reason: hexdump produces that syntax when you
> > run it on an eeprom file. Not parsing it requires editing the hexdumps by
> > hand, which is a lot more trouble than just deleting a one line header.
>
> Maybe I did not express myself clearly enough. I didn't mean to stop
> supporting the special "compact" format by choking on it, but by
> simply ignoring the "*" line as you do for i2cdump's header line (and
> filling the @bytes array with zeroes, which would be presumably simpler
> than what you did.)
It seems like doing that would be even worse than the almost correct way
I'm handing the repeat lines now. Any hex dump that my code would parse
incorrectly would also be parsed incorrectly by ignoring repeat lines.
Plus some far more likely hexdumps would also be parsed incorrectly when
ignoring the repeat codes that are handled correctly with my code.
Correctly handling the repeat lines also means one can use the same code to
turn a hexdump back into a binary file.
I've improved the hexdump reading code to handle line repeats correctly.
> > I've added some better documentation to the help output. It's the default
>
> Good start, but I'd go further and warn the user at runtime when
> parsing hexdumps using this format. For example:
>
> Warning: Assuming hexdump uses big-endian byte order
Ok, added that.
This adds a "-x" option to decode_dimms.pl, which lets one supply a list of
file names to read SPD data from. It can parse various hexdump formats, such
as the output from i2cdump, eeprog, and the util-linux and Busybox hexdump
progams run on a sysfs eeprom file.
Useful for decoding SPD data that you cut and pasted from a manufacturer's
website or from a DIMM installed on an embeded system that does not have
perl/etc, but does have a serial console with busybox.
---
Index: eeprom/decode-dimms.pl
===================================================================
--- eeprom/decode-dimms.pl (revision 5156)
+++ eeprom/decode-dimms.pl (working copy)
@@ -46,8 +46,8 @@
use strict;
use POSIX;
use Fcntl qw(:DEFAULT :seek);
-use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs
- @vendors %decode_callback $revision);
+use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs $use_hexdump
+ @vendors %decode_callback $revision @dimm_list);
$revision = '$Revision$ ($Date$)';
$revision =~ s/\$\w+: (.*?) \$/$1/g;
@@ -1100,10 +1100,63 @@
printl $l, $temp;
}
+# Read various hex dump style formats: hexdump, hexdump -C, i2cdump, eeprog
+# note that normal 'hexdump' format on a little-endian system byte-swaps
+# words, using hexdump -C is better.
+sub read_hexdump ($)
+{
+ my $addr = 0;
+ my $repstart = 0;
+ my @bytes;
+ my $header = 1;
+ my $word = 0;
+
+ open F, '<', $_[0] or die "Unable to open: $_[0]";
+ while (<F>) {
+ my $ok = 1;
+
+ chomp;
+ if (/^\*$/) {
+ $repstart = $addr;
+ next;
+ }
+ /^(?:0000 )?([a-f\d]{2,8}):?\s+((:?[a-f\d]{4}\s*){8}|(:?[a-f\d]{2}\s*){16})/i ||
+ /^(?:0000 )?([a-f\d]{2,8}):?\s*$/i;
+ next if (!defined $1 && $header); # skip leading unparsed lines
+
+ defined $1 or die "Unable to parse input";
+ $header = 0;
+
+ $addr = hex $1;
+ if ($repstart) {
+ @bytes[$repstart .. ($addr-1)] =
+ (@bytes[($repstart-16)..($repstart-1)]) x (($addr-$repstart)/16);
+ $repstart = 0;
+ }
+ last unless defined $2;
+ foreach (split(/\s+/, $2)) {
+ if (/^(..)(..)$/) {
+ $word |= 1;
+ $bytes[$addr++] = hex($1);
+ $bytes[$addr++] = hex($2);
+ } else {
+ $bytes[$addr++] = hex($_);
+ }
+ }
+ }
+ close F;
+ $header and die "Unable to parse any data from hexdump '$_[0]'";
+ $word and printc "Warning: Assuming big-endian order 16-bit hex dump";
+ return @bytes;
+}
+
sub readspd64 ($$) { # reads 64 bytes from SPD-EEPROM
my ($offset, $dimm_i) = @_;
my @bytes;
- if ($use_sysfs) {
+ if ($use_hexdump) {
+ @bytes = read_hexdump($dimm_i);
+ return @bytes[$offset..($offset+63)];
+ } elsif ($use_sysfs) {
# Kernel 2.6 with sysfs
sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY)
or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom";
@@ -1123,19 +1176,30 @@
}
for (@ARGV) {
- if (/-h/) {
- print "Usage: $0 [-c] [-f [-b]]\n",
+ if (/^-?-h/) {
+ print "Usage: $0 [-c] [-f [-b]] [-x file [files..]]\n",
" $0 -h\n\n",
" -f, --format print nice html output\n",
" -b, --bodyonly don't print html header\n",
" (useful for postprocessing the output)\n",
" -c, --checksum decode completely even if checksum fails\n",
+ " -x, Read data from hexdump files\n",
" -h, --help display this usage summary\n";
+ print <<"EOF";
+
+Hexdumps can be the output from hexdump, hexdump -C, i2cdump, eeprog and
+likely many other progams producing hex dumps of one kind or another. Note
+that the default output of "hexdump" will be byte-swapped on little-endian
+systems and will therefor not be parsed correctly. It is better to use
+"hexdump -C", which is not ambiguous.
+EOF
exit;
}
- $opt_html = 1 if (/-f/);
- $opt_bodyonly = 1 if (/-b/);
- $opt_igncheck = 1 if (/-c/);
+ $opt_html = 1 if (/^-?-f/);
+ $opt_bodyonly = 1 if (/^-?-b/);
+ $opt_igncheck = 1 if (/^-?-c/);
+ $use_hexdump = 1 if (/^-x/);
+ push @dimm_list, $_ if ($use_hexdump && !/^-/);
}
$opt_body = $opt_html && ! $opt_bodyonly;
@@ -1155,21 +1219,23 @@
my $dimm_count = 0;
-my @dimm_list;
my $dir;
-if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
-else { $dir = '/proc/sys/dev/sensors'; }
-if (-d $dir) {
- @dimm_list = split(/\s+/, `ls $dir`);
-} elsif (! -d '/sys/module/eeprom') {
- print "No EEPROM found, are you sure the eeprom module is loaded?\n";
- exit;
+if (!$use_hexdump) {
+ if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
+ else { $dir = '/proc/sys/dev/sensors'; }
+ if (-d $dir) {
+ @dimm_list = split(/\s+/, `ls $dir`);
+ } elsif (! -d '/sys/module/eeprom') {
+ print "No EEPROM found, are you sure the eeprom module is loaded?\n";
+ exit;
+ }
}
for my $i ( 0 .. $#dimm_list ) {
$_ = $dimm_list[$i];
if (($use_sysfs && /^\d+-\d+$/)
- || (!$use_sysfs && /^eeprom-/)) {
+ || (!$use_sysfs && /^eeprom-/)
+ || $use_hexdump) {
my @bytes = readspd64(0, $dimm_list[$i]);
my $dimm_checksum = 0;
$dimm_checksum += $bytes[$_] foreach (0 .. 62);
@@ -1179,15 +1245,18 @@
$dimm_count++;
print "<b><u>" if $opt_html;
- printl2 "\n\nDecoding EEPROM", ($use_sysfs ?
+ printl2 "\n\nDecoding EEPROM",
+ $use_hexdump ? $dimm_list[$i] : ($use_sysfs ?
"/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" :
"/proc/sys/dev/sensors/$dimm_list[$i]");
print "</u></b>" if $opt_html;
print "<table border=1>\n" if $opt_html;
- if (($use_sysfs && /^[^-]+-([^-]+)$/)
- || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
- my $dimm_num = $1 - 49;
- printl "Guessing DIMM is in", "bank $dimm_num";
+ if (!$use_hexdump) {
+ if (($use_sysfs && /^[^-]+-([^-]+)$/)
+ || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
+ my $dimm_num = $1 - 49;
+ printl "Guessing DIMM is in", "bank $dimm_num";
+ }
}
# Decode first 3 bytes (0-2)
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] Read SPD data from a hexdump (take 2)
[not found] ` <Pine.LNX.4.58.0803231252590.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
@ 2008-03-24 10:28 ` Jean Delvare
0 siblings, 0 replies; 11+ messages in thread
From: Jean Delvare @ 2008-03-24 10:28 UTC (permalink / raw)
To: Trent Piepho; +Cc: i2c list
Hi Trent,
On Sun, 23 Mar 2008 13:46:38 -0700 (PDT), Trent Piepho wrote:
> This adds a "-x" option to decode_dimms.pl, which lets one supply a list of
> file names to read SPD data from. It can parse various hexdump formats, such
> as the output from i2cdump, eeprog, and the util-linux and Busybox hexdump
> progams run on a sysfs eeprom file.
>
> Useful for decoding SPD data that you cut and pasted from a manufacturer's
> website or from a DIMM installed on an embeded system that does not have
> perl/etc, but does have a serial console with busybox.
>
> ---
> Index: eeprom/decode-dimms.pl
> ===================================================================
> --- eeprom/decode-dimms.pl (revision 5156)
> +++ eeprom/decode-dimms.pl (working copy)
> (...)
Patch applied, thanks for your contribution.
If you intend to work more on decode-dimms.pl or anything else in the
i2c-tools package, and would like write access to the SVN repository,
please let me know.
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2008-03-24 10:28 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-03-16 21:33 [PATCH] Read SPD data from a hexdump (take 2) Trent Piepho
[not found] ` <Pine.LNX.4.58.0803161427360.20723-13q4cmjDBaTP3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-20 11:33 ` Jean Delvare
[not found] ` <20080320123315.648911cd-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-03-20 14:59 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803200733220.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-20 16:58 ` Jean Delvare
2008-03-22 14:02 ` Jean Delvare
[not found] ` <20080322150222.2a8ccc60-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-03-22 21:46 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803221346450.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-22 23:59 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803221654220.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-23 13:36 ` Jean Delvare
2008-03-23 12:05 ` Jean Delvare
[not found] ` <20080323130547.538eed81-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-03-23 20:46 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803231252590.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-24 10:28 ` Jean Delvare
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox