Adjust memory layout for 2.6.22+ kernels with 32KB setup code
[mknbi.git] / disnbi.pl
1 #!/usr/bin/perl -w
2 #
3 # Quick Perl program to decode and display details about 
4 # tagged images created by mknbi
5 # -e extracts directory to `nbidir' and segments to `segmentN'
6 # N = 0, 1, 2, ...
7 #
8 # Added code to dump vendor tag in hex (for DOS disk parameters)
9 #
10 # Ken Yap, August 1999
11 #
12
13 use strict;
14
15 use vars qw($imagefile $data $curoffset $dirfile @seglengths $vendordata
16         $extract $status $i);
17
18 sub getvendordata ($)
19 {
20         my ($flags) = @_;
21
22         my $vendordata = '';
23         my $vendorlen = ($flags & 0xff) >> 4;
24         if ($vendorlen > 0) {
25                 $vendorlen *= 4;
26                 $vendordata = unpack("a$vendorlen", substr($data, $curoffset));
27                 $curoffset += $vendorlen;
28         }
29         return ($vendordata);
30 }
31
32 sub decodesegmentflags ($)
33 {
34         my ($flags) = @_;
35         my ($type);
36
37         $flags >>= 24;
38         $flags &= 0x3;
39         ($flags == 0) and $type = "Absolute";
40         ($flags == 1) and $type = "Follows last segment";
41         ($flags == 2) and $type = "Below end of memory";
42         ($flags == 3) and $type = "Below last segment loaded";
43         return ($type);
44 }
45
46 sub one_nbi_segment ($)
47 {
48         my ($segnum) = @_;
49         my ($type, $vendordata, @vdata, $i);
50
51         my ($flags, $loadaddr, $imagelen, $memlength) = unpack('V4', substr($data, $curoffset));
52         $curoffset += 16;
53         printf "Segment number %d\n", $segnum;
54         printf "Load address:\t\t%08x\n", $loadaddr;
55         printf "Image length:\t\t%d\n", $imagelen;
56         printf "Memory length:\t\t%d\n", $memlength;
57         $type = &decodesegmentflags($flags);
58         print "Position:\t\t$type\n";
59         printf "Vendor tag:\t\t%d\n", ($flags >> 8) & 0xff;
60         if (($vendordata = &getvendordata($flags)) ne '') {
61                 print "Vendor data:\t\t\"", $vendordata, "\"\n";
62                 @vdata = unpack('C*', $vendordata);
63                 print "Vendor data in hex:\t";
64                 foreach $i (0..$#vdata) {
65                         printf "%02x ", $vdata[$i];
66                 }
67                 print "\n";
68         }
69         print "\n";
70         push (@seglengths, $imagelen);
71         return (($flags >> 26) & 1);
72 }
73
74 sub decode_nbi
75 {
76         my ($magic, $flags, $bx, $ds, $ip, $cs) = unpack('a4Vv4', substr($data, 0, 16));
77
78         $curoffset = 16;
79         # Decode the header
80         printf "Type: NBI\nHeader location:\t%04x:%04x\n", $ds, $bx;
81         if (($flags >> 31) & 1) {
82                 printf "Start address:\t\t%04x%04x (flat)\n", $cs, $ip;
83         } else {
84                 printf "Start address:\t\t%04x:%04x\n", $cs, $ip;
85         }
86         print "Flags:\n";
87                 print "\tReturn to loader after execution (extension)\n" if (($flags >> 8) &  1);
88         if (($vendordata = &getvendordata($flags)) ne '') {
89                 print "Vendor data:\t\t", $vendordata, "\n";
90         }
91         print "\n";
92
93         # Now decode each segment record
94         my $segnum = 0;
95         do {
96                 $i = &one_nbi_segment($segnum);
97                 ++$segnum;
98         } while (!$i);
99 }
100
101 sub one_elf_segment ($$)
102 {
103         my ($segnum, $curoffset) = @_;
104
105         my ($offset, $vaddr, $paddr, $filesz, $memsz, $flags,
106                 $align) = unpack('@4V6', substr($data, $curoffset));
107         printf "Segment number %d\n", $segnum;
108         printf "Load address:\t\t%08x\n", $vaddr;
109         printf "Image length:\t\t%d\n", $filesz;
110         printf "Memory length:\t\t%d\n", $memsz;
111         print "\n";
112         push (@seglengths, $filesz);
113 }
114
115 sub decode_elf
116 {
117         my ($entry, $phoff, $shoff, $flags, $ehsize, $phentsize,
118                 $phnum) = unpack('@24V4v3', $data);
119         printf "Type: ELF\nStart address:\t\t%08x\n", $entry;
120         print "Flags:\n";
121                 print "\tReturn to loader after execution (extension)\n" if ($flags & 0x8000000);
122         print "\n";
123         $curoffset = $phoff;
124         foreach $i (0..$phnum-1) {
125                 &one_elf_segment($i, $curoffset);
126                 $curoffset += $phentsize;
127         }
128 }
129
130 $extract = 0;
131 @seglengths = ();
132 $#ARGV >= 0 or die "Usage: disnbi [-e] Etherboot-image-file\n";
133 if ($ARGV[0] eq '-e') {
134         $extract = 1; shift
135 }
136 $#ARGV >= 0 or die "Usage: disnbi [-e] Etherboot-image-file\n";
137 $imagefile= $ARGV[0];
138 open(I, $ARGV[0]) or die "$imagefile: $!\n";
139 binmode(I);
140 (defined($status = sysread(I, $data, 512)) and $status == 512)
141         or die "$imagefile: Cannot read header\n";
142 my ($magic) = unpack('a4', substr($data, 0, 4));
143 if ($magic eq "\x36\x13\x03\x1B") {
144         &decode_nbi();
145         $dirfile = 'nbidir';
146 } elsif ($magic eq "\x7FELF") {
147         &decode_elf();
148         $dirfile = 'elfdir';
149 } else {
150         die "$imagefile: Not a tagged or ELF image file\n";
151 }
152
153 exit(0) if ($extract == 0);
154 print "Dumping directory to `$dirfile'...\n";
155 open(O, ">$dirfile") or die "$dirfile: $!\n";
156 binmode(O);
157 print O $data;
158 close(O);
159 $data = '';
160 foreach $i (0..$#seglengths) {
161         print "Extracting segment $i to `segment$i'...\n";
162         open(O, ">segment$i") or die "segment$i: $!\n";
163         binmode(O);
164         (defined($status = sysread(I, $data, $seglengths[$i]))
165                 and $status = $seglengths[$i])
166                 or die "$imagefile: Cannot read data\n";
167         print O $data;
168         close(O);
169 }
170 print "Done\n";
171 exit(0);
172
173 __END__
174
175 =head1 NAME
176
177 disnbi - display Etherboot image
178
179 =head1 SYNOPSIS
180
181 B<disnbi> [C<-e>] I<Etherboot-file>
182
183 =head1 DESCRIPTION
184
185 B<disnbl> is a program that to display in symbolic form the contents
186 of a Etherboot image created by mknbi or mkelf. Detection of image type
187 is automatic.
188
189 B<-e> Extract contents of image as well. The directory will be written
190 to C<nbidir> or C<elfdir> and the segments to C<segment>I<n> where I<n>
191 is 0, 1, 2, etc.
192
193 =head1 BUGS
194
195 Please report all bugs to the author.
196
197 =head1 SEE ALSO
198
199 Etherboot tutorial at C<http://etherboot.sourceforge.net/>
200
201 =head1 COPYRIGHT
202
203 B<disnbl> is under the GNU Public License
204
205 =head1 AUTHOR
206
207 Ken Yap (C<ken_yap@users.sourceforge.net>)
208
209 =head1 DATE
210
211 Version 1.4 December 2002