These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / util / parserom.pl
1 #!/usr/bin/env perl
2 #
3 # Parse PCI_ROM and ISA_ROM entries from source file(s) specified as
4 # arguments and output the relevant Makefile rules to STDOUT.
5 #
6 # Originally based on portions of Ken Yap's genrules.pl. Completely
7 # rewritten by Robin Smidsrød to be more maintainable.
8
9 use strict;
10 use warnings;
11 use Getopt::Long;
12
13 # Parse command-line options
14 my @exclude_driver_classes = ();
15 my @exclude_drivers = ();
16 my $debug = 0;
17 my $help = 0;
18 GetOptions(
19     "exclude-driver-class=s" => \@exclude_driver_classes,
20     "exclude-driver=s"       => \@exclude_drivers,
21     "debug"                  => \$debug,
22     "help"                   => \$help,
23 );
24
25 # Convert exclution arrays to lookup tables
26 my $exclude_driver_class_map = { map { $_ => 1 } @exclude_driver_classes };
27 my $exclude_driver_map       = { map { $_ => 1 } @exclude_drivers        };
28
29 # Ensure STDOUT and STDERR are synchronized if debugging
30 if ( $debug ) {
31     STDOUT->autoflush(1);
32     STDERR->autoflush(1);
33 }
34
35 # Compile regular expressions here for slight performance boost
36 my %RE = (
37     'parse_driver_class'    => qr{ drivers/ (\w+?) / }x,
38     'parse_family'          => qr{^ (?:\./)? (.*) \..+? $}x,
39     'find_rom_line'         => qr/^ \s* ( (PCI|ISA)_ROM \s* \( \s* (.*?) ) $/x,
40     'extract_pci_id'        => qr/^ \s* 0x([0-9A-Fa-f]{4}) \s* ,? \s* (.*) $/x,
41     'extract_quoted_string' => qr/^ \s* \" ([^\"]*?) \" \s* ,? \s* (.*) $/x,
42 );
43
44 # Show help if required arguments are missing or help was requested
45 show_usage_and_exit() if $help or @ARGV < 1;
46
47 # Process each source file specified
48 process_source_file($_) for @ARGV;
49
50 exit;
51
52 sub show_usage_and_exit {
53     print STDERR <<"EOM";
54 Syntax: $0 [<options>] <source-file> [<source-file>]
55 Options:
56     --exclude-driver-class Exclude specified driver classes
57     --exclude-driver       Exclude specified drivers
58     --debug                Output debug information on STDERR
59     --help                 This help information
60 EOM
61     exit 1;
62 }
63
64 # Figure out if source file is a driver and look for ROM declarations
65 sub process_source_file {
66     my ($source_file) = @_;
67     return unless defined $source_file;
68     return unless length $source_file;
69     my $state = { 'source_file' => $source_file };
70     log_debug("SOURCE_FILE", $state->{source_file});
71     # Skip source files that aren't drivers
72     parse_driver_class( $state );
73     unless ( $state->{'driver_class'} ) {
74         log_debug("SKIP_NOT_DRIVER", $state->{source_file} );
75         return;
76     }
77     # Skip source files with driver classes that are explicitly excluded
78     if ( $exclude_driver_class_map->{ $state->{'driver_class'} } ) {
79         log_debug("SKIP_EXCL_CLASS", $state->{'driver_class'} );
80         return;
81     }
82     # Skip source files without driver information
83     parse_family( $state );
84     parse_driver_name( $state );
85     unless ( $state->{'family'} and $state->{'driver_name'} ) {
86         log_debug("SKIP_NO_DRV_INFO", $state->{source_file} );
87         return;
88     }
89     # Skip source files with drivers that are explicitly excluded
90     if ( $exclude_driver_map->{ $state->{'driver_name'} } ) {
91         log_debug("SKIP_EXCL_DRV", $state->{'driver_name'} );
92         return;
93     }
94     # Iterate through lines in source files looking for ROM declarations
95     # and # output Makefile rules
96     open( my $fh, "<", $state->{'source_file'} )
97         or die "Couldn't open $state->{source_file}: $!\n";
98     while (<$fh>) {
99         process_rom_decl($state, $1, $2, $3) if m/$RE{find_rom_line}/;
100     }
101     close($fh) or die "Couldn't close $source_file: $!\n";
102     return 1;
103 }
104
105 # Verify that the found ROM declaration is sane and dispatch to the right
106 # handler depending on type
107 sub process_rom_decl {
108     my ($state, $rom_line, $rom_type, $rom_decl) = @_;
109     return unless defined $rom_line;
110     return unless length $rom_line;
111     log_debug("ROM_LINE", $rom_line);
112     return unless defined $rom_type;
113     return unless length $rom_type;
114     log_debug("ROM_TYPE", $rom_type);
115     $state->{'type'} = lc $rom_type;
116     return process_pci_rom($state, $rom_decl) if $rom_type eq "PCI";
117     return process_isa_rom($state, $rom_decl) if $rom_type eq "ISA";
118     return;
119 }
120
121 # Extract values from PCI_ROM declaration lines and dispatch to
122 # Makefile rule generator
123 sub process_pci_rom {
124     my ($state, $decl) = @_;
125     return unless defined $decl;
126     return unless length $decl;
127     (my $vendor, $decl) = extract_pci_id($decl,        'PCI_VENDOR');
128     (my $device, $decl) = extract_pci_id($decl,        'PCI_DEVICE');
129     (my $image,  $decl) = extract_quoted_string($decl, 'IMAGE');
130     (my $desc,   $decl) = extract_quoted_string($decl, 'DESCRIPTION');
131     if ( $vendor and $device and $image and $desc ) {
132         print_make_rules( $state, "${vendor}${device}", $desc, $vendor, $device );
133         print_make_rules( $state, $image, $desc, $vendor, $device, 1 );
134     }
135     else {
136         log_debug("WARNING", "Malformed PCI_ROM macro on line $. of $state->{source_file}");
137     }
138     return 1;
139 }
140
141 # Extract values from ISA_ROM declaration lines and dispatch to
142 # Makefile rule generator
143 sub process_isa_rom {
144     my ($state, $decl) = @_;
145     return unless defined $decl;
146     return unless length $decl;
147     (my $image, $decl) = extract_quoted_string($decl, 'IMAGE');
148     (my $desc,  $decl) = extract_quoted_string($decl, 'DESCRIPTION');
149     if ( $image and $desc ) {
150         print_make_rules( $state, $image, $desc );
151     }
152     else {
153         log_debug("WARNING", "Malformed ISA_ROM macro on line $. of $state->{source_file}");
154     }
155     return 1;
156 }
157
158 # Output Makefile rules for the specified ROM declarations
159 sub print_make_rules {
160     my ( $state, my $image, my $desc, my $vendor, my $device, my $dup ) = @_;
161     unless ( $state->{'is_header_printed'} ) {
162         print "# NIC\t\n";
163         print "# NIC\tfamily\t$state->{family}\n";
164         print "DRIVERS_$state->{driver_class} += $state->{driver_name}\n";
165         print "DRIVERS += $state->{driver_name}\n";
166         print "\n";
167         $state->{'is_header_printed'} = 1;
168     }
169     return if $vendor and ( $vendor eq "ffff" or $device eq "ffff" );
170     my $ids = $vendor ? "$vendor,$device" : "-";
171     print "# NIC\t$image\t$ids\t$desc\n";
172     print "DRIVER_$image = $state->{driver_name}\n";
173     print "ROM_TYPE_$image = $state->{type}\n";
174     print "ROM_DESCRIPTION_$image = \"$desc\"\n";
175     print "PCI_VENDOR_$image = 0x$vendor\n" if $vendor;
176     print "PCI_DEVICE_$image = 0x$device\n" if $device;
177     print "ROMS += $image\n" unless $dup;
178     print "ROMS_$state->{driver_name} += $image\n" unless $dup;
179     print "\n";
180     return 1;
181 }
182
183 # Driver class is whatever comes after the "drivers" part of the filename (relative path)
184 sub parse_driver_class {
185     my ($state) = @_;
186     my $filename = $state->{'source_file'};
187     return unless defined $filename;
188     return unless length $filename;
189     if ( $filename =~ m/$RE{parse_driver_class}/ ) {
190         log_debug("DRIVER_CLASS", $1);
191         $state->{'driver_class'} = $1;
192     }
193     return;
194 }
195
196 # Family name is filename (relative path) without extension
197 sub parse_family {
198     my ($state) = @_;
199     my $filename = $state->{'source_file'};
200     return unless defined $filename;
201     return unless length $filename;
202     if ( $filename =~ m/$RE{parse_family}/ ) {
203         log_debug("FAMILY", $1);
204         $state->{'family'} = $1;
205     }
206     return;
207 }
208
209 # Driver name is last part of family name
210 sub parse_driver_name {
211     my ($state) = @_;
212     my $family = $state->{'family'};
213     return unless defined $family;
214     return unless length $family;
215     my @parts = split "/", $family;
216     $state->{'driver_name'} = $parts[-1];
217     log_debug("DRIVER", $state->{'driver_name'});
218     return;
219 }
220
221 # Extract a PCI vendor/device ID e.g. 0x8086, possibly followed by a comma
222 # Should always be 4-digit lower-case hex number
223 sub extract_pci_id {
224     my ($str, $label) = @_;
225     return "", $str unless defined $str;
226     return "", $str unless length $str;
227     if ( $str =~ m/$RE{extract_pci_id}/ ) {
228         my $id = lc $1;
229         log_debug($label, $id);
230         return $id, $2;
231     }
232     return "", $str;
233 }
234
235 # Extract a double-quoted string, possibly followed by a comma
236 sub extract_quoted_string {
237     my ($str, $label) = @_;
238     return "", $str unless defined $str;
239     return "", $str unless length $str;
240     if ( $str =~ m/$RE{extract_quoted_string}/ ) {
241         log_debug($label, $1);
242         return $1, $2;
243     }
244     return "", $str;
245 }
246
247 # Output debug info to STDERR (off by default)
248 sub log_debug {
249     my ($label, $str) = @_;
250     return unless $debug;
251     return unless defined $str;
252     print STDERR "\n" if $label eq 'SOURCE_FILE';
253     print STDERR "=";
254     if ( defined $label ) {
255         my $pad_count = 16 - length $label;
256         print STDERR $label . ":" . ( " " x $pad_count );
257     }
258     print STDERR $str . "\n";
259     return;
260 }