fxos: bring disassembling to a new level

Almost-complete implementation of fxos, the disassembler in particular
is now able to detect syscalls and register addresses on the fly, plus
support for SH4-only instructions.
This commit is contained in:
Lephe 2019-05-03 11:19:36 +02:00
parent ed8e199f47
commit 25db504c22
26 changed files with 3259 additions and 281 deletions

View file

@ -6,12 +6,10 @@ include Makefile.cfg
endif endif
# Compiler flags # Compiler flags
cflags = -Wall -Wextra -std=c11 -O2 -I $(dir $<) -D_GNU_SOURCE \ cflags = -Wall -Wextra -std=c11 -g -I $(dir $<) -D_GNU_SOURCE \
-DFXSDK_PREFIX='"$(PREFIX)"' $(CFLAGS) -DFXSDK_PREFIX='"$(PREFIX)"' $(CFLAGS)
# Linker flags # Linker flags
lflags = -lpng lflags = -lpng
# Bison generation flags
# bflags = -L C --defines=$(@:.c=.h) --verbose
# Dependency generation flags # Dependency generation flags
dflags = -MT $@ -MMD -MP -MF $(@:%.o=%.d) dflags = -MT $@ -MMD -MP -MF $(@:%.o=%.d)
@ -28,15 +26,18 @@ src = $(wildcard $1/*.c)
src-fxsdk := $(call src,fxsdk) src-fxsdk := $(call src,fxsdk)
src-fxg1a := $(call src,fxg1a) src-fxg1a := $(call src,fxg1a)
src-fxos := $(call src,fxos) src-fxos := $(call src,fxos)
lex-fxos := $(wildcard fxos/*.l)
obj = $(src-$1:%=build/%.o) obj = $($1:%=build/%.o)
obj-fxsdk := $(call obj,fxsdk) lex = $($1:%.l=build/%.yy.c.o)
obj-fxg1a := $(call obj,fxg1a) obj-fxsdk := $(call obj,src-fxsdk)
obj-fxos := $(call obj,fxos) obj-fxg1a := $(call obj,src-fxg1a)
obj-fxos := $(call obj,src-fxos) $(call lex,lex-fxos)
# Symbolic targets # Symbolic targets
all: $(bin) all: $(bin)
@echo $(lex-fxos)
all-fxsdk: bin/fxsdk all-fxsdk: bin/fxsdk
all-fxg1a: bin/fxg1a all-fxg1a: bin/fxg1a
@ -62,17 +63,11 @@ build/%.c.o: %.c
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
gcc -c $< -o $@ $(cflags) $(dflags) gcc -c $< -o $@ $(cflags) $(dflags)
# Flex lexers (unused since fxconv is written in Python) # Flex lexers for the fxos database
# build/%/lexer.yy.c: %/lexer.l build/%/parser.tab.c build/fxos/lexer-%.yy.c: fxos/lexer-%.l
# flex -o $@ -s $< flex -o $@ -s $<
# build/%/lexer.yy.c.o: build/%/lexer.yy.c build/fxos/lexer-%.yy.c.o: build/fxos/lexer-%.yy.c
# gcc -c $< -o $@ $(cflags) -Wno-unused-function $(dflags) -I $* gcc -c $< -o $@ $(cflags) -Wno-unused-function $(dflags) -I fxos
# Bison parsers (unused since fxconv is written in Python)
# build/%/parser.tab.c: %/parser.y
# bison $< -o $@ $(bflags)
# build/%/parser.tab.c.o: build/%/parser.tab.c
# gcc -c $< -o $@ $(cflags) $(dflags) -I $*
# #
# Dependency system, misc. # Dependency system, misc.
@ -95,10 +90,16 @@ Makefile.cfg:
install: $(bin) install: $(bin)
install -d $(PREFIX)/bin install -d $(PREFIX)/bin
install -d $(PREFIX)/share/fxsdk
install $(bin) -m 755 $(PREFIX)/bin install $(bin) -m 755 $(PREFIX)/bin
install fxos/*.txt -m 644 $(PREFIX)/share/fxsdk
install fxconv/fxconv-main.py -m 755 $(PREFIX)/bin/fxconv install fxconv/fxconv-main.py -m 755 $(PREFIX)/bin/fxconv
install fxconv/fxconv.py -m 644 $(PREFIX)/bin install fxconv/fxconv.py -m 644 $(PREFIX)/bin
uninstall:
rm -f $(PREFIX)/bin/{fxsdk,fxg1a,fxos,fxconv,fxconv.py}
rm -rf $(PREFIX)/share/fxsdk
# #
# Cleaning # Cleaning
# #

4
configure vendored
View file

@ -5,7 +5,7 @@
# #
# Path parameters # Path parameters
PREFIX="/usr" PREFIX="$HOME/.local"
# Individual component selection # Individual component selection
BUILD_fxsdk=1 BUILD_fxsdk=1
BUILD_fxconv=1 BUILD_fxconv=1
@ -47,7 +47,7 @@ Install folders:
Executables will be installed in <prefix>/bin and runtime data in Executables will be installed in <prefix>/bin and runtime data in
<prefix>/share/fxsdk. <prefix>/share/fxsdk.
--prefix=<prefix> Base install folder [default /usr] --prefix=<prefix> Base install folder [default $HOME/.local]
EOF EOF
exit 0 exit 0
} }

22
fxos/analysis.c Normal file
View file

@ -0,0 +1,22 @@
#include <fxos.h>
#include <stdio.h>
/* analysis_short(): Print a one-line summary for an address */
void analysis_short(struct os const *os, uint32_t value)
{
/* Find out whether it is a syscall address */
int syscall = os_syscall_find(os, value);
if(syscall != -1)
{
printf(" %%%03x", syscall);
/* Also find out the syscall's name! */
struct sys_call const *call = sys_find(syscall);
if(call) printf(" %s", call->name);
}
/* Find out any peripheral register address */
struct reg_address const *reg = reg_find(value);
if(reg) printf(" %s", reg->name);
}

220
fxos/asm-sh3.txt Normal file
View file

@ -0,0 +1,220 @@
# Instruction decoding table: 'sh3'
# Format: [01nmdi]{16}, followed by the mnemonic and the list of arguments.
# There should be at most one series of each argument letter in the opcode.
#
# Possible argument strings are predefined and include:
# rn rm #imm
# jump8 jump12 disp pcdisp
# @rn @rm @rn+ @rm+ @-rn
# @(disp,rn) @(disp,rm) @(r0,rn) @(r0,rm) @(disp,gbr)
#
# The disassembler substitutes some elements as follows:
# rn -> value of the "n"-sequence
# rm -> value of the "m"-sequence
# #imm -> value of the "i"-sequence
# disp -> value of the "d"-sequence
# jump8 -> value of the 8-bit "d"-sequence plus value of PC
# jump12 -> value of the 12-bit "d"-sequence plus value of PC
# pcdisp -> same as "jump8", but also prints pointed value (for data)
0000000001001000 clrs
0000000000001000 clrt
0000000000101000 clrmac
0000000000011001 div0u
0000000000111000 ldtlb
0000000000001001 nop
0000000000101011 rte
0000000000001011 rts
0000000001011000 sets
0000000000011000 sett
0000000000011011 sleep
0100nnnn00010101 cmp/pl rn
0100nnnn00010001 cmp/pz rn
0100nnnn00010000 dt rn
0000nnnn00101001 movt rn
0100nnnn00000100 rotl rn
0100nnnn00000101 rotr rn
0100nnnn00100100 rotcl rn
0100nnnn00100101 rotcr rn
0100nnnn00100000 shal rn
0100nnnn00100001 shar rn
0100nnnn00000000 shll rn
0100nnnn00000001 shlr rn
0100nnnn00001000 shll2 rn
0100nnnn00001001 shlr2 rn
0100nnnn00011000 shll8 rn
0100nnnn00011001 shlr8 rn
0100nnnn00101000 shll16 rn
0100nnnn00101001 shlr16 rn
0011nnnnmmmm1100 add rm, rn
0011nnnnmmmm1110 addc rm, rn
0011nnnnmmmm1111 addv rm, rn
0010nnnnmmmm1001 and rm, rn
0011nnnnmmmm0000 cmp/eq rm, rn
0011nnnnmmmm0010 cmp/hs rm, rn
0011nnnnmmmm0011 cmp/ge rm, rn
0011nnnnmmmm0110 cmp/hi rm, rn
0011nnnnmmmm0111 cmp/gt rm, rn
0010nnnnmmmm1100 cmp/str rm, rn
0011nnnnmmmm0100 div1 rm, rn
0010nnnnmmmm0111 div0s rm, rn
0011nnnnmmmm1101 dmuls.l rm, rn
0011nnnnmmmm0101 dmulu.l rm, rn
0110nnnnmmmm1110 exts.b rm, rn
0110nnnnmmmm1111 exts.w rm, rn
0110nnnnmmmm1100 extu.b rm, rn
0110nnnnmmmm1101 extu.w rm, rn
0110nnnnmmmm0011 mov rm, rn
0000nnnnmmmm0111 mul.l rm, rn
0010nnnnmmmm1111 muls.w rm, rn
0010nnnnmmmm1110 mulu.w rm, rn
0110nnnnmmmm1011 neg rm, rn
0110nnnnmmmm1010 negc rm, rn
0110nnnnmmmm0111 not rm, rn
0010nnnnmmmm1011 or rm, rn
0100nnnnmmmm1100 shad rm, rn
0100nnnnmmmm1101 shld rm, rn
0011nnnnmmmm1000 sub rm, rn
0011nnnnmmmm1010 subc rm, rn
0011nnnnmmmm1011 subv rm, rn
0110nnnnmmmm1000 swap.b rm, rn
0110nnnnmmmm1001 swap.w rm, rn
0010nnnnmmmm1000 tst rm, rn
0010nnnnmmmm1010 xor rm, rn
0010nnnnmmmm1101 xtrct rm, rn
0100mmmm00001110 ldc rm, sr
0100mmmm00011110 ldc rm, gbr
0100mmmm00101110 ldc rm, vbr
0100mmmm00111110 ldc rm, ssr
0100mmmm01001110 ldc rm, spc
0100mmmm10001110 ldc rm, r0_bank
0100mmmm10011110 ldc rm, r1_bank
0100mmmm10101110 ldc rm, r2_bank
0100mmmm10111110 ldc rm, r3_bank
0100mmmm11001110 ldc rm, r4_bank
0100mmmm11011110 ldc rm, r5_bank
0100mmmm11101110 ldc rm, r6_bank
0100mmmm11111110 ldc rm, r7_bank
0100mmmm00001010 lds rm, mach
0100mmmm00011010 lds rm, macl
0100mmmm00101010 lds rm, pr
0000nnnn00000010 stc sr, rn
0000nnnn00010010 stc gbr, rn
0000nnnn00100010 stc vbr, rn
0000nnnn00110010 stc ssr, rn
0000nnnn01000010 stc spc, rn
0000nnnn10000010 stc r0_bank, rn
0000nnnn10010010 stc r1_bank, rn
0000nnnn10100010 stc r2_bank, rn
0000nnnn10110010 stc r3_bank, rn
0000nnnn11000010 stc r4_bank, rn
0000nnnn11010010 stc r5_bank, rn
0000nnnn11100010 stc r6_bank, rn
0000nnnn11110010 stc r7_bank, rn
0000nnnn00001010 sts mach, rn
0000nnnn00011010 sts macl, rn
0000nnnn00101010 sts pr, rn
0100nnnn00101011 jmp @rn
0100nnnn00001011 jsr @rn
0000nnnn10000011 pref @rn
0100nnnn00011011 tas.b @rn
0010nnnnmmmm0000 mov.b rm, @rn
0010nnnnmmmm0001 mov.w rm, @rn
0010nnnnmmmm0010 mov.l rm, @rn
0110nnnnmmmm0000 mov.b @rm, rn
0110nnnnmmmm0001 mov.w @rm, rn
0110nnnnmmmm0010 mov.l @rm, rn
0000nnnnmmmm1111 mac.l @rm+, @rn+
0100nnnnmmmm1111 mac.w @rm+, @rn+
0110nnnnmmmm0100 mov.b @rm+, rn
0110nnnnmmmm0101 mov.w @rm+, rn
0110nnnnmmmm0110 mov.l @rm+, rn
0100mmmm00000111 ldc.l @rm+, sr
0100mmmm00010111 ldc.l @rm+, gbr
0100mmmm00100111 ldc.l @rm+, vbr
0100mmmm00110111 ldc.l @rm+, ssr
0100mmmm01000111 ldc.l @rm+, spc
0100mmmm10000111 ldc.l @rm+, r0_bank
0100mmmm10010111 ldc.l @rm+, r1_bank
0100mmmm10100111 ldc.l @rm+, r2_bank
0100mmmm10110111 ldc.l @rm+, r3_bank
0100mmmm11000111 ldc.l @rm+, r4_bank
0100mmmm11010111 ldc.l @rm+, r5_bank
0100mmmm11100111 ldc.l @rm+, r6_bank
0100mmmm11110111 ldc.l @rm+, r7_bank
0100mmmm00000110 lds.l @rm+, mach
0100mmmm00010110 lds.l @rm+, macl
0100mmmm00100110 lds.l @rm+, pr
0010nnnnmmmm0100 mov.b rm, @-rn
0010nnnnmmmm0101 mov.w rm, @-rn
0010nnnnmmmm0110 mov.l rm, @-rn
0100nnnn00000011 stc.l sr, @-rn
0100nnnn00010011 stc.l gbr, @-rn
0100nnnn00100011 stc.l vbr, @-rn
0100nnnn00110011 stc.l ssr, @-rn
0100nnnn01000011 stc.l spc, @-rn
0100nnnn10000011 stc.l r0_bank, @-rn
0100nnnn10010011 stc.l r1_bank, @-rn
0100nnnn10100011 stc.l r2_bank, @-rn
0100nnnn10110011 stc.l r3_bank, @-rn
0100nnnn11000011 stc.l r4_bank, @-rn
0100nnnn11010011 stc.l r5_bank, @-rn
0100nnnn11100011 stc.l r6_bank, @-rn
0100nnnn11110011 stc.l r7_bank, @-rn
0100nnnn00000010 sts.l mach, @-rn
0100nnnn00010010 sts.l macl, @-rn
0100nnnn00100010 sts.l pr, @-rn
10000000nnnndddd mov.b r0, @(disp, rn)
10000001nnnndddd mov.w r0, @(disp, rn)
0001nnnnmmmmdddd mov.l rm, @(disp, rn)
10000100mmmmdddd mov.b @(disp, rm), r0
10000101mmmmdddd mov.w @(disp, rm), r0
0101nnnnmmmmdddd mov.l @(disp, rm), rn
0000nnnnmmmm0100 mov.b rm, @(r0, rn)
0000nnnnmmmm0101 mov.w rm, @(r0, rn)
0000nnnnmmmm0110 mov.l rm, @(r0, rn)
0000nnnnmmmm1100 mov.b @(r0, rm), rn
0000nnnnmmmm1101 mov.w @(r0, rm), rn
0000nnnnmmmm1110 mov.l @(r0, rm), rn
11000000dddddddd mov.b r0, @(disp, gbr)
11000001dddddddd mov.w r0, @(disp, gbr)
11000010dddddddd mov.l r0, @(disp, gbr)
11000100dddddddd mov.b @(disp, gbr), r0
11000101dddddddd mov.w @(disp, gbr), r0
11000110dddddddd mov.l @(disp, gbr), r0
11001101iiiiiiii and.b #imm, @(r0, gbr)
11001111iiiiiiii or.b #imm, @(r0, gbr)
11001100iiiiiiii tst.b #imm, @(r0, gbr)
11001110iiiiiiii xor.b #imm, @(r0, gbr)
1001nnnndddddddd mov.w pcdisp, rn
1101nnnndddddddd mov.l pcdisp, rn
11000111dddddddd mova pcdisp, r0
0000mmmm00100011 braf rm
0000mmmm00000011 bsrf rm
10001011dddddddd bf jump8
10001111dddddddd bf/s jump8
10001001dddddddd bt jump8
10001101dddddddd bt/s jump8
1010dddddddddddd bra jump12
1011dddddddddddd bsr jump12
0111nnnniiiiiiii add #imm, rn
11001001iiiiiiii and #imm, r0
10001000iiiiiiii cmp/eq #imm, r0
1110nnnniiiiiiii mov #imm, rn
11001011iiiiiiii or #imm, r0
11001000iiiiiiii tst #imm, r0
11001010iiiiiiii xor #imm, r0
11000011iiiiiiii trapa #imm

26
fxos/asm-sh4.txt Normal file
View file

@ -0,0 +1,26 @@
# Instruction decoding table: 'sh4'
# This table is an extension for SH4 processors. See 'asm-sh3.txt' for details
# on the format.
0000nnnn01110011 movco.l r0, @rn
0000mmmm01100011 movli.l @rm, r0
0100mmmm10101001 movua.l @rm, r0
0100mmmm11101001 movua.l @rm+, r0
0000nnnn11000011 movca.l r0, @rn
0000nnnn11100011 icbi @rn
0000nnnn10010011 ocbi @rn
0000nnnn10100011 ocbp @rn
0000nnnn10110011 ocbwb @rn
0000nnnn11010011 prefi @rn
0000000010101011 synco
0100mmmm00111010 ldc rm, sgr
0100mmmm11111010 ldc rm, dbr
0100mmmm00110110 ldc.l @rm+, sgr
0100mmmm11110110 ldc.l @rm+, dbr
0000nnnn00111010 stc sgr, rn
0000nnnn11111010 stc dbr, rn
0100nnnn00110010 stc.l sgr, @-rn
0100nnnn11110010 stc.l dbr, @-rn

74
fxos/asm.c Normal file
View file

@ -0,0 +1,74 @@
#include <fxos.h>
#include <errors.h>
#include <util.h>
#include <string.h>
/* asm_free_item(): Free an assembly instruction details */
static void asm_free_item(void *item)
{
struct asm_insn *insn = item;
free(insn->mnemonic);
free(insn->literal1);
free(insn->literal2);
}
/* asm_load(): Load an assembly table */
void asm_load(char const *file)
{
err_context("assembly", file, NULL);
if(!table_available())
{
err("too many tables, skipping");
err_pop();
return;
}
/* Map the file to memory */
int fd;
size_t size;
void *data = map(file, &fd, &size);
if(!data) { err_pop(); return; }
/* If the file is named "asm-x.txt", use "x" as the table name */
char *name = match_table_name(file, "asm", ".txt");
/* Parse the contents; the lexer in is [lexer-asm.l] and the parser is
implemented as an automaton with basic error correction. */
int count;
struct asm_insn *ins = lex_asm(data, size, &count);
table_create("asm", name, asm_free_item, count, sizeof *ins, ins);
unmap(data, fd, size);
err_pop();
}
/* Global storage for asm_match() */
static uint16_t asm_match_opcode;
/* asm_match(): Check if an instruction matches a pattern */
int asm_match(void *item)
{
struct asm_insn *insn = item;
return ((insn->bits ^ asm_match_opcode) & insn->arg_mask) == 0;
}
/* asm_decode(): Match a 16-bit opcode against the assembly database */
int asm_decode(uint16_t opcode, struct asm_match *match, int next)
{
asm_match_opcode = opcode;
char const *table;
struct asm_insn *insn = table_find("asm", asm_match, &table, next);
if(!insn) return 1;
/* Set match details */
match->insn = insn;
match->table = table;
match->n = (opcode >> insn->n_sh) & insn->n_mask;
match->m = (opcode >> insn->m_sh) & insn->m_mask;
match->d = (opcode >> insn->d_sh) & insn->d_mask;
match->i = (opcode >> insn->i_sh) & insn->i_mask;
return 0;
}

268
fxos/disassembly.c Normal file
View file

@ -0,0 +1,268 @@
#include <fxos.h>
#include <errors.h>
#include <stdio.h>
#include <string.h>
/* Architecture we are disassembling for */
static enum mpu mpu = MPU_GUESS;
/* Current program counter */
static uint32_t pc = 0;
/* Data chunk under disassembly (whole file) */
static uint8_t *data;
static size_t len;
/* Non-NULL when disassembling an OS */
static struct os const *os = NULL;
/* pcdisp(): Compute the address of a PC-relative displacement
@pc Current PC value
@disp Displacement value (from opcode)
@unit Number of bytes per step (1, 2 or 4), depends on instruction
Returns the pointed location. */
static uint32_t pcdisp(uint32_t pc, uint32_t disp, int unit)
{
pc += 4;
if(unit == 4) pc &= ~3;
return pc + disp * unit;
}
/* pcread(): Read data pointed through a PC-relative displacement
@pc Current PC value
@disp Displacement value (from opcode)
@unit Number of bytes per set (also number of bytes read)
@out If non-NULL, set to 1 if pointed address is out of the file
Returns the value pointed at, an undefined value if out of bounds. */
static uint32_t pcread(uint32_t pc, uint32_t disp, int unit, int *out)
{
/* Take physical addresses */
uint32_t addr = pcdisp(pc, disp, unit) & 0x1fffffff;
if(out) *out = (addr + unit > len);
uint32_t value = 0;
while(unit--) value = (value << 8) | data[addr++];
return value;
}
/* matches(): Count number of matches for a single instruction
@opcode 16-bit opcode value
Returns the number of matching instructions in the database. */
static int matches(uint16_t opcode)
{
struct asm_match match;
int count = 0;
while(!asm_decode(opcode, &match, count))
{
count++;
}
return count;
}
static void arg_output(int type, char const *literal,
struct asm_match const *match, int opsize)
{
int n = match->n;
int m = match->m;
int d = match->d;
int i = match->i;
/* Sign extensions of d to 8 and 12 bits */
int32_t d8 = (int8_t)d;
int32_t d12 = (d & 0x800) ? (int32_t)(d | 0xfffff000) : (d);
/* Sign extension of i to 8 bits */
int32_t i8 = (int8_t)i;
int out_of_bounds;
uint32_t addr;
uint32_t value;
switch(type)
{
case LITERAL:
printf("%s", literal);
break;
case IMM:
printf("#%d", i8);
break;
case RN:
printf("r%d", n);
break;
case RM:
printf("r%d", m);
break;
case JUMP8:
value = pcdisp(pc, d8, 2);
printf("<%x", value);
if(os) analysis_short(os, value | 0x80000000);
printf(">");
break;
case JUMP12:
value = pcdisp(pc, d12, 2);
printf("<%x", value);
if(os) analysis_short(os, value | 0x80000000);
printf(">");
break;
case PCDISP:
addr = pcdisp(pc, d, opsize);
value = pcread(pc, d, opsize, &out_of_bounds);
printf("<%x>", addr);
if(out_of_bounds) printf("(out of bounds)");
else
{
printf("(#0x%0*x", opsize * 2, value);
if(os) analysis_short(os, value);
printf(")");
}
break;
case AT_RN:
printf("@r%d", n);
break;
case AT_RM:
printf("@r%d", m);
break;
case AT_RMP:
printf("@r%d+", m);
break;
case AT_RNP:
printf("@r%d+", n);
break;
case AT_MRN:
printf("@-r%d", n);
break;
case AT_DRN:
printf("@(%d, r%d)", d * opsize, n);
break;
case AT_DRM:
printf("@(%d, r%d)", d * opsize, m);
break;
case AT_R0RN:
printf("@(r0, r%d)", n);
break;
case AT_R0RM:
printf("@(r0, r%d)", m);
break;
case AT_DGBR:
printf("@(%d, gbr)", d * opsize);
break;
}
}
static void instruction_output(uint16_t opcode, struct asm_match const *match)
{
char const *mnemonic = match->insn->mnemonic;
printf("%6x: %04x %s", pc, opcode, mnemonic);
/* Find out operation size */
size_t n = strlen(mnemonic);
int opsize = 0;
if(n >= 3 && mnemonic[n-2] == '.')
{
int c = mnemonic[n-1];
opsize = (c == 'b') + 2 * (c == 'w') + 4 * (c == 'l');
}
/* Output arguments */
if(!match->insn->arg1) return;
printf("%*s", (int)(8-n), "");
arg_output(match->insn->arg1, match->insn->literal1, match, opsize);
if(!match->insn->arg2) return;
printf(", ");
arg_output(match->insn->arg2, match->insn->literal2, match, opsize);
}
static void instruction_single(uint16_t opcode)
{
struct asm_match match;
asm_decode(opcode, &match, 0);
instruction_output(opcode, &match);
printf("\n");
}
static void instruction_conflicts(uint16_t opcode, int count)
{
struct asm_match match;
printf("\n # conflicts[%d] on <%x>(%04x)\n", count, pc, opcode);
for(int i = 0; i < count; i++)
{
asm_decode(opcode, &match, i);
instruction_output(opcode, &match);
printf(" # table '%s'\n", match.table);
}
printf("\n");
}
/* disassembly_os(): Disassemble an address or a syscall */
void disassembly_os(struct os const *src, struct disassembly const *opt)
{
/* Initialize this file's global state */
mpu = src->mpu;
pc = opt->start;
data = src->data;
len = src->len;
os = src;
/* Override MPU guesses if user requested a specific platform */
if(opt->mpu != MPU_GUESS) mpu = opt->mpu;
/* Handle situations where the start address is a syscall */
if(opt->syscall)
{
pc = os_syscall(os, opt->start);
if(pc == (uint32_t)-1)
{
err("syscall 0x%04x does not exist", opt->start);
return;
}
}
/* Take physical addresses */
pc &= 0x1fffffff;
/* Cut the length if it reaches past the end of the file */
uint32_t limit = (pc + opt->len) & ~1;
if(limit > os->len) limit = os->len;
/* Enforce alignment of PC */
if(pc & 1)
{
err("address is not 2-aligned, skipping 1 byte");
pc += 1;
}
uint8_t *data = os->data;
while(pc < limit)
{
if(os)
{
int syscall = os_syscall_find(os, pc | 0x80000000);
if(syscall == -1)
syscall = os_syscall_find(os, pc | 0xa0000000);
if(syscall != -1)
{
struct sys_call const *s = sys_find(syscall);
printf("\n<%x %%%03x", pc, syscall);
if(s) printf(" %s", s->name);
printf(">\n");
}
}
uint16_t opcode = (data[pc] << 8) | data[pc + 1];
int count = matches(opcode);
if(count == 0) printf("%6x: %04x\n", pc, opcode);
else if(count == 1) instruction_single(opcode);
else instruction_conflicts(opcode, count);
pc += 2;
}
}

84
fxos/errors.c Normal file
View file

@ -0,0 +1,84 @@
#include <errors.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define MAX 32
/* Array of context strings. */
static char const *context[MAX] = { NULL };
/* Number of active elements. */
static int elements = 0;
/* push(): Push an element in the context buffer
@el New element
Returns non-zero if the buffer is full. */
static int push(char const *el)
{
if(elements >= MAX - 2) return 1;
context[elements++] = el;
return 0;
}
/* err_context(): Push one or more context elements */
int err_context(char const *context, ...)
{
va_list args;
va_start(args, context);
int x = 0;
/* Delimiter between calls to err_context(), for err_pop() */
x |= push(NULL);
x |= push(context);
while(1)
{
char const *el = va_arg(args, char const *);
if(!el) break;
x |= push(el);
}
va_end(args);
return x;
}
/* err_pop(): Pop back context elements */
void err_pop(void)
{
/* Clear everything until the last NULL delimiter */
while(--elements >= 0 && context[elements])
{
context[elements] = NULL;
}
}
void err_debug(void)
{
for(int i = 0; i < MAX; i++) fprintf(stderr, "%s: ", context[i]);
fprintf(stderr, "\n");
}
/* errf(): Emit an error message */
void errf(int flags, char const *str, ...)
{
int saved_errno = errno;
va_list args;
va_start(args, str);
for(int i = 0; i <= MAX-2 && (context[i] || context[i+1]); i++)
{
if(context[i]) fprintf(stderr, "%s: ", context[i]);
}
vfprintf(stderr, str, args);
if(flags & ERR_ERRNO)
{
fprintf(stderr, ": %s", strerror(saved_errno));
}
fprintf(stderr, "\n");
va_end(args);
}

63
fxos/errors.h Normal file
View file

@ -0,0 +1,63 @@
//---
// errors: Error message management
//
// An attempt at producing elaborate error messages providing context from
// multiple function calls, with a small amount of code.
//
// Basically, caller functions define context and message parameters
// before doing anything risky. When an error occurs in a sub-function,
// the context is used to prepend relevant information and fill in the
// error message where relevant.
//
// This means that the caller functions must know it advance what kind of
// messages can be emitted to accurately set the context. Although it
// would work through library calls, it is not very suitable. It's rather
// meant for the logic of applications.
//---
#ifndef FXOS_ERRORS
#define FXOS_ERRORS
/* Error levels */
#define ERR_CRIT 0x01 /* Aborts part or whole of the program's task */
#define ERR_ERR 0x02 /* Unexpected behavior */
#define ERR_WARN 0x03 /* Internal consistency issues */
#define ERR_LOG 0x04 /* Internal logging */
/* Error flags */
#define ERR_ERRNO 0x10
/* err_context(): Push one or more context elements
@context Context string, must live until it is popped by err_pop()
@... More contexts, same requirements as the first (NULL-terminated)
Returns non-zero if the deepest context level (at least 15) is reached. */
int err_context(char const *context, ...);
/* err_pop(): Pop back context elements
Pops back all context elements that were added by the previous call to
err_context(), no matter their number. */
void err_pop(void);
/* errf(): Emit an error message
Error message is printed via fprintf() and supports the same format. All the
arguments are passed directly.
Available flags are any combination of at most one error level:
ERR_CRIT -- Unrecoverable error
ERR_ERR -- Normal error
ERR_WARN -- Warning
ERR_LOG -- Logging
and any of these boolean flags:
ERR_ERRNO -- Also print strerror(errno) as a suffix (as perror()).
Error levels might be used later on for filtering. Messages without level
will always be displayed.
@flags An OR-combination of the previous flags, or 0
@str Error messages
@... Arguments to format [str] through fprintf() */
void errf(int flags, char const *str, ...);
/* err(): Short error function */
#define err(str, ...) errf(0, str __VA_OPT__(,) __VA_ARGS__)
#endif /* FXOS_ERRORS */

View file

@ -6,149 +6,405 @@
#define FX_FXOS #define FX_FXOS
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stdlib.h>
/* Microprocessor platforms */ /* Microprocessor platforms */
enum mpu enum mpu {
{ MPU_GUESS = 0,
mpu_unknown = 0, MPU_SH7705 = 1,
mpu_sh7705 = 1, MPU_SH7305 = 2,
mpu_sh7305 = 2,
}; };
/* /*
** Data tables (tables.c) ** Memory (memory.c)
*/ */
/* tables_add_asm(): Append an instruction table to the table list /* struct region: A valid memory region for at least one platform */
This function adds a new instruction table to fetch instructions from; it
will be consulted if searching any of the previously-declared tables fails.
@filename Name of instruction table file
Returns non-zero on error (and prints a message on stderr) */
int tables_add_asm(const char *filename);
/* tables_add_syscall(): Append a syscall table to the table list
This function adds a new syscall table to fetch syscalls information from;
if will be consulted if searching any of the previously-declared tables
fails.
@filename Name of instruction table file
Returns non-zero on error (and prints a message on stderr) */
int tables_add_syscall(const char *filename);
/*
** RAM dumps (ram.c)
*/
/* Region for a single RAM dump */
struct region struct region
{ {
uint32_t start; uint32_t start; /* Start address */
uint32_t length; uint32_t end; /* End address */
void *data; char const *name; /* Name, used to identify RAM dump files */
enum mpu platform; /* Platform hint or MPU_GUESS */
}; };
/* RAM dump */ /* memory_region(): Find the region where an address is located
struct ram_sh7705 Returns NULL if the address points to no valid memory. This function rejects
{ addresses of peripheral registers in P3 or P4 space and only heeds for
struct region RAM; /* Usual RAM (256k) */ contiguous RAM or ROM areas.
@address 32-bit virtual memory address
Returns a region description matching the address, NULL if none is known.*/
struct region const *memory_region(uint32_t address);
/*
** General table storage (tables.c)
*/
/* struct table: Parametric data table */
struct table {
char const *type; /* Table type, set by user */
char *name; /* Table name, also set by user */
void (*free_item)(void *); /* Function to free individual items */
int count; /* Number of items in the table */
size_t size; /* Size of each item */
void *items; /* Table data */
}; };
struct ram_sh7305
{ /* table_available(): Whether a table can be allocated
struct region RAM; /* Usual RAM (512k) */ Returns non-zero if there is space left for a new table, zero if not. */
struct region IL; /* On-chip instruction storage (16k) */ int table_available(void);
struct region RS; /* On-chip generic storage (2k) */
/* table_create(): Create a new table
Allocates a new table inside the global storage. The created table can be
searched immediately with table_find().
@type Table type, expectedly a string constant
@name Name string, this module takes ownership and will free() it
@free_item Function to use to destroy items in the future
@count Number of items
@size Size of each item
@items Full data array */
void table_create(char const *type, char *name, void (*free_item)(void *),
int count, size_t size, void *items);
/* table_find(): Find matching entries in the database tables
This function traverses all the tables of type @type and returns all the
elements [e] such that [match(e)] is non-zero.
The search starts with [next=0] and returns the first match; further calls
with [next!=0] will return more matching elements until no more are found
(in which case this function returns NULL) or this function is called again
with [next=0] to start a new search.
@type Table filter by type
@match Match function
@name Set to matching table name, if not NULL
@next Set it to 0 on the first call, and non-zero after that
Returns a match if one is found, NULL otherwise. */
void *table_find(char const *type, int (*match)(void *), char const **name,
int next);
/*
** Assembly tables (asm.c, lexer-asm.l)
** These tables reference all assembler instructions used by fxos to
** disassemble code. In case of conflict, fxos will disassemble the same
** opcode several times.
*/
/* struct asm_insn: Entry of an instruction table */
struct asm_insn {
uint16_t bits; /* Opcode; arbitrary values for arguments */
uint16_t arg_mask; /* 1 for constant bits, 0 for arguments */
/* Position of the arguments */
uint8_t n_sh, m_sh, d_sh, i_sh;
/* Masks indicating the length of arguments */
uint16_t n_mask, m_mask, d_mask, i_mask;
char *mnemonic; /* NUL-terminated mnemonic */
int arg1; /* asm_arg member */
int arg2; /* asm_arg member */
char *literal1; /* When arg1 == LITERAL, argument string */
char *literal2; /* When arg2 == LITERAL, argument string */
}; };
/* enum asm_arg: Argument variants */
enum asm_arg {
LITERAL=1, /* Literal string, eg. "vbr" or "@(r0, gbr)" */
IMM, RN, RM, /* "#imm", "rn", "rm" */
JUMP8, JUMP12, /* Jump from displacement (PC + disp) */
PCDISP, /* PC-displacement with data */
AT_RN, AT_RM, /* "@rn", "@rm" */
AT_RMP, AT_RNP, AT_MRN, /* Post-increment and pre-decrement */
AT_DRN, AT_DRM, /* Displacement structure addressing */
AT_R0RN, AT_R0RM, /* r0 structure addressing */
AT_DGBR, /* GBR addressing */
};
/* struct asm_match: Matching of a 16-bit code against an instruction
Specifies the source instruction and the value of the parameters. The value
of [m], [n], [d] or [i] is unspecified for parameters that are not used in
the matched instruction's opcode. */
struct asm_match {
/* Matching instruction */
struct asm_insn const *insn;
char const *table; /* Table name */
int m, n, d, i; /* Parameter assignment */
};
/* asm_load(): Load an assembly table
Loads all instructions described by @file into a table named "x" is @file's
basename is on the form "asm-x.txt" and the whole basename otherwise. The
resulting table is available immediately to use with asm_match().
Skips every row that does not conform to the file's syntax after printing a
message to stderr.
@file Input file path */
void asm_load(char const *file);
/* asm_decode(): Match a 16-bit opcode against the assembly database
This function searches matches of a 16-bit instruction code inside the
instruction database. Depending on the database files currently loaded,
there can be several matches; this function uses static variables to
maintain state information through several calls.
First call this function with [next] set to 0. If there is no match, the
call will return non-zero and [*match] will be left unchanged. Otherwise,
the first matching instruction will be described in [*match], the call will
return 0 and internal static variables will be reset.
Repeatedly call this function with [next != 0] to get further matches. The
search ends when there are no more matches, in which case this function
returns non-zero and [*match] is left unchanged. Any non-zero value for
[next] is suitable.
The name of the table providing the match is set in [match->table]. Please
bear in mind, though, that table names do not uniquely identify tables.
@opcode 16-bit opcode to be matched against the database
@match Set to a description of the matching instruction (must not be NULL)
@next Set it to 0 on the first call, and non-zero after that
Returns 0 if a match is found, non-zero otherwise. */
int asm_decode(uint16_t opcode, struct asm_match *match, int next);
/* asm_quit(): Unload all assembly tables
Releases all memory held by the assembly table database. */
void asm_quit(void);
/* lex_asm(): Assembly table lexer and parser
Lexes and parses string @data of length @length, allocating and filling an
instruction array whose size is stored in [*count] if @count is non-NULL.
Prints messages to stderr for every syntax error in the file.
@data Input memory, not NUL-terminated (typically a memory-mapped file)
@length Length of input string
@count Set to number of successfully decoded instructions if non-NULL
Returns a free()able array of decoded instructions. */
struct asm_insn *lex_asm(void *data, size_t length, int *count);
/*
** Syscall tables (sys.c)
*/
/* struct sys_call: Entry of a syscall table */
struct sys_call {
uint32_t number; /* Syscall number */
char *name; /* Symbol or function name */
char *descr; /* Prototype or description */
};
/* sys_load(): Load a syscall table
Loads a syscall description table. If @file is named "sys-x.txt" then the
table name is set to "x", otherwise @file's basename.
Prints syntax errors and skips invalid lines.
@file Input file path */
void sys_load(char const *path);
/* sys_find(): Find information on a given syscall number
Traverse the syscall tables currently loaded and returns the first entry
matching the provided syscall number, if any is found.
@number Syscall number
Returns a description of the syscall, NULL if none was found. */
struct sys_call const *sys_find(uint32_t number);
/* sys_quit(): Release memory held by the syscall tables */
void sys_quit(void);
/* lex_sys(): Syscall table lexer and parser
Lexes and parses string @data of length @len, allocating and filling a
syscall array whose size is stored in [*count] if @count is not NULL.
Prints syntax errors on stderr.
@data Input memory (typically memory-mapped file)
@len Length of input
@count Set to number of decoded entries if not NULL
Returns a free()able table of decoded syscall entries. */
struct sys_call *lex_sys(void *data, size_t len, int *count);
/*
** Peripheral register tables (reg.c)
*/
/* struct reg_address: Entry of a peripheral register table */
struct reg_address {
uint32_t address; /* Register address */
char *name; /* Typically an upper-case dotted specifier */
};
/* reg_load(): Load a peripheral register table
Loads a peripheral register listing. If @file is named "reg-x.txt" then the
table name is set to "x", otherwise @file's basename.
Prints syntax errors and skips invalid lines. Loaded data is available
immediately through reg_find().
@file Input file path */
void reg_load(char const *path);
/* reg_find(): Find information on a given peripheral register address
Looks up the loaded tables and returns the first entry matching the given
address (if any).
@address Any input address
Returns a pointer to the matching register, NULL if none was found. */
struct reg_address const *reg_find(uint32_t address);
/* reg_quit(): Release memory held by the peripheral register tables */
void reg_quit(void);
/* lex_reg(): Peripheral register table lexer and parser
Lexes and parses @data (of length @length). Allocates and fills a register
description array and stores its size in [*count] if @count is not NULL.
Prints messages on stderr if there are syntax errors.
@data Input string (needs not be NUL-terminated)
@len Length of input
@count Set to the number of decoded register addresses, if not NULL
Returns a free()able table with the decoded data. */
struct reg_address *lex_reg(void *data, size_t len, int *count);
/*
** General OS operations (os.c)
*/
/* struct os: Basic OS information */
struct os {
void *data; /* Operating system dump */
size_t len; /* File length */
int fd; /* Underlying file descriptor */
char version[15]; /* NUL-terminated OS version string */
enum mpu mpu; /* User-provided or guessed MPU type */
uint32_t syscall_table; /* Syscall table address */
int syscalls; /* Number of valid syscalls found */
uint32_t footer; /* Footer address (-1 if not found) */
};
/* os_load(): Load an OS file and find out basic properties
Guesses the MPU type, finds the syscall table and its size, finds the footer
address.
@path File path
@os Will be filled with loaded data and information
Returns non-zero in case of loading error or file format error. */
int os_load(char const *path, struct os *os);
/* os_syscall(): Get the address of a syscall entry
Does not check bounds, only returns (uint32_t)-1 if the requested entry of
the table is past the end of the file.
@os Source OS
@syscall Syscall entry number
Returns the syscall address. */
uint32_t os_syscall(struct os const *os, int syscall);
/* os_syscall_find(): Find a syscall which points to an address
This function looks for a syscall entry (among the ones that point to valid
memory) whose value is @entry.
@os Loaded OS structure
@entry Researched value
Returns a syscall ID if some is found, -1 otherwise. */
int os_syscall_find(struct os const *os, uint32_t entry);
/* os_free(): Free an OS file opened with os_load()
@os Loaded OS structure */
void os_free(struct os const *os);
/* /*
** File identification (info.c) ** File identification (info.c)
*/ */
/* Info options */ /* info_os(): Print general information on an OS file
struct info
{
/* OS file (0) or binary file (1) */
int binary;
/* Force underlying architecture */
enum mpu mpu;
/* RAM dumps, if any */ This function prints the OS metadata, traverses the syscall table, and
union { shows a few details of known binary regions such as the footer.
struct ram_sh7705 ram3;
struct ram_sh7305 ram4; @os Input OS file */
}; void info_os(struct os const *os);
};
/* info_binary(): Print general information on a binary file
This function tries to determine the platform by looking for SH4-only
instructions or SH7705 and SH7305-specific registers addresses. The analysis
results are printed on stdout.
@data Input file data (memory-mapped)
@len Length of input */
void info_binary(void *data, size_t len);
/* /*
** Disassembling (disassembly.c) ** Disassembling (disassembly.c)
*/ */
/* Disassembly options */ /* struct disassembly: Disassembly options */
struct disassembly struct disassembly
{ {
/* OS file (0) or binary file (1) */ int binary; /* OS file (0) or binary file (1) */
int binary; enum mpu mpu; /* Force architecture (or MPU_GUESS) */
/* Force underlying architecture */
enum mpu mpu;
/* RAM dumps, if any */ uint32_t start; /* Start address or syscall ID */
union { int syscall; /* Non-zero if [start] is a syscall ID */
struct ram_sh7705 ram3; uint32_t len; /* Length of disassembled region */
struct ram_sh7305 ram4;
};
/* Start address */
uint32_t start;
/* Length of disassembled region */
uint32_t length;
}; };
/* disassembly_os(): Disassemble an address or a syscall
Produces a disassembly listing of the program on stdout, annotated with
every piece of information that can be extracted from the OS.
@os Operating system image to disassemble
@opt Disassembly region and options */
void disassembly_os(struct os const *os, struct disassembly const *opt);
/* /*
** Blind analysis (analysis.c) ** Blind analysis (analysis.c)
*/ */
/* Analysis options */ /* analysis_short(): Print a one-line summary for an address
Prints a list of space-separated elements summarizing the information that
can be found about the provided value (typically an address). This summary
is often inserted in disassembled code as annotation.
@os Source OS
@value Analyzed value, often an address */
void analysis_short(struct os const *os, uint32_t value);
/* struct analysis: In-depth analysis options */
struct analysis struct analysis
{ {
/* Force underlying architecture */ /* Force underlying architecture */
enum mpu mpu; enum mpu mpu;
/* RAM dumps, if any */
union {
struct ram_sh7705 ram3;
struct ram_sh7305 ram4;
};
/* Analysis mode */ /* Analysis mode */
enum { enum {
ANALYSIS_FULL = 0, ANALYSIS_SYSCALL = 0x01,
ANALYSIS_SYSCALL = 1, ANALYSIS_ADDRESS = 0x02,
ANALYSIS_ADDRESS = 2, ANALYSIS_REGISTER = 0x04,
ANALYSIS_REGISTER = 3,
ANALYSIS_FULL = 0x07,
} type; } type;
/* Max number of printed occurrences */ /* Max number of printed occurrences */
int occurrences; int occurrences;
}; };
/*
** Utility functions (util.c)
*/
/* integer(): Convert base 8, 10 or 16 into integers
Prints an error message and sets *error to 1 in case of conversion error or
overflow.
@str Original integer representation ("10", "0x1f", "07")
@error Set to 1 on error, otherwise unchanged (can be NULL)
Returns result of conversion (valid if *error is not 1) */
long long integer(const char *str, int *error);
#endif /* FX_FXOS */ #endif /* FX_FXOS */

