1#!/bin/perl 2# 3# CDDL HEADER START 4# 5# The contents of this file are subject to the terms of the 6# Common Development and Distribution License (the "License"). 7# You may not use this file except in compliance with the License. 8# 9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10# or http://www.opensolaris.org/os/licensing. 11# See the License for the specific language governing permissions 12# and limitations under the License. 13# 14# When distributing Covered Code, include this CDDL HEADER in each 15# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16# If applicable, add the following below this CDDL HEADER, with the 17# fields enclosed by brackets "[]" replaced with your own identifying 18# information: Portions Copyright [yyyy] [name of copyright owner] 19# 20# CDDL HEADER END 21# 22 23# 24# Copyright 2007 Sun Microsystems, Inc. All rights reserved. 25# Use is subject to license terms. 26# 27# ident "%Z%%M% %I% %E% SMI" 28# 29 30use strict; 31use File::Basename; 32 33my $PROGNAME = basename($0); 34 35my ($funcunit, $error); 36my @funcunits = (); 37my @errorrefs = (); 38 39my $codelinesin = 0; # number of input 'code' lines for an ereport type 40my $codeoutlen = 0; # number of output lines from sub state_code 41 42my $state = "initial"; 43 44sub usage() { 45 print STDERR "Usage: $PROGNAME inputfile\n"; 46 exit(2); 47} 48 49sub bail() { 50 print STDERR "$PROGNAME: ", join(" ", @_), "\n"; 51 exit(1); 52} 53 54sub parsebail() { 55 print STDERR "$PROGNAME: $::infile: $.: ", join(" ", @_), "\n"; 56 exit(1); 57} 58 59sub error_alloc() { 60 my @a = (); 61 62 push(@::errorrefs, \@a); 63 return (\@a); 64} 65 66sub error_dup() { 67 my ($drop) = @_; 68 my $newref = &error_alloc(); 69 70 my $zeroref = $::errorrefs[0]; 71 72 my $n = $#$zeroref - $drop; 73 74 @$newref = @$zeroref[0 .. $n]; 75} 76 77sub code_lines() { 78 return ($::codelinesin++); 79} 80 81sub error_init() { 82 &error_alloc(); 83 $::codelinesin = 0; 84} 85 86sub error_reset() { 87 @::errorrefs = (); 88 $::codelinesin = 0; 89 $::codeoutlen = 0; 90} 91 92sub errout() { 93 my ($line) = @_; 94 95 foreach my $ref (@::errorrefs) { 96 push(@$ref, $line); 97 } 98} 99 100sub errout_N() { 101 my ($instance, $line) = @_; 102 my $ref = @::errorrefs[$instance]; 103 push(@$ref, $line); 104 return 1; 105} 106 107sub print_errout() { 108 foreach my $ref (@::errorrefs) { 109 print @$ref; 110 } 111} 112 113sub print_header() { 114 print "#include <sys/mca_x86.h>\n"; 115 print "#include \"ao_mca_disp.h\"\n\n"; 116} 117 118sub print_footer() { 119 print 'const ao_error_disp_t *ao_error_disp[] = {' . "\n"; 120 121 foreach my $name (@funcunits) { 122 print "\t$name,\n"; 123 } 124 125 print "};\n"; 126} 127 128sub funcunit_begin() { 129 my $arrnm = "ao_error_disp_" . $_[0]; 130 print "static const ao_error_disp_t " . $arrnm . "[] = {\n"; 131 132 @funcunits = (@funcunits, $arrnm); 133} 134 135sub funcunit_end() { 136 print "\t{ NULL }\n};\n\n"; 137} 138 139sub error_begin() { 140 my ($ereport_name) = @_; 141 142 $ereport_name =~ tr/[a-z]./[A-Z]_/; 143 my $flags_name = $ereport_name; 144 $flags_name =~ s/EREPORT_/EREPORT_PAYLOAD_FLAGS_/; 145 146 &errout("\tFM_$ereport_name,\n\tFM_$flags_name,\n"); 147} 148 149sub error_end() { 150 &errout("\t},\n\n"); 151 152 &print_errout(); 153 154 &error_reset(); 155} 156 157sub print_bits() { 158 my $name = $_[0]; 159 my @bits = @_[1..$#_]; 160 my $out = ""; 161 162 if (@bits == 0) { 163 $out = "\t0,"; 164 } elsif (@bits == 1) { 165 $out = "\t$bits[0],"; 166 } else { 167 $out = "\t( " . join(" | ", @bits) . " ),"; 168 } 169 170 $out .= " /* $name */" if (defined $name); 171 $out .= "\n"; 172 173 return ($out); 174} 175 176sub field_burst() { 177 my ($field, $valuesref, $name, $prefix) = @_; 178 179 if ($field eq "-") { 180 return (); 181 } 182 183 map { 184 if (!defined ${$valuesref}{$_}) { 185 &parsebail("unknown $name value `$_'"); 186 } 187 $_ = ${$valuesref}{$_}; 188 tr/[a-z]/[A-Z]/; 189 $prefix . "_" . $_; 190 } split(/\//, $field); 191} 192 193sub bin2dec() { 194 my $bin = $_[0]; 195 my $dec = 0; 196 197 foreach my $bit (split(//, $bin)) { 198 $dec = $dec * 2 + ($bit eq "1" ? 1 : 0); 199 } 200 201 $dec; 202} 203 204sub state_funcunit() { 205 my $val = $_[0]; 206 207 if (defined $::funcunit) { 208 &funcunit_end(); 209 } 210 211 $::funcunit = $val; 212 undef $::error; 213 &funcunit_begin($::funcunit); 214} 215 216sub state_desc() { 217 my $desc = $_[0]; 218 219 &error_init(); 220 221 &errout("\t/* $desc */\n\t{\n"); 222} 223 224sub state_error() { 225 $::error = $_[0]; 226 &error_begin($::error); 227} 228 229sub state_mask_on() { 230 @::mask_on = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); 231} 232 233sub state_mask_off() { 234 my @mask_off = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); 235 236 &errout(&print_bits("mask", @::mask_on, @mask_off)); 237 &errout(&print_bits("mask_res", @::mask_on)); 238} 239 240sub state_code() { 241 my ($ext, $type, $pp, $t, $r4, $addr, $ii, $ll, $tt) = 242 split(/\s+/, $_[0]); 243 244 my %tt_values = ( instr => 1, data => 1, gen => 1, '-' => 1 ); 245 my %ll_values = ( l0 => 1, l1 => 1, l2 => 1, lg => 1 ); 246 247 my %r4_values = ( 248 'err' => 'err', 249 'rd' => 'rd', 250 'wr' => 'wr', 251 'drd' => 'drd', 252 'dwr' => 'dwr', 253 'ird' => 'ird', 254 'pf' => 'prefetch', 255 'ev' => 'evict', 256 'snp' => 'snoop', 257 '-' => '-'); 258 259 my %pp_values = ( 260 'src' => 'src', 261 'res' => 'res', 262 'obs' => 'obs', 263 'gen' => 'gen', 264 '-' => '-' ); 265 266 my %t_values = ( 0 => 1, 1 => 1, '-' => 1 ); 267 268 my %ii_values = ( 269 'mem' => 'mem', 270 'io' => 'io', 271 'gen' => 'gen', 272 '-' => '-' ); 273 274 my $instance = &code_lines(); 275 if ($instance > 0) { 276 &error_dup($::codeoutlen); # dup info thus far 277 } 278 279 if (!defined $tt_values{$tt}) { 280 &parsebail("unknown tt value `$tt'"); 281 } 282 283 if (!defined $ll_values{$ll}) { 284 &parsebail("unknown ll value `$ll'"); 285 } 286 287 my @r4 = &field_burst($r4, \%r4_values, "r4", "AO_MCA_R4_BIT"); 288 289 my @pp = ($pp eq '-') ? () : 290 &field_burst($pp, \%pp_values, "pp", "AO_MCA_PP_BIT"); 291 292 if (!defined $t_values{$t}) { 293 &parsebail("unknown t value `$t'"); 294 } 295 296 my @ii = ($ii eq '-') ? () : 297 &field_burst($ii, \%ii_values, "ii", "AO_MCA_II_BIT"); 298 299 map { 300 tr/[a-z]/[A-Z]/; 301 } ($ii, $ll, $tt); 302 303 if ($type eq "bus") { 304 if ($pp eq "-" || $t eq "-" || $r4 eq "-" || $ii eq "-" || 305 $ll eq "-" || 306 $tt ne "-") { 307 &parsebail("invalid members for bus code type"); 308 } 309 310 $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKBUS(" . 311 "0, " . # pp 312 "MCAX86_ERRCODE_T_" . ($t ? "TIMEOUT" : "NONE") . ", " . 313 "0, " . # r4 314 "0, " . # ii 315 "MCAX86_ERRCODE_LL_$ll),\n"); 316 317 } elsif ($type eq "mem") { 318 if ($r4 eq "-" || $tt eq "-" || $ll eq "-" || 319 $pp ne "-" || $t ne "-" || $ii ne "-") { 320 &parsebail("invalid members for mem code type"); 321 } 322 323 $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKMEM(" . 324 "0, " . # r4 325 "MCAX86_ERRCODE_TT_$tt, " . 326 "MCAX86_ERRCODE_LL_$ll),\n"); 327 328 } elsif ($type eq "tlb") { 329 if ($tt eq "-" || $ll eq "-" || 330 $r4 ne "-" || $pp ne "-" || $t ne "-" || $ii ne "-") { 331 &parsebail("invalid members for tlb code type"); 332 } 333 334 $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKTLB(" . 335 "MCAX86_ERRCODE_TT_$tt, " . 336 "MCAX86_ERRCODE_LL_$ll),\n"); 337 } else { 338 &parsebail("unknown code type `$type'"); 339 } 340 341 $::codeoutlen += &errout_N($instance, "\t" . &bin2dec($ext) . 342 ", /* ext code $ext */\n"); 343 344 $::codeoutlen += &errout_N($instance, &print_bits("pp_bits", @pp)); 345 $::codeoutlen += &errout_N($instance, &print_bits("ii_bits", @ii)); 346 $::codeoutlen += &errout_N($instance, &print_bits("r4_bits", @r4)); 347 348 my $valid_hi; 349 my $valid_lo; 350 351 if ($addr eq "none") { 352 $valid_hi = $valid_lo = 0; 353 } elsif ($addr =~ /<(\d+):(\d+)>/) { 354 $valid_hi = $1; 355 $valid_lo = $2; 356 } else { 357 &parsebail("invalid addr specification"); 358 } 359 $::codeoutlen += &errout_N($instance, "\t" . $valid_hi . 360 ", /* addr valid hi */\n"); 361 $::codeoutlen += &errout_N($instance, "\t" . $valid_lo . 362 ", /* addr valid lo */\n"); 363} 364 365sub state_panic() { 366 my @vals = split(/,\s*/, $_[0]); 367 368 if ($#vals < 0) { 369 &errout("\t0, /* panic_when */\n"); 370 } else { 371 @vals = map { tr/[a-z]/[A-Z]/; "AO_AED_PANIC_" . $_; } @vals; 372 &errout(&print_bits("panic_when", @vals)); 373 } 374} 375 376sub state_flags() { 377 my @flags = split(/,\s*/, $_[0]); 378 379 @flags = map { tr/[a-z]/[A-Z]/; "AO_AED_F_" . $_; } @flags; 380 381 &errout(&print_bits("flags", @flags)); 382} 383 384sub state_errtype() { 385 my @types = split(/,\s*/, $_[0]); 386 387 @types = map { tr/[a-z]/[A-Z]/; "AO_AED_ET_" . $_; } @types; 388 389 &errout(&print_bits("errtype", @types)); 390} 391 392my %stateparse = ( 393 funcunit => [ \&state_funcunit, 'desc' ], 394 desc => [ \&state_desc, 'error' ], 395 error => [ \&state_error, 'mask on' ], 396 'mask on' => [ \&state_mask_on, 'mask off' ], 397 'mask off' => [ \&state_mask_off, 'code' ], 398 code => [ \&state_code, 'code|panic' ], 399 panic => [ \&state_panic, 'flags' ], 400 flags => [ \&state_flags, 'errtype' ], 401 errtype => [ \&state_errtype, 'initial' ] 402); 403 404usage unless (@ARGV == 1); 405 406my $infile = $ARGV[0]; 407open(INFILE, "<$infile") || &bail("failed to open $infile: $!"); 408 409&print_header(); 410 411while (<INFILE>) { 412 chop; 413 414 /^#/ && next; 415 /^$/ && next; 416 417 if (!/^\s*(\S[^=]*\S)\s*=\s*(\S.*)?$/) { 418 &parsebail("failed to parse"); 419 } 420 421 my ($keyword, $val) = ($1, $2); 422 423 if ($state eq "initial") { 424 if ($keyword eq "funcunit") { 425 $state = "funcunit"; 426 } elsif ($keyword eq "desc") { 427 $state = "desc"; 428 } else { 429 &parsebail("unexpected keyword $keyword between " . 430 "errors"); 431 } 432 433 } elsif ($state eq "desc") { 434 if ($keyword eq "funcunit") { 435 $state = "funcunit"; 436 } 437 } 438 439 if (!($keyword =~ /$state/)) { 440 &parsebail("keyword `$keyword' invalid here; expected " . 441 "`$state'"); 442 } 443 $state = $keyword; # disambiguate between multiple legal states 444 445 if (!defined $stateparse{$state}) { 446 &parsebail("attempt to transition to invalid state `$state'"); 447 } 448 449 my ($handler, $next) = @{$stateparse{$state}}; 450 451 &{$handler}($val); 452 453 $state = $next; 454 455 if ($state eq "initial") { 456 &error_end(); 457 } 458} 459 460close(INFILE); 461 462if ($state ne "initial" && $state ne "desc") { 463 &bail("input file ended prematurely"); 464} 465 466if (defined $::funcunit) { 467 &funcunit_end(); 468} else { 469 &bail("no functional units defined"); 470} 471 472&print_footer; 473