Emulating Digicam with QEMU - General Discussion and Assistance - CHDK Forum

Emulating Digicam with QEMU

  • 51 Replies
  • 45941 Views
*

Offline chr

  • ***
  • 138
  • IXUS 82 IS
Emulating Digicam with QEMU
« on: 13 / July / 2008, 14:18:16 »
Advertisements
Hi Volx!

There's some trouble getting inside the latest cameras. To dump the SD1100 I investigated a dump from 860is.
We know nothing about the .fi2 files and we need diskboot.bin files on acid.

To find out more about the boot process I simply run the firmware in qemu.

I wrote some documentation how I did it in the wiki: GPL Tools - CHDK Wiki . However, the wiki is not sufficient for exchanging code pieces so I attach that here.

So far it's just a basic ARM board setup with some memory, I/O and a binary loader. I hope, we can extend it. SD cardreader and USB support is available in qemu. I don't have a cam with chdk running, yet. So this is pure guesswork with the information from this forum.



« Last Edit: 13 / July / 2008, 15:02:15 by chr »

*

Offline chr

  • ***
  • 138
  • IXUS 82 IS
diskboot.bin massage
« Reply #1 on: 13 / July / 2008, 14:18:42 »
Latest Canon Cams refuses to boot our stuff. Naughty naughty naughty!
I'm running now the 860is firmware in qemu.

Handling the diskboot.bin starts at 0xff82bb44

At 0xff8650cc it becomes interesting:
Problems dumping the SD1100IS/IXUS80IS

The first byte must be 0x00 and it must not contain "gaonisoy". Next, it shifts the file 1 byte down.
At 0xff865008 we have the following situation: r0=r1=*file and r2=length.

What's happening there? Let's find out. First we make a macro in gdb:

define dekkode
x $r0=$r1=0x3000
x $r2=$arg0
j *0xff865008
x/16x 0x3000
end

and set a breakpoint at the end of this stuff:

b *0xff8650c8

On fresh bootup, 0x3000 is free:

(gdb) x/8x 0x3000
0x3000: 0x00000000      0x00000000      0x00000000      0x00000000
0x3010: 0x00000000      0x00000000      0x00000000      0x00000000

Let's run the decoder on these zeros:

(gdb) dekkode 64
0x3000: 0x00000000
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0x00ffffa0      0xffa0ffff      0xffff00ff      0x00ffffa0
0x3010: 0xffa0ffff      0xffff00ff      0x00ffffa0      0xffa0ffff
0x3020: 0xffff00ff      0x00ffffa0      0xffa0ffff      0xffff00ff
0x3030: 0x00ffffa0      0xffa0ffff      0xffff00ff      0x00ffffa0

Hu? Looks like tic tac toe, 96bits.
Press Return to rerun another round:

(gdb)
0x3000: 0x00ffffa0
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0x0a005f5f      0xff5f0000      0x00ffff5f      0xff0000a0
0x3010: 0x005f0000      0x00ff0a00      0x0a005f5f      0xff5f0000
0x3020: 0x00ffff5f      0xff0000a0      0x005f0000      0x00ff0a00
0x3030: 0x0a005f5f      0xff5f0000      0x00ffff5f      0xff0000a0

another:

(gdb)
0x3000: 0x0a005f5f
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0xf5a0a0a0      0xf5a0ff00      0xa000005f      0x00ff005f
0x3010: 0xffa000ff      0xfff5f5ff      0xf5a0a0a0      0xf5a0ff00
0x3020: 0xa000005f      0x00ff005f      0xffa000ff      0xfff5f5ff
0x3030: 0xf5a0a0a0      0xf5a0ff00      0xa000005f      0x00ff005f

and another:

(gdb)
0x3000: 0xf5a0a0a0
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0x0a5f5fa0      0x0a5f5f0a      0xa0ffffa0      0x0affffa0
0x3010: 0x00a00a00      0x000a0a00      0x0a5f5fa0      0x0a5f5f0a
0x3020: 0xa0ffffa0      0x0affffa0      0x00a00a00      0x000a0a00
0x3030: 0x0a5f5fa0      0x0a5f5f0a      0xa0ffffa0      0x0affffa0