120
fxos/info.c Normal file
View file

@ -0,0 +1,120 @@
#include <fxos.h>
#include <errors.h>
#include <stdio.h>
#include <string.h>
#include <endian.h>
char const *info_str =
"Header information:\n"
" Bootcode timestamp (DateA) (0x8000ffb0) : %s\n"
" Serial number (0x8000ffd0) : %s\n"
" Bootcode checksum (0x8000fffc) : 0x%s\n"
" OS version (0x80010020) : %s\n";
char const *footer_str =
"\nFooter information:\n"
" Detected footer address : 0x8%07x\n"
" Langdata entries found : %d\n"
" OS date (DateO) (0x8%07x)" " : %s\n"
" OS checksum (0x8%07x)" " : 0x%s\n";
char const *syscall_str =
"\nSyscall information:\n"
" Syscall table address (0x8001007c) : 0x%08x\n"
" Entries that point to valid memory : 0x%x\n"
" First seemingly invalid entry : 0x%08x\n"
" Syscall entries outside ROM:\n";
char const *syscall_nonrom_str =
" %%%04x -> 0x%08x (%s memory)\n";
/* extract_str(): Extract a string from the OS file
This function checks offsets and bounds and writes "(eof)" if the provided
file is too small for the tested offset. */
static void extract_str(struct os const * os, uint32_t address, size_t size,
char *dst)
{
if(address + size > os->len)
{
strcpy(dst, "(eof)");
return;
}
memcpy(dst, os->data + address, size);
dst[size] = 0;
}
/* extract_int(): Extract a string from the OS file */
static void extract_int(struct os const *os, uint32_t address, char *dst)
{
if(address + 4 > os->len)
{
strcpy(dst, "(eof)");
return;
}
uint32_t x;
memcpy(&x, os->data + address, 4);
x = be32toh(x);
sprintf(dst, "%08x", x);
}
/* info_os(): Print general information on an OS file */
void info_os(struct os const *os)
{
void *data = os->data;
size_t len = os->len;
char bios_timestamp[15];
extract_str(os, 0xffb0, 14, bios_timestamp);
char serial[9];
extract_str(os, 0xffd0, 8, serial);
char bios_checksum[9];
extract_int(os, 0xfffc, bios_checksum);
printf(info_str, bios_timestamp, serial, bios_checksum, os->version);
if(os->footer == (uint32_t)-1)
{
printf("\nFooter could not be found.\n");
}
else
{
uint32_t addr = os->footer + 8;
int langdata = 0;
while(addr + 8 < len && !memcmp(data + addr, "Langdata", 8))
{
langdata++;
addr += 0x30;
}
char os_timestamp[15];
extract_str(os, addr, 14, os_timestamp);
char os_checksum[9];
extract_int(os, addr + 0x18, os_checksum);
printf(footer_str, os->footer, langdata, addr, os_timestamp,
addr + 0x18, os_checksum);
}
printf(syscall_str, os->syscall_table, os->syscalls,
os_syscall(os, os->syscalls));
int total = 0;
for(int i = 0; i < os->syscalls; i++)
{
uint32_t e = os_syscall(os, i);
struct region const *r = memory_region(e);
if(!r || !strcmp(r->name, "ROM")) continue;
printf(syscall_nonrom_str, i, e, r->name);
total++;
}
if(!total) printf(" (none)\n");
}

