Commit b9e19faa authored by Michael Büsch's avatar Michael Büsch

Initial commit.

Signed-off-by: Michael Büsch's avatarMichael Buesch <mb@bu3sch.de>
parents
This diff is collapsed.
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
===============================================================================
== 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
/*
* 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);
}
#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_ */
#!/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" $@
/*
* 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(&sect->ops)) {
//TODO warning
return;
}
list_for_each_entry(op, &sect->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);
}
}
#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_ */
/*
* 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)