I imagine the structure and implementation of these scope's firmware will be very, very similar between versions and models. All the info I present is based on my own TDS744A with 1.1e firmware.
************** ROM header
Yay, the main ROM has a header with meaningful metadata !
It looks like this :
// the sizeof() for this is 0x2C (determined by checksum code in kernel ROM)
struct flashhdr_short {
u8 jmp_trampoline[8]; // "nop", then "jmp _romInit"
u32 cksum_body_start; //ptr to beginning of body area to sum
u32 idata_start; // initial vals for _sdata in RAM
u32 sdata; //addr of _sdata in RAM
u32 bss_start; //also end of _sdata area
u32 cksum_body; //32-bit checkum of body area
u8 unknown[6];
u8 padding[8]; //always 0xFF bytes ?
u16 cksum_hdr; //checksum of this header
};
************* Boot process (main ROM startup)
Part of the boot process goes like this :
- the kernel ROM jumps to the main ROM jmp "trampoline" (at 0x100 0000). This jumps to
- _romInit : does some basic ROM / RAM checks, including calling _InitDataSpace. Then passes control to _usrInit.
- _InitDataSpace : short function that initializes the "_sdata" section in RAM with data from the ROM's idata section; also clears the bss section in RAM.
- _usrInit : preps the interrupt and exception vectors, then calls _kernelInit . Note ! starting here, "kernel" refers to the VxWorks kernel and not the one that ran on initial power up. This function initializes Vx with a new task :
- _usrRoot ; things get interesting. It calls some interesting functions like _led_walk, _bumpLed, _symTblAdd (more on this later) , _printLogo ( !) and others. Then things branch out a lot due to the use of _taskSpawn .
************* symbol table
It took me a while to figure all this out, but here's some information that will
make the process easier when analyzing a new ROM.
ROM format : as we know the main ROM is mapped at 0x0100 0000 in the address
space. This must be kept in mind when looking at the raw data. For instance,
to be able to parse the ROM's built-in symbol table. This table
is the golden key : it associates a readable name to many, many functions and variables.
Each symbol item looks like this :
struct sym_item {
u32 unknown_0; //always 0 ?
u32 pName; //point to string
u32 pItem; //point to actual item (function or variable)
u8 type; //not 100% sure. 5 = code, 7 = idata, 9 = bss data ?
u8 unknown_1; //always 0 ?
};
Here's an example :
00 00 00 00 01 27 3E 6D 01 1E 0D 9E 05 00
pName = 0x0127 3E6D , if we look inside the ROM at 0x273E6D, there's a string "_validateBootRomHeader"
pItem = 0x011E 0D9E, this is the entry point of that function.
type = 5, by now I'm pretty sure 5 means code, 7 and 9 are variables in RAM.
This symbol table is huge (5300 entries on my ROM) and quite conspicuous;
moreover its location at the end of the .idata section makes it pretty easy to find.
Allow me to save a thousand words :
Location in address space
(= ROM file offset + 0x0100 000)
+-------------------------------------+
| ROM image header | 0x0100 0000
+-------------------------------------+
| copyright strings | 0x0100 002C
| |
| |
+-------------------------------------+
| .text | | 0x0100 01AA : _startChecksumming
| | some code |
| | "VROM" chunk |
| | |
| | more code |
| | |
| | |
| | strings for each symbol |
| | (not copied to RAM) |
| | |
| | |
+-------------------------------------+
| .idata | generic data | 0x12750AA
| | |
| | |
| +----------------------------+
| | symlist[num_of_entries] | 0x0129 92E8
| | |
| +----------------------------+
| | sym_num_of_entries | 0x012A B474
+-------------------------------------+
| empty (0xFF) | 0x012A B47C
| |
| |
| |
+-------------------------------------+ 0x013F FFFF
*************
I think that's enough writing for today.
I'd love to hear from anyone else looking at these ROMs !