187
fxos/lexer-asm.l Normal file
View file

@ -0,0 +1,187 @@
%{
#include <fxos.h>
#include <errors.h>
#include <util.h>
/* Text value for parser */
static char *yylval;
%}
%option prefix="asm"
%option noyywrap
%option nounput
code ^[01nmdi]{16}
literal [^ ,\t\n]+|[^ ,\t\n(]*"("[^")"\n]*")"[^ ,\t\n]*
space [ \t]+
%%
^#[^\n]* ;
{space} ;
, ;
[\n] yylineno++;
{code} { yylval = strdup(yytext); return 0; }
^.{0,16} { err("%d: invalid opcode at start of line", yylineno); }
"#imm" { return IMM; }
"rn" { return RN; }
"rm" { return RM; }
"jump8" { return JUMP8; }
"jump12" { return JUMP12; }
"pcdisp" { return PCDISP; }
"@rn" { return AT_RN; }
"@rm" { return AT_RM; }
"@rm+" { return AT_RMP; }
"@rn+" { return AT_RNP; }
"@-rn" { return AT_MRN; }
"@(disp,"[ ]*"rn)" { return AT_DRN; }
"@(disp,"[ ]*"rm)" { return AT_DRM; }
"@(r0,"[ ]*"rn)" { return AT_R0RN; }
"@(r0,"[ ]*"rm)" { return AT_R0RM; }
"@(disp",[ ]*"gbr)" { return AT_DGBR; }
{literal} { yylval = strdup(yytext); return LITERAL; }
<<EOF>> { return -1; }
%%
#include <stdio.h>
/* set_code(): Build an efficient representation of an opcode
Takes a 16-byte string as argument, representing the parameterized opcode,
and computes a bit-based representation inside the assembly structure.
@code 16-bit opcode made of '0', '1', 'm', 'n', 'd' and 'i'
@insn Instruction object */
void set_code(char const *code, struct asm_insn *insn)
{
insn->bits = insn->arg_mask = 0;
insn->n_sh = insn->n_mask = 0;
insn->m_sh = insn->m_mask = 0;
insn->d_sh = insn->d_mask = 0;
insn->i_sh = insn->i_mask = 0;
for(int i = 0; i < 16; i++)
{
int c = code[i];
/* Constant bits */
if(c == '0' || c == '1')
{
insn->bits = (insn->bits << 1) | (c - '0');
insn->arg_mask <<= 1;
continue;
}
/* Argument bits */
insn->bits <<= 1;
insn->arg_mask = (insn->arg_mask << 1) | 1;
if(c == 'n')
{
insn->n_sh = 15 - i;
insn->n_mask = (insn->n_mask << 1) | 1;
}
if(c == 'm')
{
insn->m_sh = 15 - i;
insn->m_mask = (insn->m_mask << 1) | 1;
}
if(c == 'd')
{
insn->d_sh = 15 - i;
insn->d_mask = (insn->d_mask << 1) | 1;
}
if(c == 'i')
{
insn->i_sh = 15 - i;
insn->i_mask = (insn->i_mask << 1) | 1;
}
}
insn->arg_mask = ~insn->arg_mask;
}
/* lex_asm(): Assembly table lexer and parser */
struct asm_insn *lex_asm(void *data, size_t length, int *count)
{
/* First count the number of instruction codes */
YY_BUFFER_STATE buf = yy_scan_bytes(data, length);
yylineno = 1;
int total = 0, t;
while((t = yylex()) != -1)
{
total += (t == 0);
if(t == 0 || t == LITERAL) free(yylval);
}
yy_delete_buffer(buf);
/* Allocate a large enough instruction array */
struct asm_insn *table = calloc(total, sizeof *table);
if(!table)
{
errf(ERR_ERRNO, "cannot allocate memory for database");
return 0;
}
/* Lex all instructions and fill in the array */
buf = yy_scan_bytes(data, length);
yylineno = 1;
struct asm_insn *insn = table - 1;
int line = -1;
int named = 1;
while(1)
{
t = yylex();
if(yylineno != line || t == 0 || t == -1)
{
/* Finalize current instruction */
if(!named) err("%d: unnamed instruction", line);
insn++;
}
if(t == -1) break;
if(t == 0)
{
set_code(yylval, insn);
free(yylval);
line = yylineno;
named = 0;
}
else if(t == LITERAL && !named)
{
insn->mnemonic = yylval;
named = 1;
}
else if(!named)
{
err("%d: missing mnemonic", line);
}
else if(!insn->arg1)
{
insn->arg1 = t;
if(t == LITERAL) insn->literal1 = yylval;
}
else if(!insn->arg2)
{
insn->arg2 = t;
if(t == LITERAL) insn->literal2 = yylval;
}
}
yy_delete_buffer(buf);
if(count) *count = insn - table;
return table;
}

117
fxos/lexer-reg.l Normal file
View file

@ -0,0 +1,117 @@
%{
#include <fxos.h>
#include <errors.h>
#include <util.h>
/* Values for tokens generated by the lexer */
static union {
char *text;
long long integer;
} yylval;
/* Token list */
#define NUMBER 0
#define SYMBOL 1
%}
%option prefix="reg"
%option noyywrap
%option nounput
decimal 0|[1-9][0-9]*
octal 0[0-7]+
hexa 0x[0-9a-fA-F]+
number {decimal}|{octal}|{hexa}
symbol [^0-9 \t\n][^\n]*
space [ \t]+
%%
^#[^\n]* ;
{space} ;
[\n] yylineno++;
{number} { yylval.integer = integer(yytext, NULL); return NUMBER; }
{symbol} { yylval.text = strdup(yytext); return SYMBOL; }
<<EOF>> return -1;
%%
#include <stdio.h>
/* lex_reg(): Peripheral register table lexer and parser */
struct reg_address *lex_reg(void *data, size_t len, int *count)
{
/* Count number of register descriptions (upper bound) */
YY_BUFFER_STATE buf = yy_scan_bytes(data, len);
yylineno = 1;
int total = 0, t;
while((t = yylex()) != -1)
{
total += (t == NUMBER);
if(t == SYMBOL) free(yylval.text);
}
yy_delete_buffer(buf);
/* Allocate a large enough register array */
struct reg_address *table = calloc(total, sizeof *table);
if(!table)
{
errf(ERR_ERRNO, "cannot allocate memory for database");
return 0;
}
/* Lex all instructions and fill in the array */
buf = yy_scan_bytes(data, len);
yylineno = 1;
struct reg_address *reg = table - 1;
int line = -1;
while(1)
{
t = yylex();
if(t == NUMBER || t == -1)
{
/* Finalize current instruction */
if(reg >= table && !reg->name)
err("%d: unnamed register", line);
else reg++;
}
if(t == -1) break;
if(t == NUMBER)
{
reg->address = yylval.integer;
line = yylineno;
}
else if(t == SYMBOL && reg < table)
{
err("%d: expected register address", yylineno);
free(yylval.text);
}
else if(t == SYMBOL && !reg->name)
{
reg->name = yylval.text;
}
else if(t == SYMBOL)
{
err("%d: excess names for 0x%08x\n", reg->address);
free(yylval.text);
}
}
yy_delete_buffer(buf);
if(count) *count = reg - table;
return table;
}

123
fxos/lexer-sys.l Normal file
View file

@ -0,0 +1,123 @@
%{
#include <fxos.h>
#include <errors.h>
#include <util.h>
/* Values for tokens generated by the lexer */
static union {
char *text;
long long integer;
} yylval;
/* Token list */
#define NUMBER 0
#define TEXT 1
%}
%option prefix="sys"
%option noyywrap
%option nounput
decimal 0|[1-9][0-9]*
octal 0[0-7]+
hexa 0x[0-9a-fA-F]+
number {decimal}|{octal}|{hexa}
space [ \t]+
%%
^#[^\n]* ;
{space} ;
[\n] yylineno++;
{number} { yylval.integer = integer(yytext, NULL); return NUMBER; }
[^ \t\n0-9].* { yylval.text = strdup(yytext); return TEXT; }
<<EOF>> return -1;
%%
#include <stdio.h>
/* lex_sys(): Syscall table lexer and parser */
struct sys_call *lex_sys(void *data, size_t len, int *count)
{
/* Count the number of syscalls */
YY_BUFFER_STATE buf = yy_scan_bytes(data, len);
yylineno = 1;
int total = 0, t;
while((t = yylex()) != -1)
{
total += (t == NUMBER);
if(t == TEXT) free(yylval.text);
}
yy_delete_buffer(buf);
/* Allocate a large enough syscall array */
struct sys_call *table = calloc(total, sizeof *table);
if(!table)
{
errf(ERR_ERRNO, "cannot allocate memory for database");
return 0;
}
/* Lex all instructions and fill in the array */
buf = yy_scan_bytes(data, len);
yylineno = 1;
struct sys_call *call = table - 1;
int line = -1;
int named = 1;
while(1)
{
t = yylex();
if(t == NUMBER || t == -1)
{
/* Finalize current instruction */
if(!named) err("%d: unnamed syscall", line);
else call++;
}
if(t == -1) break;
if(t == NUMBER)
{
call->number = yylval.integer;
line = yylineno;
named = 0;
}
else if(t == TEXT && call < table)
{
err("%d: expected syscall id", yylineno);
free(yylval.text);
}
else if(t == TEXT && named == 0)
{
call->name = yylval.text;
named = 1;
}
else if(t == TEXT && named == 1)
{
call->descr = yylval.text;
named = 2;
}
else if(t == TEXT)
{
err("%d: excess qualifiers for syscall 0x%03x", line,
call->number);
free(yylval.text);
}
}
yy_delete_buffer(buf);
if(count) *count = call - table;
return table;
}

View file

@ -4,100 +4,217 @@
#include <getopt.h> #include <getopt.h>
#include <fxos.h> #include <fxos.h>
#include <errors.h>
#include <util.h>
static const char *help_string = static char const *help_string =
"usage: %1$s info (<os file> | -b <binary file>)\n" "usage: %1$s info (<os file> | -b <binary file>)\n"
" %1$s disasm <os file> (-a <address> | -s <syscall id>) [options...]\n" " %1$s disasm <os file> (-a <address> | -s <syscall id>) [options...]\n"
" %1$s disasm -b <binary file> [options...]\n" " %1$s disasm -b <binary file> [options...]\n"
" %1$s analyze [-f|-s|-a|-r] <number> <os file> [options...]\n" " %1$s analyze [-f] [-s] [-a] [-r] <number> <os file> [options...]\n"
"\n" "\n"
"fxos disassembles or analyzes binary and OS files for efficient reverse-\n" "fxos is a reverse-engineering tool to disassemble and analyze fx9860g-like\n"
"engineering. It currently only supports fx9860g binaries.\n" "OS dumps, providing efficient annotations through an editable database.\n"
"\n" "\n"
"Commands:\n" "Commands:\n"
" info Identify an OS image: version, platform, date, checksums...\n" " info Identify an OS image: version, platform, date, checksums...\n"
" Identify the architecture of a binary file.\n" " Identify the architecture of a binary file.\n"
" disasm Disassemble and annotate code with relative address targets,\n" " disasm Disassemble and annotate code with relative address targets,\n"
" syscall invocations and hints about memory structure.\n" " syscall invocations and hints about memory structure.\n"
" analyze Dig an address or syscall number, finding syscall call graph,\n" " analyze Dig an address or syscall number, finding syscall references,\n"
" 4-aligned occurrences, memory region and probable role.\n" " 4-aligned occurrences, memory region and probable role.\n"
"\n" "\n"
"General options:\n" "General options:\n"
" -b Disassemble any binary file, not an OS file\n" " -b Work with an arbitrary binary file, not an OS\n"
" -3, --sh3 Assume SH3 OS and platform (default: guess)\n"
" -4, --sh4 Assume SH4 OS and platform (default: guess)\n"
" --ram <folder> Read RAM dumps from <folder>\n"
" --table-asm <file> Read more instruction patterns in <file>\n"
" --table-call <file> Read more syscall prototypes in <file>\n"
"\n" "\n"
"Disassembly region options:\n" "Table extensions:\n"
" --table-asm <file> Use instruction codes and mnemonics from <file>\n"
" --table-sys <file> Use syscall prototypes and descriptions from <file>\n"
" --table-reg <file> Use peripheral register addresses from <file>\n"
"\n"
"Disassembly options:\n"
" -a <address> Start disassembling at this address\n" " -a <address> Start disassembling at this address\n"
" -s <syscall id> Start disassembling at this syscall's address\n" " -s <syscall id> Start disassembling at this syscall's address\n"
" -l <length> Length of region\n" " -l <length> Length of region\n"
" -3, --sh3 Assume SH3 OS and platform (default: guess)\n"
" -4, --sh4 Assume SH4 OS and platform (default: guess)\n"
"\n" "\n"
"Analysis modes:\n" "Analysis modes:\n"
" -f, --full Find everything that can be known about <number>\n" " -f, --full Run all analysis passes on <number> (same as -sar)\n"
" -s, --syscall <number> is a syscall ID\n" " -s, --syscall Run syscall ID analysis\n"
" -a, --address <number> is a code/data address in ROM or RAM\n" " -a, --address Run code/data address analyis\n"
" -r, --register <number> is a register or peripheral address\n" " -r, --register Run peripheral register analysis\n"
"\n" "\n"
"Analysis options:\n" "Analysis options:\n"
" --occurrences <num> Show at most <num> occurrences (integer or \"all\")\n"; " --occurrences <num> Show at most <num> occurrences (integer or \"all\")\n"
"\n"
"All numbers support base prefixes '0' (octal) and '0x' (hexadecimal).\n";
/* "Low-level" command-line option set */ #define OPT_ASM 1
struct options #define OPT_SYS 2
#define OPT_REG 3
#define OPT_OCC 4
/*
** "info" command
*/
int main_info(int argc, char **argv)
{ {
const char *input; int error=0, option=0, binary=0;
int target; struct option const longs[] = {
const char *ram; { "help", no_argument, NULL, 'h' },
};
const char *a; while(option >= 0 && option != '?')
const char *s; switch((option = getopt_long(argc, argv, "hb", longs, NULL)))
size_t l;
int f;
int r;
const char *occ;
};
int main(int argc, char **argv)
{
int command = 0, error = 0;
struct options opt = { 0 };
/* For string -> int conversions, first non-int character */
/* Get command name */
if(argc >= 2)
{ {
if(!strcmp(argv[1], "info")) command = 'i'; case 'h':
if(!strcmp(argv[1], "disasm")) command = 'd'; err(help_string, argv[0]);
if(!strcmp(argv[1], "analyze")) command = 'a'; break;
case 'b':
binary = 1;
break;
case '?':
error = 1;
}
if(!command && argv[1][0] != '-') if(error) return 1;
char const *path = argv[optind + 1];
if(!path)
{ {
fprintf(stderr, "invalid operation: '%s'\n", argv[1]); err(help_string, argv[0]);
fprintf(stderr, "Try '%s --help'.\n", argv[0]);
return 1; return 1;
} }
if(command) argv[1] = ""; err_context(path, NULL);
struct os os;
if(os_load(path, &os)) { err_pop(); return 1; }
if(binary)
{
err("TODO: Binary file info x_x");
}
else
{
info_os(&os);
} }
enum { os_free(&os);
OPT_RAM = 1, err_pop();
OPT_ASM = 2, return 0;
OPT_CALL = 3, }
OPT_OCC = 4,
}; /*
const struct option longs[] = { ** "disasm" command
*/
int main_disassembly(int argc, char **argv)
{
int error=0, option=0;
/* First load some of fxos' default resources */
asm_load(FXSDK_PREFIX "/share/fxsdk/asm-sh3.txt");
asm_load(FXSDK_PREFIX "/share/fxsdk/asm-sh4.txt");
sys_load(FXSDK_PREFIX "/share/fxsdk/sys-simlo.txt");
sys_load(FXSDK_PREFIX "/share/fxsdk/sys-lephe.txt");
reg_load(FXSDK_PREFIX "/share/fxsdk/reg-sh7305.txt");
reg_load(FXSDK_PREFIX "/share/fxsdk/reg-simlo.txt");
struct disassembly opt = { 0 };
opt.mpu = MPU_GUESS;
opt.len = 0x20;
struct option const longs[] = {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "sh3", no_argument, NULL, '3' }, { "sh3", no_argument, NULL, '3' },
{ "sh4", no_argument, NULL, '4' }, { "sh4", no_argument, NULL, '4' },
{ "ram", required_argument, NULL, OPT_RAM },
{ "table-asm", required_argument, NULL, OPT_ASM }, { "table-asm", required_argument, NULL, OPT_ASM },
{ "table-call", required_argument, NULL, OPT_CALL }, { "table-sys", required_argument, NULL, OPT_SYS },
{ "table-reg", required_argument, NULL, OPT_REG },
};
while(option >= 0 && option != '?')
switch((option = getopt_long(argc, argv, "hb34a:s:l:", longs, NULL)))
{
case 'h':
err(help_string, argv[0]);
break;
case 'b':
opt.binary = 1;
break;
case '3':
opt.mpu = MPU_SH7705;
break;
case '4':
opt.mpu = MPU_SH7305;
break;
case OPT_ASM:
asm_load(optarg);
break;
case OPT_SYS:
printf("TODO: Load additional syscall tables x_x\n");
break;
case OPT_REG:
printf("TODO: Load additional register tables x_x\n");
break;
case 'a':
case 's':
opt.start = integer(optarg, &error);
opt.syscall = (option == 's');
break;
case 'l':
opt.len = integer(optarg, &error);
break;
case '?':
error = 1;
}
if(error) return 1;
char const *path = argv[optind + 1];
if(!path)
{
err(help_string, argv[0]);
return 1;
}
err_context(path, NULL);
if(opt.binary)
{
printf("TODO: Disassembly binary x_x");
err_pop();
return 1;
}
struct os os;
if(os_load(path, &os)) { err_pop(); return 1; }
disassembly_os(&os, &opt);
os_free(&os);
err_pop();
return 0;
}
/*
** "analyze" command
*/
int main_analyze(int argc, char **argv)
{
int error=0, option=0;
struct analysis opt = { 0 };
struct option const longs[] = {
{ "help", no_argument, NULL, 'h' },
{ "table-asm", required_argument, NULL, OPT_ASM },
{ "table-sys", required_argument, NULL, OPT_SYS },
{ "table-reg", required_argument, NULL, OPT_REG },
{ "full", no_argument, NULL, 'f' }, { "full", no_argument, NULL, 'f' },
{ "syscall", no_argument, NULL, 's' }, { "syscall", no_argument, NULL, 's' },
{ "address", no_argument, NULL, 'a' }, { "address", no_argument, NULL, 'a' },
@ -105,43 +222,35 @@ int main(int argc, char **argv)
{ "occurrences", required_argument, NULL, OPT_OCC }, { "occurrences", required_argument, NULL, OPT_OCC },
}; };
int option = 0;
while(option >= 0 && option != '?') while(option >= 0 && option != '?')
switch((option = getopt_long(argc, argv, "hb34a::s::l:fr",longs,NULL))) switch((option = getopt_long(argc,argv,"hfsar", longs, NULL)))
{ {
case 'h': case 'h':
fprintf(stderr, help_string, argv[0]); fprintf(stderr, help_string, argv[0]);
return 0; return 0;
case '3':
case '4':
opt.target = option;
break;
case OPT_RAM:
opt.ram = optarg;
break;
case OPT_ASM: case OPT_ASM:
tables_add_asm(optarg); asm_load(optarg);
break; break;
case OPT_CALL: case OPT_SYS:
tables_add_syscall(optarg); // sys_load(optarg);
break;
case OPT_REG:
// reg_load(optarg);
break; break;
case 'f': case 'f':
opt.f = 1; opt.type = ANALYSIS_FULL;
break; break;
case 's': case 's':
opt.s = optarg; opt.type |= ANALYSIS_SYSCALL;
break; break;
case 'a': case 'a':
opt.a = optarg; opt.type |= ANALYSIS_ADDRESS;
break;
case 'l':
opt.l = integer(optarg, &error);
break; break;
case 'r': case 'r':
opt.r = 1; opt.type |= ANALYSIS_REGISTER;
break; break;
case OPT_OCC: case OPT_OCC:
opt.occ = optarg; opt.occurrences = integer(optarg, &error);
break; break;
case '?': case '?':
error = 1; error = 1;
@ -149,35 +258,44 @@ int main(int argc, char **argv)
} }
if(error) return 1; if(error) return 1;
opt.input = argv[optind];
if(!opt.input) /* If no analysis mode was specified, do everything */
{ if(!opt.type) opt.type = ANALYSIS_FULL;
fprintf(stderr, help_string, argv[0]);
return 1;
}
/* Load default tables (user-specified tables will override them) */
tables_add_asm (FXSDK_PREFIX "/share/assembly-sh3.txt");
tables_add_syscall(FXSDK_PREFIX "/share/syscalls.txt");
/* Change interpretation of arguments depending on mode */
printf("Operation is '%c'\n", command);
printf(" input=%s\n", opt.input);
printf(" target='%c'\n", opt.target);
printf(" ram=%s\n", opt.ram);
printf(" a=%s\n", opt.a);
printf(" s=%s\n", opt.s);
printf(" l=%zu\n", opt.l);
printf(" f=%d\n", opt.f);
printf(" r=%d\n", opt.r);
printf(" occ=%s\n", opt.occ);
/* TODO: Execution procedure:
TODO: 1. Identify architecture
TODO: 2. Load RAM data, syscall tables, peripheral modules, etc
TODO: 3. Execute command */
return 0; return 0;
} }
/*
** Program entry
*/
int main(int argc, char **argv)
{
if(argc < 2)
{
err(help_string, argv[0]);
return 1;
}
char *cmd = argv[1];
argv[1] = "";
/* Switch on command name */
if(!strcmp(cmd, "info"))
return main_info(argc, argv);
else if(!strcmp(cmd, "disasm"))
return main_disassembly(argc, argv);
else if(!strcmp(cmd, "analyze"))
return main_analyze(argc, argv);
else if(!strcmp(cmd, "-?") || !strcmp(cmd, "-h") ||
!strcmp(cmd, "--help"))
{
err(help_string, argv[0]);
return 0;
}
err("invalid operation '%s'", cmd);
err("Try '%s --help'.", argv[0]);
return 1;
}

