--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null
+CC = gcc
+LEX = flex
+YACC = bison
+PREFIX = /usr/local
+CFLAGS = -std=c99 -O2 -fomit-frame-pointer -Wall -D_BSD_SOURCE -D_GNU_SOURCE
+LDFLAGS = -lfl
+
+BINARY = bcm43xx-asm.bin
+OBJECTS = parser.o scanner.o main.o initvals.o util.o args.o
+
+# YACC related CFLAGS
+CFLAGS += -DYYSTYPE="void *" -DYYERROR_VERBOSE -DYYDEBUG -Wno-unused
+
+all: $(BINARY)
+
+scanner.c: scanner.l parser.c main.h
+ $(LEX) -o scanner.c --header-file=scanner.h scanner.l
+
+scanner.o: scanner.c
+ $(CC) $(CFLAGS) -c -o scanner.o scanner.c
+
+parser.c: parser.y main.h util.h
+ $(YACC) --defines -o parser.c parser.y
+
+parser.o: parser.c
+ $(CC) $(CFLAGS) -c -o parser.o parser.c
+
+main.o: parser.c main.h list.h util.h args.h initvals.h
+
+initvals.o: initvals.h main.h list.h util.h args.h
+
+util.o: util.h
+
+args.o: args.h main.h util.h
+
+$(BINARY): $(OBJECTS)
+ $(CC) $(CFLAGS) -o $(BINARY) $(OBJECTS) $(LDFLAGS)
+
+install: all
+ -install -o 0 -g 0 -m 755 $(BINARY) $(PREFIX)/bin/
+ -cp bcm43xx-asm bcm43xx-asm.inst
+ -sed -i -e 's/installed=0/installed=1/' bcm43xx-asm.inst
+ -install -o 0 -g 0 -m 755 bcm43xx-asm.inst $(PREFIX)/bin/bcm43xx-asm
+ -rm -f bcm43xx-asm.inst
+
+clean:
+ -rm -f *~ *.o *.orig *.rej $(BINARY) scanner.c scanner.h parser.c parser.h
--- /dev/null
+===============================================================================
+== Instruction Set Summary for the core revision >= 5 microcode ==
+===============================================================================
+
+
+===============================================================================
+Mnemonics | Operands | Description | Operation
+===============================================================================
+
+Arithmetic and logic instructions:
+add | A,B,rD | Add | rD=A+B
+add. | A,B,rD | Add, set Carry | rD=A+B SaveCarry
+addc | A,B,rD | Add with Carry | rD=A+B+Carry
+addc. | A,B,rD | Add with Carry, set Carry | rD=A+B+C SaveCarry
+sub | A,B,rD | Subtract | rD=A-B
+sub. | A,B,rD | Sub, set Carry | rD=A-B SaveCarry
+subc | A,B,rD | Sub with Carry | rD=A-B-Carry
+subc. | A,B,rD | Sub with Carry, set Carry | rD=A-B-C SaveCarry
+
+Branch instructions:
+jmp | l | Unconditional jump | PC=l
+jand | A,B,l | Jump if binary AND | if(A&B) PC=l
+jnand | A,B,l | Jump if not binary AND | if(!(A&B)) PC=l
+js | A,B,l | Jump if all bits set | if((A&B)==A) PC=l
+jns | A,B,l | Jump if not all bits set | if((A&B)!=A) PC=l
+je | A,B,l | Jump if equal | if(A==B) PC=l
+jne | A,B,l | Jump if not equal | if(A!=B) PC=l
+jls | A,B,l | Jump if less (signed) | if(A<B) PC=l
+jges | A,B,l | Jump if greater or equal (sign.)| if(A>=B) PC=l
+jgs | A,B,l | Jump if greater (signed) | if(A>B) PC=l
+jles | A,B,l | Jump if less or equal (signed) | if(A<=B) PC=l
+jl | A,B,l | Jump if less | if(A<B) PC=l
+jge | A,B,l | Jump if greater or equal | if(A>=B) PC=l
+jg | A,B,l | Jump if greater | if(A>B) PC=l
+jle | A,B,l | Jump if less or equal | if(A<=B) PC=l
+call | lrX,l | Store PC, call function | lrX=PC; PC=l
+ret | lrX,lrY | Store PC, ret from func | lrX=PC; PC=lrY
+jzx | M,S,A,B,l | Jump if zero after shift + mask |
+jnzx | M,S,A,B,l | Jump if nonzero after shift+msk |
+jext | E,A,B,l | Jump if External Condition true | if(E) PC=l
+jnext | E,A,B,l | Jump if External Condition false| if(!E) PC=l
+
+Data transfer instructions:
+mov | A,rD | Copy data | rD=A
+tkiph | A,rD | TKIP S-Box lookup high | rD=SBOX[hi8(A)]
+tkiphs | A,rD | TKIP S-Box lkup hi swap'd | rD=byteswap(tkiph)
+tkipl | A,rD | TKIP S-Box lookup low | rD=SBOX[lo8(A)]
+tkipls | A,rD | TKIP S-Box lkup lo swap'd | rD=byteswap(tkipl)
+
+Bitwise instructions:
+sra | A,B,rD | Arithmetic rightshift | rD=A>>B fillup sign
+or | A,B,rD | Bitwise OR | rD=A|B
+and | A,B,rD | Bitwise AND | rD=A&B
+xor | A,B,rD | Bitwise XOR | rD=A^B
+sr | A,B,rD | Rightshift | rD=A>>B
+sl | A,B,rD | Leftshift | rD=A<<B
+srx | M,S,A,B,rD | Extended right shift |
+rl | A,B,rD | Rotate left | rD=lrot(A, B bits)
+rr | A,B,rD | Rotate right | rD=rrot(A, B bits)
+nand | A,B,rD | Clear bits (notmask+and) | rD=A&(~B)
+orx | M,S,A,B,rD | Extended bitwise OR |
+
+Other instructions:
+nap | none | Sleep until event |
+
+
+
+Description of Operands:
+
+rD = Destination Register (GPR or SPR)
+A = Source Register (GPR or SPR) or Immediate
+B = Source Register (GPR or SPR) or Immediate
+M = Mask
+S = Shift
+E = External Condition
+l = Branch label or address
+lrX = Link Register (lr0 - lr3)
+lrY = Link Register (lr0 - lr3)
+
+
+Raw instruction format:
+@bitcode_in_hexadecimal
+Example: @1C0 @C11,@C22,r3
--- /dev/null
+/*
+ * Copyright (C) 2006-2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include "args.h"
+#include "main.h"
+#include "util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+int _debug;
+
+#define ARG_MATCH 0
+#define ARG_NOMATCH 1
+#define ARG_ERROR -1
+
+static int do_cmp_arg(char **argv, int *pos,
+ const char *template,
+ int allow_merged,
+ char **param)
+{
+ char *arg;
+ char *next_arg;
+ size_t arg_len, template_len;
+
+ arg = argv[*pos];
+ next_arg = argv[*pos + 1];
+ arg_len = strlen(arg);
+ template_len = strlen(template);
+
+ if (param) {
+ /* Maybe we have a merged parameter here.
+ * A merged parameter is "-pfoobar" for example.
+ */
+ if (allow_merged && arg_len > template_len) {
+ if (memcmp(arg, template, template_len) == 0) {
+ *param = arg + template_len;
+ return ARG_MATCH;
+ }
+ return ARG_NOMATCH;
+ } else if (arg_len != template_len)
+ return ARG_NOMATCH;
+ *param = next_arg;
+ }
+ if (strcmp(arg, template) == 0) {
+ if (param) {
+ /* Skip the parameter on the next iteration. */
+ (*pos)++;
+ if (*param == 0) {
+ fprintf(stderr, "%s needs a parameter\n", arg);
+ return ARG_ERROR;
+ }
+ }
+ return ARG_MATCH;
+ }
+
+ return ARG_NOMATCH;
+}
+
+/* Simple and lean command line argument parsing. */
+static int cmp_arg(char **argv, int *pos,
+ const char *long_template,
+ const char *short_template,
+ char **param)
+{
+ int err;
+
+ if (long_template) {
+ err = do_cmp_arg(argv, pos, long_template, 0, param);
+ if (err == ARG_MATCH || err == ARG_ERROR)
+ return err;
+ }
+ err = ARG_NOMATCH;
+ if (short_template)
+ err = do_cmp_arg(argv, pos, short_template, 1, param);
+ return err;
+}
+
+static void usage(int argc, char **argv)
+{
+ fprintf(stderr, "Usage: %s INPUT_FILE OUTPUT_FILE [OPTIONS]\n", argv[0]);
+ fprintf(stderr, " -h|--help Print this help\n");
+ fprintf(stderr, " -d|--debug Print verbose debugging info\n");
+ fprintf(stderr, " Repeat for more verbose debugging\n");
+}
+
+int parse_args(int argc, char **argv)
+{
+ int i;
+ int res;
+
+ if (argc < 3)
+ goto out_usage;
+ infile_name = argv[1];
+ outfile_name = argv[2];
+
+ for (i = 3; i < argc; i++) {
+ if ((res = cmp_arg(argv, &i, "--help", "-h", 0)) == ARG_MATCH) {
+ goto out_usage;
+ } else if ((res = cmp_arg(argv, &i, "--debug", "-d", 0)) == ARG_MATCH) {
+ _debug++;
+ } else {
+ fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
+ goto out_usage;
+ }
+ }
+ return 0;
+out_usage:
+ usage(argc, argv);
+ return -1;
+}
+
+int open_input_file(void)
+{
+ int fd;
+ int err;
+
+ if (strcmp(infile_name, "-") == 0) {
+ /* infile == stdin */
+ fd = STDIN_FILENO;
+ } else {
+ fd = open(infile_name, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Could not open INPUT_FILE %s\n",
+ infile_name);
+ return -1;
+ }
+ err = dup2(fd, STDIN_FILENO);
+ if (err) {
+ fprintf(stderr, "Could not dup INPUT_FILE %s "
+ "to STDIN\n", infile_name);
+ close(fd);
+ return -1;
+ }
+ }
+ infile.fd = fd;
+
+ return 0;
+}
+
+void close_input_file(void)
+{
+ if (strcmp(infile_name, "-") != 0)
+ close(infile.fd);
+}
--- /dev/null
+#ifndef BCM43xx_ASM_ARGS_H_
+#define BCM43xx_ASM_ARGS_H_
+
+int parse_args(int argc, char **argv);
+int open_input_file(void);
+void close_input_file(void);
+
+extern int _debug;
+
+#define IS_DEBUG (_debug > 0)
+#define IS_VERBOSE_DEBUG (_debug > 1)
+#define IS_INSANE_DEBUG (_debug > 2)
+
+#endif /* BCM43xx_ASM_ARGS_H_ */
--- /dev/null
+#!/bin/sh
+
+installed=0
+
+if [ -z "$BCM43xx_ASM" ]; then
+ if [ $installed -eq 0 ] && [ -x "./bcm43xx-asm.bin" ]; then
+ BCM43xx_ASM="./bcm43xx-asm.bin"
+ else
+ BCM43xx_ASM="bcm43xx-asm.bin"
+ fi
+fi
+
+if [ -z "$CPP" ]; then
+ CPP="cpp"
+fi
+
+if [ $# -lt 2 ]; then
+ $BCM43xx_ASM --help
+ exit 1
+fi
+
+infile="$1"
+shift
+outfile="$1"
+shift
+
+cat "$infile" | $CPP -traditional-cpp | $BCM43xx_ASM "-" "$outfile" $@
--- /dev/null
+/*
+ * Copyright (C) 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include "initvals.h"
+#include "list.h"
+#include "util.h"
+#include "args.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+struct initval {
+ unsigned int offset;
+ unsigned int size;
+#define SIZE_16BIT 2
+#define SIZE_32BIT 4
+ unsigned int value;
+
+ struct list_head list;
+};
+
+/* The IV in the binary file */
+struct initval_raw {
+ be16_t offset_size;
+ union {
+ be16_t d16;
+ be32_t d32;
+ } data __attribute__((__packed__));
+} __attribute__((__packed__));
+
+#define FW_IV_OFFSET_MASK 0x7FFF
+#define FW_IV_32BIT 0x8000
+
+
+struct ivals_context {
+ /* Pointer to the parsed section structure */
+ const struct initvals_sect *sect;
+ /* List of struct initval */
+ struct list_head ivals;
+ /* Number of initvals. */
+ unsigned int ivals_count;
+};
+
+#define _msg_helper(type, ctx, msg, x...) do { \
+ fprintf(stderr, "InitVals " type); \
+ fprintf(stderr, " (Section \"%s\")", ctx->sect->name); \
+ fprintf(stderr, ":\n " msg "\n" ,##x); \
+ } while (0)
+
+#define iv_error(ctx, msg, x...) do { \
+ _msg_helper("ERROR", ctx, msg ,##x); \
+ exit(1); \
+ } while (0)
+
+#define iv_warn(ctx, msg, x...) \
+ _msg_helper("warning", ctx, msg ,##x)
+
+#define iv_info(ctx, msg, x...) \
+ _msg_helper("info", ctx, msg ,##x)
+
+
+static void assemble_write_mmio(struct ivals_context *ctx,
+ unsigned int offset,
+ unsigned int size,
+ unsigned int value)
+{
+ struct initval *iv;
+
+ iv = xmalloc(sizeof(struct initval));
+ iv->offset = offset;
+ iv->size = size;
+ iv->value = value;
+ INIT_LIST_HEAD(&iv->list);
+ list_add_tail(&iv->list, &ctx->ivals);
+ ctx->ivals_count++;
+}
+
+static void assemble_write_phy(struct ivals_context *ctx,
+ unsigned int offset,
+ unsigned int value)
+{
+ assemble_write_mmio(ctx, 0x3FC, SIZE_16BIT, offset);
+ assemble_write_mmio(ctx, 0x3FE, SIZE_16BIT, value);
+}
+
+static void assemble_write_radio(struct ivals_context *ctx,
+ unsigned int offset,
+ unsigned int value)
+{
+ assemble_write_mmio(ctx, 0x3F6, SIZE_16BIT, offset);
+ assemble_write_mmio(ctx, 0x3FA, SIZE_16BIT, value);
+}
+
+static void shm_control_word(struct ivals_context *ctx,
+ unsigned int routing,
+ unsigned int offset)
+{
+ unsigned int control;
+
+ control = (routing & 0xFFFF);
+ control <<= 16;
+ control |= (offset & 0xFFFF);
+ assemble_write_mmio(ctx, 0x160, SIZE_32BIT, control);
+}
+
+static void shm_write32(struct ivals_context *ctx,
+ unsigned int routing,
+ unsigned int offset,
+ unsigned int value)
+{
+ if ((routing & 0xFF) == 0x01) {
+ /* Is SHM Shared-memory */
+//TODO assert((offset & 0x0001) == 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ shm_control_word(ctx, routing, offset >> 2);
+ assemble_write_mmio(ctx, 0x166, SIZE_16BIT,
+ (value >> 16) & 0xFFFF);
+ shm_control_word(ctx, routing, (offset >> 2) + 1);
+ assemble_write_mmio(ctx, 0x164, SIZE_16BIT,
+ (value & 0xFFFF));
+ return;
+ }
+ offset >>= 2;
+ }
+ shm_control_word(ctx, routing, offset);
+ assemble_write_mmio(ctx, 0x164, SIZE_32BIT, value);
+}
+
+static void shm_write16(struct ivals_context *ctx,
+ unsigned int routing,
+ unsigned int offset,
+ unsigned int value)
+{
+ if ((routing & 0xFF) == 0x01) {
+ /* Is SHM Shared-memory */
+//TODO assert((offset & 0x0001) == 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ shm_control_word(ctx, routing, offset >> 2);
+ assemble_write_mmio(ctx, 0x166, SIZE_16BIT,
+ value);
+ return;
+ }
+ offset >>= 2;
+ }
+ shm_control_word(ctx, routing, offset);
+ assemble_write_mmio(ctx, 0x164, SIZE_16BIT, value);
+}
+
+static void assemble_write_shm(struct ivals_context *ctx,
+ unsigned int routing,
+ unsigned int offset,
+ unsigned int value,
+ unsigned int size)
+{
+ switch (routing & 0xFF) {
+ case 0: case 1: case 2: case 3: case 4:
+ break;
+ default:
+ //TODO error
+ break;
+ }
+ //TODO check offset
+
+ //TODO check value
+ switch (size) {
+ case SIZE_16BIT:
+ shm_write16(ctx, routing, offset, value);
+ break;
+ case SIZE_32BIT:
+ shm_write32(ctx, routing, offset, value);
+ break;
+ default:
+ fprintf(stderr, "Internal assembler BUG. SHMwrite invalid size\n");
+ exit(1);
+ }
+}
+
+static void assemble_ival_section(struct ivals_context *ctx,
+ const struct initvals_sect *sect)
+{
+ struct initval_op *op;
+
+ ctx->sect = sect;
+ if (list_empty(§->ops)) {
+ //TODO warning
+ return;
+ }
+ list_for_each_entry(op, §->ops, list) {
+ switch (op->type) {
+ case IVAL_W_MMIO16:
+ assemble_write_mmio(ctx, op->args[1],
+ SIZE_16BIT,
+ op->args[0]);
+ break;
+ case IVAL_W_MMIO32:
+ assemble_write_mmio(ctx, op->args[1],
+ SIZE_32BIT,
+ op->args[0]);
+ break;
+ case IVAL_W_PHY:
+ assemble_write_phy(ctx, op->args[1],
+ op->args[0]);
+ break;
+ case IVAL_W_RADIO:
+ assemble_write_radio(ctx, op->args[1],
+ op->args[0]);
+ break;
+ case IVAL_W_SHM16:
+ assemble_write_shm(ctx, op->args[1],
+ op->args[2],
+ op->args[0],
+ SIZE_16BIT);
+ break;
+ case IVAL_W_SHM32:
+ assemble_write_shm(ctx, op->args[1],
+ op->args[2],
+ op->args[0],
+ SIZE_32BIT);
+ break;
+ }
+ }
+}
+
+static unsigned int initval_to_raw(struct ivals_context *ctx,
+ struct initval_raw *raw,
+ const struct initval *iv)
+{
+ unsigned int size;
+
+ memset(raw, 0, sizeof(*raw));
+ if (iv->offset & ~FW_IV_OFFSET_MASK) {
+ iv_error(ctx, "Initval offset 0x%04X too big. "
+ "Offset must be <= 0x%04X",
+ iv->offset, FW_IV_OFFSET_MASK);
+ }
+ raw->offset_size = cpu_to_be16(iv->offset);
+
+ switch (iv->size) {
+ case SIZE_16BIT:
+ raw->data.d16 = cpu_to_be16(iv->value);
+ size = sizeof(be16_t) + sizeof(be16_t);
+ break;
+ case SIZE_32BIT:
+ raw->data.d32 = cpu_to_be32(iv->value);
+ raw->offset_size |= cpu_to_be16(FW_IV_32BIT);
+ size = sizeof(be16_t) + sizeof(be32_t);
+ break;
+ default:
+ iv_error(ctx, "Internal error. initval_to_raw invalid size.");
+ break;
+ }
+
+ return size;
+}
+
+static void emit_ival_section(struct ivals_context *ctx)
+{
+ FILE *fd;
+ char *fn;
+ size_t fn_len;
+ struct initval *iv;
+ struct initval_raw raw;
+ struct fw_header hdr;
+ unsigned int size;
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.type = FW_TYPE_IV;
+ hdr.ver = FW_HDR_VER;
+ hdr.size = cpu_to_be32(ctx->ivals_count);
+
+ fn_len = strlen(outfile_name) + 512;
+ fn = xmalloc(fn_len);
+ snprintf(fn, fn_len, "%s.%s.initval", outfile_name, ctx->sect->name);
+ fd = fopen(fn, "w+");
+ if (!fd) {
+ fprintf(stderr, "Could not open initval output file \"%s\"\n", fn);
+ free(fn);
+ exit(1);
+ }
+
+ if (fwrite(&hdr, sizeof(hdr), 1, fd) != 1) {
+ fprintf(stderr, "Could not write initvals outfile\n");
+ exit(1);
+ }
+
+ if (IS_VERBOSE_DEBUG)
+ fprintf(stderr, "\nInitvals \"%s\":\n", ctx->sect->name);
+ list_for_each_entry(iv, &ctx->ivals, list) {
+ if (IS_VERBOSE_DEBUG) {
+ fprintf(stderr, "%04X %u %08X\n",
+ iv->offset,
+ iv->size,
+ iv->value);
+ }
+ size = initval_to_raw(ctx, &raw, iv);
+ if (fwrite(&raw, size, 1, fd) != 1) {
+ fprintf(stderr, "Could not write initvals outfile\n");
+ exit(1);
+ }
+ }
+ fclose(fd);
+ free(fn);
+}
+
+void assemble_initvals(void)
+{
+ struct ivals_context ctx;
+ struct initvals_sect *sect;
+
+ list_for_each_entry(sect, &infile.ivals, list) {
+ memset(&ctx, 0, sizeof(ctx));
+ INIT_LIST_HEAD(&ctx.ivals);
+
+ assemble_ival_section(&ctx, sect);
+ emit_ival_section(&ctx);
+ }
+}
--- /dev/null
+#ifndef BCM43xx_ASM_INITVALS_H_
+#define BCM43xx_ASM_INITVALS_H_
+
+#include "main.h"
+
+
+struct initval_op {
+ enum {
+ IVAL_W_MMIO16,
+ IVAL_W_MMIO32,
+ IVAL_W_PHY,
+ IVAL_W_RADIO,
+ IVAL_W_SHM16,
+ IVAL_W_SHM32,
+ } type;
+ unsigned int args[3];
+
+ struct lineinfo info;
+
+ struct list_head list;
+};
+
+struct initvals_sect {
+ /* The name string for this initvals section */
+ const char *name;
+ /* List of initval operations */
+ struct list_head ops;
+
+ struct list_head list;
+};
+
+
+extern void assemble_initvals(void);
+
+#endif /* BCM43xx_ASM_INITVALS_H_ */
--- /dev/null
+/*
+ * Copied from the Linux kernel source tree, version 2.6.0-test1.
+ *
+ * Licensed under the GPL v2 as per the whole kernel source tree.
+ *
+ */
+
+#ifndef _LIST_H
+#define _LIST_H
+
+#ifndef __GNUC__
+# error "Need GNU GCC"
+#endif
+
+#define typeof __typeof__
+#define offsetof(type, member) __builtin_offsetof (type, member)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#endif /* _LIST_H */
--- /dev/null
+/*
+ * Copyright (C) 2006-2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include "main.h"
+#include "list.h"
+#include "util.h"
+#include "parser.h"
+#include "args.h"
+#include "initvals.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+extern int yyparse(void);
+extern int yydebug;
+
+struct file infile;
+const char *infile_name;
+const char *outfile_name;
+
+
+struct out_operand {
+ enum {
+ OUTOPER_NORMAL,
+ OUTOPER_LABELREF,
+ } type;
+
+ union {
+ unsigned int operand; /* For NORMAL */
+ struct label *label; /* For LABELREF */
+ } u;
+};
+
+struct code_output {
+ enum {
+ OUT_INSN,
+ OUT_LABEL,
+ } type;
+
+ unsigned int opcode;
+ struct out_operand operands[3];
+
+ /* The absolute address of this instruction.
+ * Only used in resolve_labels(). */
+ unsigned int address;
+
+ const char *labelname; /* only for OUT_LABEL */
+ /* Set to 1, if this is the %start instruction. */
+ int is_start_insn;
+
+ struct list_head list;
+};
+
+struct assembler_context {
+ int arch;
+ struct label *start_label;
+
+ /* Tracking stuff */
+ struct statement *cur_stmt;
+
+ struct list_head output;
+};
+
+
+#define for_each_statement(ctx, s) \
+ list_for_each_entry(s, &infile.sl, list) { \
+ ctx->cur_stmt = s;
+
+#define for_each_statement_end(ctx, s) \
+ } do { ctx->cur_stmt = NULL; } while (0)
+
+#define _msg_helper(type, stmt, msg, x...) do { \
+ fprintf(stderr, "Assembler " type); \
+ if (stmt) { \
+ fprintf(stderr, " (file \"%s\", line %u)", \
+ stmt->info.file, \
+ stmt->info.lineno); \
+ } \
+ fprintf(stderr, ":\n " msg "\n" ,##x); \
+ } while (0)
+
+#define asm_error(ctx, msg, x...) do { \
+ _msg_helper("ERROR", (ctx)->cur_stmt, msg ,##x); \
+ exit(1); \
+ } while (0)
+
+#define asm_warn(ctx, msg, x...) \
+ _msg_helper("warning", (ctx)->cur_stmt, msg ,##x)
+
+#define asm_info(ctx, msg, x...) \
+ _msg_helper("info", (ctx)->cur_stmt, msg ,##x)
+
+
+static void eval_directives(struct assembler_context *ctx)
+{
+ struct statement *s;
+ struct asmdir *ad;
+ struct label *l;
+ int have_start_label = 0;
+ int have_arch = 0;
+
+ for_each_statement(ctx, s) {
+ if (s->type == STMT_ASMDIR) {
+ ad = s->u.asmdir;
+ switch (ad->type) {
+ case ADIR_ARCH:
+ if (have_arch)
+ asm_error(ctx, "Multiple %%arch definitions");
+ ctx->arch = ad->u.arch;
+ have_arch = 1;
+ break;
+ case ADIR_START:
+ if (have_start_label)
+ asm_error(ctx, "Multiple %%start definitions");
+ ctx->start_label = ad->u.start;
+ have_start_label = 1;
+ break;
+ default:
+ asm_error(ctx, "Unknown ASM directive");
+ }
+ }
+ } for_each_statement_end(ctx, s);
+
+ if (!have_arch)
+ asm_error(ctx, "No %%arch defined");
+ if (ctx->arch != NEWWORLD)
+ asm_error(ctx, "TODO: Only NEWWORLD arch supported, yet");
+ if (!have_start_label)
+ asm_info(ctx, "Using start address 0");
+}
+
+static int is_possible_imm(unsigned int imm)
+{
+ unsigned int mask;
+
+ /* Immediates are only possible up to 16bit (wordsize). */
+ mask = ~0;
+ mask <<= 16;
+ if (imm & (1 << 15)) {
+ if ((imm & mask) != mask &&
+ (imm & mask) != 0)
+ return 0;
+ } else {
+ if ((imm & mask) != 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int is_valid_imm(unsigned int imm)
+{
+ unsigned int mask;
+
+ /* This function checks if the immediate value is representable
+ * as a native immediate operand.
+ *
+ * The value itself is 10bit long, signed.
+ * We also honor sign-extension, so we allow values
+ * of 0xFFFF, for example.
+ */
+
+ if (!is_possible_imm(imm))
+ return 0;
+ imm &= 0xFFFF;
+
+ /* assert sign extension */
+ mask = 0xFC00;
+ if (imm & (1 << 9)) {
+ /* sign-extended */
+ if ((imm & mask) != mask)
+ return 0;
+ } else {
+ if (imm & mask)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int is_contiguous_bitmask(unsigned int mask)
+{
+ int bit;
+ int only_zero_now = 0;
+
+ /* This checks if the mask is contiguous.
+ * A contiguous mask is:
+ * 0b0001111110000
+ * A non-contiguous mask is:
+ * 0b0001101110000
+ */
+
+ bit = ffs(mask);
+ if (!bit)
+ return 1;
+ if (bit > 16)
+ return 1;
+ bit--;
+ for ( ; bit < 16; bit++) {
+ if (mask & (1 << bit)) {
+ if (only_zero_now)
+ return 0;
+ } else
+ only_zero_now = 1;
+ }
+
+ return 1;
+}
+
+static unsigned int generate_imm_operand(struct assembler_context *ctx,
+ const struct immediate *imm)
+{
+ unsigned int val, tmp;
+ unsigned int mask;
+ int too_long = 0;
+
+ /* format: 0b11ii iiii iiii */
+
+ val = 0xC00;
+ tmp = imm->imm;
+
+ if (!is_valid_imm(tmp)) {
+ asm_warn(ctx, "IMMEDIATE 0x%X (%d) too long "
+ "(> 9 bits + sign). Did you intend to "
+ "use implicit sign extension?",
+ tmp, (int)tmp);
+ }
+
+ tmp &= 0x3FF;
+ val |= tmp;
+
+ return val;
+}
+
+static unsigned int generate_reg_operand(struct assembler_context *ctx,
+ const struct registr *reg)
+{
+ unsigned int val = 0;
+
+ switch (reg->type) {
+ case GPR:
+ /* format: 0b1011 11rr rrrr */
+ val |= 0xBC0;
+ if (reg->nr & ~0x3F)
+ asm_error(ctx, "GPR-nr too big");
+ val |= reg->nr;
+ break;
+ case SPR:
+ /* format: 0b100. .... .... */
+ val |= 0x800;
+ if (reg->nr & ~0x1FF)
+ asm_error(ctx, "SPR-nr too big");
+ val |= reg->nr;
+ break;
+ case OFFR:
+ /* format: 0b1000 0110 0rrr */
+ val |= 0x860;
+ if (reg->nr & ~0x7)
+ asm_error(ctx, "OFFR-nr too big");
+ val |= reg->nr;
+ break;
+ default:
+ asm_error(ctx, "generate_reg_operand() regtype");
+ }
+
+ return val;
+}
+
+static unsigned int generate_mem_operand(struct assembler_context *ctx,
+ const struct memory *mem)
+{
+ unsigned int val = 0, off, reg;
+
+ switch (mem->type) {
+ case MEM_DIRECT:
+ /* format: 0b0mmm mmmm mmmm */
+ off = mem->offset;
+ if (off & ~0x7FF) {
+ asm_warn(ctx, "DIRECT memoffset 0x%X too long (> 11 bits)", off);
+ off &= 0x7FF;
+ }
+ val |= off;
+ break;
+ case MEM_INDIRECT:
+ /* format: 0b101r rroo oooo */
+ off = mem->offset;
+ reg = mem->offr_nr;
+ val |= 0xA00;
+ if (off & ~0x3F) {
+ asm_warn(ctx, "INDIRECT memoffset 0x%X too long (> 6 bits)", off);
+ off &= 0x3F;
+ }
+ if (reg & ~0x7)
+ asm_error(ctx, "OFFR-nr too big");
+ val |= off;
+ val |= (reg << 6);
+ break;
+ default:
+ asm_error(ctx, "generate_mem_operand() memtype");
+ }
+
+ return val;
+}
+
+static void generate_operand(struct assembler_context *ctx,
+ const struct operand *oper,
+ struct out_operand *out)
+{
+ out->type = OUTOPER_NORMAL;
+
+ switch (oper->type) {
+ case OPER_IMM:
+ out->u.operand = generate_imm_operand(ctx, oper->u.imm);
+ break;
+ case OPER_REG:
+ out->u.operand = generate_reg_operand(ctx, oper->u.reg);
+ break;
+ case OPER_MEM:
+ out->u.operand = generate_mem_operand(ctx, oper->u.mem);
+ break;
+ case OPER_LABEL:
+ out->type = OUTOPER_LABELREF;
+ out->u.label = oper->u.label;
+ break;
+ case OPER_ADDR:
+ out->u.operand = oper->u.addr->addr;
+ break;
+ case OPER_RAW:
+ out->u.operand = oper->u.raw;
+ break;
+ default:
+ asm_error(ctx, "generate_operand() operstate");
+ }
+}
+
+static void do_assemble_insn(struct assembler_context *ctx,
+ struct instruction *insn,
+ unsigned int opcode)
+{
+ int i;
+ struct operlist *ol;
+ int nr_oper = 0;
+ uint64_t code = 0;
+ struct code_output *out;
+ struct label *labelref = NULL;
+ struct operand *oper;
+ int have_spr_operand = 0;
+ int have_mem_operand = 0;
+
+ out = xmalloc(sizeof(*out));
+ INIT_LIST_HEAD(&out->list);
+ out->opcode = opcode;
+
+ ol = insn->operands;
+ if (ARRAY_SIZE(out->operands) > ARRAY_SIZE(ol->oper))
+ asm_error(ctx, "Internal operand array confusion");
+
+ for (i = 0; i < ARRAY_SIZE(out->operands); i++) {
+ oper = ol->oper[i];
+ if (!oper)
+ continue;
+
+ /* If this is an INPUT operand (first or second), we must
+ * make sure that not both are accessing SPR or MEMORY.
+ * The device only supports one SPR or MEMORY operand in
+ * the input operands. */
+ if ((i == 0) || (i == 1)) {
+ if ((oper->type == OPER_REG) &&
+ (oper->u.reg->type == SPR)) {
+ if (have_spr_operand)
+ asm_error(ctx, "Multiple SPR input operands in one instruction");
+ have_spr_operand = 1;
+ }
+ if (oper->type == OPER_MEM) {
+ if (have_mem_operand)
+ asm_error(ctx, "Multiple MEMORY input operands in on instruction");
+ have_mem_operand = 1;
+ }
+ }
+
+ generate_operand(ctx, oper, &out->operands[i]);
+ nr_oper++;
+ }
+ if (nr_oper != 3)
+ asm_error(ctx, "Internal error: nr_oper at "
+ "lowlevel do_assemble_insn");
+
+ list_add_tail(&out->list, &ctx->output);
+}
+
+static unsigned int merge_ext_into_opcode(struct assembler_context *ctx,
+ unsigned int opbase,
+ struct instruction *insn)
+{
+ struct operlist *ol;
+ unsigned int opcode;
+ unsigned int mask, shift;
+
+ ol = insn->operands;
+ opcode = opbase;
+ mask = ol->oper[0]->u.raw;
+ if (mask & ~0xF)
+ asm_error(ctx, "opcode MASK extension too big (> 0xF)");
+ shift = ol->oper[1]->u.raw;
+ if (shift & ~0xF)
+ asm_error(ctx, "opcode SHIFT extension too big (> 0xF)");
+ opcode |= (mask << 4);
+ opcode |= shift;
+ ol->oper[0] = ol->oper[2];
+ ol->oper[1] = ol->oper[3];
+ ol->oper[2] = ol->oper[4];
+
+ return opcode;
+}
+
+static unsigned int merge_external_jmp_into_opcode(struct assembler_context *ctx,
+ unsigned int opbase,
+ struct instruction *insn)
+{
+ struct operlist *ol;
+ unsigned int cond;
+ unsigned int opcode;
+
+ ol = insn->operands;
+ opcode = opbase;
+ cond = ol->oper[0]->u.raw;
+ if (cond & ~0xFF)
+ asm_error(ctx, "External jump condition value too big (> 0xFF)");
+ opcode |= cond;
+ ol->oper[0] = ol->oper[1];
+ ol->oper[1] = ol->oper[2];
+ ol->oper[2] = ol->oper[3];
+
+ return opcode;
+}
+
+static void assemble_instruction(struct assembler_context *ctx,
+ struct instruction *insn);
+
+static void emulate_mov_insn(struct assembler_context *ctx,
+ struct instruction *insn)
+{
+ struct instruction em_insn;
+ struct operlist em_ol;
+ struct operand em_op_shift;
+ struct operand em_op_mask;
+ struct operand em_op_x;
+ struct operand em_op_y;
+ struct immediate em_imm_x;
+ struct immediate em_imm_y;
+
+ struct operand *in, *out;
+ unsigned int tmp;
+
+ /* This is a pseudo-OP. We emulate it by OR or ORX */
+
+ in = insn->operands->oper[0];
+ out = insn->operands->oper[1];
+
+ em_insn.op = OP_OR;
+ em_ol.oper[0] = in;
+ em_imm_x.imm = 0;
+ em_op_x.type = OPER_IMM;
+ em_op_x.u.imm = &em_imm_x;
+ em_ol.oper[1] = &em_op_x;
+ em_ol.oper[2] = out;
+
+ if (in->type == OPER_IMM) {
+ tmp = in->u.imm->imm;
+ if (!is_possible_imm(tmp))
+ asm_error(ctx, "MOV operand 0x%X > 16bit", tmp);
+ if (!is_valid_imm(tmp)) {
+ /* Immediate too big for plain OR */
+ em_insn.op = OP_ORX;
+
+ em_op_mask.type = OPER_RAW;
+ em_op_mask.u.raw = 0x7;
+ em_op_shift.type = OPER_RAW;
+ em_op_shift.u.raw = 0x8;
+
+ em_imm_x.imm = (tmp & 0xFF00) >> 8;
+ em_op_x.type = OPER_IMM;
+ em_op_x.u.imm = &em_imm_x;
+
+ em_imm_y.imm = (tmp & 0x00FF);
+ em_op_y.type = OPER_IMM;
+ em_op_y.u.imm = &em_imm_y;
+
+ em_ol.oper[0] = &em_op_mask;
+ em_ol.oper[1] = &em_op_shift;
+ em_ol.oper[2] = &em_op_x;
+ em_ol.oper[3] = &em_op_y;
+ em_ol.oper[4] = out;
+ }
+ }
+
+ em_insn.operands = &em_ol;
+ assemble_instruction(ctx, &em_insn); /* recurse */
+}
+
+static void emulate_jmp_insn(struct assembler_context *ctx,
+ struct instruction *insn)
+{
+ struct instruction em_insn;
+ struct operlist em_ol;
+ struct operand em_op;
+ struct immediate em_imm;
+
+ /* This is a pseudo-OP. We emulate it by JE */
+
+ em_insn.op = OP_JE;
+ em_imm.imm = 1;
+ em_op.type = OPER_IMM;
+ em_op.u.imm = &em_imm;
+ em_ol.oper[0] = &em_op;
+ em_ol.oper[1] = &em_op;
+ em_ol.oper[2] = insn->operands->oper[0];
+ em_insn.operands = &em_ol;
+ assemble_instruction(ctx, &em_insn); /* recurse */
+}
+
+static void emulate_jand_insn(struct assembler_context *ctx,
+ struct instruction *insn,
+ int inverted)
+{
+ struct instruction em_insn;
+ struct operlist em_ol;
+ struct operand em_op_shift;
+ struct operand em_op_mask;
+ struct operand em_op_y;
+ struct immediate em_imm;
+
+ struct operand *oper0, *oper1, *oper2;
+ struct operand *imm_oper = NULL;
+ unsigned int tmp;
+ int first_bit, last_bit;
+
+ oper0 = insn->operands->oper[0];
+ oper1 = insn->operands->oper[1];
+ oper2 = insn->operands->oper[2];
+
+ if (oper0->type == OPER_IMM)
+ imm_oper = oper0;
+ if (oper1->type == OPER_IMM)
+ imm_oper = oper1;
+ if (oper0->type == OPER_IMM && oper1->type == OPER_IMM)
+ imm_oper = NULL;
+
+ if (imm_oper) {
+ /* We have a single immediate operand.
+ * Check if it's representable by a normal JAND insn.
+ */
+ tmp = imm_oper->u.imm->imm;
+ if (!is_valid_imm(tmp)) {
+ /* Nope, this must be emulated by JZX/JNZX */
+ if (!is_contiguous_bitmask(tmp)) {
+ asm_error(ctx, "Long bitmask 0x%X is not contiguous",
+ tmp);
+ }
+
+ first_bit = ffs(tmp);
+ last_bit = ffs(~(tmp >> (first_bit - 1))) - 1 + first_bit - 1;
+
+ if (inverted)
+ em_insn.op = OP_JZX;
+ else
+ em_insn.op = OP_JNZX;
+ em_op_shift.type = OPER_RAW;
+ em_op_shift.u.raw = first_bit - 1;
+ em_op_mask.type = OPER_RAW;
+ em_op_mask.u.raw = last_bit - first_bit;
+
+ em_imm.imm = 0;
+ em_op_y.type = OPER_IMM;
+ em_op_y.u.imm = &em_imm;
+
+ em_ol.oper[0] = &em_op_mask;
+ em_ol.oper[1] = &em_op_shift;
+ if (oper0->type != OPER_IMM)
+ em_ol.oper[2] = oper0;
+ else
+ em_ol.oper[2] = oper1;
+ em_ol.oper[3] = &em_op_y;
+ em_ol.oper[4] = oper2;
+
+ em_insn.operands = &em_ol;
+
+ assemble_instruction(ctx, &em_insn); /* recurse */
+ return;
+ }
+ }
+
+ /* Do a normal JAND/JNAND instruction */
+ if (inverted)
+ do_assemble_insn(ctx, insn, 0x040 | 0x1);
+ else
+ do_assemble_insn(ctx, insn, 0x040);
+}
+
+static void assemble_instruction(struct assembler_context *ctx,
+ struct instruction *insn)
+{
+ unsigned int opcode;
+
+ switch (insn->op) {
+ case OP_ADD:
+ do_assemble_insn(ctx, insn, 0x1C0);
+ break;
+ case OP_ADDSC:
+ do_assemble_insn(ctx, insn, 0x1C2);
+ break;
+ case OP_ADDC:
+ do_assemble_insn(ctx, insn, 0x1C1);
+ break;
+ case OP_ADDSCC:
+ do_assemble_insn(ctx, insn, 0x1C3);
+ break;
+ case OP_SUB:
+ do_assemble_insn(ctx, insn, 0x1D0);
+ break;
+ case OP_SUBSC:
+ do_assemble_insn(ctx, insn, 0x1D2);
+ break;
+ case OP_SUBC:
+ do_assemble_insn(ctx, insn, 0x1D1);
+ break;
+ case OP_SUBSCC:
+ do_assemble_insn(ctx, insn, 0x1D3);
+ break;
+ case OP_SRA:
+ do_assemble_insn(ctx, insn, 0x130);
+ break;
+ case OP_OR:
+ do_assemble_insn(ctx, insn, 0x160);
+ break;
+ case OP_AND:
+ do_assemble_insn(ctx, insn, 0x140);
+ break;
+ case OP_XOR:
+ do_assemble_insn(ctx, insn, 0x170);
+ break;
+ case OP_SR:
+ do_assemble_insn(ctx, insn, 0x120);
+ break;
+ case OP_SRX:
+ opcode = merge_ext_into_opcode(ctx, 0x200, insn);
+ do_assemble_insn(ctx, insn, opcode);
+ break;
+ case OP_SL:
+ do_assemble_insn(ctx, insn, 0x110);
+ break;
+ case OP_RL:
+ do_assemble_insn(ctx, insn, 0x1A0);
+ break;
+ case OP_RR:
+ do_assemble_insn(ctx, insn, 0x1B0);
+ break;
+ case OP_NAND:
+ do_assemble_insn(ctx, insn, 0x150);
+ break;
+ case OP_ORX:
+ opcode = merge_ext_into_opcode(ctx, 0x300, insn);
+ do_assemble_insn(ctx, insn, opcode);
+ break;
+ case OP_MOV:
+ emulate_mov_insn(ctx, insn);
+ return;
+ case OP_JMP:
+ emulate_jmp_insn(ctx, insn);
+ return;
+ case OP_JAND:
+ emulate_jand_insn(ctx, insn, 0);
+ return;
+ case OP_JNAND:
+ emulate_jand_insn(ctx, insn, 1);
+ return;
+ case OP_JS:
+ do_assemble_insn(ctx, insn, 0x050);
+ break;
+ case OP_JNS:
+ do_assemble_insn(ctx, insn, 0x050 | 0x1);
+ break;
+ case OP_JE:
+ do_assemble_insn(ctx, insn, 0x0D0);
+ break;
+ case OP_JNE:
+ do_assemble_insn(ctx, insn, 0x0D0 | 0x1);
+ break;
+ case OP_JLS:
+ do_assemble_insn(ctx, insn, 0x0D2);
+ break;
+ case OP_JGES:
+ do_assemble_insn(ctx, insn, 0x0D2 | 0x1);
+ break;
+ case OP_JGS:
+ do_assemble_insn(ctx, insn, 0x0D4);
+ break;
+ case OP_JLES:
+ do_assemble_insn(ctx, insn, 0x0D4 | 0x1);
+ break;
+ case OP_JL:
+ do_assemble_insn(ctx, insn, 0x0DA);
+ break;
+ case OP_JGE:
+ do_assemble_insn(ctx, insn, 0x0DA | 0x1);
+ break;
+ case OP_JG:
+ do_assemble_insn(ctx, insn, 0x0DC);
+ break;
+ case OP_JLE:
+ do_assemble_insn(ctx, insn, 0x0DC | 0x1);
+ break;
+ case OP_JZX:
+ opcode = merge_ext_into_opcode(ctx, 0x400, insn);
+ do_assemble_insn(ctx, insn, opcode);
+ break;
+ case OP_JNZX:
+ opcode = merge_ext_into_opcode(ctx, 0x500, insn);
+ do_assemble_insn(ctx, insn, opcode);
+ break;
+ case OP_JEXT:
+ opcode = merge_external_jmp_into_opcode(ctx, 0x700, insn);
+ do_assemble_insn(ctx, insn, opcode);
+ break;
+ case OP_JNEXT:
+ opcode = merge_external_jmp_into_opcode(ctx, 0x600, insn);
+ do_assemble_insn(ctx, insn, opcode);
+ break;
+ case OP_CALL:
+ do_assemble_insn(ctx, insn, 0x002);
+ break;
+ case OP_RET:
+ do_assemble_insn(ctx, insn, 0x003);
+ break;
+ case OP_TKIPH:
+ case OP_TKIPHS:
+ case OP_TKIPL:
+ case OP_TKIPLS:
+ do_assemble_insn(ctx, insn, 0x1E0);
+ break;
+ case OP_NAP:
+ do_assemble_insn(ctx, insn, 0x001);
+ break;
+ case RAW_CODE:
+ do_assemble_insn(ctx, insn, insn->opcode);
+ break;
+ default:
+ asm_error(ctx, "Unknown op");
+ }
+}
+
+static void assemble_instructions(struct assembler_context *ctx)
+{
+ struct statement *s;
+ struct instruction *insn;
+ struct code_output *out;
+
+ if (ctx->start_label) {
+ /* Generate a jump instruction at offset 0 to
+ * jump to the code start.
+ */
+ struct instruction sjmp;
+ struct operlist ol;
+ struct operand oper;
+
+ oper.type = OPER_LABEL;
+ oper.u.label = ctx->start_label;
+ ol.oper[0] = &oper;
+ sjmp.op = OP_JMP;
+ sjmp.operands = &ol;
+
+ assemble_instruction(ctx, &sjmp);
+ out = list_entry(ctx->output.next, struct code_output, list);
+ out->is_start_insn = 1;
+ }
+
+ for_each_statement(ctx, s) {
+ switch (s->type) {
+ case STMT_INSN:
+ ctx->cur_stmt = s;
+ insn = s->u.insn;
+ assemble_instruction(ctx, insn);
+ break;
+ case STMT_LABEL:
+ out = xmalloc(sizeof(*out));
+ INIT_LIST_HEAD(&out->list);
+ out->type = OUT_LABEL;
+ out->labelname = s->u.label->name;
+
+ list_add_tail(&out->list, &ctx->output);
+ break;
+ case STMT_ASMDIR:
+ break;
+ }
+ } for_each_statement_end(ctx, s);
+}
+
+/* Resolve a label reference to the address it points to. */
+static int get_labeladdress(struct assembler_context *ctx,
+ struct code_output *this_insn,
+ struct label *labelref)
+{
+ struct code_output *c;
+ bool found = 0;
+ int address = -1;
+
+ switch (labelref->direction) {
+ case LABELREF_ABSOLUTE:
+ list_for_each_entry(c, &ctx->output, list) {
+ if (c->type != OUT_LABEL)
+ continue;
+ if (strcmp(c->labelname, labelref->name) != 0)
+ continue;
+ if (found) {
+ asm_error(ctx, "Ambiguous label reference \"%s\"",
+ labelref->name);
+ }
+ found = 1;
+ address = c->address;
+ }
+ break;
+ case LABELREF_RELATIVE_BACK:
+ for (c = list_entry(this_insn->list.prev, typeof(*c), list);
+ &c->list != &ctx->output;
+ c = list_entry(c->list.prev, typeof(*c), list)) {
+ if (c->type != OUT_LABEL)
+ continue;
+ if (strcmp(c->labelname, labelref->name) == 0) {
+ /* Found */
+ address = c->address;
+ break;
+ }
+ }
+ break;
+ case LABELREF_RELATIVE_FORWARD:
+ for (c = list_entry(this_insn->list.next, typeof(*c), list);
+ &c->list != &ctx->output;
+ c = list_entry(c->list.next, typeof(*c), list)) {
+ if (c->type != OUT_LABEL)
+ continue;
+ if (strcmp(c->labelname, labelref->name) == 0) {
+ /* Found */
+ address = c->address;
+ break;
+ }
+ }
+ break;
+ }
+
+ return address;
+}
+
+static void resolve_labels(struct assembler_context *ctx)
+{
+ struct code_output *c;
+ int addr;
+ int i;
+ unsigned int current_address;
+
+ /* Calculate the absolute addresses for each instruction. */
+recalculate_addresses:
+ current_address = 0;
+ list_for_each_entry(c, &ctx->output, list) {
+ switch (c->type) {
+ case OUT_INSN:
+ c->address = current_address;
+ current_address++;
+ break;
+ case OUT_LABEL:
+ c->address = current_address;
+ break;
+ }
+ }
+
+ /* Resolve the symbolic label references. */
+ list_for_each_entry(c, &ctx->output, list) {
+ switch (c->type) {
+ case OUT_INSN:
+ if (c->is_start_insn) {
+ /* If the first %start-jump jumps to 001, we can
+ * optimize it away, as it's unneeded.
+ */
+ i = 2;
+ if (c->operands[i].type != OUTOPER_LABELREF)
+ asm_error(ctx, "Internal error, %%start insn oper 2 not labelref");
+ if (c->operands[i].u.label->direction != LABELREF_ABSOLUTE)
+ asm_error(ctx, "%%start label reference not absolute");
+ addr = get_labeladdress(ctx, c, c->operands[i].u.label);
+ if (addr < 0)
+ goto does_not_exist;
+ if (addr == 1) {
+ list_del(&c->list); /* Kill it */
+ goto recalculate_addresses;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(c->operands); i++) {
+ if (c->operands[i].type != OUTOPER_LABELREF)
+ continue;
+ addr = get_labeladdress(ctx, c, c->operands[i].u.label);
+ if (addr < 0)
+ goto does_not_exist;
+ c->operands[i].u.operand = addr;
+ if (i != 2) /* Is not a jump target */
+ c->operands[i].u.operand |= 0xC00; /* Make it be an immediate */
+ }
+ break;
+ case OUT_LABEL:
+ break;
+ }
+ }
+
+ return;
+does_not_exist:
+ asm_error(ctx, "Label \"%s\" does not exist",
+ c->operands[i].u.label->name);
+}
+
+static void emit_code(struct assembler_context *ctx)
+{
+ FILE *fd;
+ char *fn;
+ size_t fn_len;
+ struct code_output *c;
+ uint64_t code;
+ unsigned char outbuf[8];
+ unsigned int insn_count = 0;
+ struct fw_header hdr;
+
+ fn_len = strlen(outfile_name) + 20;
+ fn = xmalloc(fn_len);
+ snprintf(fn, fn_len, "%s.ucode", outfile_name);
+ fd = fopen(fn, "w+");
+ if (!fd) {
+ fprintf(stderr, "Could not open microcode output file \"%s\"\n", fn);
+ free(fn);
+ exit(1);
+ }
+ if (IS_VERBOSE_DEBUG)
+ fprintf(stderr, "\nCode:\n");
+
+ list_for_each_entry(c, &ctx->output, list) {
+ switch (c->type) {
+ case OUT_INSN:
+ insn_count++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.type = FW_TYPE_UCODE;
+ hdr.ver = FW_HDR_VER;
+ hdr.size = cpu_to_be32(8 * insn_count);
+ if (fwrite(&hdr, sizeof(hdr), 1, fd) != 1) {
+ fprintf(stderr, "Could not write microcode outfile\n");
+ exit(1);
+ }
+
+ if (insn_count > NUM_INSN_LIMIT)
+ asm_warn(ctx, "Generating more than %d instructions. This "
+ "will overflow the device microcode memory.",
+ NUM_INSN_LIMIT);
+
+ list_for_each_entry(c, &ctx->output, list) {
+ switch (c->type) {
+ case OUT_INSN:
+ if (IS_VERBOSE_DEBUG) {
+ fprintf(stderr, "%03X %03X,%03X,%03X\n",
+ c->opcode,
+ c->operands[0].u.operand,
+ c->operands[1].u.operand,
+ c->operands[2].u.operand);
+ }
+ code = 0;
+
+ /* Instruction binary format is: xxyy yzzz 0000 oooX
+ * Big-Endian, X is the most significant part of Xxx.
+ */
+ code |= (c->opcode << 4);
+
+ code |= (((uint64_t)c->operands[0].u.operand & 0xF00) >> 8);
+ code |= (((uint64_t)c->operands[0].u.operand & 0x0FF) << 56);
+
+ code |= ((uint64_t)c->operands[1].u.operand << 44);
+
+ code |= ((uint64_t)c->operands[2].u.operand << 32);
+
+ outbuf[7] = (code & 0x00000000000000FFULL);
+ outbuf[6] = (code & 0x000000000000FF00ULL) >> 8;
+ outbuf[5] = (code & 0x0000000000FF0000ULL) >> 16;
+ outbuf[4] = (code & 0x00000000FF000000ULL) >> 24;
+ outbuf[3] = (code & 0x000000FF00000000ULL) >> 32;
+ outbuf[2] = (code & 0x0000FF0000000000ULL) >> 40;
+ outbuf[1] = (code & 0x00FF000000000000ULL) >> 48;
+ outbuf[0] = (code & 0xFF00000000000000ULL) >> 56;
+
+ if (fwrite(&outbuf, ARRAY_SIZE(outbuf), 1, fd) != 1) {
+ fprintf(stderr, "Could not write microcode outfile\n");
+ exit(1);
+ }
+ break;
+ case OUT_LABEL:
+ break;
+ }
+ }
+ fclose(fd);
+ free(fn);
+}
+
+static void assemble(void)
+{
+ struct assembler_context ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
+ INIT_LIST_HEAD(&ctx.output);
+
+ eval_directives(&ctx);
+ assemble_instructions(&ctx);
+ resolve_labels(&ctx);
+ emit_code(&ctx);
+}
+
+static void initialize(void)
+{
+ INIT_LIST_HEAD(&infile.sl);
+ INIT_LIST_HEAD(&infile.ivals);
+#ifdef YYDEBUG
+ if (IS_INSANE_DEBUG)
+ yydebug = 1;
+ else
+ yydebug = 0;
+#endif /* YYDEBUG */
+}
+
+int main(int argc, char **argv)
+{
+ int err, res = 1;
+
+ err = parse_args(argc, argv);
+ if (err)
+ goto out;
+ err = open_input_file();
+ if (err)
+ goto out;
+ initialize();
+ yyparse();
+ assemble();
+ assemble_initvals();
+ close_input_file();
+ res = 0;
+out:
+ /* Lazyman simply leaks all allocated memory. */
+ return res;
+}
--- /dev/null
+#ifndef BCM43xx_ASM_MAIN_H_
+#define BCM43xx_ASM_MAIN_H_
+
+#include <stdint.h>
+
+#include "list.h"
+#include "util.h"
+
+
+/* The header that fwcutter also puts in to every .fw file */
+struct fw_header {
+ /* Type of the firmware data */
+ uint8_t type;
+ /* Version number of the firmware data format */
+ uint8_t ver;
+ uint8_t __padding[2];
+ /* Size of the data. For ucode and PCM this is in bytes.
+ * For IV this is in number-of-ivs. (big-endian!) */
+ be32_t size;
+} __attribute__ ((__packed__));
+
+/* struct fw_header -> type */
+#define FW_TYPE_UCODE 'u'
+#define FW_TYPE_PCM 'p'
+#define FW_TYPE_IV 'i'
+/* struct fw_header -> ver */
+#define FW_HDR_VER 0x01
+
+
+/* Maximum number of allowed instructions in the code output.
+ * This is what device memory can hold at maximum.
+ */
+#define NUM_INSN_LIMIT 4096
+
+
+struct lineinfo {
+ char file[64];
+ char linecopy[128];
+ unsigned int lineno;
+ unsigned int column;
+};
+extern struct lineinfo cur_lineinfo;
+
+
+struct immediate {
+ unsigned int imm;
+};
+
+struct address {
+ unsigned int addr;
+};
+
+struct registr {
+ int type; /* SPR, GPR or OFFR */
+ unsigned int nr;
+};
+
+struct memory {
+ enum {
+ MEM_DIRECT,
+ MEM_INDIRECT,
+ } type;
+ /* Offset immediate */
+ unsigned int offset;
+ /* Offset Register number (only MEM_INDIRECT) */
+ unsigned int offr_nr;
+};
+
+struct label {
+ const char *name;
+
+ /* direction is only used for label references. */
+ enum {
+ LABELREF_ABSOLUTE,
+ LABELREF_RELATIVE_BACK,
+ LABELREF_RELATIVE_FORWARD,
+ } direction;
+};
+
+struct operand {
+ enum {
+ OPER_IMM,
+ OPER_REG,
+ OPER_MEM,
+ OPER_LABEL,
+ OPER_ADDR,
+ OPER_RAW,
+ } type;
+ union {
+ struct immediate *imm;
+ struct registr *reg;
+ struct memory *mem;
+ struct label *label;
+ struct address *addr;
+ unsigned int raw;
+ } u;
+};
+
+struct operlist {
+ struct operand *oper[5];
+};
+
+struct instruction {
+ int op;
+ struct operlist *operands;
+ unsigned int opcode; /* only for RAW */
+};
+
+struct asmdir {
+ enum {
+ ADIR_ARCH,
+ ADIR_START,
+ } type;
+ union {
+ enum {
+ OLDWORLD,
+ NEWWORLD,
+ } arch;
+ struct label *start;
+ } u;
+};
+
+struct statement {
+ enum {
+ STMT_INSN,
+ STMT_LABEL,
+ STMT_ASMDIR,
+ } type;
+ union {
+ struct instruction *insn;
+ struct label *label;
+ struct asmdir *asmdir;
+ } u;
+ struct lineinfo info;
+
+ struct list_head list;
+};
+
+
+struct file {
+ /* The (microcode) statement list */
+ struct list_head sl;
+ /* The initvals sections list */
+ struct list_head ivals;
+ /* The file descriptor */
+ int fd;
+};
+
+
+extern struct file infile;
+extern const char *infile_name;
+extern const char *outfile_name;
+
+#endif /* BCM43xx_ASM_MAIN_H_ */
--- /dev/null
+%{
+
+/*
+ * Copyright (C) 2006-2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include "main.h"
+#include "initvals.h"
+#include "util.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+extern char *yytext;
+extern void yyerror(char *);
+extern int yyparse(void);
+extern int yylex(void);
+
+static struct operand * store_oper_sanity(struct operand *oper);
+
+/* The current .section */
+extern int section;
+/* Pointer to the current initvals section data structure. */
+extern struct initvals_sect *cur_initvals_sect;
+
+%}
+
+%token SECTION_TEXT SECTION_IVALS
+
+%token ASM_ARCH ASM_START SPR GPR OFFR LR COMMA BRACK_OPEN BRACK_CLOSE PAREN_OPEN PAREN_CLOSE HEXNUM DECNUM ARCH_NEWWORLD ARCH_OLDWORLD LABEL IDENT LABELREF
+
+%token PLUS MINUS MULTIPLY DIVIDE BITW_OR BITW_AND BITW_XOR BITW_NOT LEFTSHIFT RIGHTSHIFT
+
+%token OP_ADD OP_ADDSC OP_ADDC OP_ADDSCC OP_SUB OP_SUBSC OP_SUBC OP_SUBSCC OP_SRA OP_OR OP_AND OP_XOR OP_SR OP_SRX OP_SL OP_RL OP_RR OP_NAND OP_ORX OP_MOV OP_JMP OP_JAND OP_JNAND OP_JS OP_JNS OP_JE OP_JNE OP_JLS OP_JGES OP_JGS OP_JLES OP_JL OP_JGE OP_JG OP_JLE OP_JZX OP_JNZX OP_JEXT OP_JNEXT OP_CALL OP_RET OP_TKIPH OP_TKIPHS OP_TKIPL OP_TKIPLS OP_NAP RAW_CODE
+
+%token IVAL_MMIO16 IVAL_MMIO32 IVAL_PHY IVAL_RADIO IVAL_SHM16 IVAL_SHM32
+
+%start line
+
+%%
+
+line : /* empty */
+ | line statement {
+ struct statement *s = $2;
+ if (section != SECTION_TEXT)
+ yyerror("Microcode text instruction in non .text section");
+ memcpy(&s->info, &cur_lineinfo, sizeof(struct lineinfo));
+ list_add_tail(&s->list, &infile.sl);
+ }
+ | line section_switch {
+ }
+ | line ivals_write {
+ struct initval_op *io = $2;
+ if (section != SECTION_IVALS)
+ yyerror("InitVals write in non .initvals section");
+ memcpy(&io->info, &cur_lineinfo, sizeof(struct lineinfo));
+ INIT_LIST_HEAD(&io->list);
+ list_add_tail(&io->list, &cur_initvals_sect->ops);
+ }
+ ;
+
+section_switch : SECTION_TEXT {
+ section = SECTION_TEXT;
+ }
+ | SECTION_IVALS PAREN_OPEN identifier PAREN_CLOSE {
+ const char *sectname = $3;
+ struct initvals_sect *s;
+ cur_initvals_sect = NULL;
+ /* Search if there already is a section by that name. */
+ list_for_each_entry(s, &infile.ivals, list) {
+ if (strcmp(sectname, s->name) == 0)
+ cur_initvals_sect = s;
+ }
+ if (!cur_initvals_sect) {
+ /* Not found, create a new one. */
+ s = xmalloc(sizeof(struct initvals_sect));
+ s->name = sectname;
+ INIT_LIST_HEAD(&s->ops);
+ INIT_LIST_HEAD(&s->list);
+ list_add_tail(&s->list, &infile.ivals);
+ cur_initvals_sect = s;
+ }
+ section = SECTION_IVALS;
+ }
+ ;
+
+ivals_write : IVAL_MMIO16 hexnum_decnum COMMA hexnum_decnum {
+ struct initval_op *iop = xmalloc(sizeof(struct initval_op));
+ iop->type = IVAL_W_MMIO16;
+ iop->args[0] = (unsigned int)(unsigned long)$2;
+ iop->args[1] = (unsigned int)(unsigned long)$4;
+ $$ = iop;
+ }
+ | IVAL_MMIO32 hexnum_decnum COMMA hexnum_decnum {
+ struct initval_op *iop = xmalloc(sizeof(struct initval_op));
+ iop->type = IVAL_W_MMIO32;
+ iop->args[0] = (unsigned int)(unsigned long)$2;
+ iop->args[1] = (unsigned int)(unsigned long)$4;
+ $$ = iop;
+ }
+ | IVAL_PHY hexnum_decnum COMMA hexnum_decnum {
+ struct initval_op *iop = xmalloc(sizeof(struct initval_op));
+ iop->type = IVAL_W_PHY;
+ iop->args[0] = (unsigned int)(unsigned long)$2;
+ iop->args[1] = (unsigned int)(unsigned long)$4;
+ $$ = iop;
+ }
+ | IVAL_RADIO hexnum_decnum COMMA hexnum_decnum {
+ struct initval_op *iop = xmalloc(sizeof(struct initval_op));
+ iop->type = IVAL_W_RADIO;
+ iop->args[0] = (unsigned int)(unsigned long)$2;
+ iop->args[1] = (unsigned int)(unsigned long)$4;
+ $$ = iop;
+ }
+ | IVAL_SHM16 hexnum_decnum COMMA hexnum_decnum COMMA hexnum_decnum {
+ struct initval_op *iop = xmalloc(sizeof(struct initval_op));
+ iop->type = IVAL_W_SHM16;
+ iop->args[0] = (unsigned int)(unsigned long)$2;
+ iop->args[1] = (unsigned int)(unsigned long)$4;
+ iop->args[2] = (unsigned int)(unsigned long)$6;
+ $$ = iop;
+ }
+ | IVAL_SHM32 hexnum_decnum COMMA hexnum_decnum COMMA hexnum_decnum {
+ struct initval_op *iop = xmalloc(sizeof(struct initval_op));
+ iop->type = IVAL_W_SHM32;
+ iop->args[0] = (unsigned int)(unsigned long)$2;
+ iop->args[1] = (unsigned int)(unsigned long)$4;
+ iop->args[2] = (unsigned int)(unsigned long)$6;
+ $$ = iop;
+ }
+ ;
+
+statement : asmdir {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_ASMDIR;
+ s->u.asmdir = $1;
+ $$ = s;
+ }
+ | label {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_LABEL;
+ s->u.label = $1;
+ $$ = s;
+ }
+ | insn_add {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_addsc {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_addc {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_addscc {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_sub {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_subsc {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_subc {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_subscc {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_sra {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_or {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_and {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_xor {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_sr {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_srx {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_sl {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_rl {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_rr {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_nand {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_orx {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_mov {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jmp {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jand {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jnand {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_js {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jns {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_je {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jne {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jls {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jges {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jgs {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jles {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jl {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jge {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jg {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jle {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jzx {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jnzx {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jext {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_jnext {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_call {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_ret {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_tkiph {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_tkiphs {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_tkipl {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_tkipls {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_nap {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ | insn_raw {
+ struct statement *s = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&s->list);
+ s->type = STMT_INSN;
+ s->u.insn = $1;
+ $$ = s;
+ }
+ ;
+
+/* ASM directives */
+asmdir : asmarch {
+ $$ = $1;
+ }
+ | ASM_START identifier {
+ struct asmdir *ad = xmalloc(sizeof(struct asmdir));
+ struct label *label = xmalloc(sizeof(struct label));
+ label->name = $2;
+ label->direction = LABELREF_ABSOLUTE;
+ ad->type = ADIR_START;
+ ad->u.start = label;
+ $$ = ad;
+ }
+ ;
+
+asmarch : ASM_ARCH ARCH_NEWWORLD {
+ struct asmdir *ad = xmalloc(sizeof(struct asmdir));
+ ad->type = ADIR_ARCH;
+ ad->u.arch = NEWWORLD;
+ $$ = ad;
+ }
+ | ASM_ARCH ARCH_OLDWORLD {
+ struct asmdir *ad = xmalloc(sizeof(struct asmdir));
+ ad->type = ADIR_ARCH;
+ ad->u.arch = OLDWORLD;
+ $$ = ad;
+ }
+ ;
+
+label : LABEL {
+ struct label *label = xmalloc(sizeof(struct label));
+ char *l;
+ l = xstrdup(yytext);
+ l[strlen(l) - 1] = '\0';
+ label->name = l;
+ $$ = label;
+ }
+ ;
+
+/* add */
+insn_add : OP_ADD operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_ADD;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+/* add. */
+insn_addsc : OP_ADDSC operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_ADDSC;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+/* addc */
+insn_addc : OP_ADDC operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_ADDC;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+/* addc. */
+insn_addscc : OP_ADDSCC operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_ADDSCC;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+/* sub */
+insn_sub : OP_SUB operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_SUB;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+/* sub. */
+insn_subsc : OP_SUBSC operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_SUBSC;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+/* subc */
+insn_subc : OP_SUBC operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_SUBC;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+/* subc. */
+insn_subscc : OP_SUBSCC operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_SUBSCC;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_sra : OP_SRA operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_SRA;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_or : OP_OR operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_OR;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_and : OP_AND operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_AND;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_xor : OP_XOR operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_XOR;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_sr : OP_SR operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_SR;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_srx : OP_SRX extended_operlist {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_SRX;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_sl : OP_SL operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_SL;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_rl : OP_RL operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_RL;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_rr : OP_RR operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_RR;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_nand : OP_NAND operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_NAND;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_orx : OP_ORX extended_operlist {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_ORX;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_mov : OP_MOV operlist_2 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_MOV;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jmp : OP_JMP labelref {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ ol->oper[0] = $2;
+ insn->op = OP_JMP;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
+insn_jand : OP_JAND operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JAND;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jnand : OP_JNAND operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JNAND;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_js : OP_JS operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JS;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jns : OP_JNS operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JNS;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_je : OP_JE operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JE;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jne : OP_JNE operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JNE;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jls : OP_JLS operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JLS;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jges : OP_JGES operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JGES;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jgs : OP_JGS operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JGS;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jles : OP_JLES operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JLES;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jl : OP_JL operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JL;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jge : OP_JGE operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JGE;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jg : OP_JG operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JG;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jle : OP_JLE operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JLE;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jzx : OP_JZX extended_operlist {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JZX;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jnzx : OP_JNZX extended_operlist {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JNZX;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jext : OP_JEXT external_jump_operands {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JEXT;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+insn_jnext : OP_JNEXT external_jump_operands {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = OP_JNEXT;
+ insn->operands = $2;
+ $$ = insn;
+ }
+ ;
+
+linkreg : LR regnr {
+ $$ = $2;
+ }
+ ;
+
+insn_call : OP_CALL linkreg COMMA labelref {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ struct operand *oper_lr = xmalloc(sizeof(struct operand));
+ struct operand *oper_zero = xmalloc(sizeof(struct operand));
+ oper_zero->type = OPER_RAW;
+ oper_zero->u.raw = 0;
+ oper_lr->type = OPER_RAW;
+ oper_lr->u.raw = (unsigned long)$2;
+ ol->oper[0] = oper_lr;
+ ol->oper[1] = oper_zero;
+ ol->oper[2] = $4;
+ insn->op = OP_CALL;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
+insn_ret : OP_RET linkreg COMMA linkreg {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ struct operand *oper_lr0 = xmalloc(sizeof(struct operand));
+ struct operand *oper_lr1 = xmalloc(sizeof(struct operand));
+ struct operand *oper_zero = xmalloc(sizeof(struct operand));
+ oper_zero->type = OPER_RAW;
+ oper_zero->u.raw = 0;
+ oper_lr0->type = OPER_RAW;
+ oper_lr0->u.raw = (unsigned long)$2;
+ oper_lr1->type = OPER_RAW;
+ oper_lr1->u.raw = (unsigned long)$4;
+ ol->oper[0] = oper_lr0;
+ ol->oper[1] = oper_zero;
+ ol->oper[2] = oper_lr1;
+ insn->op = OP_RET;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
+insn_tkiph : OP_TKIPH operlist_2 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = $2;
+ struct operand *flags = xmalloc(sizeof(struct operand));
+ struct immediate *imm = xmalloc(sizeof(struct immediate));
+ imm->imm = 0x1;
+ flags->type = OPER_IMM;
+ flags->u.imm = imm;
+ ol->oper[2] = ol->oper[1];
+ ol->oper[1] = flags;
+ insn->op = OP_TKIPH;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
+insn_tkiphs : OP_TKIPHS operlist_2 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = $2;
+ struct operand *flags = xmalloc(sizeof(struct operand));
+ struct immediate *imm = xmalloc(sizeof(struct immediate));
+ imm->imm = 0x1 | 0x2;
+ flags->type = OPER_IMM;
+ flags->u.imm = imm;
+ ol->oper[2] = ol->oper[1];
+ ol->oper[1] = flags;
+ insn->op = OP_TKIPH;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
+insn_tkipl : OP_TKIPL operlist_2 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = $2;
+ struct operand *flags = xmalloc(sizeof(struct operand));
+ struct immediate *imm = xmalloc(sizeof(struct immediate));
+ imm->imm = 0x0;
+ flags->type = OPER_IMM;
+ flags->u.imm = imm;
+ ol->oper[2] = ol->oper[1];
+ ol->oper[1] = flags;
+ insn->op = OP_TKIPH;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
+insn_tkipls : OP_TKIPLS operlist_2 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = $2;
+ struct operand *flags = xmalloc(sizeof(struct operand));
+ struct immediate *imm = xmalloc(sizeof(struct immediate));
+ imm->imm = 0x0 | 0x2;
+ flags->type = OPER_IMM;
+ flags->u.imm = imm;
+ ol->oper[2] = ol->oper[1];
+ ol->oper[1] = flags;
+ insn->op = OP_TKIPH;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
+insn_nap : OP_NAP {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ struct operand *regop = xmalloc(sizeof(struct operand));
+ struct operand *zeroop = xmalloc(sizeof(struct operand));
+ struct registr *r0 = xmalloc(sizeof(struct registr));
+ r0->type = GPR;
+ r0->nr = 0;
+ regop->type = OPER_REG;
+ regop->u.reg = r0;
+ zeroop->type = OPER_RAW;
+ zeroop->u.raw = 0x000;
+ ol->oper[0] = regop;
+ ol->oper[1] = regop;
+ ol->oper[2] = zeroop;
+ insn->op = OP_NAP;
+ insn->operands = ol;
+ $$ = insn;
+ }
+ ;
+
+insn_raw : raw_code operlist_3 {
+ struct instruction *insn = xmalloc(sizeof(struct instruction));
+ insn->op = RAW_CODE;
+ insn->operands = $2;
+ insn->opcode = (unsigned long)$1;
+ $$ = insn;
+ }
+ ;
+
+raw_code : RAW_CODE {
+ yytext++; /* skip @ */
+ $$ = (void *)(unsigned long)strtoul(yytext, NULL, 16);
+ }
+ ;
+
+extended_operlist : decnum COMMA decnum COMMA operand COMMA operand COMMA operand {
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ struct operand *mask_oper = xmalloc(sizeof(struct operand));
+ struct operand *shift_oper = xmalloc(sizeof(struct operand));
+ mask_oper->type = OPER_RAW;
+ mask_oper->u.raw = (unsigned long)$1;
+ shift_oper->type = OPER_RAW;
+ shift_oper->u.raw = (unsigned long)$3;
+ ol->oper[0] = mask_oper;
+ ol->oper[1] = shift_oper;
+ ol->oper[2] = $5;
+ ol->oper[3] = $7;
+ ol->oper[4] = store_oper_sanity($9);
+ $$ = ol;
+ }
+ ;
+
+external_jump_operands : hexnum COMMA operand COMMA operand COMMA labelref {
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ struct operand *cond = xmalloc(sizeof(struct operand));
+ cond->type = OPER_RAW;
+ cond->u.raw = (unsigned long)$1;
+ ol->oper[0] = cond;
+ ol->oper[1] = $3;
+ ol->oper[2] = $5;
+ ol->oper[3] = $7;
+ $$ = ol;
+ }
+ ;
+
+operlist_2 : operand COMMA operand {
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ ol->oper[0] = $1;
+ ol->oper[1] = store_oper_sanity($3);
+ $$ = ol;
+ }
+ ;
+
+operlist_3 : operand COMMA operand COMMA operand {
+ struct operlist *ol = xmalloc(sizeof(struct operlist));
+ ol->oper[0] = $1;
+ ol->oper[1] = $3;
+ ol->oper[2] = store_oper_sanity($5);
+ $$ = ol;
+ }
+ ;
+
+operand : reg {
+ struct operand *oper = xmalloc(sizeof(struct operand));
+ oper->type = OPER_REG;
+ oper->u.reg = $1;
+ $$ = oper;
+ }
+ | mem {
+ struct operand *oper = xmalloc(sizeof(struct operand));
+ oper->type = OPER_MEM;
+ oper->u.mem = $1;
+ $$ = oper;
+ }
+ | raw_code {
+ struct operand *oper = xmalloc(sizeof(struct operand));
+ oper->type = OPER_RAW;
+ oper->u.raw = (unsigned long)$1;
+ $$ = oper;
+ }
+ | imm {
+ struct operand *oper = xmalloc(sizeof(struct operand));
+ oper->type = OPER_IMM;
+ oper->u.imm = $1;
+ $$ = oper;
+ }
+ | labelref {
+ $$ = $1;
+ }
+ ;
+
+reg : GPR regnr {
+ struct registr *reg = xmalloc(sizeof(struct registr));
+ reg->type = GPR;
+ reg->nr = (unsigned long)$2;
+ $$ = reg;
+ }
+ | SPR {
+ struct registr *reg = xmalloc(sizeof(struct registr));
+ reg->type = SPR;
+ yytext += 3; /* skip "spr" */
+ reg->nr = strtoul(yytext, NULL, 16);
+ $$ = reg;
+ }
+ | OFFR regnr {
+ struct registr *reg = xmalloc(sizeof(struct registr));
+ reg->type = OFFR;
+ reg->nr = (unsigned long)$2;
+ $$ = reg;
+ }
+ ;
+
+mem : BRACK_OPEN hexnum_decnum BRACK_CLOSE {
+ struct memory *mem = xmalloc(sizeof(struct memory));
+ mem->type = MEM_DIRECT;
+ mem->offset = (unsigned long)$2;
+ $$ = mem;
+ }
+ | BRACK_OPEN hexnum_decnum COMMA OFFR regnr BRACK_CLOSE {
+ struct memory *mem = xmalloc(sizeof(struct memory));
+ mem->type = MEM_INDIRECT;
+ mem->offset = (unsigned long)$2;
+ mem->offr_nr = (unsigned long)$5;
+ $$ = mem;
+ }
+ ;
+
+imm : hexnum {
+ struct immediate *imm = xmalloc(sizeof(struct immediate));
+ imm->imm = (unsigned long)$1;
+ $$ = imm;
+ }
+ | decnum {
+ struct immediate *imm = xmalloc(sizeof(struct immediate));
+ imm->imm = (unsigned long)$1;
+ $$ = imm;
+ }
+ | complex_imm {
+ struct immediate *imm = xmalloc(sizeof(struct immediate));
+ imm->imm = (unsigned long)$1;
+ $$ = imm;
+ }
+ ;
+
+complex_imm : PAREN_OPEN complex_imm_arg complex_imm_oper complex_imm_arg PAREN_CLOSE {
+ unsigned long a = (unsigned long)$2;
+ unsigned long b = (unsigned long)$4;
+ unsigned long operation = (unsigned long)$3;
+ unsigned long res = 31337;
+ switch (operation) {
+ case PLUS:
+ res = a + b;
+ break;
+ case MINUS:
+ res = a - b;
+ break;
+ case MULTIPLY:
+ res = a * b;
+ break;
+ case DIVIDE:
+ res = a / b;
+ break;
+ case BITW_OR:
+ res = a | b;
+ break;
+ case BITW_AND:
+ res = a & b;
+ break;
+ case BITW_XOR:
+ res = a ^ b;
+ break;
+ case LEFTSHIFT:
+ res = a << b;
+ break;
+ case RIGHTSHIFT:
+ res = a >> b;
+ break;
+ default:
+ yyerror("Internal parser BUG. complex_imm oper unknown");
+ }
+ $$ = (void *)res;
+ }
+ | PAREN_OPEN complex_imm PAREN_CLOSE {
+ $$ = $2;
+ }
+ | PAREN_OPEN BITW_NOT complex_imm PAREN_CLOSE {
+ unsigned long n = (unsigned long)$3;
+ n = ~n;
+ $$ = (void *)n;
+ }
+ | PAREN_OPEN complex_imm_const PAREN_CLOSE {
+ $$ = $2;
+ }
+ ;
+
+complex_imm_oper : PLUS {
+ $$ = (void *)(unsigned long)PLUS;
+ }
+ | MINUS {
+ $$ = (void *)(unsigned long)MINUS;
+ }
+ | MULTIPLY {
+ $$ = (void *)(unsigned long)MULTIPLY;
+ }
+ | DIVIDE {
+ $$ = (void *)(unsigned long)DIVIDE;
+ }
+ | BITW_OR {
+ $$ = (void *)(unsigned long)BITW_OR;
+ }
+ | BITW_AND {
+ $$ = (void *)(unsigned long)BITW_AND;
+ }
+ | BITW_XOR {
+ $$ = (void *)(unsigned long)BITW_XOR;
+ }
+ | LEFTSHIFT {
+ $$ = (void *)(unsigned long)LEFTSHIFT;
+ }
+ | RIGHTSHIFT {
+ $$ = (void *)(unsigned long)RIGHTSHIFT;
+ }
+ ;
+
+complex_imm_arg : complex_imm_const {
+ $$ = $1;
+ }
+ | complex_imm {
+ $$ = $1;
+ }
+ ;
+
+complex_imm_const : hexnum_decnum {
+ $$ = $1;
+ }
+ | BITW_NOT hexnum_decnum {
+ unsigned long n = (unsigned long)$2;
+ n = ~n;
+ $$ = (void *)n;
+ }
+ ;
+
+hexnum : HEXNUM {
+ while (yytext[0] != 'x') {
+ if (yytext[0] == '\0')
+ yyerror("Internal HEXNUM parser error");
+ yytext++;
+ }
+ yytext++;
+ $$ = (void *)(unsigned long)strtoul(yytext, NULL, 16);
+ }
+ ;
+
+decnum : DECNUM {
+ $$ = (void *)(unsigned long)strtol(yytext, NULL, 10);
+ }
+ ;
+
+hexnum_decnum : hexnum {
+ $$ = $1;
+ }
+ | decnum {
+ $$ = $1;
+ }
+ ;
+
+labelref : identifier {
+ struct operand *oper = xmalloc(sizeof(struct operand));
+ struct label *label = xmalloc(sizeof(struct label));
+ label->name = $1;
+ label->direction = LABELREF_ABSOLUTE;
+ oper->type = OPER_LABEL;
+ oper->u.label = label;
+ $$ = oper;
+ }
+ | identifier MINUS {
+ struct operand *oper = xmalloc(sizeof(struct operand));
+ struct label *label = xmalloc(sizeof(struct label));
+ label->name = $1;
+ label->direction = LABELREF_RELATIVE_BACK;
+ oper->type = OPER_LABEL;
+ oper->u.label = label;
+ $$ = oper;
+ }
+ | identifier PLUS {
+ struct operand *oper = xmalloc(sizeof(struct operand));
+ struct label *label = xmalloc(sizeof(struct label));
+ label->name = $1;
+ label->direction = LABELREF_RELATIVE_FORWARD;
+ oper->type = OPER_LABEL;
+ oper->u.label = label;
+ $$ = oper;
+ }
+ ;
+
+regnr : DECNUM {
+ $$ = (void *)(unsigned long)strtoul(yytext, NULL, 10);
+ }
+ ;
+
+identifier : IDENT {
+ $$ = xstrdup(yytext);
+ }
+ ;
+
+%%
+
+int section = SECTION_TEXT; /* default to .text section */
+struct initvals_sect *cur_initvals_sect;
+
+void yyerror(char *str)
+{
+ unsigned int i;
+
+ fprintf(stderr,
+ "Parser ERROR (file \"%s\", line %u, col %u):\n",
+ cur_lineinfo.file,
+ cur_lineinfo.lineno,
+ cur_lineinfo.column);
+ fprintf(stderr, "%s\n", cur_lineinfo.linecopy);
+ for (i = 0; i < cur_lineinfo.column - 1; i++)
+ fprintf(stderr, " ");
+ fprintf(stderr, "^\n");
+ fprintf(stderr, "%s\n", str);
+ exit(1);
+}
+
+static struct operand * store_oper_sanity(struct operand *oper)
+{
+ if (oper->type == OPER_IMM &&
+ oper->u.imm->imm != 0) {
+ yyerror("Only 0x000 Immediate is allowed for "
+ "Output operands");
+ }
+ return oper;
+}
--- /dev/null
+%{
+
+/*
+ * Copyright (C) 2006-2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include "parser.h"
+#include "main.h"
+
+#include <stdio.h>
+
+#undef min
+#define min(x,y) ((x) < (y) ? (x) : (y))
+
+
+static void interpret_cppinfo(const char *);
+static void update_lineinfo(void);
+
+static inline void log_current_line(void)
+{
+ size_t len;
+
+ len = min(sizeof(cur_lineinfo.linecopy) - 1, strlen(yytext));
+ strncpy(cur_lineinfo.linecopy, yytext, len);
+ cur_lineinfo.linecopy[len] = '\0';
+}
+
+%}
+
+IDENTIFIER ([a-zA-Z_][0-9a-zA-Z_]*)
+WS ([ \t])
+NEWLINE ((\r)|(\n)|(\r\n))
+
+%%
+
+^.*$ { log_current_line(); REJECT; }
+#\ [0-9]+\ \".*\"[ ]*[0-9]*{NEWLINE} { interpret_cppinfo(yytext); }
+
+
+{WS}+ { update_lineinfo(); /* whitespace */ }
+{NEWLINE} { cur_lineinfo.lineno++; update_lineinfo(); }
+;.*$ { update_lineinfo(); /* comment */ }
+
+^{WS}*"%"{WS}*arch { update_lineinfo(); return ASM_ARCH; }
+^{WS}*"%"{WS}*start { update_lineinfo(); return ASM_START; }
+
+^{WS}*\.text{WS}*$ { update_lineinfo(); return SECTION_TEXT; }
+^{WS}*\.initvals/\({IDENTIFIER}\){WS}*{NEWLINE} { update_lineinfo(); return SECTION_IVALS; }
+
+spr[0-9a-fA-F]{3,3} { update_lineinfo(); return SPR; }
+r/([0-9]|([1-5][0-9])|(6[0-3])) { update_lineinfo(); return GPR; }
+off/[0-6] { update_lineinfo(); return OFFR; }
+lr/[0-3] { update_lineinfo(); return LR; }
+
+, { update_lineinfo(); return COMMA; }
+\[ { update_lineinfo(); return BRACK_OPEN; }
+\] { update_lineinfo(); return BRACK_CLOSE; }
+\( { update_lineinfo(); return PAREN_OPEN; }
+\) { update_lineinfo(); return PAREN_CLOSE; }
+
+\+ { update_lineinfo(); return PLUS; }
+\- { update_lineinfo(); return MINUS; }
+\* { update_lineinfo(); return MULTIPLY; }
+\/ { update_lineinfo(); return DIVIDE; }
+\| { update_lineinfo(); return BITW_OR; }
+\& { update_lineinfo(); return BITW_AND; }
+\^ { update_lineinfo(); return BITW_XOR; }
+\~ { update_lineinfo(); return BITW_NOT; }
+\<\< { update_lineinfo(); return LEFTSHIFT; }
+\>\> { update_lineinfo(); return RIGHTSHIFT; }
+
+add { update_lineinfo(); return OP_ADD; }
+add\. { update_lineinfo(); return OP_ADDSC; }
+addc { update_lineinfo(); return OP_ADDC; }
+addc\. { update_lineinfo(); return OP_ADDSCC; }
+
+sub { update_lineinfo(); return OP_SUB; }
+sub\. { update_lineinfo(); return OP_SUBSC; }
+subc { update_lineinfo(); return OP_SUBC; }
+subc\. { update_lineinfo(); return OP_SUBSCC; }
+
+sra { update_lineinfo(); return OP_SRA; }
+or { update_lineinfo(); return OP_OR; }
+and { update_lineinfo(); return OP_AND; }
+xor { update_lineinfo(); return OP_XOR; }
+sr { update_lineinfo(); return OP_SR; }
+srx { update_lineinfo(); return OP_SRX; }
+sl { update_lineinfo(); return OP_SL; }
+rl { update_lineinfo(); return OP_RL; }
+rr { update_lineinfo(); return OP_RR; }
+nand { update_lineinfo(); return OP_NAND; }
+orx { update_lineinfo(); return OP_ORX; }
+mov { update_lineinfo(); return OP_MOV; }
+
+jmp { update_lineinfo(); return OP_JMP; }
+jand { update_lineinfo(); return OP_JAND; }
+jnand { update_lineinfo(); return OP_JNAND; }
+js { update_lineinfo(); return OP_JS; }
+jns { update_lineinfo(); return OP_JNS; }
+je { update_lineinfo(); return OP_JE; }
+jne { update_lineinfo(); return OP_JNE; }
+jls { update_lineinfo(); return OP_JLS; }
+jges { update_lineinfo(); return OP_JGES; }
+jgs { update_lineinfo(); return OP_JGS; }
+jles { update_lineinfo(); return OP_JLES; }
+jl { update_lineinfo(); return OP_JL; }
+jge { update_lineinfo(); return OP_JGE; }
+jg { update_lineinfo(); return OP_JG; }
+jle { update_lineinfo(); return OP_JLE; }
+jzx { update_lineinfo(); return OP_JZX; }
+jnzx { update_lineinfo(); return OP_JNZX; }
+jext { update_lineinfo(); return OP_JEXT; }
+jnext { update_lineinfo(); return OP_JNEXT; }
+
+call { update_lineinfo(); return OP_CALL; }
+ret { update_lineinfo(); return OP_RET; }
+
+tkiph { update_lineinfo(); return OP_TKIPH; }
+tkiphs { update_lineinfo(); return OP_TKIPHS; }
+tkipl { update_lineinfo(); return OP_TKIPL; }
+tkipls { update_lineinfo(); return OP_TKIPLS; }
+
+nap { update_lineinfo(); return OP_NAP; }
+
+mmio16 { update_lineinfo(); return IVAL_MMIO16; }
+mmio32 { update_lineinfo(); return IVAL_MMIO32; }
+phy { update_lineinfo(); return IVAL_PHY; }
+radio { update_lineinfo(); return IVAL_RADIO; }
+shm16 { update_lineinfo(); return IVAL_SHM16; }
+shm32 { update_lineinfo(); return IVAL_SHM32; }
+
+@[0-9a-fA-F]{3,3} { update_lineinfo(); return RAW_CODE; }
+
+0x[0-9a-fA-F]+ { update_lineinfo(); return HEXNUM; }
+-?[0-9]+ { update_lineinfo(); return DECNUM; }
+
+bcm43xx_newworld { update_lineinfo(); return ARCH_NEWWORLD; }
+bcm43xx_oldworld { update_lineinfo(); return ARCH_OLDWORLD; }
+
+{IDENTIFIER}: { update_lineinfo(); return LABEL; }
+{IDENTIFIER} { update_lineinfo(); return IDENT; }
+
+%%
+
+struct lineinfo cur_lineinfo;
+
+static void interpret_cppinfo(const char *str)
+{
+ const char * const orig = str;
+ char tmp[64];
+ char *found;
+
+ /* This will interpret lines added by CPP.
+ * They look like:
+ * # 3 "file.asm" 1
+ */
+
+ if (*str == '\0')
+ goto error;
+ str++; /* skip # character */
+ if (*str == '\0')
+ goto error;
+ str++; /* skip whitespace */
+
+ /* Line number */
+ found = strchr(str, ' ');
+ if (!found)
+ goto error;
+ memset(tmp, 0, sizeof(tmp));
+ memcpy(tmp, str, min(sizeof(tmp) - 1,
+ (int)(found - str)));
+ cur_lineinfo.lineno = strtoul(tmp, NULL, 10);
+ str = found;
+ str++;
+
+ /* File name */
+ if (*str != '\"')
+ goto error;
+ str++;
+ if (*str == '\0')
+ goto error;
+ found = strchr(str, '\"');
+ if (!found)
+ goto error;
+ memset(cur_lineinfo.file, 0, sizeof(cur_lineinfo.file));
+ memcpy(cur_lineinfo.file, str,
+ min(sizeof(cur_lineinfo.file) - 1,
+ (int)(found - str)));
+
+ if (strcmp(cur_lineinfo.file, "<stdin>") == 0)
+ strcpy(cur_lineinfo.file, "Input File");
+
+ return;
+error:
+ fprintf(stderr, "Invalid CPP line directive: %s\n", orig);
+ exit(1);
+}
+
+static void update_lineinfo(void)
+{
+ int i = 0;
+
+ while (yytext[i] != '\0') {
+ switch (yytext[i]) {
+ case '\r':
+ case '\n':
+ cur_lineinfo.column = 0;
+ break;
+ case '\t':
+ cur_lineinfo.column += 8 - (cur_lineinfo.column % 8);
+ break;
+ default:
+ cur_lineinfo.column++;
+ }
+ i++;
+ }
+}
--- /dev/null
+; This is a bcm43xx microcode assembly example.
+;
+; In this example file, r0 and r1 are always input
+; registers and r2 is output.
+; For input we can always have constant values or (one) memory
+; operand instead of the input registers shown here.
+;
+; Registers:
+; GPRs: r0 - r63
+; Offset Registers: off0 - off5
+; SPRs: spr000
+;
+; To access memory, two methods can be used. Examples follow.
+; Direct linear:
+; mov r0,[0xCA]
+; Indirect through Offset Register (pointer):
+; mov r0,[0xCA,off0]
+;
+
+
+%arch bcm43xx_newworld ; or bcm43xx-oldworld
+%start testlabel
+
+#define PSM_BRC spr848
+
+#define ECOND_MAC_ON 0x24
+
+
+.text
+
+label:
+ ; ADD instructions
+ add r0,r1,r2 ; add
+ add. r0,r1,r2 ; add, set carry
+ addc r0,r1,r2 ; add with carry
+ addc. r0,r1,r2 ; add with carry, set carry
+
+testlabel:
+ ; SUB instructions
+ sub r0,r1,r2 ; sub
+ sub. r0,r1,r2 ; sub, set carry
+ subc r0,r1,r2 ; sub with carry
+ subc. r0,r1,r2 ; sub with carry, set carry
+
+ sra r0,r1,r2 ; arithmetic rightshift
+
+ ; Logical instructions
+ or r0,r1,r2 ; bitwise OR
+ and r0,r1,r2 ; bitwise AND
+ xor r0,r1,r2 ; bitwise XOR
+ sr r0,r1,r2 ; rightshift
+ sl r0,r1,r2 ; leftshift
+
+ srx 7,8,r0,r1,r2 ; eXtended right shift (two input regs)
+
+ rl r0,r1,r2 ; rotate left
+ rr r0,r1,r2 ; rotate right
+ nand r0,r1,r2 ; clear bits (notmask + and)
+
+ orx 7,8,r0,r1,r2 ; eXtended OR
+
+ ; Copy instruction. This is a virtual instruction
+ ; translated to more lowlevel stuff like OR.
+ mov r0,r2 ; copy data
+
+ ; Jumps
+ jmp label ; unconditional jump
+ jand r0,r1,label ; jump if binary AND
+ jnand r0,r1,label ; jump if not binary AND
+ js r0,r1,label ; jump if all bits set
+ jns r0,r1,label ; jump if not all bits set
+ je r0,r1,label ; jump if equal
+ jne r0,r1,label ; jump if not equal
+ jls r0,r1,label ; jump if less (signed)
+ jges r0,r1,label ; jump if greater or equal (signed)
+ jgs r0,r1,label ; jump if greater (signed)
+ jles r0,r1,label ; jump if less or equal (signed)
+ jl r0,r1,label ; jump if less
+ jge r0,r1,label ; jump if greater or equal
+ jg r0,r1,label ; jump if greater
+ jle r0,r1,label ; jump if less or equal
+
+ jzx 7,8,r0,r1,label ; Jump if zero after shift and mask
+ jnzx 7,8,r0,r1,label ; Jump if nonzero after shift and mask
+
+ ; jump on external conditions
+ jext ECOND_MAC_ON,r0,r0,label ; jump if external condition is TRUE
+ jnext ECOND_MAC_ON,r0,r0,label ; jump if external condition is FALSE
+
+ ; Subroutines
+ call lr0,label ; store PC in lr0, call func at label
+ ret lr0,lr1 ; store PC in lr0, return to lr1
+ ; Both link registers can be the same
+ ; and don't interfere.
+
+ ; TKIP sbox lookup
+ tkiph r0,r2 ; Lookup high
+ tkiphs r0,r2 ; Lookup high, byteswap
+ tkipl r0,r2 ; Lookup low
+ tkipls r0,r2 ; Lookup low, byteswap
+
+ nap ; sleep until event
+
+ ; raw instruction
+ @160 r0,r1,r2 ; equivalent to or r0,r1,r2
+ @1C0 @C11, @C22, @BC3
+
+
+ ; Support for directional jumps.
+ ; Directional jumps can be used to conveniently jump inside of
+ ; functions without using function specific label prefixes. Note
+ ; that this does not establish a sub-namespace, though. "loop"
+ ; and "out" are still in the global namespace and can't be used
+ ; anymore for absolute jumps (Assembler will warn about duplication).
+function_a:
+ jl r0, r1, out+
+ loop:
+ nap
+ jmp loop-
+ out:
+ ret lr0, lr1
+
+function_b:
+ jl r0, r1, out+
+ loop:
+ nap
+ jmp loop-
+ out:
+ ret lr0, lr1
+
+
+; The assembler has support for fancy assemble-time
+; immediate constant expansion. This is called "complex immediates".
+; Complex immediates are _always_ clamped by parentheses. There is no
+; operator precedence. You must use parentheses to tell precedence.
+ mov (2 + 3),r0
+ mov (6 - 2),r0
+ mov (2 * 3),r0
+ mov (10 / 5),r0
+ mov (1 | 2),r0
+ mov (3 & 2),r0
+ mov (3 ^ 2),r0
+ mov (~1),r0
+ mov (2 << 3),r0
+ mov (8 >> 2),r0
+ mov (1 << (0x3 + 2)),r0
+ mov (1 + (2 + (3 + 4))),r0
+ mov (4 >> (((((~5 | 0x21)))) | (~((10) & 2)))),r0
+
+
+; Some regression testing for the assembler follows
+ mov 2,off0 ; test memory stuff
+ xor 0x124,r1,[0x0,off0] ; test memory stuff
+ xor 0x124,r0,[0x0] ; test memory stuff
+ mov -34,r0 ; negative dec numbers are supported
+ or r0,r1,@BC2 ; We also support single raw operands
+ mov 0xEEEE,r0 ; MOV supports up to 16bit
+ jand 0x3800,r0,label ; This is emulated by jnzx
+ jnand 0x3800,r0,label ; This is emulated by jzx
+ or spr06c,0,spr06c ; Can have one spr input and one spr output
+ or [0],0,[0] ; Can have one mem input and one mem output
+ mov testlabel, r0 ; Can use label as immediate value
+
+
+; The .initvals section generates an "Initial Values" file
+; with the name "foobar" in this example, which is uploaded
+; by the kernel driver on load. This is useful for writing ucode
+; specific values to the chip without bloating the small ucode
+; memory space with this initialization stuff.
+; Values are written in order they appear here.
+.initvals(foobar)
+ mmio16 0x1234, 0xABC ; Write 0x1234 to MMIO register 0xABC
+ mmio32 0x12345678, 0xABC ; Write 0x12345678 to MMIO register 0xABC
+ phy 0x1234, 0xABC ; Write 0x1234 to PHY register 0xABC
+ radio 0x1234, 0xABC ; Write 0x1234 to RADIO register 0xABC
+ shm16 0x1234, 0x0001, 0x0002 ; Write 0x1234 to SHM routing 0x0001, register 0x0002
+ shm32 0x12345678, 0x0001, 0x0002 ; Write 0x12345678 to SHM routing 0x0001, register 0x0002
--- /dev/null
+/*
+ * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include "util.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+void dump(const char *data,
+ size_t size,
+ const char *description)
+{
+ size_t i;
+ char c;
+
+ fprintf(stderr, "Data dump (%s, %zd bytes):",
+ description, size);
+ for (i = 0; i < size; i++) {
+ c = data[i];
+ if (i % 8 == 0) {
+ fprintf(stderr, "\n0x%08zx: 0x%02x, ",
+ i, c & 0xff);
+ } else
+ fprintf(stderr, "0x%02x, ", c & 0xff);
+ }
+ fprintf(stderr, "\n");
+}
+
+void * xmalloc(size_t size)
+{
+ void *p;
+
+ p = malloc(size);
+ if (!p) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ memset(p, 0, size);
+
+ return p;
+}
+
+char * xstrdup(const char *str)
+{
+ char *c;
+
+ c = strdup(str);
+ if (!c) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+
+ return c;
+}
+
+be16_t cpu_to_be16(uint16_t x)
+{
+ be16_t ret;
+ uint8_t *tmp = (uint8_t *)(&ret);
+
+ tmp[0] = (x & 0xFF00) >> 8;
+ tmp[1] = (x & 0x00FF);
+
+ return ret;
+}
+
+be32_t cpu_to_be32(uint32_t x)
+{
+ be32_t ret;
+ uint8_t *tmp = (uint8_t *)(&ret);
+
+ tmp[0] = (x & 0xFF000000) >> 24;
+ tmp[1] = (x & 0x00FF0000) >> 16;
+ tmp[2] = (x & 0x0000FF00) >> 8;
+ tmp[3] = (x & 0x000000FF);
+
+ return ret;
+}
--- /dev/null
+#ifndef BCM43xx_ASM_UTIL_H_
+#define BCM43xx_ASM_UTIL_H_
+
+#include <stdlib.h>
+#include <stdint.h>
+
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+
+void dump(const char *data,
+ size_t size,
+ const char *description);
+
+
+void * xmalloc(size_t size);
+char * xstrdup(const char *str);
+
+
+typedef _Bool bool;
+
+typedef uint16_t be16_t;
+typedef uint32_t be32_t;
+
+be16_t cpu_to_be16(uint16_t x);
+be32_t cpu_to_be32(uint32_t x);
+
+#endif /* BCM43xx_ASM_UTIL_H_ */
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null
+CC = gcc
+PREFIX = /usr/local
+CFLAGS = -std=gnu99 -O2 -fomit-frame-pointer -Wall -D_BSD_SOURCE -D_GNU_SOURCE
+LDFLAGS =
+
+BINARY = bcm43xx-dasm.bin
+OBJECTS = main.o util.o
+
+all: $(BINARY)
+
+main.o: util.h list.h
+
+util.o: util.h
+
+$(BINARY): $(OBJECTS)
+ $(CC) $(CFLAGS) -o $(BINARY) $(OBJECTS) $(LDFLAGS)
+
+install: all
+ -install -o 0 -g 0 -m 755 $(BINARY) $(PREFIX)/bin/
+ -cp bcm43xx-dasm bcm43xx-dasm.inst
+ -sed -i -e 's/installed=0/installed=1/' bcm43xx-dasm.inst
+ -install -o 0 -g 0 -m 755 bcm43xx-dasm.inst $(PREFIX)/bin/bcm43xx-dasm
+ -rm -f bcm43xx-dasm.inst
+
+clean:
+ -rm -f *~ *.o *.orig *.rej $(BINARY)
--- /dev/null
+#!/bin/sh
+
+installed=0
+
+if [ $# -ne 2 ]; then
+ echo "Usage: $0 input_file.fw output_file.asm"
+ exit 1
+fi
+
+if [ -z "$BCM43xx_DASM" ]; then
+ if [ $installed -eq 0 ] && [ -x "./bcm43xx-dasm.bin" ]; then
+ BCM43xx_DASM="./bcm43xx-dasm.bin"
+ else
+ BCM43xx_DASM="bcm43xx-dasm.bin"
+ fi
+fi
+
+infile="$1"
+outfile="$2"
+
+cat "$infile" | $BCM43xx_DASM "$outfile"
+
--- /dev/null
+/*
+ * Copied from the Linux kernel source tree, version 2.6.0-test1.
+ *
+ * Licensed under the GPL v2 as per the whole kernel source tree.
+ *
+ */
+
+#ifndef _LIST_H
+#define _LIST_H
+
+#ifndef __GNUC__
+# error "Need GNU GCC"
+#endif
+
+#define typeof __typeof__
+#define offsetof(type, member) __builtin_offsetof (type, member)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#endif /* _LIST_H */
--- /dev/null
+/*
+ * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include "list.h"
+#include "util.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+/* The header that fwcutter puts in to every .fw file */
+struct fw_header {
+ /* Type of the firmware data */
+ uint8_t type;
+ /* Version number of the firmware data format */
+ uint8_t ver;
+ uint8_t __padding[2];
+ /* Size of the data. For ucode and PCM this is in bytes.
+ * For IV this is in number-of-ivs. */
+ uint32_t size;
+} __attribute__ ((__packed__));
+
+
+struct bin_instruction {
+ unsigned int opcode;
+ unsigned int operands[3];
+};
+
+struct statement {
+ enum {
+ STMT_INSN,
+ STMT_LABEL,
+ } type;
+
+ union {
+ struct {
+ struct bin_instruction *bin;
+ const char *name;
+ const char *operands[5];
+
+ int is_labelref;
+ unsigned int labeladdr;
+ struct statement *labelref;
+ } insn;
+ struct {
+ char *name;
+ } label;
+ } u;
+
+ struct list_head list;
+};
+
+struct disassembler_context {
+ struct bin_instruction *code;
+ size_t nr_insns;
+
+ struct list_head stmt_list;
+};
+
+
+static FILE *infile;
+const char *outfile_name;
+
+
+static const char * gen_raw_code(unsigned int operand)
+{
+ char *ret;
+
+ ret = xmalloc(5);
+ snprintf(ret, 5, "@%03X", operand);
+
+ return ret;
+}
+
+static const char * disasm_mem_operand(unsigned int operand)
+{
+ char *ret;
+
+ ret = xmalloc(8);
+ snprintf(ret, 8, "[0x%03X]", operand);
+
+ return ret;
+}
+
+static const char * disasm_indirect_mem_operand(unsigned int operand)
+{
+ char *ret;
+
+ ret = xmalloc(12);
+ snprintf(ret, 12, "[0x%02X,off%u]",
+ (operand & 0x3F), ((operand >> 6) & 0x7));
+
+ return ret;
+}
+
+static const char * disasm_imm_operand(unsigned int operand)
+{
+ char *ret;
+
+ operand &= ~0xC00;
+
+ ret = xmalloc(7);
+ if (operand & (1 << 9))
+ snprintf(ret, 7, "0x%04X", (operand | 0xFC00));
+ else
+ snprintf(ret, 7, "0x%03X", operand);
+
+ return ret;
+}
+
+static const char * disasm_spr_operand(unsigned int operand)
+{
+ char *ret;
+
+ ret = xmalloc(7);
+ snprintf(ret, 7, "spr%03X", (operand & 0x1FF));
+
+ return ret;
+}
+
+static const char * disasm_gpr_operand(unsigned int operand)
+{
+ char *ret;
+
+ ret = xmalloc(4);
+ snprintf(ret, 4, "r%u", (operand & 0x3F));
+
+ return ret;
+}
+
+static const char * disasm_offr_operand(unsigned int operand)
+{
+ char *ret;
+
+ ret = xmalloc(5);
+ snprintf(ret, 5, "off%u", (operand & 0x7));
+
+ return ret;
+}
+
+static void disasm_std_operand(struct statement *stmt,
+ int oper_idx,
+ int out_idx,
+ int forceraw)
+{
+ unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
+
+ if (forceraw)
+ goto raw;
+
+ if (!(operand & 0x800)) {
+ stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
+ return;
+ } else if ((operand & 0xC00) == 0xC00) {
+ stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
+ return;
+ } else if ((operand & 0xFC0) == 0xBC0) {
+ stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
+ return;
+ } else if ((operand & 0xE00) == 0x800) {
+ stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
+ return;
+ } else if ((operand & 0xFF8) == 0x860) {
+ stmt->u.insn.operands[out_idx] = disasm_offr_operand(operand);
+ return;
+ } else if ((operand & 0xE00) == 0xA00) {
+ stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
+ return;
+ }
+raw:
+ stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
+}
+
+static void disasm_constant_opcodes(struct disassembler_context *ctx,
+ struct statement *stmt)
+{
+ struct bin_instruction *bin = stmt->u.insn.bin;
+
+ switch (bin->opcode) {
+ case 0x1C0:
+ stmt->u.insn.name = "add";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x1C2:
+ stmt->u.insn.name = "add.";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x1C1:
+ stmt->u.insn.name = "addc";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x1C3:
+ stmt->u.insn.name = "addc.";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x1D0:
+ stmt->u.insn.name = "sub";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x1D2:
+ stmt->u.insn.name = "sub.";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x1D1:
+ stmt->u.insn.name = "subc";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x1D3:
+ stmt->u.insn.name = "subc.";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x130:
+ stmt->u.insn.name = "sra";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x160:
+ stmt->u.insn.name = "or";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x140:
+ stmt->u.insn.name = "and";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x170:
+ stmt->u.insn.name = "xor";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x120:
+ stmt->u.insn.name = "sr";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x110:
+ stmt->u.insn.name = "sl";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x1A0:
+ stmt->u.insn.name = "rl";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x1B0:
+ stmt->u.insn.name = "rr";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x150:
+ stmt->u.insn.name = "nand";
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ case 0x040:
+ stmt->u.insn.name = "jand";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case (0x040 | 0x1):
+ stmt->u.insn.name = "jnand";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case 0x050:
+ stmt->u.insn.name = "js";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case (0x050 | 0x1):
+ stmt->u.insn.name = "jns";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case 0x0D0:
+ stmt->u.insn.name = "je";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case (0x0D0 | 0x1):
+ stmt->u.insn.name = "jne";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case 0x0D2:
+ stmt->u.insn.name = "jls";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case (0x0D2 | 0x1):
+ stmt->u.insn.name = "jges";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case 0x0D4:
+ stmt->u.insn.name = "jgs";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case (0x0D4 | 0x1):
+ stmt->u.insn.name = "jles";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case 0x0DA:
+ stmt->u.insn.name = "jl";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case (0x0DA | 0x1):
+ stmt->u.insn.name = "jge";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case 0x0DC:
+ stmt->u.insn.name = "jg";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case (0x0DC | 0x1):
+ stmt->u.insn.name = "jle";
+ stmt->u.insn.is_labelref = 2;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 1, 1, 0);
+ break;
+ case 0x002: {
+ char *str;
+
+ stmt->u.insn.name = "call";
+ stmt->u.insn.is_labelref = 1;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ str = xmalloc(4);
+ snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
+ stmt->u.insn.operands[0] = str;
+ break;
+ }
+ case 0x003: {
+ char *str;
+
+ stmt->u.insn.name = "ret";
+ str = xmalloc(4);
+ snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
+ stmt->u.insn.operands[0] = str;
+ str = xmalloc(4);
+ snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[2]);
+ stmt->u.insn.operands[2] = str;
+ break;
+ }
+ case 0x1E0: {
+ unsigned int flags;
+
+ flags = stmt->u.insn.bin->operands[1];
+ switch (flags & ~0xC00) {
+ case 0x1:
+ stmt->u.insn.name = "tkiph";
+ break;
+ case (0x1 | 0x2):
+ stmt->u.insn.name = "tkiphs";
+ break;
+ case 0x0:
+ stmt->u.insn.name = "tkipl";
+ break;
+ case (0x0 | 0x2):
+ stmt->u.insn.name = "tkipls";
+ break;
+ default:
+ fprintf(stderr, "Invalid TKIP flags %X\n",
+ flags);
+ exit(1);
+ }
+ disasm_std_operand(stmt, 0, 0, 0);
+ disasm_std_operand(stmt, 2, 2, 0);
+ break;
+ }
+ case 0x001: {
+ stmt->u.insn.name = "nap";
+ if (stmt->u.insn.bin->operands[0] != 0xBC0) {
+ fprintf(stderr, "NAP: invalid first argument 0x%03X\n",
+ stmt->u.insn.bin->operands[0]);
+ }
+ if (stmt->u.insn.bin->operands[1] != 0xBC0) {
+ fprintf(stderr, "NAP: invalid second argument 0x%03X\n",
+ stmt->u.insn.bin->operands[1]);
+ }
+ if (stmt->u.insn.bin->operands[2] != 0x000) {
+ fprintf(stderr, "NAP: invalid third argument 0x%03X\n",
+ stmt->u.insn.bin->operands[2]);
+ }
+ break;
+ }
+ default:
+ stmt->u.insn.name = gen_raw_code(bin->opcode);
+ disasm_std_operand(stmt, 0, 0, 1);
+ disasm_std_operand(stmt, 1, 1, 1);
+ disasm_std_operand(stmt, 2, 2, 1);
+ break;
+ }
+}
+
+static void disasm_opcodes(struct disassembler_context *ctx)
+{
+ struct bin_instruction *bin;
+ size_t i;
+ struct statement *stmt;
+ char *str;
+
+ for (i = 0; i < ctx->nr_insns; i++) {
+ bin = &(ctx->code[i]);
+
+ stmt = xmalloc(sizeof(struct statement));
+ stmt->type = STMT_INSN;
+ INIT_LIST_HEAD(&stmt->list);
+ stmt->u.insn.bin = bin;
+ stmt->u.insn.is_labelref = -1;
+
+ switch (bin->opcode & 0xF00) {
+ case 0x200:
+ stmt->u.insn.name = "srx";
+
+ str = xmalloc(3);
+ snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
+ stmt->u.insn.operands[0] = str;
+ str = xmalloc(3);
+ snprintf(str, 3, "%d", (bin->opcode & 0x00F));
+ stmt->u.insn.operands[1] = str;
+
+ disasm_std_operand(stmt, 0, 2, 0);
+ disasm_std_operand(stmt, 1, 3, 0);
+ disasm_std_operand(stmt, 2, 4, 0);
+ break;
+ case 0x300:
+ stmt->u.insn.name = "orx";
+
+ str = xmalloc(3);
+ snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
+ stmt->u.insn.operands[0] = str;
+ str = xmalloc(3);
+ snprintf(str, 3, "%d", (bin->opcode & 0x00F));
+ stmt->u.insn.operands[1] = str;
+
+ disasm_std_operand(stmt, 0, 2, 0);
+ disasm_std_operand(stmt, 1, 3, 0);
+ disasm_std_operand(stmt, 2, 4, 0);
+ break;
+ case 0x400:
+ stmt->u.insn.name = "jzx";
+
+ str = xmalloc(3);
+ snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
+ stmt->u.insn.operands[0] = str;
+ str = xmalloc(3);
+ snprintf(str, 3, "%d", (bin->opcode & 0x00F));
+ stmt->u.insn.operands[1] = str;
+
+ disasm_std_operand(stmt, 0, 2, 0);
+ disasm_std_operand(stmt, 1, 3, 0);
+ stmt->u.insn.is_labelref = 4;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ break;
+ case 0x500:
+ stmt->u.insn.name = "jnzx";
+
+ str = xmalloc(3);
+ snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
+ stmt->u.insn.operands[0] = str;
+ str = xmalloc(3);
+ snprintf(str, 3, "%d", (bin->opcode & 0x00F));
+ stmt->u.insn.operands[1] = str;
+
+ disasm_std_operand(stmt, 0, 2, 0);
+ disasm_std_operand(stmt, 1, 3, 0);
+ stmt->u.insn.is_labelref = 4;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ break;
+ case 0x600:
+ stmt->u.insn.name = "jnext";
+
+ str = xmalloc(5);
+ snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
+ stmt->u.insn.operands[0] = str;
+
+ disasm_std_operand(stmt, 0, 1, 0);
+ disasm_std_operand(stmt, 1, 2, 0);
+ stmt->u.insn.is_labelref = 3;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ break;
+ case 0x700:
+ stmt->u.insn.name = "jext";
+
+ str = xmalloc(5);
+ snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
+ stmt->u.insn.operands[0] = str;
+
+ disasm_std_operand(stmt, 0, 1, 0);
+ disasm_std_operand(stmt, 1, 2, 0);
+ stmt->u.insn.is_labelref = 3;
+ stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
+ break;
+ default:
+ disasm_constant_opcodes(ctx, stmt);
+ break;
+ }
+
+ list_add_tail(&stmt->list, &ctx->stmt_list);
+ }
+}
+
+static struct statement * get_label_at(struct disassembler_context *ctx,
+ unsigned int addr)
+{
+ unsigned int addrcnt = 0;
+ struct statement *stmt, *ret, *prev;
+
+ list_for_each_entry(stmt, &ctx->stmt_list, list) {
+ if (stmt->type != STMT_INSN)
+ continue;
+ if (addrcnt == addr) {
+ prev = list_entry(stmt->list.prev, struct statement, list);
+ if (prev->type == STMT_LABEL)
+ return prev;
+ ret = xmalloc(sizeof(struct statement));
+ INIT_LIST_HEAD(&ret->list);
+ ret->type = STMT_LABEL;
+ list_add(&ret->list, &prev->list);
+
+ return ret;
+ }
+ addrcnt++;
+ }
+
+ return NULL;
+}
+
+static void resolve_labels(struct disassembler_context *ctx)
+{
+ struct statement *stmt;
+ struct statement *label;
+ struct statement *n;
+ unsigned int labeladdr;
+ unsigned int namecnt = 0;
+
+ /* Resolve label references */
+ list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
+ if (stmt->type != STMT_INSN)
+ continue;
+ if (stmt->u.insn.is_labelref == -1)
+ continue;
+ labeladdr = stmt->u.insn.labeladdr;
+ label = get_label_at(ctx, labeladdr);
+ if (!label) {
+ fprintf(stderr, "Labeladdress %X out of bounds\n",
+ labeladdr);
+ exit(1);
+ }
+ stmt->u.insn.labelref = label;
+ }
+
+ /* Name the labels */
+ list_for_each_entry(stmt, &ctx->stmt_list, list) {
+ if (stmt->type != STMT_LABEL)
+ continue;
+ stmt->u.label.name = xmalloc(20);
+ snprintf(stmt->u.label.name, 20, "L%u", namecnt);
+ namecnt++;
+ }
+}
+
+static void emit_asm(struct disassembler_context *ctx)
+{
+ struct statement *stmt;
+ FILE *fd;
+ int first, i;
+
+ fd = fopen(outfile_name, "w+");
+ if (!fd) {
+ fprintf(stderr, "Could not open output file \"%s\"\n",
+ outfile_name);
+ exit(1);
+ }
+ fprintf(fd, "%%arch bcm43xx_newworld\n\n");
+ list_for_each_entry(stmt, &ctx->stmt_list, list) {
+ switch (stmt->type) {
+ case STMT_INSN:
+ fprintf(fd, "\t%s", stmt->u.insn.name);
+ first = 1;
+ for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
+ if (stmt->u.insn.is_labelref == i) {
+ fprintf(fd, ",%s",
+ stmt->u.insn.labelref->u.label.name);
+ }
+ if (!stmt->u.insn.operands[i])
+ continue;
+ if (first)
+ fprintf(fd, "\t");
+ if (!first)
+ fprintf(fd, ",");
+ first = 0;
+ fprintf(fd, "%s",
+ stmt->u.insn.operands[i]);
+ }
+ fprintf(fd, "\n");
+ break;
+ case STMT_LABEL:
+ fprintf(fd, "%s:\n", stmt->u.label.name);
+ break;
+ }
+ }
+ fclose(fd);
+}
+
+static void read_input(struct disassembler_context *ctx)
+{
+ size_t size = 0, pos = 0;
+ size_t ret;
+ struct bin_instruction *code = NULL;
+ unsigned char tmp[sizeof(uint64_t)];
+ uint64_t codeword;
+ struct fw_header hdr;
+
+ ret = fread(&hdr, 1, sizeof(hdr), infile);
+ if (!ret || ret != sizeof(hdr)) {
+ fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
+ exit(1);
+ }
+
+ if (hdr.ver != 1) {
+ fprintf(stderr, "Invalid fwcutter header version\n");
+ exit(1);
+ }
+
+ if (hdr.type != 'u') {
+ fprintf(stderr, "Not a microcode image\n");
+ exit(1);
+ }
+
+ while (1) {
+ if (pos >= size) {
+ size += 512;
+ code = xrealloc(code, size * sizeof(struct bin_instruction));
+ }
+ ret = fread(tmp, 1, sizeof(uint64_t), infile);
+ if (!ret)
+ break;
+ if (ret != sizeof(uint64_t)) {
+ fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
+ exit(1);
+ }
+
+ codeword = 0;
+ codeword |= ((uint64_t)tmp[0]) << 56;
+ codeword |= ((uint64_t)tmp[1]) << 48;
+ codeword |= ((uint64_t)tmp[2]) << 40;
+ codeword |= ((uint64_t)tmp[3]) << 32;
+ codeword |= ((uint64_t)tmp[4]) << 24;
+ codeword |= ((uint64_t)tmp[5]) << 16;
+ codeword |= ((uint64_t)tmp[6]) << 8;
+ codeword |= ((uint64_t)tmp[7]);
+
+ code[pos].opcode = (codeword >> 4) & 0xFFF;
+ code[pos].operands[0] = (codeword & 0xF) << 8;
+ code[pos].operands[0] |= (codeword >> 56) & 0xFF;
+ code[pos].operands[1] = (codeword >> 44) & 0xFFF;
+ code[pos].operands[2] = (codeword >> 32) & 0xFFF;
+
+ pos++;
+ }
+
+ ctx->code = code;
+ ctx->nr_insns = pos;
+}
+
+static void disassemble(void)
+{
+ struct disassembler_context ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
+ INIT_LIST_HEAD(&ctx.stmt_list);
+
+ read_input(&ctx);
+ disasm_opcodes(&ctx);
+ resolve_labels(&ctx);
+ emit_asm(&ctx);
+}
+
+static void usage(int argc, char **argv)
+{
+ fprintf(stderr, "Usage: %s output_file\n", argv[0]);
+}
+
+static void parse_args(int argc, char **argv)
+{
+ if (argc != 2) {
+ usage(argc, argv);
+ exit(1);
+ }
+ outfile_name = argv[1];
+}
+
+int main(int argc, char **argv)
+{
+ infile = stdin;
+ parse_args(argc, argv);
+ disassemble();
+
+ /* Lazyman simply leaks all allocated memory. */
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include "util.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+void dump(const char *data,
+ size_t size,
+ const char *description)
+{
+ size_t i;
+ char c;
+
+ fprintf(stderr, "Data dump (%s, %zd bytes):",
+ description, size);
+ for (i = 0; i < size; i++) {
+ c = data[i];
+ if (i % 8 == 0) {
+ fprintf(stderr, "\n0x%08zx: 0x%02x, ",
+ i, c & 0xff);
+ } else
+ fprintf(stderr, "0x%02x, ", c & 0xff);
+ }
+ fprintf(stderr, "\n");
+}
+
+void * xmalloc(size_t size)
+{
+ void *p;
+
+ p = malloc(size);
+ if (!p) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ memset(p, 0, size);
+
+ return p;
+}
+
+char * xstrdup(const char *str)
+{
+ char *c;
+
+ c = strdup(str);
+ if (!c) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+
+ return c;
+}
+
+void * xrealloc(void *in, size_t size)
+{
+ void *out;
+
+ out = realloc(in, size);
+ if (!out) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+
+ return out;
+}
--- /dev/null
+#ifndef BCM43xx_DASM_UTIL_H_
+#define BCM43xx_DASM_UTIL_H_
+
+#include <stdlib.h>
+
+
+void dump(const char *data,
+ size_t size,
+ const char *description);
+
+
+void * xmalloc(size_t size);
+char * xstrdup(const char *str);
+void * xrealloc(void *in, size_t size);
+
+#endif /* BCM43xx_DASM_UTIL_H_ */
--- /dev/null
+VERSION = 008
+
+CC ?= cc
+PREFIX ?= /usr/local
+CFLAGS ?= -Os -fomit-frame-pointer
+CFLAGS += -std=c99 -Wall -pedantic -D_BSD_SOURCE
+LDFLAGS ?=
+
+
+OBJECTS = fwcutter.o md5.o
+BIN = b43-fwcutter
+
+CFLAGS += -DFWCUTTER_VERSION_=$(VERSION)
+
+all: $(BIN)
+
+fwcutter.o: fwcutter.h fwcutter_list.h md5.h
+
+md5.o: md5.h
+
+$(BIN): $(OBJECTS)
+ $(CC) $(CFLAGS) -o $(BIN) $(OBJECTS) $(LDFLAGS)
+
+install: all
+ -install -d -o 0 -g 0 -m 755 $(PREFIX)/bin/
+ -install -o 0 -g 0 -m 755 $(BIN) $(PREFIX)/bin/
+ -install -d -o 0 -g 0 -m 755 $(PREFIX)/man/man1/
+ -install -o 0 -g 0 -m 644 $(BIN).1 $(PREFIX)/man/man1/
+
+clean:
+ -rm -f *.o $(BIN)
+
+distclean: clean
+ -rm -f *.fw *.orig *.rej *~
--- /dev/null
+ BCM43XX Linux Driver Project
+ ============================
+
+
+About this software
+-------------------
+
+b43-fwcutter is a tool which can extract firmware from various source files.
+It's written for BCM43xx driver files.
+
+The project page is http://bcm43xx.berlios.de/
+
+
+Usage
+-----
+
+b43-fwcutter FILE extracts the firmware from a source FILE to
+ the current directory, creating a directory
+ "b43" or "b43legacy" with files in it.
+b43-fwcutter -i FILE identify the driver file; print information
+ but don't extract.
+b43-fwcutter -w /tmp FILE extract and write firmware to /tmp.
+b43-fwcutter -l prints a list of supported driver source files.
+
+After extraction, copy the "b43" or "b43legacy" directory to your firmware
+directory (usually /lib/firmware or similar, see below). Alternatively you
+can use the -w option to b43-fwcutter.
+
+Different distributions use different directories to load firmware from.
+If the driver complains about missing firmware files look for the correct
+directory. For some distributions you have to use /lib/hotplug/firmware
+or /usr/lib/hotplug/firmware but other directories are also possible.
+
+Because firmware file are stored in big endian, extraction doesn't depend
+on the system you're using. You can use extracted firmware from any driver
+on any system and also copy the extracted files to any other system (e.g.
+if extraction on the target system isn't feasible.)
+
+
+Where can I find some driver source files?
+------------------------------------------
+
+Please check the references at
+http://www.linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware
+
+It is recommended that you extract firmware for both b43 and b43legacy in
+order to support both types of cards on your system.
--- /dev/null
+.\" Initially generated by help2man 1.36.
+.TH B43-FWCUTTER "1" "2007" "b43-fwcutter" "User Commands"
+.SH NAME
+b43-fwcutter \- manual page for b43-fwcutter
+.SH SYNOPSIS
+.B b43-fwcutter
+[\fIOPTION\fR] [\fIDRIVER\fR]
+.SH DESCRIPTION
+b43-fwcutter can extract the firmware for your Broadcom 43xx hardware from different closed source drivers. The b43 driver depends on this firmware files and can't work without them.
+.PP
+Currently b43-fwcutter supports Apple MacOS X, Microsoft Windows 98/ME/2000/XP and Linux drivers, but keep in mind that b43-fwcutter doesn't support all driver versions.
+.PP
+Example:
+.IP
+b43-fwcutter bcmwl5.sys
+.PP
+to cut the firmware out of bcmwl5.sys
+.SH OPTIONS
+.TP
+\fB\-l\fR|\-\-list
+List supported driver versions
+.TP
+\fB\-i\fR|\-\-identify
+Only identify the driver file (don't extract)
+.TP
+\fB\-w\fR|\-\-target\-dir DIR
+Extract and write firmware to DIR
+.TP
+\fB\-a\fR|\-\-alt\-iv
+Extract alternative initvals (only 3.10.x.x)
+.TP
+\fB\-p\fR|\-\-postfix ".FOO"
+Postfix for firmware filenames (.FOO.fw)
+.TP
+\fB\-v\fR|\-\-version
+Print b43-fwcutter version
+.TP
+\fB\-h\fR|\-\-help
+Print help information
+.SH AUTHORS
+b43 development team, http://bcm43xx.berlios.de
--- /dev/null
+/*
+ * firmware cutter for broadcom 43xx wireless driver files
+ *
+ * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ * 2005-2007 Michael Buesch <mb@bu3sch.de>
+ * 2005 Alex Beregszaszi
+ * 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef __DragonFly__
+#include <sys/endian.h>
+#else
+#include <byteswap.h>
+#endif
+
+#include "md5.h"
+#include "fwcutter.h"
+#include "fwcutter_list.h"
+
+#ifdef __DragonFly__
+#define V3_FW_DIRNAME "v3"
+#define V4_FW_DIRNAME "v4"
+#else
+#define V3_FW_DIRNAME "b43legacy"
+#define V4_FW_DIRNAME "b43"
+#endif
+
+static struct cmdline_args cmdargs;
+
+
+/* Convert a CPU-endian 16bit integer to Big-Endian */
+static be16_t to_be16(uint16_t v)
+{
+ uint8_t ret[2];
+
+ ret[0] = (v & 0xFF00) >> 8;
+ ret[1] = (v & 0x00FF);
+
+ return *((be16_t *)ret);
+}
+
+#if 0
+/* Convert a Big-Endian 16bit integer to CPU-endian */
+static uint16_t from_be16(be16_t v)
+{
+ uint16_t ret = 0;
+
+ ret |= (uint16_t)(((uint8_t *)&v)[0]) << 8;
+ ret |= (uint16_t)(((uint8_t *)&v)[1]);
+
+ return ret;
+}
+#endif
+
+/* Convert a CPU-endian 32bit integer to Big-Endian */
+static be32_t to_be32(uint32_t v)
+{
+ uint8_t ret[4];
+
+ ret[0] = (v & 0xFF000000) >> 24;
+ ret[1] = (v & 0x00FF0000) >> 16;
+ ret[2] = (v & 0x0000FF00) >> 8;
+ ret[3] = (v & 0x000000FF);
+
+ return *((be32_t *)ret);
+}
+
+/* Convert a Big-Endian 32bit integer to CPU-endian */
+static uint32_t from_be32(be32_t v)
+{
+ uint32_t ret = 0;
+
+ ret |= (uint32_t)(((uint8_t *)&v)[0]) << 24;
+ ret |= (uint32_t)(((uint8_t *)&v)[1]) << 16;
+ ret |= (uint32_t)(((uint8_t *)&v)[2]) << 8;
+ ret |= (uint32_t)(((uint8_t *)&v)[3]);
+
+ return ret;
+}
+
+/* tiny disassembler */
+static void print_ucode_version(struct insn *insn)
+{
+ int val;
+
+ /*
+ * The instruction we're looking for is a store to memory
+ * offset insn->op3 of the constant formed like `val' below.
+ * 0x2de00 is the opcode for type 1, 0x378 is the opcode
+ * for type 2 and 3.
+ */
+ if (insn->opcode != 0x378 && insn->opcode != 0x2de00)
+ return;
+
+ val = ((0xFF & insn->op1) << 8) | (0xFF & insn->op2);
+
+ /*
+ * Memory offsets are word-offsets, for the meaning
+ * see http://bcm-v4.sipsolutions.net/802.11/ObjectMemory
+ */
+ switch (insn->op3) {
+ case 0:
+ printf(" ucode version: %d\n", val);
+ break;
+ case 1:
+ printf(" ucode revision: %d\n", val);
+ break;
+ case 2:
+ printf(" ucode date: %.4d-%.2d-%.2d\n",
+ 2000 + (val >> 12), (val >> 8) & 0xF, val & 0xFF);
+ break;
+ case 3:
+ printf(" ucode time: %.2d:%.2d:%.2d\n",
+ val >> 11, (val >> 5) & 0x3f, val & 0x1f);
+ break;
+ }
+}
+
+static void disasm_ucode_1(uint64_t in, struct insn *out)
+{
+ /* xxyyyzzz00oooooX -> ooooo Xxx yyy zzz
+ * if we swap the upper and lower 32-bits first it becomes easier:
+ * 00oooooxxxyyyzzz -> ooooo xxx yyy zzz
+ */
+ in = (in >> 32) | (in << 32);
+
+ out->op3 = in & 0xFFF;
+ out->op2 = (in >> 12) & 0xFFF;
+ out->op1 = (in >> 24) & 0xFFF;
+ out->opcode = (in >> 36) & 0xFFFFF;
+ /* the rest of the in word should be zero */
+}
+
+static void disasm_ucode_2(uint64_t in, struct insn *out)
+{
+ /* xxyyyzzz0000oooX -> ooo Xxx yyy zzz
+ * if we swap the upper and lower 32-bits first it becomes easier:
+ * 0000oooxxxyyyzzz -> ooo xxx yyy zzz
+ */
+ in = (in >> 32) | (in << 32);
+
+ out->op3 = in & 0xFFF;
+ out->op2 = (in >> 12) & 0xFFF;
+ out->op1 = (in >> 24) & 0xFFF;
+ out->opcode = (in >> 36) & 0xFFF;
+ /* the rest of the in word should be zero */
+}
+
+static void disasm_ucode_3(uint64_t in, struct insn *out)
+{
+ /*
+ * like 2, but each operand has one bit more; appears
+ * to use the same instruction set slightly extended
+ */
+ in = (in >> 32) | (in << 32);
+
+ out->op3 = in & 0x1FFF;
+ out->op2 = (in >> 13) & 0x1FFF;
+ out->op1 = (in >> 26) & 0x1FFF;
+ out->opcode = (in >> 39) & 0xFFF;
+ /* the rest of the in word should be zero */
+}
+
+static void analyse_ucode(int ucode_rev, uint8_t *data, uint32_t len)
+{
+ uint64_t *insns = (uint64_t*)data;
+ struct insn insn;
+ uint32_t i;
+
+ for (i=0; i<len/sizeof(*insns); i++) {
+ switch (ucode_rev) {
+ case 1:
+ disasm_ucode_1(insns[i], &insn);
+ print_ucode_version(&insn);
+ break;
+ case 2:
+ disasm_ucode_2(insns[i], &insn);
+ print_ucode_version(&insn);
+ break;
+ case 3:
+ disasm_ucode_3(insns[i], &insn);
+ print_ucode_version(&insn);
+ break;
+ }
+ }
+}
+
+static void swap_endianness_ucode(uint8_t *buf, uint32_t len)
+{
+ uint32_t *buf32 = (uint32_t*)buf;
+ uint32_t i;
+
+ for (i=0; i<len/4; i++)
+ buf32[i] = bswap_32(buf32[i]);
+}
+
+#define swap_endianness_pcm swap_endianness_ucode
+
+static void swap_endianness_iv(struct iv *iv)
+{
+ iv->reg = bswap_16(iv->reg);
+ iv->size = bswap_16(iv->size);
+ iv->val = bswap_32(iv->val);
+}
+
+static void build_ivs(struct b43_iv **_out, size_t *_out_size,
+ struct iv *in, size_t in_size,
+ struct fw_header *hdr,
+ uint32_t flags)
+{
+ struct iv *iv;
+ struct b43_iv *out;
+ uint32_t i;
+ size_t out_size = 0;
+
+ if (sizeof(struct b43_iv) != 6) {
+ printf("sizeof(struct b43_iv) != 6\n");
+ exit(255);
+ }
+
+ out = malloc(in_size);
+ if (!out) {
+ perror("failed to allocate buffer");
+ exit(1);
+ }
+ *_out = out;
+ for (i = 0; i < in_size / sizeof(*iv); i++, in++) {
+ if (flags & FW_FLAG_LE)
+ swap_endianness_iv(in);
+ /* input-IV is BigEndian */
+ if (in->reg & to_be16(~FW_IV_OFFSET_MASK)) {
+ printf("Input file IV offset > 0x%X\n", FW_IV_OFFSET_MASK);
+ exit(1);
+ }
+ out->offset_size = in->reg;
+ if (in->size == to_be16(4)) {
+ out->offset_size |= to_be16(FW_IV_32BIT);
+ out->data.d32 = in->val;
+
+ out_size += sizeof(be16_t) + sizeof(be32_t);
+ out = (struct b43_iv *)((uint8_t *)out + sizeof(be16_t) + sizeof(be32_t));
+ } else if (in->size == to_be16(2)) {
+ if (in->val & to_be32(~0xFFFF)) {
+ printf("Input file 16bit IV value overflow\n");
+ exit(1);
+ }
+ out->data.d16 = to_be16(from_be32(in->val));
+
+ out_size += sizeof(be16_t) + sizeof(be16_t);
+ out = (struct b43_iv *)((uint8_t *)out + sizeof(be16_t) + sizeof(be16_t));
+ } else {
+ printf("Input file IV size != 2|4\n");
+ exit(1);
+ }
+ }
+ hdr->size = to_be32(i);
+ *_out_size = out_size;
+}
+
+static void write_file(const char *name, uint8_t *buf, uint32_t len,
+ const struct fw_header *hdr, uint32_t flags)
+{
+ FILE *f;
+ char nbuf[4096];
+ const char *dir;
+ int r;
+
+ if (flags & FW_FLAG_V4)
+ dir = V4_FW_DIRNAME;
+ else
+ dir = V3_FW_DIRNAME;
+
+ r = snprintf(nbuf, sizeof(nbuf),
+ "%s/%s", cmdargs.target_dir, dir);
+ if (r >= sizeof(nbuf)) {
+ fprintf(stderr, "name too long");
+ exit(2);
+ }
+
+ r = mkdir(nbuf, 0770);
+ if (r && errno != EEXIST) {
+ perror("failed to create output directory");
+ exit(2);
+ }
+
+ r = snprintf(nbuf, sizeof(nbuf),
+ "%s/%s/%s.fw", cmdargs.target_dir, dir, name);
+ if (r >= sizeof(nbuf)) {
+ fprintf(stderr, "name too long");
+ exit(2);
+ }
+ f = fopen(nbuf, "w");
+ if (!f) {
+ perror("failed to open file");
+ exit(2);
+ }
+ if (fwrite(hdr, sizeof(*hdr), 1, f) != 1) {
+ perror("failed to write file");
+ exit(2);
+ }
+ if (fwrite(buf, 1, len, f) != len) {
+ perror("failed to write file");
+ exit(2);
+ }
+ fclose(f);
+}
+
+static void extract_or_identify(FILE *f, const struct extract *extract,
+ uint32_t flags)
+{
+ uint8_t *buf;
+ size_t data_length;
+ int ucode_rev = 0;
+ struct fw_header hdr;
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ver = FW_HDR_VER;
+
+ if (fseek(f, extract->offset, SEEK_SET)) {
+ perror("failed to seek on file");
+ exit(2);
+ }
+
+ buf = malloc(extract->length);
+ if (!buf) {
+ perror("failed to allocate buffer");
+ exit(3);
+ }
+ if (fread(buf, 1, extract->length, f) != extract->length) {
+ perror("failed to read complete data");
+ exit(3);
+ }
+
+ switch (extract->type) {
+ case EXT_UCODE_3:
+ ucode_rev += 1;
+ case EXT_UCODE_2:
+ ucode_rev += 1;
+ case EXT_UCODE_1:
+ ucode_rev += 1;
+ data_length = extract->length;
+ if (flags & FW_FLAG_LE)
+ swap_endianness_ucode(buf, data_length);
+ analyse_ucode(ucode_rev, buf, data_length);
+ hdr.type = FW_TYPE_UCODE;
+ hdr.size = to_be32(data_length);
+ break;
+ case EXT_PCM:
+ data_length = extract->length;
+ if (flags & FW_FLAG_LE)
+ swap_endianness_pcm(buf, data_length);
+ hdr.type = FW_TYPE_PCM;
+ hdr.size = to_be32(data_length);
+ break;
+ case EXT_IV: {
+ struct b43_iv *ivs;
+
+ hdr.type = FW_TYPE_IV;
+ build_ivs(&ivs, &data_length,
+ (struct iv *)buf, extract->length,
+ &hdr, flags);
+ free(buf);
+ buf = (uint8_t *)ivs;
+ break;
+ }
+ default:
+ exit(255);
+ }
+
+ if (!cmdargs.identify_only)
+ write_file(extract->name, buf, data_length, &hdr, flags);
+
+ free(buf);
+}
+
+static void print_banner(void)
+{
+ printf("b43-fwcutter version " FWCUTTER_VERSION "\n");
+}
+
+static void print_file(const struct file *file)
+{
+ char filename[30];
+ char shortname[30];
+
+ if (file->flags & FW_FLAG_V4)
+ printf(V4_FW_DIRNAME "\t\t");
+ else
+ printf(V3_FW_DIRNAME "\t");
+
+ if (strlen(file->name) > 20) {
+ strncpy(shortname, file->name, 20);
+ shortname[20] = '\0';
+ snprintf(filename, sizeof(filename), "%s..", shortname);
+ } else
+ strcpy (filename, file->name);
+
+ printf("%s\t", filename);
+ if (strlen(filename) < 8) printf("\t");
+ if (strlen(filename) < 16) printf("\t");
+
+ printf("%s\t", file->ucode_version);
+ if (strlen(file->ucode_version) < 8) printf("\t");
+
+ printf("%s\n", file->md5);
+}
+
+static void print_supported_files(void)
+{
+ int i;
+
+ print_banner();
+ printf("\nExtracting firmware is possible "
+ "from these binary driver files:\n\n");
+ printf("<driver>\t"
+ "<filename>\t\t"
+ "<microcode>\t"
+ "<MD5 checksum>\n\n");
+ /* print for legacy driver first */
+ for (i = 0; i < FILES; i++)
+ if (!(files[i].flags & FW_FLAG_V4))
+ print_file(&files[i]);
+ for (i = 0; i < FILES; i++)
+ if (files[i].flags & FW_FLAG_V4)
+ print_file(&files[i]);
+ printf("\n");
+}
+
+static const struct file *find_file(FILE *fd)
+{
+ unsigned char buffer[16384], signature[16];
+ struct MD5Context md5c;
+ char md5sig[33];
+ int i;
+
+ MD5Init(&md5c);
+ while ((i = (int) fread(buffer, 1, sizeof(buffer), fd)) > 0)
+ MD5Update(&md5c, buffer, (unsigned) i);
+ MD5Final(signature, &md5c);
+
+ snprintf(md5sig, sizeof(md5sig),
+ "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x"
+ "%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
+ signature[0], signature[1], signature[2], signature[3],
+ signature[4], signature[5], signature[6], signature[7],
+ signature[8], signature[9], signature[10], signature[11],
+ signature[12], signature[13], signature[14], signature[15]);
+
+ for (i = 0; i < FILES; ++i) {
+ if (strcasecmp(md5sig, files[i].md5) == 0) {
+ printf("This file is recognised as:\n");
+ printf(" filename : %s\n", files[i].name);
+ printf(" version : %s\n", files[i].ucode_version);
+ printf(" MD5 : %s\n", files[i].md5);
+ return &files[i];
+ }
+ }
+ printf("Sorry, the input file is either wrong or "
+ "not supported by b43-fwcutter.\n");
+ printf("This file has an unknown MD5sum %s.\n", md5sig);
+
+ return NULL;
+}
+
+static void print_usage(int argc, char *argv[])
+{
+ print_banner();
+ printf("\nUsage: %s [OPTION] [driver.sys]\n", argv[0]);
+ printf(" -l|--list "
+ "List supported driver versions\n");
+ printf(" -i|--identify "
+ "Only identify the driver file (don't extract)\n");
+ printf(" -w|--target-dir DIR "
+ "Extract and write firmware to DIR\n");
+ printf(" -v|--version "
+ "Print b43-fwcutter version\n");
+ printf(" -h|--help "
+ "Print this help\n");
+ printf("\nExample: %s bcmwl5.sys\n"
+ " to extract the firmware blobs from bcmwl5.sys\n",
+ argv[0]);
+}
+
+static int do_cmp_arg(char **argv, int *pos,
+ const char *template,
+ int allow_merged,
+ char **param)
+{
+ char *arg;
+ char *next_arg;
+ size_t arg_len, template_len;
+
+ arg = argv[*pos];
+ next_arg = argv[*pos + 1];
+ arg_len = strlen(arg);
+ template_len = strlen(template);
+
+ if (param) {
+ /* Maybe we have a merged parameter here.
+ * A merged parameter is "-pfoobar" for example.
+ */
+ if (allow_merged && arg_len > template_len) {
+ if (memcmp(arg, template, template_len) == 0) {
+ *param = arg + template_len;
+ return ARG_MATCH;
+ }
+ return ARG_NOMATCH;
+ } else if (arg_len != template_len)
+ return ARG_NOMATCH;
+ *param = next_arg;
+ }
+ if (strcmp(arg, template) == 0) {
+ if (param) {
+ /* Skip the parameter on the next iteration. */
+ (*pos)++;
+ if (*param == 0) {
+ printf("%s needs a parameter\n", arg);
+ return ARG_ERROR;
+ }
+ }
+ return ARG_MATCH;
+ }
+
+ return ARG_NOMATCH;
+}
+
+/* Simple and lean command line argument parsing. */
+static int cmp_arg(char **argv, int *pos,
+ const char *long_template,
+ const char *short_template,
+ char **param)
+{
+ int err;
+
+ if (long_template) {
+ err = do_cmp_arg(argv, pos, long_template, 0, param);
+ if (err == ARG_MATCH || err == ARG_ERROR)
+ return err;
+ }
+ err = ARG_NOMATCH;
+ if (short_template)
+ err = do_cmp_arg(argv, pos, short_template, 1, param);
+ return err;
+}
+
+static int parse_args(int argc, char *argv[])
+{
+ int i, res;
+ char *param;
+
+ if (argc < 2)
+ goto out_usage;
+ for (i = 1; i < argc; i++) {
+ res = cmp_arg(argv, &i, "--list", "-l", 0);
+ if (res == ARG_MATCH) {
+ print_supported_files();
+ return 1;
+ } else if (res == ARG_ERROR)
+ goto out;
+
+ res = cmp_arg(argv, &i, "--version", "-v", 0);
+ if (res == ARG_MATCH) {
+ print_banner();
+ return 1;
+ } else if (res == ARG_ERROR)
+ goto out;
+
+ res = cmp_arg(argv, &i, "--help", "-h", 0);
+ if (res == ARG_MATCH)
+ goto out_usage;
+ else if (res == ARG_ERROR)
+ goto out;
+
+ res = cmp_arg(argv, &i, "--identify", "-i", 0);
+ if (res == ARG_MATCH) {
+ cmdargs.identify_only = 1;
+ continue;
+ } else if (res == ARG_ERROR)
+ goto out;
+
+ res = cmp_arg(argv, &i, "--target-dir", "-w", ¶m);
+ if (res == ARG_MATCH) {
+ cmdargs.target_dir = param;
+ continue;
+ } else if (res == ARG_ERROR)
+ goto out;
+
+ cmdargs.infile = argv[i];
+ break;
+ }
+
+ if (!cmdargs.infile)
+ goto out_usage;
+ return 0;
+
+out_usage:
+ print_usage(argc, argv);
+out:
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *fd;
+ const struct file *file;
+ const struct extract *extract;
+ int err;
+ const char *dir;
+
+ cmdargs.target_dir = ".";
+ err = parse_args(argc, argv);
+ if (err == 1)
+ return 0;
+ else if (err != 0)
+ return err;
+
+ fd = fopen(cmdargs.infile, "rb");
+ if (!fd) {
+ fprintf(stderr, "Cannot open input file %s\n", cmdargs.infile);
+ return 2;
+ }
+
+ err = -1;
+ file = find_file(fd);
+ if (!file)
+ goto out_close;
+
+ if (file->flags & FW_FLAG_V4)
+ dir = V4_FW_DIRNAME;
+ else
+ dir = V3_FW_DIRNAME;
+
+ extract = file->extract;
+ while (extract->name) {
+ printf("%s %s/%s.fw\n",
+ cmdargs.identify_only ? "Contains" : "Extracting",
+ dir, extract->name);
+ extract_or_identify(fd, extract, file->flags);
+ extract++;
+ }
+
+ err = 0;
+out_close:
+ fclose(fd);
+
+ return err;
+}
--- /dev/null
+#ifndef _FWCUTTER_H_
+#define _FWCUTTER_H_
+
+#define FW_FLAG_LE 0x01 /* little endian? convert */
+#define FW_FLAG_V4 0x02 /* b43 vs. b43legacy */
+
+#define fwcutter_stringify_1(x) #x
+#define fwcutter_stringify(x) fwcutter_stringify_1(x)
+#define FWCUTTER_VERSION fwcutter_stringify(FWCUTTER_VERSION_)
+
+typedef uint16_t be16_t; /* Big-endian 16bit */
+typedef uint32_t be32_t; /* Big-endian 32bit */
+
+#ifdef __DragonFly__
+#define bswap_16 bswap16
+#define bswap_32 bswap32
+#endif
+
+#define ARG_MATCH 0
+#define ARG_NOMATCH 1
+#define ARG_ERROR -1
+
+struct cmdline_args {
+ const char *infile;
+ const char *target_dir;
+ int identify_only;
+};
+
+struct insn {
+ uint32_t opcode;
+ uint16_t op1, op2, op3;
+};
+
+/* The IV how it's done in the binary driver files. */
+struct iv {
+ be16_t reg, size;
+ be32_t val;
+} __attribute__((__packed__));
+
+enum extract_type {
+ EXT_UNDEFINED, /* error catcher */
+ EXT_UCODE_1, /* rev <= 4 ucode */
+ EXT_UCODE_2, /* rev 5..14 ucode */
+ EXT_UCODE_3, /* rev >= 15 ucode */
+ EXT_PCM, /* "pcm" values */
+ EXT_IV, /* initial values */
+};
+
+struct extract {
+ const char *name;
+ const uint32_t offset;
+ const uint32_t length;
+ const enum extract_type type;
+};
+
+#define EXTRACT_LIST_END { .name = NULL, }
+
+struct file {
+ const char *name;
+ const char *ucode_version;
+ const char *md5;
+ const struct extract *extract;
+ const uint32_t flags;
+};
+
+/* The header that's put in to every .fw file */
+struct fw_header {
+ /* Type of the firmware data */
+ uint8_t type;
+ /* Version number of the firmware data format */
+ uint8_t ver;
+ uint8_t __padding[2];
+ /* Size of the data. For ucode and PCM this is in bytes.
+ * For IV this is in number-of-ivs. */
+ be32_t size;
+} __attribute__((__packed__));
+
+#define FW_TYPE_UCODE 'u'
+#define FW_TYPE_PCM 'p'
+#define FW_TYPE_IV 'i'
+
+#define FW_HDR_VER 0x01
+
+/* The IV in the .fw file */
+struct b43_iv {
+ be16_t offset_size;
+ union {
+ be16_t d16;
+ be32_t d32;
+ } data __attribute__((__packed__));
+} __attribute__((__packed__));
+
+#define FW_IV_OFFSET_MASK 0x7FFF
+#define FW_IV_32BIT 0x8000
+
+
+#endif /* _FWCUTTER_H_ */
--- /dev/null
+
+/* file member lists */
+struct extract _e08665c5c5b66beb9c3b2dd54aa80cb3[] =
+{
+ { .name = "ucode2", .offset = 0x59ca0, .length = 0x3fe0, .type = EXT_UCODE_1, },
+ { .name = "ucode4", .offset = 0x5dc84, .length = 0x4e78, .type = EXT_UCODE_1, },
+ { .name = "ucode5", .offset = 0x62b00, .length = 0x5700, .type = EXT_UCODE_2, },
+ { .name = "ucode11", .offset = 0x68204, .length = 0x54a8, .type = EXT_UCODE_2, },
+ { .name = "pcm4", .offset = 0x6d6b0, .length = 0x520, .type = EXT_PCM, },
+ { .name = "pcm5", .offset = 0x6dbd4, .length = 0x520, .type = EXT_PCM, },
+ { .name = "a0g0bsinitvals2", .offset = 0x54ad0 + 0x30d8, .length = 0x18 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals5", .offset = 0x54ad0 + 0x3ae0, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g0initvals5", .offset = 0x54ad0 + 0x3be0, .length = 0x9f0 - 8, .type = EXT_IV, },
+ { .name = "a0g1bsinitvals5", .offset = 0x54ad0 + 0x50c0, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g0initvals2", .offset = 0x54ad0 + 0x2320, .length = 0xdb8 - 8, .type = EXT_IV, },
+ { .name = "a0g1initvals5", .offset = 0x54ad0 + 0x45d0, .length = 0x9f0 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals2", .offset = 0x54ad0 + 0x2308, .length = 0x18 - 8, .type = EXT_IV, },
+ { .name = "b0g0initvals5", .offset = 0x54ad0 + 0x30f0, .length = 0x9f0 - 8, .type = EXT_IV, },
+ { .name = "b0g0initvals2", .offset = 0x54ad0 + 0x1550, .length = 0xdb8 - 8, .type = EXT_IV, },
+ { .name = "a0g0bsinitvals5", .offset = 0x54ad0 + 0x4fc0, .length = 0x100 - 8, .type = EXT_IV, },
+ EXTRACT_LIST_END
+};
+
+struct extract _9207bc565c2fc9fa1591f6c7911d3fc0[] =
+{
+ { .name = "ucode4", .offset = 0x66220 + 0x7ad8, .length = 0x4e68, .type = EXT_UCODE_1, },
+ { .name = "ucode5", .offset = 0x66220 + 0xc944, .length = 0x5640, .type = EXT_UCODE_2, },
+ { .name = "ucode11", .offset = 0x66220 + 0x11f90, .length = 0x67e0, .type = EXT_UCODE_2, },
+ { .name = "ucode13", .offset = 0x66220 + 0x18774, .length = 0x5f60, .type = EXT_UCODE_2, },
+ { .name = "pcm4", .offset = 0x66220 + 0x1e6d8, .length = 0x520, .type = EXT_PCM, },
+ { .name = "pcm5", .offset = 0x66220 + 0x1ebfc, .length = 0x520, .type = EXT_PCM, },
+ { .name = "b0g0initvals4", .offset = 0x66220 + 0x1710, .length = 0xe90 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals4", .offset = 0x66220 + 0x25a0, .length = 0x18 - 8, .type = EXT_IV, },
+ { .name = "a0g0initvals4", .offset = 0x66220 + 0x25b8, .length = 0xe90 - 8, .type = EXT_IV, },
+ { .name = "a0g0bsinitvals4", .offset = 0x66220 + 0x3448, .length = 0x18 - 8, .type = EXT_IV, },
+ { .name = "b0g0initvals5", .offset = 0x66220 + 0x3460, .length = 0xa28 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals5", .offset = 0x66220 + 0x3e88, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g0initvals5", .offset = 0x66220 + 0x3f88, .length = 0xa28 - 8, .type = EXT_IV, },
+ { .name = "a0g1initvals5", .offset = 0x66220 + 0x49b0, .length = 0xa28 - 8, .type = EXT_IV, },
+ { .name = "a0g0bsinitvals5", .offset = 0x66220 + 0x53d8, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g1bsinitvals5", .offset = 0x66220 + 0x54d8, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "lp0initvals13", .offset = 0x66220 + 0x5620, .length = 0xb38 - 8, .type = EXT_IV, },
+ { .name = "lp0bsinitvals13", .offset = 0x66220 + 0x6158, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "b0g0initvals13", .offset = 0x66220 + 0x6258, .length = 0xb40 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals13",.offset = 0x66220 + 0x6d98, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g1initvals13", .offset = 0x66220 + 0x6e98, .length = 0xb40 - 8, .type = EXT_IV, },
+ { .name = "a0g1bsinitvals13",.offset = 0x66220 + 0x79d8, .length = 0x100 - 8, .type = EXT_IV, },
+ EXTRACT_LIST_END
+};
+
+struct extract _722e2e0d8cc04b8f118bb5afe6829ff9[] =
+{
+ { .name = "ucode4", .offset = 0x76a10 + 0x8960, .length = 0x4e68, .type = EXT_UCODE_1, },
+ { .name = "ucode5", .offset = 0x76a10 + 0xd7cc, .length = 0x5640, .type = EXT_UCODE_2, },
+ { .name = "ucode11", .offset = 0x76a10 + 0x12e18, .length = 0x67e0, .type = EXT_UCODE_2, },
+ { .name = "ucode13", .offset = 0x76a10 + 0x195fc, .length = 0x5f60, .type = EXT_UCODE_2, },
+ { .name = "pcm4", .offset = 0x76a10 + 0x1f560, .length = 0x520, .type = EXT_PCM, },
+ { .name = "pcm5", .offset = 0x76a10 + 0x1fa84, .length = 0x520, .type = EXT_PCM, },
+ { .name = "b0g0initvals4", .offset = 0x76a10 + 0x1840, .length = 0xe90 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals4", .offset = 0x76a10 + 0x26d0, .length = 0x18 - 8, .type = EXT_IV, },
+ { .name = "a0g0initvals4", .offset = 0x76a10 + 0x26e8, .length = 0xe90 - 8, .type = EXT_IV, },
+ { .name = "a0g0bsinitvals4", .offset = 0x76a10 + 0x3578, .length = 0x18 - 8, .type = EXT_IV, },
+ { .name = "b0g0initvals5", .offset = 0x76a10 + 0x3590, .length = 0xa28 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals5", .offset = 0x76a10 + 0x3fb8, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g0initvals5", .offset = 0x76a10 + 0x40b8, .length = 0xa28 - 8, .type = EXT_IV, },
+ { .name = "a0g1initvals5", .offset = 0x76a10 + 0x4ae0, .length = 0xa28 - 8, .type = EXT_IV, },
+ { .name = "a0g0bsinitvals5", .offset = 0x76a10 + 0x5508, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g1bsinitvals5", .offset = 0x76a10 + 0x5608, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "lp0initvals13", .offset = 0x76a10 + 0x64a8, .length = 0xb38 - 8, .type = EXT_IV, },
+ { .name = "lp0bsinitvals13", .offset = 0x76a10 + 0x6fe0, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "b0g0initvals13", .offset = 0x76a10 + 0x70e0, .length = 0xb40 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals13",.offset = 0x76a10 + 0x7c20, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g1initvals13", .offset = 0x76a10 + 0x7d20, .length = 0xb40 - 8, .type = EXT_IV, },
+ { .name = "a0g1bsinitvals13",.offset = 0x76a10 + 0x8860, .length = 0x100 - 8, .type = EXT_IV, },
+ EXTRACT_LIST_END
+};
+
+struct extract _1e4763b4cb8cfbaae43e5c6d3d6b2ae7[] =
+{
+ { .name = "ucode5", .offset = 0x71c80 + 0xacd0, .length = 0x5768, .type = EXT_UCODE_2, },
+ { .name = "ucode9", .offset = 0x71c80 + 0x1043c, .length = 0x6240, .type = EXT_UCODE_2, },
+ { .name = "ucode11", .offset = 0x71c80 + 0x16680, .length = 0x74a0, .type = EXT_UCODE_2, },
+ { .name = "ucode13", .offset = 0x71c80 + 0x1db24, .length = 0x7de0, .type = EXT_UCODE_2, },
+ { .name = "ucode14", .offset = 0x71c80 + 0x25908, .length = 0x7a90, .type = EXT_UCODE_2, },
+ { .name = "ucode15", .offset = 0x71c80 + 0x2d39c, .length = 0x7710, .type = EXT_UCODE_3, },
+ { .name = "pcm5", .offset = 0x71c80 + 0x34ab0, .length = 0x520, .type = EXT_PCM, },
+ { .name = "b0g0initvals5", .offset = 0x71c80 + 0x14d0, .length = 0xa10 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals5", .offset = 0x71c80 + 0x1ee0, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g0initvals5", .offset = 0x71c80 + 0x1fe0, .length = 0xa10 - 8, .type = EXT_IV, },
+ { .name = "a0g1initvals5", .offset = 0x71c80 + 0x29f0, .length = 0xa10 - 8, .type = EXT_IV, },
+ { .name = "a0g0bsinitvals5", .offset = 0x71c80 + 0x3400, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g1bsinitvals5", .offset = 0x71c80 + 0x3500, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "b0g0initvals9", .offset = 0x71c80 + 0x3600, .length = 0xae8 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals9", .offset = 0x71c80 + 0x40e8, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g0initvals9", .offset = 0x71c80 + 0x41e8, .length = 0xae8 - 8, .type = EXT_IV, },
+ { .name = "a0g1initvals9", .offset = 0x71c80 + 0x4cd0, .length = 0xae8 - 8, .type = EXT_IV, },
+ { .name = "a0g0bsinitvals9", .offset = 0x71c80 + 0x57b8, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g1bsinitvals9", .offset = 0x71c80 + 0x58b8, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "n0initvals11", .offset = 0x71c80 + 0x59b8, .length = 0xb78 - 8, .type = EXT_IV, },
+ { .name = "n0bsinitvals11", .offset = 0x71c80 + 0x6530, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "n0absinitvals11", .offset = 0x71c80 + 0x6630, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "lp0initvals13", .offset = 0x71c80 + 0x6730, .length = 0x1360 - 8, .type = EXT_IV, },
+ { .name = "lp0bsinitvals13", .offset = 0x71c80 + 0x7a90, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "b0g0initvals13", .offset = 0x71c80 + 0x7b90, .length = 0xb60 - 8, .type = EXT_IV, },
+ { .name = "b0g0bsinitvals13",.offset = 0x71c80 + 0x86f0, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "a0g1initvals13", .offset = 0x71c80 + 0x87f0, .length = 0xb60 - 8, .type = EXT_IV, },
+ { .name = "a0g1bsinitvals13",.offset = 0x71c80 + 0x9350, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "lp0initvals14", .offset = 0x71c80 + 0x9450, .length = 0xb48 - 8, .type = EXT_IV, },
+ { .name = "lp0bsinitvals14", .offset = 0x71c80 + 0x9f98, .length = 0x100 - 8, .type = EXT_IV, },
+ { .name = "lp0initvals15", .offset = 0x71c80 + 0xa098, .length = 0xb38 - 8, .type = EXT_IV, },
+ { .name = "lp0bsinitvals15", .offset = 0x71c80 + 0xabd0, .length = 0x100 - 8, .type = EXT_IV, },
+ EXTRACT_LIST_END
+};
+
+
+/*
+ * Links change, so let's not put them into the README.
+ * I still put them here so we know where the file was obtained.
+ */
+static const struct file files[] =
+{
+ {
+ .name = "wl_apsta.o",
+ .ucode_version = "295.14",
+ .md5 = "e08665c5c5b66beb9c3b2dd54aa80cb3",
+ .flags = FW_FLAG_LE,
+ .extract = _e08665c5c5b66beb9c3b2dd54aa80cb3,
+ },
+ {
+ /* http://downloads.openwrt.org/sources/broadcom-wl-4.80.53.0.tar.bz2 */
+ .name = "wl_apsta.o",
+ .ucode_version = "351.126",
+ .md5 = "9207bc565c2fc9fa1591f6c7911d3fc0",
+ .flags = FW_FLAG_LE | FW_FLAG_V4,
+ .extract = _9207bc565c2fc9fa1591f6c7911d3fc0,
+ },
+ {
+ /* http://downloads.openwrt.org/sources/broadcom-wl-4.80.53.0.tar.bz2 */
+ .name = "wl_apsta_mimo.o",
+ .ucode_version = "351.126",
+ .md5 = "722e2e0d8cc04b8f118bb5afe6829ff9",
+ .flags = FW_FLAG_LE | FW_FLAG_V4,
+ .extract = _722e2e0d8cc04b8f118bb5afe6829ff9,
+ },
+ {
+ /* ftp://ftp.linksys.com/opensourcecode/wrt150nv11/1.51.3/ */
+ .name = "wl_ap.o",
+ .ucode_version = "410.2160",
+ .md5 = "1e4763b4cb8cfbaae43e5c6d3d6b2ae7",
+ .flags = FW_FLAG_LE | FW_FLAG_V4,
+ .extract = _1e4763b4cb8cfbaae43e5c6d3d6b2ae7,
+ },
+};
+
+#define FILES (sizeof(files) / sizeof(files[0]))
--- /dev/null
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* Brutally hacked by John Walker back from ANSI C to K&R (no
+ prototypes) to maintain the tradition that Netfone will compile
+ with Sun's original "cc". */
+/* Ripped out ugly K&R again ;) --mbuesch */
+/* killed stupid endianness thing --jmberg */
+
+#include <memory.h> /* for memcpy() */
+#include "md5.h"
+
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+/* we need the value in big-endian */
+ uint32_t t;
+
+ do {
+ t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32_t *) buf = t;
+ buf += 4;
+ } while (--longs);
+#endif
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32_t *buf, uint32_t *in)
+{
+ register uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len)
+{
+ uint32_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char *digest, struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+ ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
--- /dev/null
+#ifndef FWCUTTER_MD5_H_
+#define FWCUTTER_MD5_H_
+
+#include <stdint.h>
+
+struct MD5Context {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *ctx);
+void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len);
+void MD5Final(unsigned char *digest, struct MD5Context *ctx);
+
+#endif /* FWCUTTER_MD5_H_ */
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+VERSION = 001
+
+CC = cc
+PREFIX = /usr/local
+CFLAGS = -std=c99 -O2 -fomit-frame-pointer -Wall -D_BSD_SOURCE
+LDFLAGS =
+
+
+OBJECTS = ssb_sprom.o utils.o
+
+CFLAGS += -DVERSION_=$(VERSION)
+
+all: ssb_sprom
+
+ssb_sprom: $(OBJECTS)
+ $(CC) $(CFLAGS) -o ssb-sprom $(OBJECTS) $(LDFLAGS)
+
+install: all
+ -install -o 0 -g 0 -m 755 ssb-sprom $(PREFIX)/bin/
+
+clean:
+ -rm -f *~ *.o *.orig *.rej ssb-sprom
+
+# dependencies
+ssb_sprom.o: ssb_sprom.h utils.h
+utils.o: utils.h ssb_sprom.h
--- /dev/null
+
+ Broadcom-SSB SPROM data modification tool
+ =========================================
+
+About this software
+-------------------
+
+A tool for the convenient modification of the
+Broadcom Sonics Silicon Backplane SPROM.
+This tool automatically adjusts the CRC after the modification.
+
+Requirements
+------------
+
+1) C99 compatible compiler.
--- /dev/null
+/*
+
+ Broadcom Sonics Silicon Backplane bus SPROM data modification tool
+
+ Copyright (c) 2006-2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "ssb_sprom.h"
+#include "utils.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+
+struct cmdline_args cmdargs;
+
+static int value_length_map[] = { /* value to number of bits */
+ [VALUE_RAW] = 8,
+ [VALUE_SUBP] = 16,
+ [VALUE_SUBV] = 16,
+ [VALUE_PPID] = 16,
+ [VALUE_BFLHI] = 16,
+ [VALUE_BFL] = 16,
+ [VALUE_BGMAC] = -1,
+ [VALUE_ETMAC] = -1,
+ [VALUE_AMAC] = -1,
+ [VALUE_ET0PHY] = 8,
+ [VALUE_ET1PHY] = 8,
+ [VALUE_ET0MDC] = 1,
+ [VALUE_ET1MDC] = 1,
+ [VALUE_BREV] = 8,
+ [VALUE_LOC] = 4,
+ [VALUE_ANTA0] = 1,
+ [VALUE_ANTA1] = 1,
+ [VALUE_ANTBG0] = 1,
+ [VALUE_ANTBG1] = 1,
+ [VALUE_ANTGA] = 8,
+ [VALUE_ANTGBG] = 8,
+ [VALUE_PA0B0] = 16,
+ [VALUE_PA0B1] = 16,
+ [VALUE_PA0B2] = 16,
+ [VALUE_PA1B0] = 16,
+ [VALUE_PA1B1] = 16,
+ [VALUE_PA1B2] = 16,
+ [VALUE_WL0GPIO0] = 8,
+ [VALUE_WL0GPIO1] = 8,
+ [VALUE_WL0GPIO2] = 8,
+ [VALUE_WL0GPIO3] = 8,
+ [VALUE_MAXPA] = 8,
+ [VALUE_MAXPBG] = 8,
+ [VALUE_ITSSIA] = 8,
+ [VALUE_ITSSIBG] = 8,
+ [VALUE_SVER] = 8,
+};
+
+
+static int hexdump_sprom(const uint8_t *sprom, char *buffer, size_t bsize)
+{
+ int i, pos = 0;
+
+ for (i = 0; i < SPROM_SIZE; i++) {
+ pos += snprintf(buffer + pos, bsize - pos - 1,
+ "%02X", sprom[i] & 0xFF);
+ }
+
+ return pos + 1;
+}
+
+static uint8_t sprom_crc(const uint8_t *sprom)
+{
+ int i;
+ uint8_t crc = 0xFF;
+
+ for (i = 0; i < SPROM_SIZE - 1; i++)
+ crc = crc8(crc, sprom[i]);
+ crc ^= 0xFF;
+
+ return crc;
+}
+
+static int write_output_binary(int fd, const uint8_t *sprom)
+{
+ ssize_t w;
+
+ w = write(fd, sprom, SPROM_SIZE);
+ if (w < 0)
+ return -1;
+
+ return 0;
+}
+
+static int write_output_hex(int fd, const uint8_t *sprom)
+{
+ ssize_t w;
+ char tmp[SPROM_SIZE * 2 + 10] = { 0 };
+
+ hexdump_sprom(sprom, tmp, sizeof(tmp));
+ prinfo("Raw output: %s\n", tmp);
+ w = write(fd, tmp, SPROM_SIZE * 2);
+ if (w < 0)
+ return -1;
+
+ return 0;
+}
+
+static int write_output(int fd, const uint8_t *sprom)
+{
+ int err;
+
+ if (cmdargs.outfile) {
+ err = ftruncate(fd, 0);
+ if (err) {
+ prerror("Could not truncate --outfile %s\n",
+ cmdargs.outfile);
+ return -1;
+ }
+ }
+
+ if (cmdargs.bin_mode)
+ err = write_output_binary(fd, sprom);
+ else
+ err = write_output_hex(fd, sprom);
+ if (err)
+ prerror("Could not write output data.\n");
+
+ return err;
+}
+
+static int modify_value(uint8_t *sprom,
+ struct cmdline_vparm *vparm)
+{
+ const uint16_t v = vparm->u.value;
+ uint16_t tmp = 0;
+
+ switch (vparm->type) {
+ case VALUE_RAW:
+ sprom[vparm->u.raw.offset] = vparm->u.raw.value;
+ break;
+ case VALUE_SUBP:
+ sprom[SPROM_SUBP + 0] = (v & 0x00FF);
+ sprom[SPROM_SUBP + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_SUBV:
+ sprom[SPROM_SUBV + 0] = (v & 0x00FF);
+ sprom[SPROM_SUBV + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_PPID:
+ sprom[SPROM_PPID + 0] = (v & 0x00FF);
+ sprom[SPROM_PPID + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_BFLHI:
+ sprom[SPROM_BFLHI + 0] = (v & 0x00FF);
+ sprom[SPROM_BFLHI + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_BFL:
+ sprom[SPROM_BOARDFLAGS + 0] = (v & 0x00FF);
+ sprom[SPROM_BOARDFLAGS + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_BGMAC:
+ sprom[SPROM_IL0MACADDR + 1] = vparm->u.mac[0];
+ sprom[SPROM_IL0MACADDR + 0] = vparm->u.mac[1];
+ sprom[SPROM_IL0MACADDR + 3] = vparm->u.mac[2];
+ sprom[SPROM_IL0MACADDR + 2] = vparm->u.mac[3];
+ sprom[SPROM_IL0MACADDR + 5] = vparm->u.mac[4];
+ sprom[SPROM_IL0MACADDR + 4] = vparm->u.mac[5];
+ break;
+ case VALUE_ETMAC:
+ sprom[SPROM_ET0MACADDR + 1] = vparm->u.mac[0];
+ sprom[SPROM_ET0MACADDR + 0] = vparm->u.mac[1];
+ sprom[SPROM_ET0MACADDR + 3] = vparm->u.mac[2];
+ sprom[SPROM_ET0MACADDR + 2] = vparm->u.mac[3];
+ sprom[SPROM_ET0MACADDR + 5] = vparm->u.mac[4];
+ sprom[SPROM_ET0MACADDR + 4] = vparm->u.mac[5];
+ break;
+ case VALUE_AMAC:
+ sprom[SPROM_ET1MACADDR + 1] = vparm->u.mac[0];
+ sprom[SPROM_ET1MACADDR + 0] = vparm->u.mac[1];
+ sprom[SPROM_ET1MACADDR + 3] = vparm->u.mac[2];
+ sprom[SPROM_ET1MACADDR + 2] = vparm->u.mac[3];
+ sprom[SPROM_ET1MACADDR + 5] = vparm->u.mac[4];
+ sprom[SPROM_ET1MACADDR + 4] = vparm->u.mac[5];
+ break;
+ case VALUE_ET0PHY:
+ tmp |= sprom[SPROM_ETHPHY + 0];
+ tmp |= sprom[SPROM_ETHPHY + 1] << 8;
+ tmp = ((tmp & 0x001F) | (v & 0x1F));
+ sprom[SPROM_ETHPHY + 0] = (tmp & 0x00FF);
+ sprom[SPROM_ETHPHY + 1] = (tmp & 0xFF00) >> 8;
+ break;
+ case VALUE_ET1PHY:
+ tmp |= sprom[SPROM_ETHPHY + 0];
+ tmp |= sprom[SPROM_ETHPHY + 1] << 8;
+ tmp = ((tmp & 0x03E0) | ((v & 0x1F) << 5));
+ sprom[SPROM_ETHPHY + 0] = (tmp & 0x00FF);
+ sprom[SPROM_ETHPHY + 1] = (tmp & 0xFF00) >> 8;
+ break;
+ case VALUE_ET0MDC:
+ sprom[SPROM_ETHPHY + 1] &= ~(1 << 6);
+ if (v)
+ sprom[SPROM_ETHPHY + 1] |= (1 << 6);
+ break;
+ case VALUE_ET1MDC:
+ sprom[SPROM_ETHPHY + 1] &= ~(1 << 7);
+ if (v)
+ sprom[SPROM_ETHPHY + 1] |= (1 << 7);
+ break;
+ case VALUE_BREV:
+ sprom[SPROM_BOARDREV + 0] = v;
+ break;
+ case VALUE_LOC:
+ tmp = (sprom[SPROM_BOARDREV + 1] & 0xF0);
+ tmp |= (v & 0x0F);
+ sprom[SPROM_BOARDREV + 1] = (tmp & 0xFF);
+ break;
+ case VALUE_ANTA0:
+ sprom[SPROM_BOARDREV + 1] &= ~(1 << 4);
+ if (v)
+ sprom[SPROM_BOARDREV + 1] |= (1 << 4);
+ break;
+ case VALUE_ANTA1:
+ sprom[SPROM_BOARDREV + 1] &= ~(1 << 5);
+ if (v)
+ sprom[SPROM_BOARDREV + 1] |= (1 << 5);
+ break;
+ case VALUE_ANTBG0:
+ sprom[SPROM_BOARDREV + 1] &= ~(1 << 6);
+ if (v)
+ sprom[SPROM_BOARDREV + 1] |= (1 << 6);
+ break;
+ case VALUE_ANTBG1:
+ sprom[SPROM_BOARDREV + 1] &= ~(1 << 7);
+ if (v)
+ sprom[SPROM_BOARDREV + 1] |= (1 << 7);
+ break;
+ case VALUE_ANTGA:
+ sprom[SPROM_ANTENNA_GAIN + 0] = (v & 0xFF);
+ break;
+ case VALUE_ANTGBG:
+ sprom[SPROM_ANTENNA_GAIN + 1] = (v & 0xFF);
+ break;
+ case VALUE_PA0B0:
+ sprom[SPROM_PA0B0 + 0] = (v & 0x00FF);
+ sprom[SPROM_PA0B0 + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_PA0B1:
+ sprom[SPROM_PA0B1 + 0] = (v & 0x00FF);
+ sprom[SPROM_PA0B1 + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_PA0B2:
+ sprom[SPROM_PA0B2 + 0] = (v & 0x00FF);
+ sprom[SPROM_PA0B2 + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_PA1B0:
+ sprom[SPROM_PA1B0 + 0] = (v & 0x00FF);
+ sprom[SPROM_PA1B0 + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_PA1B1:
+ sprom[SPROM_PA1B1 + 0] = (v & 0x00FF);
+ sprom[SPROM_PA1B1 + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_PA1B2:
+ sprom[SPROM_PA1B2 + 0] = (v & 0x00FF);
+ sprom[SPROM_PA1B2 + 1] = (v & 0xFF00) >> 8;
+ break;
+ case VALUE_WL0GPIO0:
+ sprom[SPROM_WL0GPIO0 + 0] = (v & 0xFF);
+ break;
+ case VALUE_WL0GPIO1:
+ sprom[SPROM_WL0GPIO0 + 1] = (v & 0xFF);
+ break;
+ case VALUE_WL0GPIO2:
+ sprom[SPROM_WL0GPIO2 + 0] = (v & 0xFF);
+ break;
+ case VALUE_WL0GPIO3:
+ sprom[SPROM_WL0GPIO2 + 1] = (v & 0xFF);
+ break;
+ case VALUE_MAXPA:
+ sprom[SPROM_MAXPWR + 0] = (v & 0xFF);
+ break;
+ case VALUE_MAXPBG:
+ sprom[SPROM_MAXPWR + 1] = (v & 0xFF);
+ break;
+ case VALUE_ITSSIA:
+ sprom[SPROM_IDL_TSSI_TGT + 0] = (v & 0xFF);
+ break;
+ case VALUE_ITSSIBG:
+ sprom[SPROM_IDL_TSSI_TGT + 1] = (v & 0xFF);
+ break;
+ case VALUE_SVER:
+ sprom[SPROM_VERSION + 0] = (v & 0xFF);
+ break;
+ default:
+ prerror("vparm->type internal error (0)\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+static int modify_sprom(uint8_t *sprom)
+{
+ struct cmdline_vparm *vparm;
+ int i;
+ int modified = 0;
+ uint8_t crc;
+
+ for (i = 0; i < cmdargs.nr_vparm; i++) {
+ vparm = &(cmdargs.vparm[i]);
+ if (!vparm->set)
+ continue;
+ modify_value(sprom, vparm);
+ modified = 1;
+ }
+ if (modified) {
+ /* Recalculate the CRC. */
+ crc = sprom_crc(sprom);
+ sprom[SPROM_VERSION + 1] = crc;
+ }
+
+ return modified;
+}
+
+static void display_value(const uint8_t *sprom,
+ struct cmdline_vparm *vparm)
+{
+ const char *desc;
+ uint8_t offset;
+ uint16_t value;
+ uint16_t tmp;
+
+ switch (vparm->type) {
+ case VALUE_RAW:
+ desc = "RAW";
+ offset = vparm->u.raw.offset;
+ value = sprom[offset];
+ break;
+ case VALUE_SUBP:
+ desc = "Subsytem product ID";
+ offset = SPROM_SUBP;
+ value = sprom[SPROM_SUBP + 0];
+ value |= sprom[SPROM_SUBP + 1] << 8;
+ break;
+ case VALUE_SUBV:
+ desc = "Subsystem vendor ID";
+ offset = SPROM_SUBV;
+ value = sprom[SPROM_SUBV + 0];
+ value |= sprom[SPROM_SUBV + 1] << 8;
+ break;
+ case VALUE_PPID:
+ desc = "PCI Product ID";
+ offset = SPROM_PPID;
+ value = sprom[SPROM_PPID + 0];
+ value |= sprom[SPROM_PPID + 1] << 8;
+ break;
+ case VALUE_BFLHI:
+ desc = "High 16 bits of Boardflags";
+ offset = SPROM_BFLHI;
+ value = sprom[SPROM_BFLHI + 0];
+ value |= sprom[SPROM_BFLHI + 1] << 8;
+ break;
+ case VALUE_BFL:
+ desc = "Low 16 bits of Boardflags";
+ offset = SPROM_BOARDFLAGS;
+ value = sprom[SPROM_BOARDFLAGS + 0];
+ value |= sprom[SPROM_BOARDFLAGS + 1] << 8;
+ break;
+ case VALUE_BGMAC:
+ desc = "MAC address for 802.11b/g";
+ offset = SPROM_IL0MACADDR;
+ value = 0;
+ break;
+ case VALUE_ETMAC:
+ desc = "MAC address for ethernet";
+ offset = SPROM_ET0MACADDR;
+ value = 0;
+ break;
+ case VALUE_AMAC:
+ desc = "MAC address for 802.11a";
+ offset = SPROM_ET1MACADDR;
+ value = 0;
+ break;
+ case VALUE_ET0PHY:
+ desc = "Ethernet phy settings (0)";
+ offset = SPROM_ETHPHY;
+ tmp = sprom[SPROM_ETHPHY + 0];
+ tmp |= sprom[SPROM_ETHPHY + 1] << 8;
+ value = (tmp & 0x001F);
+ break;
+ case VALUE_ET1PHY:
+ desc = "Ethernet phy settings (1)";
+ offset = SPROM_ETHPHY;
+ tmp = sprom[SPROM_ETHPHY + 0];
+ tmp |= sprom[SPROM_ETHPHY + 1] << 8;
+ value = (tmp & 0x03E0) >> 5;
+ break;
+ case VALUE_ET0MDC:
+ desc = "et0mdcport";
+ offset = SPROM_ETHPHY + 1;
+ value = 0;
+ if (sprom[SPROM_ETHPHY + 1] & (1 << 6))
+ value = 1;
+ break;
+ case VALUE_ET1MDC:
+ desc = "et1mdcport";
+ offset = SPROM_ETHPHY + 1;
+ value = 0;
+ if (sprom[SPROM_ETHPHY + 1] & (1 << 7))
+ value = 1;
+ break;
+ case VALUE_BREV:
+ desc = "Board revision";
+ offset = SPROM_BOARDREV;
+ value = sprom[SPROM_BOARDREV + 0];
+ break;
+ case VALUE_LOC:
+ desc = "Locale / Country Code";
+ offset = SPROM_BOARDREV + 1;
+ value = (sprom[SPROM_BOARDREV + 1] & 0x0F);
+ break;
+ case VALUE_ANTA0:
+ desc = "A PHY antenna 0 available";
+ offset = SPROM_BOARDREV + 1;
+ value = 0;
+ if (sprom[SPROM_BOARDREV + 1] & (1 << 4))
+ value = 1;
+ break;
+ case VALUE_ANTA1:
+ desc = "A PHY antenna 1 available";
+ offset = SPROM_BOARDREV + 1;
+ value = 0;
+ if (sprom[SPROM_BOARDREV + 1] & (1 << 5))
+ value = 1;
+ break;
+ case VALUE_ANTBG0:
+ desc = "B/G PHY antenna 0 available";
+ offset = SPROM_BOARDREV + 1;
+ value = 0;
+ if (sprom[SPROM_BOARDREV + 1] & (1 << 6))
+ value = 1;
+ break;
+ case VALUE_ANTBG1:
+ desc = "B/G PHY antenna 1 available";
+ offset = SPROM_BOARDREV + 1;
+ value = 0;
+ if (sprom[SPROM_BOARDREV + 1] & (1 << 7))
+ value = 1;
+ break;
+ case VALUE_ANTGA:
+ desc = "A PHY antenna gain";
+ offset = SPROM_ANTENNA_GAIN;
+ value = sprom[SPROM_ANTENNA_GAIN];
+ break;
+ case VALUE_ANTGBG:
+ desc = "B/G PHY antenna gain";
+ offset = SPROM_ANTENNA_GAIN + 1;
+ value = sprom[SPROM_ANTENNA_GAIN + 1];
+ break;
+ case VALUE_PA0B0:
+ desc = "pa0b0";
+ offset = SPROM_PA0B0;
+ value = sprom[offset + 0];
+ value |= sprom[offset + 1] << 8;
+ break;
+ case VALUE_PA0B1:
+ desc = "pa0b1";
+ offset = SPROM_PA0B1;
+ value = sprom[offset + 0];
+ value |= sprom[offset + 1] << 8;
+ break;
+ case VALUE_PA0B2:
+ desc = "pa0b2";
+ offset = SPROM_PA0B2;
+ value = sprom[offset + 0];
+ value |= sprom[offset + 1] << 8;
+ break;
+ case VALUE_PA1B0:
+ desc = "pa1b0";
+ offset = SPROM_PA1B0;
+ value = sprom[offset + 0];
+ value |= sprom[offset + 1] << 8;
+ break;
+ case VALUE_PA1B1:
+ desc = "pa1b1";
+ offset = SPROM_PA1B1;
+ value = sprom[offset + 0];
+ value |= sprom[offset + 1] << 8;
+ break;
+ case VALUE_PA1B2:
+ desc = "pa1b2";
+ offset = SPROM_PA1B2;
+ value = sprom[offset + 0];
+ value |= sprom[offset + 1] << 8;
+ break;
+ case VALUE_WL0GPIO0:
+ desc = "LED 0 behaviour";
+ offset = SPROM_WL0GPIO0 + 0;
+ value = sprom[offset];
+ break;
+ case VALUE_WL0GPIO1:
+ desc = "LED 1 behaviour";
+ offset = SPROM_WL0GPIO0 + 1;
+ value = sprom[offset];
+ break;
+ case VALUE_WL0GPIO2:
+ desc = "LED 2 behaviour";
+ offset = SPROM_WL0GPIO2 + 0;
+ value = sprom[offset];
+ break;
+ case VALUE_WL0GPIO3:
+ desc = "LED 3 behaviour";
+ offset = SPROM_WL0GPIO2 + 1;
+ value = sprom[offset];
+ break;
+ case VALUE_MAXPA:
+ desc = "A PHY max powerout";
+ offset = SPROM_MAXPWR + 0;
+ value = sprom[offset];
+ break;
+ case VALUE_MAXPBG:
+ desc = "B/G PHY max powerout";
+ offset = SPROM_MAXPWR + 1;
+ value = sprom[offset];
+ break;
+ case VALUE_ITSSIA:
+ desc = "A PHY idle TSSI target";
+ offset = SPROM_IDL_TSSI_TGT + 0;
+ value = sprom[offset];
+ break;
+ case VALUE_ITSSIBG:
+ desc = "B/G PHY idle TSSI target";
+ offset = SPROM_IDL_TSSI_TGT + 1;
+ value = sprom[offset];
+ break;
+ case VALUE_SVER:
+ desc = "SPROM version";
+ offset = SPROM_VERSION;
+ value = sprom[offset];
+ break;
+ default:
+ prerror("vparm->type internal error (1)\n");
+ exit(1);
+ }
+
+ switch (vparm->bits) {
+ case 1:
+ prdata("SPROM(0x%02X, %s) = %s\n",
+ offset, desc, value ? "ON" : "OFF");
+ break;
+ case 4:
+ prdata("SPROM(0x%02X, %s) = 0x%01X\n",
+ offset, desc, (value & 0xF));
+ break;
+ case 8:
+ prdata("SPROM(0x%02X, %s) = 0x%02X\n",
+ offset, desc, (value & 0xFF));
+ break;
+ case 16:
+ prdata("SPROM(0x%02X, %s) = 0x%04X\n",
+ offset, desc, (value & 0xFFFF));
+ break;
+ case -1: {
+ /* MAC address. */
+ const uint8_t *p = &(sprom[offset]);
+
+ prdata("SPROM(0x%02X, %s) = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ offset, desc,
+ p[1], p[0], p[3], p[2], p[5], p[4]);
+ break;
+ }
+ default:
+ prerror("vparm->bits internal error (%d)\n",
+ vparm->bits);
+ exit(1);
+ }
+}
+
+static int display_sprom(const uint8_t *sprom)
+{
+ struct cmdline_vparm *vparm;
+ int i;
+
+ for (i = 0; i < cmdargs.nr_vparm; i++) {
+ vparm = &(cmdargs.vparm[i]);
+ if (vparm->set)
+ continue;
+ display_value(sprom, vparm);
+ }
+
+ return 0;
+}
+
+static int validate_input(const uint8_t *sprom)
+{
+ uint8_t crc, expected_crc;
+
+ crc = sprom_crc(sprom);
+ expected_crc = sprom[SPROM_VERSION + 1];
+ if (crc != expected_crc) {
+ prerror("Corrupt input data (crc: 0x%02X, expected: 0x%02X)\n",
+ crc, expected_crc);
+ if (!cmdargs.force)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int parse_input(uint8_t *sprom, char *buffer, size_t bsize)
+{
+ char *input;
+ size_t inlen;
+ size_t cnt;
+ unsigned long parsed;
+ char tmp[SPROM_SIZE * 2 + 10] = { 0 };
+
+ if (cmdargs.bin_mode) {
+ /* The input buffer already contains
+ * the binary sprom data.
+ */
+ internal_error_on(bsize != SPROM_SIZE);
+ memcpy(sprom, buffer, SPROM_SIZE);
+ return 0;
+ }
+
+ inlen = bsize;
+ input = strchr(buffer, ':');
+ if (input) {
+ input++;
+ inlen -= input - buffer;
+ } else
+ input = buffer;
+
+ if (inlen < SPROM_SIZE * 2) {
+ prerror("Input data too short\n");
+ return -1;
+ }
+ for (cnt = 0; cnt < SPROM_SIZE; cnt++) {
+ memcpy(tmp, input + cnt * 2, 2);
+ parsed = strtoul(tmp, NULL, 16);
+ sprom[cnt] = parsed & 0xFF;
+ }
+
+ if (cmdargs.verbose) {
+ hexdump_sprom(sprom, tmp, sizeof(tmp));
+ prinfo("Raw input: %s\n", tmp);
+ }
+
+ return 0;
+}
+
+static int read_infile(int fd, char **buffer, size_t *bsize)
+{
+ struct stat s;
+ int err;
+ ssize_t r;
+
+ err = fstat(fd, &s);
+ if (err) {
+ prerror("Could not stat input file.\n");
+ return err;
+ }
+ if (s.st_size == 0) {
+ prerror("No input data\n");
+ return -1;
+ }
+ if (cmdargs.bin_mode) {
+ if (s.st_size != SPROM_SIZE) {
+ prerror("The input data is no SPROM Binary data. "
+ "The size must be exactly %d bytes, "
+ "but it is %u bytes\n",
+ SPROM_SIZE, (unsigned int)(s.st_size));
+ return -1;
+ }
+ } else {
+ if (s.st_size > 1024 * 1024) {
+ prerror("The input data does not look "
+ "like SPROM HEX data (too long).\n");
+ return -1;
+ }
+ }
+
+ *bsize = s.st_size;
+ if (!cmdargs.bin_mode)
+ (*bsize)++;
+ *buffer = malloce(*bsize);
+ r = read(fd, *buffer, s.st_size);
+ if (r != s.st_size) {
+ prerror("Could not read input data.\n");
+ return -1;
+ }
+ if (!cmdargs.bin_mode)
+ (*buffer)[r] = '\0';
+
+ return 0;
+}
+
+static void close_infile(int fd)
+{
+ if (cmdargs.infile)
+ close(fd);
+}
+
+static void close_outfile(int fd)
+{
+ if (cmdargs.outfile)
+ close(fd);
+}
+
+static int open_infile(int *fd)
+{
+ *fd = STDIN_FILENO;
+ if (!cmdargs.infile)
+ return 0;
+ *fd = open(cmdargs.infile, O_RDONLY);
+ if (*fd < 0) {
+ prerror("Could not open --infile %s\n",
+ cmdargs.infile);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int open_outfile(int *fd)
+{
+ *fd = STDOUT_FILENO;
+ if (!cmdargs.outfile)
+ return 0;
+ *fd = open(cmdargs.outfile, O_RDWR | O_CREAT, 0644);
+ if (*fd < 0) {
+ prerror("Could not open --outfile %s\n",
+ cmdargs.outfile);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void print_banner(int forceprint)
+{
+ const char *str = "Broadcom-SSB SPROM data modification tool version " VERSION "\n";
+ if (forceprint)
+ prdata(str);
+ else
+ prinfo(str);
+}
+
+static void print_usage(int argc, char *argv[])
+{
+ print_banner(1);
+ prdata("\nUsage: %s [OPTION]\n", argv[0]);
+ prdata(" -i|--input FILE Input file\n");
+ prdata(" -o|--output FILE Output file\n");
+ prdata(" -b|--binmode The Input data is plain binary data and Output will be binary\n");
+ prdata(" -V|--verbose Be verbose\n");
+ prdata(" -f|--force Override error checks\n");
+ prdata(" -v|--version Print version\n");
+ prdata(" -h|--help Print this help\n");
+ prdata("\n");
+ prdata("Value Parameters:\n");
+ prdata("\n");
+ prdata(" -s|--rawset OFF,VAL Set a VALue at a byte-OFFset\n");
+ prdata(" -g|--rawget OFF Get a value at a byte-OFFset\n");
+ prdata("\n");
+ prdata("Predefined values (for displaying (GET) or modification):\n");
+ prdata(" --subp [0xFFFF] Subsytem product ID for PCI\n");
+ prdata(" --subv [0xFFFF] Subsystem vendor ID for PCI\n");
+ prdata(" --ppid [0xFFFF] Product ID for PCI\n");
+ prdata(" --bflhi [0xFFFF] High 16 bits of boardflags (only if spromversion > 1)\n");
+ prdata(" --bfl [0xFFFF] Low 16 bits of boardflags\n");
+ prdata(" --bgmac [MAC-ADDR] MAC address for 802.11b/g\n");
+ prdata(" --etmac [MAC-ADDR] MAC address for ethernet, see b44 driver\n");
+ prdata(" --amac [MAC-ADDR] Mac address for 802.11a\n");
+ prdata(" --et0phy [0xFF]\n");
+ prdata(" --et1phy [0xFF]\n");
+ prdata(" --et0mdc [BOOL]\n");
+ prdata(" --et1mdc [BOOL]\n");
+ prdata(" --brev [0xFF] Board revision\n");
+ prdata(" --loc [0xF] Country code\n");
+ prdata(" --anta0 [BOOL] Antenna 0 available for A PHY\n");
+ prdata(" --anta1 [BOOL] Antenna 1 available for A PHY\n");
+ prdata(" --antbg0 [BOOL] Antenna 0 available for B/G PHY\n");
+ prdata(" --antbg1 [BOOL] Antenna 1 available for B/G PHY\n");
+ prdata(" --antga [0xFF] Antenna gain for A PHY\n");
+ prdata(" --antgbg [0xFF] Antenna gain for B/G PHY\n");
+ prdata(" --pa0b0 [0xFFFF]\n");
+ prdata(" --pa0b1 [0xFFFF]\n");
+ prdata(" --pa0b2 [0xFFFF]\n");
+ prdata(" --pa1b0 [0xFFFF]\n");
+ prdata(" --pa1b1 [0xFFFF]\n");
+ prdata(" --pa1b2 [0xFFFF]\n");
+ prdata(" --wl0gpio0 [0xFF] LED 0 behaviour\n");
+ prdata(" --wl0gpio1 [0xFF] LED 1 behaviour\n");
+ prdata(" --wl0gpio2 [0xFF] LED 2 behaviour\n");
+ prdata(" --wl0gpio3 [0xFF] LED 3 behaviour\n");
+ prdata(" --maxpa [0xFF] A PHY max power\n");
+ prdata(" --maxpbg [0xFF] B/G PHY max power\n");
+ prdata(" --itssia [0xFF] Idle tssi target for A PHY\n");
+ prdata(" --itssibg [0xFF] Idle tssi target for B/G PHY\n");
+ prdata(" --sver [0xFF] SPROM-version\n");
+ prdata("\n");
+ prdata(" -P|--print-all Display all values\n");
+ prdata("\n");
+ prdata(" BOOL is a boolean value. Either 0 or 1\n");
+ prdata(" 0xF.. is a hexadecimal value\n");
+ prdata(" MAC-ADDR is a MAC address in the format 00:00:00:00:00:00\n");
+ prdata(" If the value parameter is \"GET\", the value will be printed;\n");
+ prdata(" otherwise it is modified.\n");
+}
+
+#define ARG_MATCH 0
+#define ARG_NOMATCH 1
+#define ARG_ERROR -1
+
+static int do_cmp_arg(char **argv, int *pos,
+ const char *template,
+ int allow_merged,
+ char **param)
+{
+ char *arg;
+ char *next_arg;
+ size_t arg_len, template_len;
+
+ arg = argv[*pos];
+ next_arg = argv[*pos + 1];
+ arg_len = strlen(arg);
+ template_len = strlen(template);
+
+ if (param) {
+ /* Maybe we have a merged parameter here.
+ * A merged parameter is "-pfoobar" for example.
+ */
+ if (allow_merged && arg_len > template_len) {
+ if (memcmp(arg, template, template_len) == 0) {
+ *param = arg + template_len;
+ return ARG_MATCH;
+ }
+ return ARG_NOMATCH;
+ } else if (arg_len != template_len)
+ return ARG_NOMATCH;
+ *param = next_arg;
+ }
+ if (strcmp(arg, template) == 0) {
+ if (param) {
+ /* Skip the parameter on the next iteration. */
+ (*pos)++;
+ if (*param == 0) {
+ prerror("%s needs a parameter\n", arg);
+ return ARG_ERROR;
+ }
+ }
+ return ARG_MATCH;
+ }
+
+ return ARG_NOMATCH;
+}
+
+/* Simple and lean command line argument parsing. */
+static int cmp_arg(char **argv, int *pos,
+ const char *long_template,
+ const char *short_template,
+ char **param)
+{
+ int err;
+
+ if (long_template) {
+ err = do_cmp_arg(argv, pos, long_template, 0, param);
+ if (err == ARG_MATCH || err == ARG_ERROR)
+ return err;
+ }
+ err = ARG_NOMATCH;
+ if (short_template)
+ err = do_cmp_arg(argv, pos, short_template, 1, param);
+ return err;
+}
+
+static int parse_err;
+
+static int arg_match(char **argv, int *i,
+ const char *long_template,
+ const char *short_template,
+ char **param)
+{
+ int res;
+
+ res = cmp_arg(argv, i, long_template,
+ short_template, param);
+ if (res == ARG_ERROR) {
+ parse_err = 1;
+ return 0;
+ }
+ return (res == ARG_MATCH);
+}
+
+static int parse_value(const char *str,
+ struct cmdline_vparm *vparm,
+ const char *param)
+{
+ unsigned long v;
+ int i;
+
+ vparm->bits = value_length_map[vparm->type];
+ vparm->set = 1;
+ if (strcmp(str, "GET") == 0 || strcmp(str, "get") == 0) {
+ vparm->set = 0;
+ return 0;
+ }
+ if (vparm->bits == 1) {
+ /* This is a boolean value. */
+ if (strcmp(str, "0") == 0)
+ vparm->u.value = 0;
+ else if (strcmp(str, "1") == 0)
+ vparm->u.value = 1;
+ else
+ goto error_bool;
+ return 1;
+ }
+
+ if (strncmp(str, "0x", 2) != 0)
+ goto error;
+ str += 2;
+ for (i = 0; i < vparm->bits / 4; i++) {
+ if (str[i] == '\0')
+ goto error;
+ }
+ if (str[i] != '\0')
+ goto error;
+ errno = 0;
+ v = strtoul(str, NULL, 16);
+ if (errno)
+ goto error;
+ vparm->u.value = v;
+
+ return 1;
+error:
+ if (param) {
+ prerror("%s value parsing error. Format: 0x", param);
+ for (i = 0; i < vparm->bits / 4; i++)
+ prerror("F");
+ prerror("\n");
+ }
+ return -1;
+
+error_bool:
+ if (param)
+ prerror("%s value parsing error. Format: 0 or 1 (boolean)\n", param);
+ return -1;
+}
+
+static int parse_mac(const char *str,
+ struct cmdline_vparm *vparm,
+ const char *param)
+{
+ int i;
+ char *delim;
+ const char *in = str;
+ uint8_t *out = vparm->u.mac;
+
+ vparm->bits = -1;
+ vparm->set = 1;
+ if (strcmp(str, "GET") == 0 || strcmp(str, "get") == 0) {
+ vparm->set = 0;
+ return 0;
+ }
+
+ for (i = 0; ; i++) {
+ errno = 0;
+ out[i] = strtoul(in, NULL, 16);
+ if (errno)
+ goto error;
+ if (i == 5) {
+ if (in[1] != '\0' && in[2] != '\0')
+ goto error;
+ break;
+ }
+ delim = strchr(in, ':');
+ if (!delim)
+ goto error;
+ in = delim + 1;
+ }
+
+ return 1;
+error:
+ prerror("%s MAC parsing error. Format: 00:00:00:00:00:00\n", param);
+ return -1;
+}
+
+static int parse_rawset(const char *str,
+ struct cmdline_vparm *vparm)
+{
+ char *delim;
+ uint8_t value;
+ uint8_t offset;
+ int err;
+
+ vparm->type = VALUE_RAW;
+
+ delim = strchr(str, ',');
+ if (!delim)
+ goto error;
+ *delim = '\0';
+ err = parse_value(str, vparm, NULL);
+ if (err != 1)
+ goto error;
+ offset = vparm->u.value;
+ if (offset >= SPROM_SIZE) {
+ prerror("--rawset offset too big (>= 0x%02X)\n",
+ SPROM_SIZE);
+ return -1;
+ }
+ err = parse_value(delim + 1, vparm, NULL);
+ if (err != 1)
+ goto error;
+ value = vparm->u.value;
+
+ vparm->u.raw.value = value;
+ vparm->u.raw.offset = offset;
+ vparm->set = 1;
+
+ return 0;
+error:
+ prerror("--rawset value parsing error. Format: 0xFF,0xFF "
+ "(first Offset, second Value)\n");
+ return -1;
+}
+
+static int parse_rawget(const char *str,
+ struct cmdline_vparm *vparm)
+{
+ int err;
+ uint8_t offset;
+
+ vparm->type = VALUE_RAW;
+
+ err = parse_value(str, vparm, "--rawget");
+ if (err != 1)
+ return -1;
+ offset = vparm->u.value;
+ if (offset >= SPROM_SIZE) {
+ prerror("--rawget offset too big (>= 0x%02X)\n",
+ SPROM_SIZE);
+ return -1;
+ }
+
+ vparm->u.raw.offset = offset;
+ vparm->type = VALUE_RAW;
+ vparm->set = 0;
+
+ return 0;
+}
+
+static int generate_printall(void)
+{
+ struct cmdline_vparm *vparm;
+ int count, i;
+ enum valuetype vt = VALUE_FIRST;
+
+ count = VALUE_LAST - VALUE_FIRST + 1;
+ for (i = 0; i < count; i++, vt++) {
+ if (cmdargs.nr_vparm == MAX_VPARM) {
+ prerror("Too many value parameters.\n");
+ return -1;
+ }
+
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = vt;
+ vparm->set = 0;
+ vparm->bits = value_length_map[vt];
+ }
+
+ return 0;
+}
+
+static int parse_args(int argc, char *argv[])
+{
+ struct cmdline_vparm *vparm;
+ int i, err;
+ char *param;
+
+ parse_err = 0;
+ for (i = 1; i < argc; i++) {
+ if (cmdargs.nr_vparm == MAX_VPARM) {
+ prerror("Too many value parameters.\n");
+ return -1;
+ }
+
+ if (arg_match(argv, &i, "--version", "-v", 0)) {
+ print_banner(1);
+ return 1;
+ } else if (arg_match(argv, &i, "--help", "-h", 0)) {
+ goto out_usage;
+ } else if (arg_match(argv, &i, "--input", "-i", ¶m)) {
+ cmdargs.infile = param;
+ } else if (arg_match(argv, &i, "--output", "-o", ¶m)) {
+ cmdargs.outfile = param;
+ } else if (arg_match(argv, &i, "--verbose", "-V", 0)) {
+ cmdargs.verbose = 1;
+ } else if (arg_match(argv, &i, "--force", "-n", 0)) {
+ cmdargs.force = 1;
+ } else if (arg_match(argv, &i, "--binmode", "-b", 0)) {
+ cmdargs.bin_mode = 1;
+
+
+ } else if (arg_match(argv, &i, "--rawset", "-s", ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ err = parse_rawset(param, vparm);
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--rawget", "-g", ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ err = parse_rawget(param, vparm);
+ if (err < 0)
+ goto error;
+
+
+ } else if (arg_match(argv, &i, "--subp", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_SUBP;
+ err = parse_value(param, vparm, "--subp");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--subv", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_SUBV;
+ err = parse_value(param, vparm, "--subv");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--ppid", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_PPID;
+ err = parse_value(param, vparm, "--ppid");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--bflhi", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_BFLHI;
+ err = parse_value(param, vparm, "--bflhi");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--bfl", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_BFL;
+ err = parse_value(param, vparm, "--bfl");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--bgmac", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_BGMAC;
+ err = parse_mac(param, vparm, "--bgmac");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--etmac", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ETMAC;
+ err = parse_mac(param, vparm, "--etmac");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--amac", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_AMAC;
+ err = parse_mac(param, vparm, "--amac");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--et0phy", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ET0PHY;
+ err = parse_value(param, vparm, "--et0phy");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--et1phy", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ET1PHY;
+ err = parse_value(param, vparm, "--et1phy");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--et0mdc", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ET0MDC;
+ err = parse_value(param, vparm, "--et0mdc");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--et1mdc", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ET1MDC;
+ err = parse_value(param, vparm, "--et1mdc");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--brev", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_BREV;
+ err = parse_value(param, vparm, "--brev");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--loc", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_LOC;
+ err = parse_value(param, vparm, "--loc");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--anta0", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ANTA0;
+ err = parse_value(param, vparm, "--anta0");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--anta1", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ANTA1;
+ err = parse_value(param, vparm, "--anta1");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--antbg0", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ANTBG0;
+ err = parse_value(param, vparm, "--antbg0");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--antbg1", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ANTBG1;
+ err = parse_value(param, vparm, "--antbg1");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--antga", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ANTGA;
+ err = parse_value(param, vparm, "--antga");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--antgbg", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ANTGBG;
+ err = parse_value(param, vparm, "--antgbg");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--pa0b0", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_PA0B0;
+ err = parse_value(param, vparm, "--pa0b0");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--pa0b1", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_PA0B1;
+ err = parse_value(param, vparm, "--pa0b1");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--pa0b2", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_PA0B2;
+ err = parse_value(param, vparm, "--pa0b2");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--pa1b0", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_PA1B0;
+ err = parse_value(param, vparm, "--pa1b0");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--pa1b1", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_PA1B1;
+ err = parse_value(param, vparm, "--pa1b1");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--pa1b2", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_PA1B2;
+ err = parse_value(param, vparm, "--pa1b2");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--wl0gpio0", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_WL0GPIO0;
+ err = parse_value(param, vparm, "--wl0gpio0");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--wl0gpio1", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_WL0GPIO1;
+ err = parse_value(param, vparm, "--wl0gpio1");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--wl0gpio2", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_WL0GPIO2;
+ err = parse_value(param, vparm, "--wl0gpio2");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--wl0gpio3", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_WL0GPIO3;
+ err = parse_value(param, vparm, "--wl0gpio3");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--maxpa", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_MAXPA;
+ err = parse_value(param, vparm, "--maxpa");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--maxpbg", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_MAXPBG;
+ err = parse_value(param, vparm, "--maxpbg");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--itssia", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ITSSIA;
+ err = parse_value(param, vparm, "--itssia");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--itssibg", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_ITSSIBG;
+ err = parse_value(param, vparm, "--itssibg");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--sver", 0, ¶m)) {
+ vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
+ vparm->type = VALUE_SVER;
+ err = parse_value(param, vparm, "--sver");
+ if (err < 0)
+ goto error;
+ } else if (arg_match(argv, &i, "--print-all", "-P", 0)) {
+ err = generate_printall();
+ if (err)
+ goto error;
+ } else {
+ prerror("Unrecognized argument: %s\n", argv[i]);
+ goto out_usage;
+ }
+ if (parse_err)
+ goto out_usage;
+ }
+ if (cmdargs.nr_vparm == 0) {
+ prerror("No Value parameter given. See --help.\n");
+ return -1;
+ }
+ return 0;
+
+out_usage:
+ print_usage(argc, argv);
+error:
+ return -1;
+}
+
+
+int main(int argc, char **argv)
+{
+ int err;
+ int fd;
+ uint8_t sprom[SPROM_SIZE];
+ char *buffer = NULL;
+ size_t buffer_size = 0;
+
+ err = parse_args(argc, argv);
+ if (err == 1)
+ return 0;
+ else if (err != 0)
+ goto out;
+
+ print_banner(0);
+ prinfo("\nReading input from \"%s\"...\n",
+ cmdargs.infile ? cmdargs.infile : "stdin");
+
+ err = open_infile(&fd);
+ if (err)
+ goto out;
+ err = read_infile(fd, &buffer, &buffer_size);
+ close_infile(fd);
+ if (err)
+ goto out;
+ err = parse_input(sprom, buffer, buffer_size);
+ free(buffer);
+ if (err)
+ goto out;
+ err = validate_input(sprom);
+ if (err)
+ goto out;
+
+ err = display_sprom(sprom);
+ if (err)
+ goto out;
+ err = modify_sprom(sprom);
+ if (err < 0)
+ goto out;
+ if (err) {
+ err = open_outfile(&fd);
+ if (err)
+ goto out;
+ err = write_output(fd, sprom);
+ close_outfile(fd);
+ if (err)
+ goto out;
+ prinfo("SPROM modified.\n");
+ }
+out:
+ return err;
+}
--- /dev/null
+/*
+
+ Broadcom Sonics Silicon Backplane bus SPROM data modification tool
+
+ Copyright (c) 2006-2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef SSB_SPROMTOOL_H_
+#define SSB_SPROMTOOL_H_
+
+#include "utils.h"
+
+#define VERSION ssb_stringify(VERSION_)
+
+#define SPROM_SIZE 128 /* bytes */
+
+/* byte offsets */
+#define SPROM_SUBP (0x02 * 2)
+#define SPROM_SUBV (0x03 * 2)
+#define SPROM_PPID (0x04 * 2)
+#define SPROM_BFLHI (0x1C * 2)
+#define SPROM_IL0MACADDR (0x24 * 2)
+#define SPROM_ET0MACADDR (0x27 * 2)
+#define SPROM_ET1MACADDR (0x2a * 2)
+#define SPROM_ETHPHY (0x2d * 2)
+#define SPROM_BOARDREV (0x2e * 2)
+#define SPROM_PA0B0 (0x2f * 2)
+#define SPROM_PA0B1 (0x30 * 2)
+#define SPROM_PA0B2 (0x31 * 2)
+#define SPROM_WL0GPIO0 (0x32 * 2)
+#define SPROM_WL0GPIO2 (0x33 * 2)
+#define SPROM_MAXPWR (0x34 * 2)
+#define SPROM_PA1B0 (0x35 * 2)
+#define SPROM_PA1B1 (0x36 * 2)
+#define SPROM_PA1B2 (0x37 * 2)
+#define SPROM_IDL_TSSI_TGT (0x38 * 2)
+#define SPROM_BOARDFLAGS (0x39 * 2)
+#define SPROM_ANTENNA_GAIN (0x3a * 2)
+#define SPROM_VERSION (0x3f * 2)
+
+enum valuetype {
+ VALUE_RAW,
+
+ VALUE_SUBP,
+ VALUE_FIRST = VALUE_SUBP,
+ VALUE_SUBV,
+ VALUE_PPID,
+ VALUE_BFLHI,
+ VALUE_BFL,
+ VALUE_BGMAC,
+ VALUE_ETMAC,
+ VALUE_AMAC,
+ VALUE_ET0PHY,
+ VALUE_ET1PHY,
+ VALUE_ET0MDC,
+ VALUE_ET1MDC,
+ VALUE_BREV,
+ VALUE_LOC,
+ VALUE_ANTA0,
+ VALUE_ANTA1,
+ VALUE_ANTBG0,
+ VALUE_ANTBG1,
+ VALUE_ANTGA,
+ VALUE_ANTGBG,
+ VALUE_PA0B0,
+ VALUE_PA0B1,
+ VALUE_PA0B2,
+ VALUE_PA1B0,
+ VALUE_PA1B1,
+ VALUE_PA1B2,
+ VALUE_WL0GPIO0,
+ VALUE_WL0GPIO1,
+ VALUE_WL0GPIO2,
+ VALUE_WL0GPIO3,
+ VALUE_MAXPA,
+ VALUE_MAXPBG,
+ VALUE_ITSSIA,
+ VALUE_ITSSIBG,
+ VALUE_SVER,
+ VALUE_LAST = VALUE_SVER,
+};
+
+struct cmdline_vparm {
+ enum valuetype type;
+ int set;
+ int bits;
+ union {
+ uint16_t value;
+ uint8_t mac[6];
+ struct {
+ uint8_t value;
+ uint8_t offset;
+ } raw;
+ } u;
+};
+
+struct cmdline_args {
+ const char *infile;
+ const char *outfile;
+ int verbose;
+ int force;
+ int bin_mode;
+
+#define MAX_VPARM 512
+ struct cmdline_vparm vparm[MAX_VPARM];
+ int nr_vparm;
+};
+extern struct cmdline_args cmdargs;
+
+#endif /* SSB_SPROMTOOL_H_ */
--- /dev/null
+/*
+
+ Broadcom Sonics Silicon Backplane bus SPROM data modification tool
+
+ Copyright (c) 2006-2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "utils.h"
+#include "ssb_sprom.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+
+int prinfo(const char *fmt, ...)
+{
+ int ret;
+ va_list va;
+
+ if (!cmdargs.verbose)
+ return 0;
+
+ va_start(va, fmt);
+ ret = vfprintf(stderr, fmt, va);
+ va_end(va);
+
+ return ret;
+}
+
+int prerror(const char *fmt, ...)
+{
+ int ret;
+ va_list va;
+
+ va_start(va, fmt);
+ ret = vfprintf(stderr, fmt, va);
+ va_end(va);
+
+ return ret;
+}
+
+int prdata(const char *fmt, ...)
+{
+ int ret;
+ va_list va;
+
+ va_start(va, fmt);
+ ret = vfprintf(stderr, fmt, va);
+ va_end(va);
+
+ return ret;
+}
+
+void internal_error(const char *message)
+{
+ prerror("Internal programming error: %s\n", message);
+ exit(1);
+}
+
+static void oom(void)
+{
+ prerror("ERROR: Out of memory!\n"
+ "Virtual memory exhausted. "
+ "Please close some applications, "
+ "add more RAM or SWAP space.\n");
+ exit(1);
+}
+
+void * malloce(size_t size)
+{
+ void *ret;
+
+ ret = malloc(size);
+ if (!ret)
+ oom();
+
+ return ret;
+}
+
+void * realloce(void *ptr, size_t newsize)
+{
+ void *ret;
+
+ ret = realloc(ptr, newsize);
+ if (!ret)
+ oom();
+
+ return ret;
+}
+
+uint8_t crc8(uint8_t crc, uint8_t data)
+{
+ static const uint8_t t[] = {
+ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
+ };
+ return t[crc ^ data];
+}
--- /dev/null
+#ifndef SSB_SPROMTOOL_UTILS_H_
+#define SSB_SPROMTOOL_UTILS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#define ssb_stringify_1(x) #x
+#define ssb_stringify(x) ssb_stringify_1(x)
+
+#ifdef ATTRIBUTE_FORMAT
+# undef ATTRIBUTE_FORMAT
+#endif
+#ifdef __GNUC__
+# define ATTRIBUTE_FORMAT(t, a, b) __attribute__((format(t, a, b)))
+#else
+# define ATTRIBUTE_FORMAT(t, a, b) /* nothing */
+#endif
+
+int prinfo(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+int prerror(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+int prdata(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+
+void internal_error(const char *message);
+#define internal_error_on(condition) \
+ do { \
+ if (condition) \
+ internal_error(ssb_stringify(condition)); \
+ } while (0)
+
+void * malloce(size_t size);
+void * realloce(void *ptr, size_t newsize);
+
+/* CRC-8 with polynomial x^8+x^7+x^6+x^4+x^2+1 */
+uint8_t crc8(uint8_t crc, uint8_t data);
+
+#endif /* SSB_SPROMTOOL_UTILS_H_ */