Hey, it's free, so take another trip:

(gdb)
0x3000: 0x0a5f5fa0
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0x0aa0a0aa      0xf5ffa0f5      0x5f00ff5f      0x0a0000aa
0x3010: 0xffaaf5ff      0xfff50aff      0x0aa0a0aa      0xf5ffa0f5
0x3020: 0x5f00ff5f      0x0a0000aa      0xffaaf5ff      0xfff50aff
0x3030: 0x0aa0a0aa      0xf5ffa0f5      0x5f00ff5f      0x0a0000aa

(gdb)
0x3000: 0x0aa0a0aa
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0xaa5f0055      0xf5005f0a      0xa0000055      0xf5ffffaa
0x3010: 0x00550a00      0x00f5aa00      0xaa5f0055      0xf5005f0a
0x3020: 0xa0000055      0xf5ffffaa      0x00550a00      0x00f5aa00
0x3030: 0xaa5f0055      0xf5005f0a      0xa0000055      0xf5ffffaa

(gdb)
0x3000: 0xaa5f0055
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0x55ffffaa      0x55ffa00a      0xaaffff55      0x0a00ff55
0x3010: 0xffaa0aff      0xff5555ff      0x55ffffaa      0x55ffa00a
0x3020: 0xaaffff55      0x0a00ff55      0xffaa0aff      0xff5555ff
0x3030: 0x55ffffaa      0x55ffa00a      0xaaffff55      0x0a00ff55

(gdb)
0x3000: 0x55ffffaa
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0xaa0000aa      0xaa0000aa      0xaa0000aa      0xaa0000aa
0x3010: 0x00aaaa00      0x00aaaa00      0xaa0000aa      0xaa0000aa
0x3020: 0xaa0000aa      0xaa0000aa      0x00aaaa00      0x00aaaa00
0x3030: 0xaa0000aa      0xaa0000aa      0xaa0000aa      0xaa0000aa

(gdb)
0x3000: 0xaa0000aa
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0xaaffff0a      0x55a0ff55      0x55ff0055      0xaaffff0a
0x3010: 0xff0a55ff      0xff55aaff      0xaaffff0a      0x55a0ff55
0x3020: 0x55ff0055      0xaaffff0a      0xff0a55ff      0xff55aaff
0x3030: 0xaaffff0a      0x55a0ff55      0x55ff0055      0xaaffff0a

(gdb)
0x3000: 0xaaffff0a
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0xa0005ff5      0x555f00aa      0xaafffff5      0x5500000a
0x3010: 0x00f5aa00      0x0055a000      0xa0005ff5      0x555f00aa
0x3020: 0xaafffff5      0x5500000a      0x00f5aa00      0x0055a000
0x3030: 0xa0005ff5      0x555f00aa      0xaafffff5      0x5500000a

(gdb)
0x3000: 0xa0005ff5
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0x5fa0a00a      0x5fa0ffaa      0x0a0000f5      0xaaff00f5
0x3010: 0xff0aaaff      0xff5f5fff      0x5fa0a00a      0x5fa0ffaa
0x3020: 0x0a0000f5      0xaaff00f5      0xff0aaaff      0xff5f5fff
0x3030: 0x5fa0a00a      0x5fa0ffaa      0x0a0000f5      0xaaff00f5

(gdb)
0x3000: 0x5fa0a00a
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0xa05f5f0a      0xa05f5fa0      0x0affff0a      0xa0ffff0a
0x3010: 0x000aa000      0x00a0a000      0xa05f5f0a      0xa05f5fa0
0x3020: 0x0affff0a      0xa0ffff0a      0x000aa000      0x00a0a000
0x3030: 0xa05f5f0a      0xa05f5fa0      0x0affff0a      0xa0ffff0a