38
fxos/memory.c Normal file
View file

@ -0,0 +1,38 @@
#include <fxos.h>
/* Shared by all platforms (though ROM is 4M on most) */
static struct region ROM = { 0x80000000, 0x807fffff, "ROM", MPU_GUESS };
static struct region RAM = { 0x88000000, 0x88040000, "RAM", MPU_GUESS };
static struct region P2_ROM = { 0xa0000000, 0xa07fffff, "P2 ROM", MPU_GUESS };
static struct region P2_RAM = { 0xa8000000, 0xa8040000, "P2 RAM", MPU_GUESS };
/* SH7305 only */
static struct region RS = { 0xfd800000, 0xfd8007ff, "RS", MPU_SH7305 };
static struct region IL = { 0xe5200000, 0xe5203fff, "IL", MPU_SH7305 };
static struct region XRAM = { 0xe5007000, 0xe5008fff, "XRAM", MPU_SH7305 };
static struct region YRAM = { 0xe5017000, 0xe5018fff, "YRAM", MPU_SH7305 };
/* A summary */
static struct region *regions[] = {
&ROM, &RAM, &P2_ROM, &P2_RAM, &IL, &RS, NULL,
};
/* memory_in(): Check if an address if inside a given region */
static int memory_in(uint32_t address, struct region const *reg)
{
return reg && address >= reg->start && address <= reg->end;
}
/* memory_region(): Find the region where an address is located */
struct region const *memory_region(uint32_t address)
{
for(int i = 0; regions[i]; i++)
{
if(memory_in(address, regions[i])) return regions[i];
}
return NULL;
}

