/* * Copyright (C) 2006, Intel Corporation * * This file is part of the Linux-ready Firmware Developer Kit * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation;version 2.1 of the License. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include struct SUN_line { char SUN_hexnum[5]; /* _SUN hex id (e.g. 0x01) */ int line_num; /* line # in dsdt where Name (_SUN,...) occurs */ }; #define MAX_SUNS 32 struct SUN_line SUN_list[MAX_SUNS]; extern GList *ssdt[]; extern void load_acpi_tables(); static int lineno; int current_SUN; /* find a certain line in the given dsdt table * that we represented in the linked-list (ssdt) */ static char *find_line(int nr) { GList *list; list = g_list_nth(ssdt[0], nr-1); if(list->data) return (char *) list->data; else return NULL; } /* do_SUN_check() -- check for duplicate hard-coded _SUNs * * Parameters * void * Returns * void */ void do_SUN_check() { struct SUN_hash { char SUN_id[5]; /* SUN hex id (e.g. 0x01) */ int SUN_list_linenums[MAX_SUNS]; /* array of line #s that use this SUN id */ int list_ptr; /* ptr for SUN_list_linenums to track how many line #s exist that use this _SUN */ } SUN_hash_list[MAX_SUNS]; /* hash table indexed by a _SUN id that holds how many AML Name functions use a certain _SUN id */ int testres = PASS; int hash_ptr=0; int i; /* Initialize struct values */ for(i = 0;i < MAX_SUNS;i++) { SUN_hash_list[i].SUN_id[0] = '\0'; SUN_hash_list[i].list_ptr = 0; } /* Add our first table entry */ i=0; strcpy(SUN_hash_list[0].SUN_id, SUN_list[0].SUN_hexnum); SUN_hash_list[0].SUN_list_linenums[0] = SUN_list[0].line_num; SUN_hash_list[0].list_ptr = 1; i++; /* go through our list of Name (_SUN,..) calls and identify * any duplicates (this list was compiled in parse_dsdt() * with add_SUN_name() and is contained in SUN_list[]) */ while(SUN_list[i].line_num) { int j = 0; int k = 0; int dup = 0; /* Compare this _SUN with our hash table, see if we have dups */ for(k = hash_ptr;k>-1;k--) { /* We have a dup., add to correct hash index */ if(strcmp(SUN_list[i].SUN_hexnum, SUN_hash_list[j].SUN_id) == 0) { int cur_ptr = SUN_hash_list[j].list_ptr; strcpy(SUN_hash_list[j].SUN_id, SUN_list[i].SUN_hexnum); SUN_hash_list[j].SUN_list_linenums[cur_ptr] = SUN_list[i].line_num; SUN_hash_list[j].list_ptr++; dup = 1; break; } j++; } /* No dup., create new hash index */ if(dup == 0) { hash_ptr++; strcpy(SUN_hash_list[hash_ptr].SUN_id, SUN_list[i].SUN_hexnum); SUN_hash_list[hash_ptr].SUN_list_linenums[0] = SUN_list[i].line_num; SUN_hash_list[hash_ptr].list_ptr++; } i++; } /* Now go through our hash table and report a warning for every * duplicate we've encountered */ i=0; while(SUN_hash_list[i].list_ptr != 0) { int j, tmp_num; char reportmsg[4096]; char *details; char* dsdt_line; if(SUN_hash_list[i].list_ptr > 1) { testres = WARN; sprintf(reportmsg,"Duplicate hardcoded _SUN \'%s\' found:\n\n", SUN_hash_list[i].SUN_id); details = strdup(""); details = scatprintf(details,"%s",reportmsg); for(j=0;j < SUN_hash_list[i].list_ptr;j++) { tmp_num = SUN_hash_list[i].SUN_list_linenums[j]; dsdt_line = find_line(tmp_num); if(dsdt_line) { details = scatprintf(details,"At line #%d of DSDT.dsl\n", tmp_num); details = scatprintf(details,">>> %s\n", dsdt_line); } } report_result("SUN", testres, reportmsg, details, NULL); } i++; } if(testres == PASS) { report_result("SUN", testres, "Tested _SUN ids, successfully found no duplicates", NULL, NULL); } } /* add_SUN_name() -- Add a _SUN Name occurance to our list * (i.e. Name (_SUN, 0x..)) * * Parameters * line - name of table to compile with iasl (usually dsdt.dsl) * current_SUN - current index for SUN_list[] * line_no - line # in dsdt where this occurs * Returns * void */ void add_SUN_name(char *line, int current_SUN, int line_no) { char tline[4096]; char *x; /* So we don't mess with the 'real' line */ strcpy(tline, line); x = tline; /* Skip , and ' ' until we have the * the beginning of a hex num (0x..), then * chop the newline and last chars until we reach ')' * to get the pure hex num */ while(*x != '0') x++; chop_newline(x); while(x[strlen(x) -1] != ')') chop_lastchar(x); chop_lastchar(x); /* add to our _SUN list */ SUN_list[current_SUN].line_num = line_no; strcpy(SUN_list[current_SUN].SUN_hexnum, x); } /* parse_SUN_name () -- parses a dsdt line for the Name method * using the _SUN parameter i.e the line * "Name (_SUN" then adds the * found hex SUN id in our SUN_list. * * Parameters * gpointer data, gpointer user_data * Returns * void */ static void parse_SUN_name(gpointer data, gpointer user_data) { char *line = (char *) data; char name[256]; char *c; lineno++; memset(name, 0, 256); /* We hit a Name label (looking for _SUN) */ c = strstr(line, "Name ("); if (c) { c+=6; while (*c) { if (*c!=')' && *c!=',') name[strlen(name)]=*c; else break; c++; } if(strcmp(name, "_SUN") == 0) { add_SUN_name(&c[0], current_SUN, lineno); current_SUN++; } } } /* main() -- Parses the DSDT for the Name (_SUN, ...) method, and * ensures that we do not have any duplicate SUN ids * (Slot Unique Number). * * Parameters * argc & argv * Returns * EXIT_SUCCESS upon success of running this plugin * EXIT_FAILURE upon failure of running this plugin */ int main(int argc, char **argv) { start_test("SUN", "SUN duplicate test", "This makes sure that each SUN (Slot Unique Number) that is " "called in the DSDT through the Name() method is unique, no " "duplicates should be found." ); /* Get the dsdt and ssdt tables */ load_acpi_tables(); report_testrun_progress(30); /* Get all the SUNs used in method Name(_SUN,0x..) */ lineno = 0; current_SUN = 0; if (ssdt[0] != NULL) g_list_foreach(ssdt[0], parse_SUN_name, NULL); else fprintf(stderr, "WARN: No DSDT found.\n"); report_testrun_progress(60); /* List SUN duplicates (if any) */ do_SUN_check(); finish_test("SUN"); return EXIT_SUCCESS; }