(gdb)
0x3000: 0xa05f5f0a
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0xa0a0a000      0x5fffa05f      0xf500fff5      0xa0000000
0x3010: 0xff005fff      0xff5fa0ff      0xa0a0a000      0x5fffa05f
0x3020: 0xf500fff5      0xa0000000      0xff005fff      0xff5fa0ff
0x3030: 0xa0a0a000      0x5fffa05f      0xf500fff5      0xa0000000

(gdb)
0x3000: 0xa0a0a000
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0x005f00ff      0x5f005fa0      0x0a0000ff      0x5fffff00
0x3010: 0x00ffa000      0x005f0000      0x005f00ff      0x5f005fa0
0x3020: 0x0a0000ff      0x5fffff00      0x00ffa000      0x005f0000
0x3030: 0x005f00ff      0x5f005fa0      0x0a0000ff      0x5fffff00

(gdb)
0x3000: 0x005f00ff
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0xffffff00      0xffffa0a0      0x00ffffff      0xa000ffff
0x3010: 0xff00a0ff      0xffffffff      0xffffff00      0xffffa0a0
0x3020: 0x00ffffff      0xa000ffff      0xff00a0ff      0xffffffff
0x3030: 0xffffff00      0xffffa0a0      0x00ffffff      0xa000ffff

(gdb)
0x3000: 0xffffff00
0x40:   0x00000000

Breakpoint 1, 0xff8650c8 in _binary_ixus860is_dump_start ()
0x3000: 0x00000000      0x00000000      0x00000000      0x00000000
0x3010: 0x00000000      0x00000000      0x00000000      0x00000000
0x3020: 0x00000000      0x00000000      0x00000000      0x00000000
0x3030: 0x00000000      0x00000000      0x00000000      0x00000000

 :-* :lol :haha :P :D :lol :haha :P :lol :-* :haha :lol  :-* :lol :haha :P :D :lol :haha :P :lol :-* :haha :lol

So here we go. Encoding a diskboot.bin is simply decoding it 15 times:


(gdb) restore led/diskboot.bin binary 0x3000
Restoring binary file led/diskboot.bin into memory (0x3000 to 0x3088)

(gdb) dekkode 0x100
repeat 15 times

(gdb) dump memory outfile.bin 0x3000-1 0x3000+0x19000

The last commands writes out from 0x2fff, which is hopefully still 0x00 and we write out more so we have the necessary padding.

Pressing return 15 times is a matter of practise. So run the last round and you should see the unencoded binary again:

(gdb) dekkode 0x100

« Last Edit: 13 / July / 2008, 16:48:38 by chr »

*

Offline fudgey

  • *****
  • 1705
  • a570is
Re: Emulating Digicam with QEMU
« Reply #2 on: 26 / July / 2008, 15:43:12 »
I wrote a little shell script to make the disassembly from these tools http://chdk.wikia.com/wiki/Gpl_Disassembling a little bit easier to follow (unless I've understood something wrong...). Basically it goes thru dump.dis and dump.strings and combines them by modifying each line that has an ldr instruction such as this one:

ffea4f84:      e59f1050        ldr     r1, [pc, #80]   ; ffea4fdc <_binary_dump_bin_start+0x2a4fdc>

into something like this:

ffea4f84:       e59f1050        ldr     r1, [pc, #80]   ; ffea4fdc VALUE:<ffea4f64> STRING:<SSAPI::EnterToCompensationEVF>

i.e. it digs the value at ROM address pc+80=ffea4fdc and adds it to the comment (in this case for a570is 1.00e it is 0xffea4f64, useful if it isn't a string but for instance a RAM address), and if the dump.strings file has a line with an address equaling this value, it adds the string to the comment as well (in this case "SSAPI::EnterToCompensationEVF").

The bad news is that this quick hack turned out to be extremely slow, seems to take like a day to process a single disassembly on my computer :o... so if someone finds this useful, please make better one. :)  Processing small parts is obviously fast enough.

And in case the output formatting of different tools differs, I used
arm-elf-objdump --version
GNU objdump (GNU Binutils) 2.18

strings --version
GNU strings (GNU Binutils for Debian) 2.18.0.20080103

Code: [Select]
#!/bin/sh
### addstrings.sh
### Add strings and values to a firmware dump dissassembly

if [ -z "$1" ]; then
  echo "usage:"
  echo "cat dump.dis | ./addstrings.sh dump.strings dump.dis > dump.diss"
  exit 0
fi

STRINGSFILE=$1
DISFILE=$2

# empty separator list for read, otherwise it removes whitespaces
IFS=""

while [ "$eof_found" != "1" ]; do
  read -n 1024 row
  eof_found=$?
  # process rows which have an ldr assembler command and something that looks like <_binary_dump_bin_start+0x178>
  ldr=`echo "$row" | grep ldr | grep "start+" | wc -l | tr -c -d 0-9`
  if [ "$ldr" = "1" ]; then
    # remove that <...start+0x...> thing: from line end:
    row=`echo $row | cut -d '<' -f 1 `
    # extract string pointer:
    pntraddr=`echo $row | cut -d ';' -f 2 | tr -c -d '0-9a-f\n'`
   
    echo -n $row

    # print the value in hex as it may be an interesting RAM address if there is no
    # string or the string is not a real string but just something the filter passed thru.
    value=`grep "$pntraddr:" $DISFILE | cut -f 2 | tr -c -d 0-9a-f`
    echo -n "VALUE:<"$value">"

   # search the strings file for a match at our address (if we have an address):
    if [ "$value" != "" ]; then
      gout=`grep $value $STRINGSFILE`
      rv=$?
      if [ "$rv" == "0" ]; then
        # string found
        string=`echo $gout|cut -d ' ' -f 2-`
        echo -n " STRING:<"$string">"
      fi
    fi
    # line feed
    echo
  else
    # pass thru other rows
    echo "$row"
  fi
done


edit: oops...fixed the script, changed the example...
edit 2: krhm...fixed the script again
« Last Edit: 27 / July / 2008, 07:54:37 by fudgey »

*

Offline chr

  • ***
  • 138
  • IXUS 82 IS
Re: Emulating Digicam with QEMU
« Reply #3 on: 28 / July / 2008, 11:09:16 »
The bad news is that this quick hack turned out to be extremely slow, seems to take like a day to process a single disassembly on my computer :o... so if someone finds this useful, please make better one. :)  Processing small parts is obviously fast enough.

I also have this "slowness". I found out, it only happens sometimes when gdb is in tui mode.
Switch to cmd mode (ctrl-x a) and it runs fine!

I guess ... it's maybe the incomplete symbol table and gdb calculates the offsets for the display on each step.

Hope to have some time the next days to look at your script and continue hacking:
I think about patching objcopy so we can put the symbols in the elf file. qemu can load elf too but it did not work for me.


*

Offline PhyrePhoX

  • *****
  • 2254
  • make RAW not WAR
    • PhyreWorX
Re: Emulating Digicam with QEMU
« Reply #4 on: 28 / July / 2008, 11:12:53 »
funny, when you make a search on google for "disassembling arm on linux" the first page you find is the chdk wiki, your page :D
good luck!

*

Offline fudgey

  • *****
  • 1705
  • a570is
Re: Emulating Digicam with QEMU
« Reply #5 on: 28 / July / 2008, 11:20:47 »
I also have this "slowness". I found out, it only happens sometimes when gdb is in tui mode.
Switch to cmd mode (ctrl-x a) and it runs fine!

The script isn't actually qemu related in any way, it just makes the disassembly a bit easier to read when searching for stuff manually.

*

Offline fudgey

  • *****
  • 1705
  • a570is
Re: Emulating Digicam with QEMU
« Reply #6 on: 28 / July / 2008, 12:59:56 »
One more script to help the lives of poor developers. If you have the necessary arm-elf tools and a CHDK source tree with firmware dumps all set, this script finds all the dumps and disassembles them for you. It requires platform/*/sub/*/makefile.inc to exist, because it fetches ROMBASEADDR from there. Otherwise it will not disassemble.

So this isn't really meant to help porting CHDK to new cameras, it's meant to help people who have developed a new feature for their camera to port the new feature to other models as well.

Code: [Select]
#!/bin/sh

### This script disassembles all firmwared dumps in it's reach using
### arm-elf-objdump and arm-elf-objcopy. You need chr's renumber.pl from
###
### [url=http://chdk.wikia.com/wiki/Gpl_renumber.pl]Gpl renumber.pl - CHDK Wiki[/url]
###
### and you will want to read
###
### [url=http://chdk.wikia.com/wiki/GPL_Tools]GPL Tools - CHDK Wiki[/url].
###
### Run the script in trunk/platform with firmware dumps in their
### respective subdirecories, named PRIMARY.BIN or primary.bin.

### uncomment and set path to your arm-elf binaries here if
### they are not in your path:
#export PATH=/usr/local/arm-elf/bin:$PATH

### path to renumber.pl
RENUMBER_PATH=.

disassemble ()
{
  echo -n "disassembling $fwdump: strings..."
  strings -t x $fwdump | $RENUMBER_PATH/renumber.pl 0x$ROMBASEADDR > $p/primary.strings
#  echo -n hexdump...
#  hexdump -C $fwdump |$RENUMBER_PATH/renumber.pl 0x$ROMBASEADDR > $p/primary.hex
  echo -n objcopy...
  arm-elf-objcopy --change-addresses=0x$ROMBASEADDR -I binary -O elf32-littlearm -B arm $fwdump $p/primary.elf
  arm-elf-objcopy --set-section-flags .data=code $p/primary.elf
  echo -n objdump...
#  arm-elf-objdump -x dump.elf
  arm-elf-objdump -d $p/primary.elf > $p/primary.dis
  echo done.
}

# loop thru all sub-platforms
for p in */sub/*; do
  fwdump=""
  # if makefile.inc exists and is readable
  if [ -r $p/makefile.inc ]; then
    # get ROMBASEADDR from makefile.inc
    ROMBASEADDR=`grep ROMBASEADDR $p/makefile.inc | cut -f 2 -d '=' | tr -c -d 0-9a-fA-F`
    echo -n "$p: ROMBASEADDR=$ROMBASEADDR, "
    # if a non-zero firmware dump exists:
    if [ -s $p/PRIMARY.BIN ]; then
      fwdump=$p/PRIMARY.BIN
    elif [ -s $p/primary.bin ]; then
      fwdump=$p/primary.bin
    fi
    if [ "$fwdump" == "" ]; then
      echo no non-zero PRIMARY.BIN or primary.bin found.
    elif [ -r $fwdump ]; then
      disassemble
    else
      echo $fwdump found but unreadable.
    fi
  fi
done


Hmm... the forum apparently wans to add some ugly url tags to my precious comments. Never mind them.

*

Offline chr

  • ***
  • 138
  • IXUS 82 IS
Re: Emulating Digicam with QEMU
« Reply #7 on: 31 / July / 2008, 20:45:44 »
Hi!

Just about slowness ... *g* inspired by fudgey's script, here's my perl version. It creates strings, disassemble, renumbers and looks up strings. Also it processes "add/sub r0, pc, #744" instructions.

And it's quite fast: 30s on a 2.4GHZ ;)

example output:

ff936a40:   e59f12e8    ldr r1, [pc, #744]  ; ff936d30: (0xff81d88c)
ff936a44:   e28f0fba    add r0, pc, #744    ; ff936d34: (0x63727473)  "strcpy"
ff936a48:   ebfccc5a    bl  ff869bb8 <_binary_dump_bin_start+0x59bb8>
ff936a4c:   e59f12e8    ldr r1, [pc, #744]  ; ff936d3c: (0xff81d8e8)
ff936a50:   e28f0fba    add r0, pc, #744    ; ff936d40: (0x6c727473)  "strlen"
ff936a54:   ebfccc57    bl  ff869bb8 <_binary_dump_bin_start+0x59bb8>
ff936a58:   e59f12e8    ldr r1, [pc, #744]  ; ff936d48: (0xff81d8a4)
ff936a5c:   e28f0fba    add r0, pc, #744    ; ff936d4c: (0x63727473)  "strcmp"
ff936a60:   ebfccc54    bl  ff869bb8 <_binary_dump_bin_start+0x59bb8>


*

Offline fudgey

  • *****
  • 1705
  • a570is
Re: Emulating Digicam with QEMU
« Reply #8 on: 01 / August / 2008, 04:00:32 »
Cool, I was hoping someone would make a speedier thing :) But is it working as intended? I can't find any strings after ldr or add instructions, just as comments before the strings themselves (a570is 1.00e):

From my script:
Code: [Select]
ffea4f64:       50415353        subpl   r5, r1, r3, asr r3
ffea4f68:       453a3a49        ldrmi   r3, [sl, #-2633]!
ffea4f6c:       7265746e        rsbvc   r7, r5, #1845493760     ; 0x6e000000
ffea4f70:       6f436f54        svcvs   0x00436f54
ffea4f74:       6e65706d        cdpvs   0, 6, cr7, cr5, cr13, {3}
ffea4f78:       69746173        ldmdbvs r4!, {r0, r1, r4, r5, r6, r8, sp, lr}^
ffea4f7c:       56456e6f        strbpl  r6, [r5], -pc, ror #28
ffea4f80:       00000046        andeq   r0, r0, r6, asr #32
ffea4f84:       e59f1050        ldr     r1, [pc, #80]   ; ffea4fdc VALUE:<ffea4f64> STRING:<SSAPI::EnterToCompensationEVF>
ffea4f88:       e3a00020        mov     r0, #32 ; 0x20

From your script:
Code: [Select]
"SSAPI::EnterToCompensationEVF":
ffea4f64:       50415353        subpl   r5, r1, r3, asr r3
ffea4f68:       453a3a49        ldrmi   r3, [sl, #-2633]!
ffea4f6c:       7265746e        rsbvc   r7, r5, #1845493760     ; 0x6e000000
ffea4f70:       6f436f54        svcvs   0x00436f54
ffea4f74:       6e65706d        cdpvs   0, 6, cr7, cr5, cr13, {3}
ffea4f78:       69746173        ldmdbvs r4!, {r0, r1, r4, r5, r6, r8, sp, lr}^
ffea4f7c:       56456e6f        strbpl  r6, [r5], -pc, ror #28
ffea4f80:       00000046        andeq   r0, r0, r6, asr #32
ffea4f84:       e59f1050        ldr     r1, [pc, #80]   ; ffea4fdc: (0xffea4f64)
ffea4f88:       e3a00020        mov     r0, #32 ; 0x20

*

Offline chr

  • ***
  • 138
  • IXUS 82 IS
Re: Emulating Digicam with QEMU
« Reply #9 on: 01 / August / 2008, 10:24:57 »
Cool, I was hoping someone would make a speedier thing :) But is it working as intended? I can't find any strings after ldr or add instructions, just as comments before the strings themselves (a570is 1.00e):
The comments are intended. But you can't find any strings after ldr/add/sub ???

However, the difference is:

ff936a5c:   e28f0fba    add r0, pc, #744    ; ff936d4c: (0x63727473)  "strcmp"

Is a pointer to string, and this

ffea4f84:       e59f1050        ldr     r1, [pc, #80]   ; ffea4fdc VALUE:<ffea4f64> STRING:<SSAPI::EnterToCompensationEVF>

is pointer to pointer ... my script doesn't look up that, yet. But should easy to hack. I haven't thought about this.

Any more ideas for the next script version? ;)

 

Related Topics