91
fxos/os.c Normal file
View file

@ -0,0 +1,91 @@
#include <endian.h>
#include <string.h>
#include <fxos.h>
#include <errors.h>
#include <util.h>
/* os_load(): Load an OS file and find out basic properties */
int os_load(char const *path, struct os *os)
{
if(!path || !os) return 1;
os->data = map(path, &os->fd, &os->len);
if(!os->data) return 1;
if(os->len < 0x10080)
{
err("too small for the OS format I know (min. 0x10080 bytes)",
os->len);
return 1;
}
/* Get the OS version */
memcpy(os->version, os->data + 0x10020, 14);
os->version[14] = 0;
/* Guess the MPU type (or assume SH7305). Until version 03.00, the last
digit of the version number indicated the presence of an SH7305 */
os->mpu = MPU_SH7305;
if(!strncmp(os->version, "02.", 3) && os->version[13] == '0')
os->mpu = MPU_SH7705;
/* Find the syscall table address */
memcpy(&os->syscall_table, os->data + 0x1007c, 4);
os->syscall_table = be32toh(os->syscall_table);
/* Count the number of valid syscall entries */
os->syscalls = 0;
while(memory_region(os_syscall(os, os->syscalls))) os->syscalls++;
/* Find the footer address (last occurrence of "CASIOABSLangdata") */
char const *signature = "CASIOABSLangdata";
void *occ = NULL, *next = memmem(os->data, os->len, signature, 16);
void *end = os->data + os->len;
while(next)
{
occ = next;
next = memmem(next + 1, end - (next + 1), signature, 16);
}
os->footer = (occ) ? (occ - os->data) : (uint32_t)-1;
return 0;
}
/* os_syscall(): Get the address of a syscall entry */
uint32_t os_syscall(struct os const *os, int syscall)
{
uint32_t table_entry = (os->syscall_table & 0x1fffffff) + 4 * syscall;
if(table_entry + 4 > os->len) return (uint32_t)-1;
uint32_t address;
memcpy(&address, os->data + table_entry, 4);
address = be32toh(address);
return address;
}
/* os_syscall_find(): Find a syscall which points to an address */
int os_syscall_find(struct os const *os, uint32_t entry)
{
/* Try to make this slightly quicker */
uint32_t table_entry = (os->syscall_table & 0x1fffffff);
entry = htobe32(entry);
uint32_t *entries = os->data + table_entry;
for(int i = 0; i < os->syscalls; i++) if(entries[i] == entry) return i;
return -1;
}
/* os_free(): Free an OS file opened with os_load() */
void os_free(struct os const *os)
{
if(os && os->data) unmap(os->data, os->fd, os->len);
}

114
fxos/reg-sh7305.txt Normal file
View file

@ -0,0 +1,114 @@
# T6K11 interface
0xb4000000 T6K11.REG
0xb4010000 T6K11.DATA
# Exception handling
0xff000020 TRA
0xff000024 EXPEVT
0xff000028 INTEVT
0xff2f0004 EXPMASK
# Memory Management Unit
0xff000000 MMU.PTEH
0xff000004 MMU.PTEL
0xff00000c MMU.TEA
0xff000010 MMU.MMUCR
0xff000034 MMU.PTEA
0xff000070 MMU.PASCR
0xff000078 MMU.IRMCR
# Interrupt controller
0xa4140000 INTC.ICR0
0xa414001c INTC.ICR1
0xa4140010 INTC.INTPRI00
0xa4140024 INTC.INTREQ00
0xa4140044 INTC.INTMSK00
0xa4140064 INTC.INTMSKCLR00
0xa41400c0 INTC.NMIFCR
0xa4700000 INTC.USERIMSK
0xa4080000 INTC.IPRA
0xa4080004 INTC.IPRB
0xa4080008 INTC.IPRC
0xa408000c INTC.IPRD
0xa4080010 INTC.IPRE
0xa4080014 INTC.IPRF
0xa4080018 INTC.IPRG
0xa408001c INTC.IPRH
0xa4080020 INTC.IPRI
0xa4080024 INTC.IPRJ
0xa4080028 INTC.IPRK
0xa408002c INTC.IPRL
0xa4080080 INTC.IMR0
0xa4080084 INTC.IMR1
0xa4080088 INTC.IMR2
0xa408008c INTC.IMR3
0xa4080090 INTC.IMR4
0xa4080094 INTC.IMR5
0xa4080098 INTC.IMR6
0xa408009c INTC.IMR7
0xa40800a0 INTC.IMR8
0xa40800a4 INTC.IMR9
0xa40800a8 INTC.IMR10
0xa40800ac INTC.IMR11
0xa40800b0 INTC.IMR12
0xa40800c0 INTC.IMCR0
0xa40800c4 INTC.IMCR1
0xa40800c8 INTC.IMCR2
0xa40800cc INTC.IMCR3
0xa40800d0 INTC.IMCR4
0xa40800d4 INTC.IMCR5
0xa40800d8 INTC.IMCR6
0xa40800dc INTC.IMCR7
0xa40800e0 INTC.IMCR8
0xa40800e4 INTC.IMCR9
0xa40800e8 INTC.IMCR10
0xa40800ec INTC.IMCR11
0xa40800f0 INTC.IMCR12
# Direct Memory Access Controller: TODO
# Reset and power-down modes
0xa4150020 POWER.STBCR
0xa4150030 POWER.MSTPCR0
0xa4150034 POWER.MSTPCR1
0xa4150038 POWER.MSTPCR2
0xa4150040 POWER.BAR
# Real-Time Clock
0xa465fec0 RTC.R64CNT
0xa465fec2 RTC.RSECCNT
0xa465fec4 RTC.RMINCNT
0xa465fec6 RTC.RHRCNT
0xa465fec8 RTC.RWKCNT
0xa465feca RTC.RDAYCNT
0xa465fecc RTC.RMONCNT
0xa465fece RTC.RYRCNT
0xa465fed0 RTC.RSECAR
0xa465fed2 RTC.RMINAR
0xa465fed4 RTC.RHRAR
0xa465fed6 RTC.RWKAR
0xa465fed8 RTC.RDAYAR
0xa465feda RTC.RMONAR
0xa465fedc RTC.RCR1
0xa465fede RTC.RCR2
0xa465fee0 RTC.RYRAR
0xa465fee4 RTC.RCR3
# User Break Controller
0xff200000 UBC.CBR0
0xff200004 UBC.CRR0
0xff200008 UBC.CAR0
0xff20000c UBC.CAMR0
0xff200020 UBC.CBR1
0xff200024 UBC.CRR1
0xff200028 UBC.CAR1
0xff20002c UBC.CAMR1
0xff200030 UBC.CDR1
0xff200034 UBC.CDMR1
0xff200038 UBC.CETR1
0xff200600 UBC.CCMFR
0xff200620 UBC.CBCR
# RCLK Watchdog Timer
0xa4520000 RWDT.RWTCNT
0xA4520004 RWDT.RWTCSR

141
fxos/reg-simlo.txt Normal file
View file

@ -0,0 +1,141 @@
# Processor version
0xff2f0000 CPUOPM
0xff000030 PVR
0xff000040 CVR
0xff000044 PRR
# Key Scan Interface
0xa44b0000 KEYSC.DATA
0xa44b000c KEYSC.UCNTREG
0xa44b000e KEYSC.AUTOFIXREG
0xa44b0010 KEYSC.UMODEREG
0xa44b0012 KEYSC.USTATEREG
0xa44b0014 KEYSC.UINTREG
0xa44b0016 KEYSC.UWSETREG
0xa44b0018 KEYSC.UINTERVALREG
0xa44b001a KEYSC.OUTPINSET
0xa44b001c KEYSC.INPINSET
# Timer Unit
0xa4490004 TMU.TSTR
0xa4490008 TMU0.TCOR
0xa449000c TMU0.TCNT
0xa4490010 TMU0.TCR
0xa4490014 TMU1.TCOR
0xa4490018 TMU1.TCNT
0xa449001c TMU1.TCR
0xa4490020 TMU2.TCOR
0xa4490024 TMU2.TCNT
0xa4490028 TMU2.TCR
# Serial Communication Interface
0xa4410000 SCIF.SCSMR
0xa4410004 SCIF.SCBRR
0xa4410008 SCIF.SCSCR
0xa441000c SCIF.SCFTDR
0xa4410010 SCIF.SCFSR
0xa4410014 SCIF.SCFRDR
0xa4410018 SCIF.SCFCR
0xa441001c SCIF.SCFDR
0xa4410024 SCIF.SCLSR
# Pin Function Controller
0xa4050100 PFC.PACR
0xa4050102 PFC.PBCR
0xa4050104 PFC.PCCR
0xa4050106 PFC.PDCR
0xa4050108 PFC.PECR
0xa405010a PFC.PFCR
0xa405010c PFC.PGCR
0xa405010e PFC.PHCR
0xa4050110 PFC.PJCR
0xa4050112 PFC.PKCR
0xa4050114 PFC.PLCR
0xa4050116 PFC.PMCR
0xa4050118 PFC.PNCR
0xa405014c PFC.PPCR
0xa405011a PFC.PQCR
0xa405011c PFC.PRCR
0xa405011e PFC.PSCR
0xa4050140 PFC.PTCR
0xa4050142 PFC.PUCR
0xa4050144 PFC.PVCR
0xa405014e PFC.PSELA
0xa4050150 PFC.PSELB
0xa4050152 PFC.PSELC
0xa4050154 PFC.PSELD
0xa4050156 PFC.PSELE
0xa405015e PFC.PSELF
0xa40501c8 PFC.PSELG
0xa40501d6 PFC.PSELH
0xa4050158 PFC.HIZCRA
0xa405015a PFC.HIZCRB
0xa405015c PFC.HIZCRC
0xa4050180 PFC.MSELCRA
0xa4050182 PFC.MSELCRB
0xa4050184 PFC.DRVCRD
0xa4050186 PFC.DRVCRA
0xa4050188 PFC.DRVCRB
0xa405018a PFC.DRVCRC
0xa40501c3 PFC.PULCRBSC
0xa40501c5 PFC.PULCRTRST
0xa4050190 PFC.PULCRA
0xa4050191 PFC.PULCRB
0xa4050192 PFC.PULCRC
0xa4050193 PFC.PULCRD
0xa4050194 PFC.PULCRE
0xa4050195 PFC.PULCRF
0xa4050196 PFC.PULCRG
0xa4050197 PFC.PULCRH
0xa4050198 PFC.PULCRJ
0xa4050199 PFC.PULCRK
0xa405019a PFC.PULCRL
0xa405019b PFC.PULCRM
0xa405019c PFC.PULCRN
0xa40501c6 PFC.PULCRP
0xa405019d PFC.PULCRQ
0xa405019e PFC.PULCRR
0xa405019f PFC.PULCRS
0xa40501c0 PFC.PULCRT
0xa40501c1 PFC.PULCRU
0xa40501c2 PFC.PULCRV
# Bus State Controller
0xfec10000 BSC.CMNCR
0xfec10004 BSC.CS0BCR
0xfec10008 BSC.CS2BCR
0xfec1000c BSC.CS3BCR
0xfec10010 BSC.CS4BCR
0xfec10014 BSC.CS5ABCR
0xfec10018 BSC.CS5BBCR
0xfec1001c BSC.CS6ABCR
0xfec10020 BSC.CS6BBCR
0xfec10024 BSC.CS0WCR
0xfec10028 BSC.CS2WCR
0xfec1002c BSC.CS3WCR
0xfec10030 BSC.CS4WCR
0xfec10034 BSC.CS5AWCR
0xfec10038 BSC.CS5BWCR
0xfec1003c BSC.CS6AWCR
0xfec10040 BSC.CS6BWCR
0xfec10044 BSC.SDCR
0xfec10048 BSC.RTCSR
0xfec1004c BSC.RTCNT
0xfec10050 BSC.RTCOR
0xfec14000 BSC.SDMR2
0xfec15000 BSC.SDMR3
# Clock Pulse Generator
0xa4150000 CPG.FRQCR
0xa4150008 CPG.FCLKCR
0xa4150010 CPG.DDCLKCR
0xa4150014 CPG.USBCLKCR
0xa4150024 CPG.PLLCR
0xa4150028 CPG.PLL2CR
0xa415003c CPG.SPUCLKCR
0xa4150044 CPG.SSCGCR
0xa4150050 CPG.FLLFRQ
0xa4150060 CPG.LSTATS
# More addresses are around on Casiopeia.
# See http://www.casiopeia.net/forum/viewtopic.php?f=11&t=1756#p14588.

58
fxos/reg.c Normal file
View file

@ -0,0 +1,58 @@
#include <fxos.h>
#include <errors.h>
#include <string.h>
#include <util.h>
/* reg_free_item(): Free a peripheral register item */
static void reg_free_item(void *item)
{
struct reg_address *reg = item;
free(reg->name);
}
/* reg_load(): Load a peripheral register table */
void reg_load(char const *file)
{
err_context("register", file, NULL);
if(!table_available())
{
err("too many tables, skipping");
err_pop();
return;
}
/* Map the file to memory */
int fd;
size_t size;
void *data = map(file, &fd, &size);
if(!data) { err_pop(); return; }
/* If the file is named "reg-x.txt", use "x" as the table name */
char *name = match_table_name(file, "reg", ".txt");
/* Parse the contents */
int count;
struct reg_address *regs = lex_reg(data, size, &count);
table_create("reg", name, reg_free_item, count, sizeof *regs, regs);
unmap(data, fd, size);
err_pop();
}
/* Global storage for reg_match() */
static uint32_t reg_match_address;
/* reg_match(): Search routine for reg_find() */
static int reg_match(void *item)
{
struct reg_address *reg = item;
return reg->address == reg_match_address;
}
/* reg_find(): Find information on a given peripheral register address */
struct reg_address const *reg_find(uint32_t address)
{
reg_match_address = address;
return table_find("reg", reg_match, NULL, 0);
}

7
fxos/sys-lephe.txt Normal file
View file

@ -0,0 +1,7 @@
0x000 sys_init
0x004 tlb_init
void tlb_init(void)
0x025 t6k11_read_datareg
uint8_t t6k11_read_datareg(void)
0x3fc tlb_map
void tlb_map(int shifted_vpn, int way, uint32_t data_field)

656
fxos/sys-simlo.txt Normal file
View file

@ -0,0 +1,656 @@
0x001 vbr_tlb_error
0x002 vbr_cpu_address
0x003 vbr_tlb_exception
0x005 App_RegisterAddins
int App_RegisterAddins(void)
0x009 App_FindFreeAddinSlot
int FindFreeAddinSlot(void)
0x00a App_GetAddinHeaderAddr
int GetAddindHeaderAddr(int addin_no, int offset, void *result)
0x00e App_GetAddindEstrip
int App_GetAddindEstrip(int addin_no, int estrip_no, void *result)
0x013 GlibAddinAplExecutionCheck
0x014 GlibGetAddinLibInfo
0x015 GlibGetOSVersionInfo
int GlibGetOSVersionInfo(char *a, char *b, short *c, short *d)
0x018 MMU_FlushCache
0x01b DD_Clear
0x01c Bdisp_WriteGraph_VRAM
0x01d Bdisp_WriteGraph_DD
0x01e Bdisp_WriteGraph_DDVRAM
0x022 Bdisp_ReadArea_VRAM
0x023 Bdisp_ReadArea_DD
0x024 Bdisp_GetDisp_DD
0x025 DD_Read
0x026 DD_ReadFromPage
0x027 DD_WriteToPage
0x028 Bdisp_PutDisp_DD
0x02a Bdisp_DrawShapeToVRAM
0x02f Bdisp_DrawShapeToVRAM
0x030 Bdisp_DrawLineVRAM
0x031 Bdisp_ClearLineVRAM
0x032 Bdisp_DrawShapeToDD
0x033 Bdisp_DrawShapeToVRAM_DD
0x034 Bdisp_DrawShapeToDD
0x035 Bdisp_DrawShapeToVRAM_DD
0x039 RTC_Reset
void RTC_Reset(unsigned int mode)
0x03a RTC_GetTime
void RTC_GetTime(uint *hour, uint *minute, uint *second, uint *millisecond)
0x03b RTC_GetTicks
int RTC_GetTicks(void)
0x03c RTC_Elapsed_ms
int RTC_Elapsed_ms(int start_value, int duration_ms)
0x05c Num_UIntToBCD
0x05d Num_BCDToUInt
0x118 Timer_Install
int Timer_Install(int timerID, void *handler, int elapse), also known as Bcre_cychdr
0x119 Timer_Deinstall
int Timer_Deinstall(int timerID), also known as Bdel_cychdr
0x11a Timer_Start
int Timer_Start(int timerID)
0x11b Timer_Stop
int Timer_Stop(int timerID)
0x11f Bdisp_PutDispArea_DD
0x12d DD_Poweroff
0x130 Wait_ms
0x132 DD_SetContrast
0x133 DD_SetFRS
0x134 DD_SetBias
0x135 GetVRAMAddress
0x136 GetCharacterGlyph
0x137 GetCharacterMiniGlyph
0x138 Cursor_SetPosition
int Cursor_SetPosition(char column, char row)
0x139 Cursor_SetFlashStyle
int Cursor_SetFlashStyle(short flashStyle)
0x13a Cursor_SetFlashMode
void Cursor_SetFlashMode(long flashMode)
0x13b Cursor_GetSettings
uint Cursor_GetSettings(uint *settingsArray)
0x13c Print_OS
void Print_OS(unsigned char *msg, int type)
0x142 Bdisp_AllClr_DD
0x143 Bdisp_AllClr_VRAM
0x144 Bdisp_AllClr_DDVRAM
0x145 Bdisp_GetDisp_VRAM
0x146 Bdisp_SetPoint_VRAM
0x147 Bdisp_SetPoint_DD
0x148 Bdisp_SetPoint_DDVRAM
0x149 Bdisp_GetPoint_VRAM
0x14a Bdisp_AreaClr_DD
0x14b Bdisp_AreaClr_VRAM
0x14c Bdisp_AreaClr_DDVRAM
0x14d Bdisp_AreaReverseVRAM
0x150 PrintXY
void PrintXY(int x, int y, unsigned char *msg, int type)
0x153 Disp_Save
0x154 Disp_Restore
0x155 Disp_GetPtr
0x156 PopUpWin
0x158 Disp_Manage
0x159 System_UpdateOS
0x15d PrintCR
0x15f atoi
0x160 LongToAsc
int LongToAsc(int value, unsigned char *dest, int digits)
0x161 LongToAscHex
int LongToAscHex(int value, unsigned char *dest, int digits)
0x162 pc_toupper
void pc_toupper(char *str)
0x163 pc_tolower
void pc_tolower(char *str)
0x172 strcmp
0x173 strcmp
0x175 some_datatable
0x176 DiagnosticMode
0x18a InvertMem
void InvertMem(void *memoryrange, int count)
0x19f SMEM_Optimization
void SMEM_Optimization(void)
0x1a9 GUI_ProgressBar
0x1b7 Get8x8BitmapPointer_1
0x1b8 Get8x8BitmapPointer_2
0x1b9 Get8x8BitmapPointer_3
0x1ba Get8x8BitmapPointer_4
0x1bb Get8x8BitmapPointer_5
0x1bc Get8x8BitmapPointer_6
0x1bd Get8x8BitmapPointer_7
0x20e StorageMemory_GetFilePos
int StorageMemory_GetFilePos(int handle, int *pos)
0x236 RebootOS
0x23d RTC_TriggerAlarm
void RTC_TriggerAlarm(void)
0x23e RTC_SetDateTime
void RTC_SetDateTime(unsigned char *[7] time)
0x241 Keyboard_ClrBuffer
0x242 Bkey_Set_RepeatTime
0x243 Bkey_Get_RepeatTime
0x244 Bkey_Set_RepeatTime_Default
0x245 Keyboard_EnableAutoRepeat
0x246 Keyboard_DisableAutoRepeat
0x247 Keyboard_GetKeyWait
0x248 Keyboard_PutKeycode
0x249 Keyboard_GetKeyDownTime
short Keyboard_GetKeyDownTime(void)
0x24a Keyboard_IsAnyKeyDown
int Keyboard_IsAnyKeyDown(short *matrixcode)
0x24b Keyboard_IsSpecialKeyDown
int Keyboard_IsSpecialKeyDown(short *matrixcode)
0x24c Keyboard_IsSpecialKeyDown
int Keyboard_IsSpecialKeyDown(short *matrixcode)
0x24d Keyboard_KeyDown
int Keyboard_KeyDown(void)
0x24e Keyboard_SecondaryInterruptHandler
0x24f Keyboard_PutKeymatrixCode
int Keyboard_PutKeymatrixCode(short *matrixcode)
0x251 Keyboard_TimerHandler
0x25e Keyboard_PrimaryInterruptHandler
0x268 GetFKeyIconPointer
void GetFKeyIconPointer(int fkeyno, unsigned char *bitmap)
0x284 BCD_GetNaN
int BCD_GetNaN(unsigned char *value, unsigned char *result)
0x285 Serial_Open_57600
int Serial_Open_57600(void)
0x286 BCD_AnsToSerial
0x28d Comm_Open
int Comm_Open(unsigned short parameters)
0x28e Comm_Close
0x28f Comm_WaitForAnyBuffer
int Comm_WaitForAnyBuffer(int timeout_ms, int P2, int *P3)
0x290 Comm_ReadOneByte
int Comm_ReadOneByte(unsigned char *result)
0x291 Comm_TransmitOneByte
0x292 Comm_WaitForAndReadNBytes
int Comm_WaitForAndReadNBytes(char *buffer, int bytes)
0x293 Comm_TransmitNBytes
0x294 Comm_ClearReceiveBuffer
0x295 Comm_ClearTransmitBuffer
0x296 Comm_IsValidPacketAvailable
int Comm_IsValidPacketAvailable(unsigned char *result)
0x298 Comm_IsOpen
0x299 Comm_GetCurrentSelector
int Comm_GetCurrentSelector(void)
0x2a1 HexToByte
int HexToByte(short *hex, char *result)
0x2a2 HexToWord
int HexToWord(int *hex, short *result)
0x2a3 ByteToHex
0x2a4 WordToHex
0x2a5 Comm_Padding_5C
0x2a6 Comm_ReversePadding_5C
0x2a7 AscHexToNibble
void AscHexToNibble(char hex, char *result)
0x2a8 NibbleToAscHex
0x2a9 strlen
0x2aa slow_memcpy
0x2ab Serial_Open2
int Serial_Open2(unsigned short parameters)
0x2af Comm_Spy0thByte
int Comm_Spy0thByte(unsigned char *result)
0x2db Comm_ProcessInPacket
int Comm_ProcessInPacket(TReceivePacketDesc *rpd)
0x2e1 Comm_PrepareAckPacket
int Comm_PrepareAckPacket(TReceivePacketDesc *rpd, unsigned char subtype, void *datapointer, unsigned short datasize)
0x2e2 Comm_PrepareErrorPacket
void Comm_PrepareErrorPacket(TReceivePacketDesc *rpd, unsigned char subtype)
0x2e3 Comm_PrepareTerminatePacket
void Comm_PrepareTerminatePacket(TReceivePacketDesc *rpd, unsigned char subtype)
0x2e4 Comm_PrepareRoleswapPacket
void Comm_PrepareRoleswapPacket(TReceivePacketDesc *rpd, unsigned char subtype)
0x2e5 Comm_PrepareCheckPacket
void Comm_PrepareCheckPacket(TReceivePacketDesc *rpd, unsigned char subtype)
0x2e6 Comm_PrepareCommandPacket
int Comm_PrepareCommandPacket(TReceivePacketDesc *rpd, unsigned char subtype, void *datapointer, unsigned short datasize)
0x2e7 Comm_PrepareDataPacket
int Comm_PrepareDataPacket(TReceivePacketDesc *rpd, unsigned char subtype, void *datapointer, unsigned short datasize)
0x2ee System_GetOSVersion
void System_GetOSVersion(unsigned char *version)
0x35e memset_range
0x35f memset
0x363 MCS_CreateDirectory
int MCS_CreateDirectory(unsigned char *dir, char *dirno)
0x364 MCS_WriteItem
int MCS_WriteItem(unsigned char *dir, unsigned char *item, short itemType, int data_length, int buffer)
0x366 MCS_DeleteDirectory
int MCS_DeleteDirectory(unsigned char *dir)
0x367 MCS_DeleteItem
int MCS_DeleteItem(unsigned char *dir, unsigned char *item)
0x368 MCS_GetState
int MCS_GetState(int *maxspace, int *currentload, int *remainingspace)
0x369 MCS_GetSystemDirectoryInfo
int MCS_GetSystemDirectoryInfo(unsigned char *dir, unsigned int *pdir, char *dirno)
0x370 MCS_RenameItem
int MCS_RenameItem(unsigned char *srcdir, unsigned char *srcitem, unsigned char *tgtdir, int tgtitem)
0x371 MCS_OverwriteData
int MCS_OverwriteData(unsigned char *dir, unsigned char *item, int write_offset, int bytes_to_write, void *buffer)
0x372 MCS_GetItemData
int MCS_GetItemData(unsigned char *dir, unsigned char *item, int offset, int bytes_to_read, void *buffer)
0x373 MCS_RenameDirectory
int MCS_RenameDirectory(unsigned char *oldname, unsigned char *newname)
0x374 BMCSRenameVariable
0x375 MCS_SearchDirectory
int MCS_SearchDirectory(unsigned char *dir, TMainMemoryDirectoryEntry *dir, char *dirno)
0x376 MCS_SearchDirectoryItem
int MCS_SearchDirectoryItem(unsigned char *dir, unsigned char *item, char *flags_0, TDirectoryItem *item, int *data, int *data_length)
0x37c MCS_GetFirstDataPointerByDirno
int MCS_GetFirstDataPointerByDirno(char *dirno, void *pdata)
0x37d MCS_GetDirectoryEntryByNumber
int MCS_GetDirectoryEntryByNumber(char dirno, TMainMemoryDirectoryEntry *pdir)
0x37e MCS_SearchItem
int MCS_SearchItem(unsigned char *item, TMainMemoryDirectoryEntry *pdir, unsigned short *itemno)
0x37f MCS_str8cpy
int MCS_str8cpy(unsigned char *source, unsigned char *target, int mode)
0x380 MCS_GetDirectoryEntryAddress
void MCS_GetDirectoryEntryAddress(void *directory_entry_address)
0x381 MCS_GetCurrentBottomAddress
void MCS_GetCurrentBottomAddress(void *current_bottom_address)
0x383 MCS_GetCapa
int MCS_GetCapa(int *current_bottom)
0x392 MCS_GetMainMemoryStart
int MCS_GetMainMemoryStart(void)
0x3dc Setup_GetInfo
int Setup_GetInfo(unsigned char *, int, TSetupInfo *info), where the first arguments are used only in fx-CG 10/20
0x3ea the start of a datatable ***
0x3ed Interrupt_SetOrClrStatusFlags
int Interrupt_SetOrClrStatusFlags(int flagmask, int set)
0x3ee Interrupt_QueryStatusFlags
int Interrupt_QueryStatusFlags(int flagmask, int clear)
0x3f4 PowerOff
0x3f5 ClearMainMemory
0x3f6 SH7337_TMU_Stop
0x3f7 SH7337_TMU_int_handler
0x3fa Hmem_SetMMU
void Hmem_SetMMU(int virtualPageNumber, int physicalPageNumber, int pageManagement)
0x3fb MMU_ConfigureAndFlush
void MMU_ConfigureAndFlush(void)
0x3fc TLB_SetAddressValue
void TLB_SetAddressValue(int entryAddress, int way, int value)
0x3fe GetStackPtr
0x3ff MMU_FlushCache
0x400 MMU_ConfigureAndEnable
void MMU_ConfigureAndEnable(void)
0x404 GetPhysicalROMstart
0x405 GetPhysicalRAMstart
0x409 Serial_ResetAndDisable
void *Serial_ResetAndDisable(void)
0x40a Serial_GetInterruptHandler
void *Serial_GetInterruptHandler(void)
0x40b Serial_SetInterruptHandler
int Serial_SetInterruptHandler(int type, void *handler)
0x40c Serial_ReadOneByte
int Serial_ReadOneByte(unsigned char *result)
0x40d Serial_ReadNBytes
int Serial_ReadNBytes(unsigned char *result, int max_size, short *actually_transferred)
0x40e Serial_BufferedTransmitOneByte
int Serial_BufferedTransmitOneByte(unsigned char byte)
0x40f Serial_BufferedTransmitNBytes
int Serial_BufferedTransmitNBytes(unsigned char *bytes, int requested_count)
0x410 Serial_DirectTransmitOneByte
int Serial_DirectTransmitOneByte(unsigned char byte)
0x411 Serial_GetReceivedBytesAvailable
int Serial_GetReceivedBytesAvailable(void)
0x412 Serial_GetFreeTransmitSpace
int Serial_GetFreeTransmitSpace(void)
0x413 Serial_ClearReceiveBuffer
int Serial_ClearReceiveBuffer(void)
0x414 Serial_ClearTransmitBuffer
int Serial_ClearTransmitBuffer(void)
0x418 Serial_Open
int Serial_Open(unsigned char *mode)
0x419 Serial_Close(int mode)
0x41b Serial_CallReceiveIntErrorResetHandler
void *Serial_CallReceiveIntErrorResetHandler(void)
0x41c Serial_CallReceiveIntHandler
void *Serial_CallReceiveIntHandler(void)
0x41d Serial_CallTransmitIntErrorResetHandler
void *Serial_CallTransmitIntErrorResetHandler(void)
0x41e Serial_CallTransmitIntHandler
void *Serial_CallTransmitIntHandler(void)
0x420 OS_inner_Sleep
0x422 Serial_SpyNthByte
int Serial_SpyNthByte(int byteno_to_spy, unsigned char *result)
0x423 Serial_GetStatus
void Serial_GetStatus(unsigned int *serial_status)
0x425 Serial_IsOpen
int Serial_IsOpen(void)
0x429 Bfile_identify_device_OS
int Bfile_identify_device_OS(const FONTCHARACTER *filename)
0x42c Bfile_OpenFile_OS
0x42d Bfile_CloseFile_OS
0x42e Bfile_GetMediaFree_OS
0x42f Bfile_GetFileSize_OS
0x431 Bfile_SeekFile_OS
0x432 Bfile_ReadFile_OS
0x434 Bfile_CreateEntry_OS
0x435 Bfile_WriteFile_OS
0x438 Bfile_RenameEntry
0x439 Bfile_DeleteEntry
0x43b Bfile_FindFirst
0x43c Bfile_FindNext
0x43d Bfile_FindClose
0x44e memcpy
0x44f memcmp
0x450 Bfile_GetFilenameLength
int Bfile_GetFilenameLength(const FONTCHARACTER *filename)
0x451 Bfile_Name_cmp
0x452 Bfile_Name_cpy
0x453 Bfile_Name_ncpy
0x456 Bfile_NameToStr_ncpy
void Bfile_NameToStr_ncpy(char *dest, FONTCHARACTER *src, int n)
0x457 Bfile_StrToName_ncpy
void Bfile_StrToName_ncpy(FONTCHARACTER *dest, char *src, int n)
0x462 GetAppName
char *GetAppName(char *dest)
0x463 SetAppName
int SetAppName(char *src)
0x464 CmpAppName
int CmpAppName(char *name)
0x465 GetIntPtrContent
int GetIntPtrContent(unsigned char *ptr)
0x467 LongToAscHex
int LongToAscHex(int value, char *dest, int digits)
0x468 hasSDOption
0x469 Battery_DisplayLowStatus
int Battery_DisplayLowStatus(int delayflag)
0x46b App_BuiltInCount
int App_BuiltInCount(void)
0x476 Battery_IsLow
int Battery_IsLow(void)
0x477 EnableGetkeyToMainFunctionReturn
void EnableGetkeyToMainFunctionReturn(void)
0x478 DisableGetkeyToMainFunctionReturn
void DisableGetkeyToMainFunctionReturn(void)
0x47f SetAutoPowerOffTime
0x480 GetAutoPowerOffTime
0x486 GetdatatablePtr
0x48d SetAutoPowerOffFlag
0x48e GetAutoPowerOffFlag
0x492 Battery_IsLow
int Battery_IsLow(int delayflag)
0x494 CallbackAtQuitMainFunction
0x495 Battery_DisplayLowStatus
int Battery_DisplayLowStatus(int delayflag)
0x499 Heap_SetTopChunk
int Heap_SetTopChunk(int size)
0x49a App_Start
int App_Start(int r4, int r5, int index, int force)
0x49c Battery_GetStatus
int Battery_GetStatus(int delayflag)
0x49e RebootOS
0x4a0 AUX_DisplayErrorMessage
void AUX_DisplayErrorMessage(void)
0x4ad USB_InterruptHandler
0x4ae USB_TimerHandler
void USB_TimerHandler(void)
0x4b0 AUX_DisplayFKeyIcons
void AUX_DisplayFKeyIcons(void)
0x4cb Keyboard_RemapFKeyCode
void Keyboard_RemapFKeyCode(int mode, TFKeyDef *source)
0x4d1 AUX_DisplayFKeyIcon
void AUX_DisplayFKeyIcon(int pos, unsigned char *bitmap)
0x4dc char Setup_GetEntry(unsigned int index)
0x4dd Setup_SetEntry
char *Setup_SetEntry(unsigned int index, char setting)
0x4de Setup_GetEntryPtr
char *Setup_GetEntryPtr(unsigned int index)
0x4df Alpha_GetData
char *Alpha_GetData(char var, char *dest)
0x4e0 Alpha_SetData
char *Alpha_SetData(char var, char *src)
0x4e1 Alpha_ClearAll
void Alpha_ClearAll(void)
0x4e6 HourGlass
void HourGlass(void)
0x4e9 LocalizeStringID
0x4f5 BCD_ToStrAsNumber1
int BCD_ToStrAsNumber1(char *data, char *string)
0x4f6 BCD_ToStrAsNumber2
int BCD_ToStrAsNumber2(char *data, char *string)
0x500 BCDToInternal
int BCDToInternal(TBCDinternal *target, TBCDvalue *source)
0x518 Setup_GetEntry_3E
0x519 Setup_GetEntry_40
0x51a Setup_SetEntry_3E
0x51b Setup_SetEntry_40
0x531 MB_IsLead
int MB_IsLead(char c)
0x533 MB_ElementCount
int MB_ElementCount(char *str)
0x534 MB_ByteCount
int MB_ByteCount(char *str)
0x536 MB_strcat
char *MB_strcat(char *dest, char *src)
0x537 MB_strncat
char *MB_strncat(char *dest, char *src, int bytes)
0x538 MB_strcpy
char *MB_strcpy(char *dest, char *src)
0x53c MB_GetSecondElemPtr
char *MB_GetSecondElemPtr(char *str)
0x53d MB_GetElement
short MB_GetElement(char *str)
0x53e MB_CopyToHeap
char *MB_CopyToHeap(char *src)
0x53f memcmp
0x541 itoa
0x542 to_uppercase
0x543 to_lowercase
0x544 BCD_0
0x545 BCD_1
0x546 BCD_2
0x547 BCD_10
0x548 BCD_1/3
0x549 BCD_0.5
0x54a BCD_32767
0x54b BCD_-32768
0x54c BCD_65536
0x54d BCD_0x7fffffff
0x54e BCD_-2Gi
0x54f BCD_4Gi
0x550 BCD_pi
0x551 BCD_2pi
0x552 BCD_pi/2
0x553 BCD_e
0x554 BCD_5
0x5a6 BCD_SetAsInt
int BCD_SetAsInt(int input, TBCDValue *result)
0x5af BCD_pi/4
0x5b0 BCD_ln(10)
0x5b1 BCD_ln(2)
0x5b2 BCD_9.99e+99
0x5b3 BCD_-9.99e+99
0x5b4 BCD_9.99999999999999e+99
0x5b5 BCD_227.85
0x5b6 BCD_sqrt(2)
0x5b7 BCD_sqrt(2)/2
0x5b8 BCD_506.6282746310
0x645 CalculateExpression
void CalculateExpression(char **formula, char opcode[2], TBCDValue *result, int p4)
0x64a CalculateExpression0
0x652 PRGM_NextOpcode
void PRGM_NextOpcode(char opcode[2], char **program)
0x6a6 PRGM_IsEndOfLine
int PRGM_IsEndOfLine(char *opcode)
0x6c4 Keyboard_PRGM_GetKey
int Keyboard_PRGM_GetKey(TBCDValue *result)
0x6d4 Alpha_GetData2
int Alpha_GetData2(char var, char *dest)
0x713 Print_ClearLine
0x763 Bdisp_DrawRectangle
void Bdisp_DrawRectangle(int x1, int y1, int x2, int y2)
0x7fc OpcodeToStr
int OpcodeToStr(unsigned short opcode, unsigned char *string)
0x804 CLIP_Store
int CLIP_Store(unsigned char *buffer, int length)
0x807 locate
0x808 Print
0x809 PrintRev
0x80a PrintC
0x80b PrintRevC
0x80c PrintLine
0x80d PrintRLine
0x80e Cursor_GetFlashStyle
int Cursor_GetFlashStyle(void)
0x80f Cursor_GetSettings
int Cursor_GetSettings(struct CursorSettings *settings)
0x811 Cursor_SetFlashOn
void Cursor_SetFlashOn(char flash_style)
0x812 Cursor_SetFlashOff
void Cursor_SetFlashOff(void)
0x813 SaveDisp
0x814 RestoreDisp
0x829 MCS_CreateDirectory
unsigned char *MCS_CreateDirectory(unsigned char *dir)
0x82a MCS_PutInternalItem
int MCS_PutInternalItem(char dirtype, unsigned char *item, int data_len, void *buffer)
0x82b MCSPutVar2
int MCSPutVar2(unsigned char *dir, unsigned char *item, int data_len, void *buffer)
0x830 MCSOvwDat2
int MCSOvwDat2(unsigned char *dir, unsigned char *item, int bytes_to_write, void *buffer, int write_offset)
0x832 MCS_OverwriteOpenItem
int MCS_OverwriteOpenItem(int bytes_to_write, void *buffer, int write_offset)
0x833 MCS_ClearInternalDirectory
int MCS_ClearInternalDirectory(char dirtype)
0x834 MCS_ClearDirectory
int MCS_ClearDirectory(unsigned char *dir)
0x835 MCS_DeleteInternalItem
int MCS_DeleteInternalItem(char dirtype, unsigned char *dir)
0x836 MCSDelVar2
int MCSDelVar2(unsigned char *dir, unsigned char *item)
0x83a MCS_GotoInternalItem
int MCS_GotoInternalItem(char dirtype, unsigned char *item, int direction)
0x83b MCS_OpenMainMemoryItem
int MCS_OpenMainMemoryItem(unsigned char *dir, unsigned char *item, char direction)
0x83c MCS_GotoHandleNeighbour
int MCS_GotoHandleNeighbour(char direction)
0x83d MCS_CheckOpenedItem
int MCS_CheckOpenedItem(char *dirtype, int *data_len)
0x83e MCS_GetOpenItem
int MCS_GetOpenItem(unsigned char *item)
0x83f MCS_OpenInternalDirectoryItem
int MCS_OpenInternalDirectoryItem(char dirtype, unsigned char *item, int *data_len)
0x840 MCSGetDlen2
int MCSGetDlen2(unsigned char *dir, unsigned char *item, int *data_len)
0x841 MCSGetData1
int MCSGetData1(int offset, int len_to_copy, void *buffer)
0x843 MCS_MapMCS_Result
int MCS_MapMCS_Result(void)
0x844 MCSGetCapa
0x84d MCS_OpenAlphaMemItem
int MCS_OpenAlphaMemItem(char variablename, int *data_len, void *data_ptr)
0x852 MCS_DirtypeToItemtype
int MCS_DirtypeToItemtype(char dirtype)
0x853 MCS_ItemtypeToDirtype
int MCS_ItemtypeToDirtype(char itemtype)
0x863 MCS_DirtypeToName
unsigned char *MCS_DirtypeToName(char dirtype)
0x866 MCS_MapError
int MCS_MapError(int error_in)
0x869 Alpha_ClearAllAndAns
void Alpha_ClearAllAndAns(void)
0x86f MCS_DeleteDirectoryItems
void MCS_DeleteDirectoryItems(unsigned char *dir)
0x8db EditExpression
int EditExpression(int mode, short key, int row, TBCDValue *value, char *editbuffer, short editbufferlen, char *pretext, int mode2)
0x8dc EditValue
int EditValue(int mode, short key, int row, TBCDValue *value, char *pretext)
0x8e6 EditMBStringCtrl
void EditMBStringCtrl(unsigned char *, int xposmax, void *, void *, void *, int, int)
0x8ea DisplayMBString
void DisplayMBString(unsigned char *, int, int xpos, int x, int y)
0x8ec EditMBStringChar
void EditMBStringChar(unsigned char *, int xposmax, int xpos, int char)
0x8f7 DisplayMBString2
void DisplayMBString2(int, unsigned char *, int, int xpos, int zero, int x, int y, int, int, int)
0x8fe PopupWin
void PopupWin(int nlines)
0x901 DisplayMessageBox
void DisplayMessageBox(int height, unsigned char *message)
0x905 DisplayErrorMessage
void DisplayErrorMessage(int id)
0x90b SetShiftAlphaState
0x90c GetInsOverwriteState
0x90d SetInsOverwriteState
0x90e ClrShiftAlphaState
0x90f GetKey
int GetKey(unsigned int *keycode)
0x910 PutKey
int PutKey(int keycode, int mode)
0x91b GetShiftAlphaState
0x924 TestMode
void TestMode(void)
0x954 DisplayErrorMessage
0x985 App_CONICS
0x998 App_DYNA
0x9ad PrintXY
0x9df App_EACT
0x9e1 App_Equation
0x9e2 App_EQUA
0x9f5 App_Program
0xa00 App_FINANCE
0xa1f Keyboard_RemapFKeyCode
void Keyboard_RemapFKeyCode(TKeyDef *workspace, TKeyDef *source, int mode)
0xa35 AUX_DisplayMessage
0xa48 App_GRAPH_TABLE
0xa4a App_LINK
0xa6a App_Optimization
0xa6b App_Memory
0xa75 App_RECUR
0xa97 App_RUN_MAT_EXE
0xaae App_RUN_MAT
0xac6 App_STAT
0xac8 App_SYSTEM
0xacc free
0xacd malloc
0xace memcmp
0xacf smart_memcpy
0xad0 memset
0xad4 strcat
0xad5 smart_strcmp
0xad6 strlen
0xad7 strncat
0xad8 strncmp
0xad9 strncpy
0xada strrchr
0xae8 CatalogDialog
0xc4f PrintMiniSd
0xca7 OpcodeType
int OpcodeType(char *);
0xcb0 Basic_Send_Send38k
0xcb1 Basic_Receive_Receive38k
0xcb2 Basic_OpenComPort38k_CloseComPort38k
0xcc4 InputNumber
int InputNumber(unsigned char *heading, int maxlen, int mode)
0xcc5 InputString
int InputString(unsigned char *buffer, unsigned char *heading, int maxlen)
0xccb GetRAMSize
int GetRAMSize(void)
0xcd0 another_diagnostic_dialog
0xd64 InputDateDialog
int InputDateDialog(int *day, int *month, int *year, int *p4)
0xd65 InputMonthDialog
int InputMonthDialog(int *month, int *p2)
0xd66 InputDayDialog
int InputDayDialog(int *day, int *p2)
0xd67 InputYearDialog
int InputYearDialog(int *year, int *p2)
0xdab StoreExpressionToGraphFuncMemory
void StoreExpressionToGraphFuncMemory(int fun_no, int, char *expression)
0xe6b calloc
0xe6c memmove
0xe6d realloc
0xe6e strchr
0xe6f strstr

59
fxos/sys.c Normal file
View file

@ -0,0 +1,59 @@
#include <fxos.h>
#include <errors.h>
#include <util.h>
#include <string.h>
/* sys_free_item(): Free a syscall description item */
static void sys_free_item(void *item)
{
struct sys_call *call = item;
free(call->name);
free(call->descr);
}
/* sys_load(): Load a syscall table */
void sys_load(char const *file)
{
err_context("syscall", file, NULL);
if(!table_available())
{
err("too many tables, skipping");
err_pop();
return;
}
/* Map the file to memory */
int fd;
size_t size;
void *data = map(file, &fd, &size);
if(!data) { err_pop(); return; }
/* If the file is named "sys-x.txt", use "x" as the table name */
char *name = match_table_name(file, "sys", ".txt");
/* Parse the contents */
int count;
struct sys_call *calls = lex_sys(data, size, &count);
table_create("sys", name, sys_free_item, count, sizeof *calls, calls);
unmap(data, fd, size);
err_pop();
}
/* Global storage for the sys_match() function */
static uint32_t sys_match_number;
/* sys_match(): Search routine for sys_find() */
static int sys_match(void *item)
{
struct sys_call *call = item;
return call->number == sys_match_number;
}
/* sys_find(): Find information on a given syscall number */
struct sys_call const *sys_find(uint32_t number)
{
sys_match_number = number;
return table_find("sys", sys_match, NULL, 0);
}

View file

@ -1,59 +1,82 @@
#include <stdlib.h>
#include <fxos.h> #include <fxos.h>
#include <errors.h>
#include <string.h>
/* A linked list of pointers (either file names or tables) */ /* Up to 128 tables can be defined */
struct element #define MAX 128
static struct table db[MAX] = { 0 };
/* Number of tables currently used */
static int db_size = 0;
/* table_free(): Free a table and its contents
@t Table pointer */
static void table_free(struct table *t)
{ {
void *data; if(!t) return;
struct element *next; free(t->name);
};
/* list_append(): Append a pointer to a linked list if(t->items) for(int i = 0; i < t->count; i++)
Returns a pointer to the new node, NULL on error. */
struct element *list_append(struct element **head, void *data)
{
struct element *el = malloc(sizeof *el);
if(!el) return NULL;
el->data = data;
el->next = NULL;
while(*head) head = &((*head)->next);
*head = el;
return el;
}
/* list_free(): Free a linked list */
void list_free(struct element *head, void (*destructor)(void *))
{
struct element *next;
while(head)
{ {
destructor(head->data); t->free_item(t->items + i * t->size);
next = head->next;
free(head);
head = next;
} }
free(t->items);
} }
/* Table of assembly instruction listings */ /* table_quit(): Destroy all allocated tables and release memory */
static struct element *tasm = NULL; __attribute__((destructor))
/* Table of system call information listings */ static void table_quit(void)
static struct element *tcall = NULL;
/*
** Public API
*/
/* tables_add_asm(): Append an instruction table to the table list */
int tables_add_asm(const char *filename)
{ {
return !list_append(&tasm, (void *)filename); for(int i = 0; i < db_size; i++) table_free(&db[i]);
} }
/* tables_add_syscall(): Append a syscall table to the table list */ /* table_available(): Whether a table can be allocated */
int tables_add_syscall(const char *filename) int table_available(void)
{ {
return !list_append(&tcall, (void *)filename); return db_size < MAX;
}
/* table_create(): Create a new table */
void table_create(char const *type, char *name, void (*free_item)(void *),
int count, size_t size, void *items)
{
if(!table_available()) return;
struct table *t = &db[db_size++];
t->type = type;
t->name = name;
t->free_item = free_item;
t->count = count;
t->size = size;
t->items = items;
}
/* table_find(): Find matching entries in the database tables */
void *table_find(char const *type, int (*match)(void *), char const **name,
int next)
{
static int table = 0;
static int index = 0;
if(!next) table = index = 0;
while(table < db_size)
{
struct table const *t = &db[table];
if(!strcmp(t->type, type))
while(index < t->count)
{
void *entry = t->items + index * t->size;
index++;
if(match(entry))
{
if(name) *name = t->name;
return entry;
}
}
table++;
index = 0;
}
return NULL;
} }

View file

@ -1,10 +1,18 @@
#include <fxos.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fxos.h>
#include <errors.h>
/* integer(): Convert base 8, 10 or 16 into integers */ /* integer(): Convert base 8, 10 or 16 into integers */
long long integer(const char *str, int *error) long long integer(char const *str, int *error)
{ {
char *end; char *end;
errno = 0; errno = 0;
@ -28,3 +36,63 @@ long long integer(const char *str, int *error)
return ll; return ll;
} }
/* match_table_name(): Some specific matching on filenames */
char *match_table_name(char const *path, char const *type, char const *suffix)
{
char const *base = strrchr(path, '/');
base = (base) ? (base + 1) : (path);
size_t len = strlen(base);
size_t len_t = strlen(type);
size_t len_s = strlen(suffix);
if(len > len_t + len_s + 1
&& !strncmp(type, base, len_t)
&& base[len_t] == '-'
&& !strcmp(suffix, base + len - len_s))
{
return strndup(base + len_t + 1, len - len_t - len_s - 1);
}
return strdup(base);
}
/* map(): Map a file to memory */
void *map(char const *path, int *fd, size_t *size)
{
int x;
struct stat statbuf;
*fd = open(path, O_RDONLY);
if(*fd < 0)
{
errf(ERR_ERRNO, "cannot open file");
return NULL;
}
x = fstat(*fd, &statbuf);
if(x < 0)
{
errf(ERR_ERRNO, "cannot stat file");
close(*fd);
return NULL;
}
*size = statbuf.st_size;
void *data = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, *fd, 0);
if(data == MAP_FAILED)
{
errf(ERR_ERRNO, "cannot map file");
close(*fd);
}
return data;
}
/* unmap(): Unmap a file loaded with map() */
void unmap(void *data, int fd, size_t size)
{
munmap(data, size);
close(fd);
}

44
fxos/util.h Normal file
View file

@ -0,0 +1,44 @@
//---
// util: Utility functions
//---
#ifndef FXOS_UTIL
#define FXOS_UTIL
/* integer(): Convert base 8, 10 or 16 into integers
Prints an error message and sets *error to 1 in case of conversion error or
overflow.
@str Original integer representation ("10", "0x1f", "07")
@error Set to 1 on error, otherwise unchanged (can be NULL)
Returns result of conversion (valid if *error is not 1) */
long long integer(const char *str, int *error);
/* match_table_name(): Some specific matching on filenames
Returns the table name to associate with the file located at @path for a
table of type @type, with file suffix @suffix.
Essentially if the basename of the file at @path is on the form
{@type}-{x}{@suffix}
then an malloc'ed copy of x is returned. Otherwise an malloc'ed copy of the
basename is returned. */
char *match_table_name(char const *path, char const *type, char const *suffix);
/* map(): Map a file to memory
Maps a file given by its path to memory, and return the associated region,
a file descriptor and the size.
@path File path
@fd Will be set to fd of open file
@size Will be set to file size
Returns NULL no error, in which case the file is closed and [*fd] and
[*size] are undefined; otherwise, returns a pointer to mapped data. */
void *map(char const *path, int *fd, size_t *size);
/* unmap(): Unmap a file loaded with map()
@data Region returned by map()
@fd File descriptor set by map()
@size Size set by map() */
void unmap(void *data, int fd, size_t size);
#endif /* FXOS_UTIL */